Add "codec-data" property for additional codec data.
authorgb <gb@5584edef-b1fe-4b99-b61b-dd2bab72e969>
Wed, 28 Apr 2010 21:50:44 +0000 (21:50 +0000)
committerGwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Mon, 20 Sep 2010 10:55:32 +0000 (12:55 +0200)
e.g. VC-1 sequence headers for elementary streams.

gst-libs/gst/vaapi/gstvaapidecoder.c
gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.c
gst-libs/gst/vaapi/gstvaapidecoder_ffmpeg.h
gst-libs/gst/vaapi/gstvaapidecoder_priv.h
tests/test-decode.c

index d9e17eb..a2d9400 100644 (file)
@@ -42,6 +42,7 @@ enum {
 
     PROP_DISPLAY,
     PROP_CODEC,
+    PROP_CODEC_DATA
 };
 
 static gboolean
@@ -163,6 +164,20 @@ pop_buffer(GstVaapiDecoder *decoder)
     return buffer;
 }
 
+static inline void
+set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+    if (priv->codec_data) {
+        gst_buffer_unref(priv->codec_data);
+        priv->codec_data = NULL;
+    }
+
+    if (codec_data)
+        priv->codec_data = gst_buffer_ref(codec_data);
+}
+
 static void
 clear_async_queue(GAsyncQueue *q)
 {
@@ -180,6 +195,8 @@ gst_vaapi_decoder_finalize(GObject *object)
 
     gst_vaapi_decoder_stop(decoder);
 
+    set_codec_data(decoder, NULL);
+
     if (priv->context) {
         g_object_unref(priv->context);
         priv->context = NULL;
@@ -222,6 +239,9 @@ gst_vaapi_decoder_set_property(
     case PROP_CODEC:
         priv->codec = g_value_get_uint(value);
         break;
+    case PROP_CODEC_DATA:
+        set_codec_data(GST_VAAPI_DECODER(object), gst_value_get_buffer(value));
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -245,6 +265,9 @@ gst_vaapi_decoder_get_property(
     case PROP_CODEC:
         g_value_set_uint(value, priv->codec);
         break;
+    case PROP_CODEC_DATA:
+        gst_value_set_buffer(value, priv->codec_data);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -284,6 +307,15 @@ gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
                            "The codec handled by the decoder",
                            0, G_MAXINT32, 0,
                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property
+        (object_class,
+         PROP_CODEC_DATA,
+         gst_param_spec_mini_object("codec-data",
+                                    "Codec data",
+                                    "Extra codec data",
+                                    GST_TYPE_BUFFER,
+                                    G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
 }
 
 static void
@@ -294,6 +326,7 @@ gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
     decoder->priv               = priv;
     priv->context               = NULL;
     priv->codec                 = 0;
+    priv->codec_data            = NULL;
     priv->fps_n                 = 1000;
     priv->fps_d                 = 30;
     priv->next_ts               = 0;
index eae18eb..6361eaf 100644 (file)
@@ -234,6 +234,7 @@ gst_vaapi_decoder_ffmpeg_destroy(GstVaapiDecoderFfmpeg *ffdecoder)
     }
 
     if (priv->avctx) {
+        av_freep(&priv->avctx->extradata);
         avcodec_close(priv->avctx);
         priv->avctx = NULL;
     }
@@ -252,6 +253,7 @@ gst_vaapi_decoder_ffmpeg_create(GstVaapiDecoderFfmpeg *ffdecoder)
     GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(ffdecoder);
     GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
     GstVaapiCodec codec = GST_VAAPI_DECODER_CODEC(decoder);
+    GstBuffer * const codec_data = GST_VAAPI_DECODER_CODEC_DATA(decoder);
     enum CodecID codec_id;
     AVCodec *ffcodec;
 
@@ -275,6 +277,18 @@ gst_vaapi_decoder_ffmpeg_create(GstVaapiDecoderFfmpeg *ffdecoder)
             return FALSE;
     }
 
+    if (codec_data) {
+        const guchar *data = GST_BUFFER_DATA(codec_data);
+        const guint   size = GST_BUFFER_SIZE(codec_data);
+        av_freep(&priv->avctx->extradata);
+        priv->avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+        if (!priv->avctx->extradata)
+            return FALSE;
+        priv->avctx->extradata_size = size;
+        memcpy(priv->avctx->extradata, data, size);
+        memset(priv->avctx->extradata + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+    }
+
     if (!priv->vactx) {
         priv->vactx = g_new(GstVaapiContextFfmpeg, 1);
         if (!priv->vactx)
@@ -436,21 +450,25 @@ gst_vaapi_decoder_ffmpeg_init(GstVaapiDecoderFfmpeg *decoder)
  * gst_vaapi_decoder_ffmpeg_new:
  * @display: a #GstVaapiDisplay
  * @codec: a #GstVaapiCodec
+ * @codec_data: an optional #GstBuffer holding extra codec data, or %NULL
  *
  * Creates a new #GstVaapiDecoder with the specified @codec bound to
- * @display. If @codec is zero, the first video stream will be
- * selected. Otherwise, the first video stream matching @codec is
- * used, if any.
+ * @display. @codec_data holds extra codec data like sequence headers.
  *
  * Return value: the newly allocated #GstVaapiDecoder object
  */
 GstVaapiDecoder *
-gst_vaapi_decoder_ffmpeg_new(GstVaapiDisplay *display, GstVaapiCodec codec)
+gst_vaapi_decoder_ffmpeg_new(
+    GstVaapiDisplay *display,
+    GstVaapiCodec    codec,
+    GstBuffer       *codec_data
+)
 {
     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
 
     return g_object_new(GST_VAAPI_TYPE_DECODER_FFMPEG,
-                        "display", display,
-                        "codec",   codec,
+                        "display",    display,
+                        "codec",      codec,
+                        "codec-data", codec_data,
                         NULL);
 }
index 184759a..487a9a6 100644 (file)
@@ -79,7 +79,11 @@ GType
 gst_vaapi_decoder_ffmpeg_get_type(void);
 
 GstVaapiDecoder *
-gst_vaapi_decoder_ffmpeg_new(GstVaapiDisplay *display, GstVaapiCodec codec);
+gst_vaapi_decoder_ffmpeg_new(
+    GstVaapiDisplay *display,
+    GstVaapiCodec    codec,
+    GstBuffer       *codec_data
+);
 
 G_END_DECLS
 
index 146c760..e5f87e6 100644 (file)
@@ -63,6 +63,18 @@ G_BEGIN_DECLS
 #define GST_VAAPI_DECODER_CODEC(decoder) \
     GST_VAAPI_DECODER_CAST(decoder)->priv->codec
 
+/**
+ * GST_VAAPI_DECODER_CODEC_DATA:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the #GstBuffer holding optional codec data
+ * for @decoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_CODEC_DATA
+#define GST_VAAPI_DECODER_CODEC_DATA(decoder) \
+    GST_VAAPI_DECODER_CAST(decoder)->priv->codec_data
+
 /* End-of-Stream buffer */
 #define GST_BUFFER_FLAG_EOS (GST_BUFFER_FLAG_LAST + 0)
 
@@ -78,6 +90,7 @@ struct _GstVaapiDecoderPrivate {
     GstVaapiDisplay            *display;
     GstVaapiContext            *context;
     GstVaapiCodec               codec;
+    GstBuffer                  *codec_data;
     guint                       fps_n;
     guint                       fps_d;
     GstClockTime                next_ts;
index 7702f60..f076ec1 100644 (file)
@@ -114,7 +114,7 @@ main(int argc, char *argv[])
         g_error("could not create window");
 
     codec->get_video_data(&vdata, &vdata_size);
-    decoder = gst_vaapi_decoder_ffmpeg_new(display, codec->codec);
+    decoder = gst_vaapi_decoder_ffmpeg_new(display, codec->codec, NULL);
     if (!decoder)
         g_error("could not create FFmpeg decoder");