videodecoder: Add transform_meta() vfunc with default implementation
authorSebastian Dröge <sebastian@centricular.com>
Mon, 29 Jun 2015 13:58:38 +0000 (15:58 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 30 Jun 2015 08:40:09 +0000 (10:40 +0200)
The default implementation copies all metadata without tags, and metadata
with only the video tag. Same behaviour as in GstVideoFilter.

This currently does not work if the ::parse() vfunc is implemented as all
metas are getting lost inside GstAdapter.

https://bugzilla.gnome.org/show_bug.cgi?id=742385

gst-libs/gst/video/gstvideodecoder.c
gst-libs/gst/video/gstvideodecoder.h

index fc7b8b7..7128580 100644 (file)
@@ -468,6 +468,9 @@ static gboolean gst_video_decoder_sink_query_default (GstVideoDecoder * decoder,
 static gboolean gst_video_decoder_src_query_default (GstVideoDecoder * decoder,
     GstQuery * query);
 
+static gboolean gst_video_decoder_transform_meta_default (GstVideoDecoder *
+    decoder, GstVideoCodecFrame * frame, GstMeta * meta);
+
 /* we can't use G_DEFINE_ABSTRACT_TYPE because we need the klass in the _init
  * method to get to the padtemplates */
 GType
@@ -523,6 +526,7 @@ gst_video_decoder_class_init (GstVideoDecoderClass * klass)
   klass->negotiate = gst_video_decoder_negotiate_default;
   klass->sink_query = gst_video_decoder_sink_query_default;
   klass->src_query = gst_video_decoder_src_query_default;
+  klass->transform_meta = gst_video_decoder_transform_meta_default;
 }
 
 static void
@@ -2834,6 +2838,67 @@ gst_video_decoder_drop_frame (GstVideoDecoder * dec, GstVideoCodecFrame * frame)
   return GST_FLOW_OK;
 }
 
+static gboolean
+gst_video_decoder_transform_meta_default (GstVideoDecoder *
+    decoder, GstVideoCodecFrame * frame, GstMeta * meta)
+{
+  const GstMetaInfo *info = meta->info;
+  const gchar *const *tags;
+
+  tags = gst_meta_api_type_get_tags (info->api);
+
+  if (!tags || (g_strv_length ((gchar **) tags) == 1
+          && gst_meta_api_type_has_tag (info->api,
+              g_quark_from_string (GST_META_TAG_VIDEO_STR))))
+    return TRUE;
+
+  return FALSE;
+}
+
+typedef struct
+{
+  GstVideoDecoder *decoder;
+  GstVideoCodecFrame *frame;
+} CopyMetaData;
+
+static gboolean
+foreach_metadata (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
+{
+  CopyMetaData *data = user_data;
+  GstVideoDecoder *decoder = data->decoder;
+  GstVideoDecoderClass *klass = GST_VIDEO_DECODER_GET_CLASS (decoder);
+  GstVideoCodecFrame *frame = data->frame;
+  const GstMetaInfo *info = (*meta)->info;
+  gboolean do_copy = FALSE;
+
+  if (GST_META_FLAG_IS_SET (*meta, GST_META_FLAG_POOLED)) {
+    /* never call the transform_meta with pool private metadata */
+    GST_DEBUG_OBJECT (decoder, "not copying pooled metadata %s",
+        g_type_name (info->api));
+    do_copy = FALSE;
+  } else if (gst_meta_api_type_has_tag (info->api, _gst_meta_tag_memory)) {
+    /* never call the transform_meta with memory specific metadata */
+    GST_DEBUG_OBJECT (decoder, "not copying memory specific metadata %s",
+        g_type_name (info->api));
+    do_copy = FALSE;
+  } else if (klass->transform_meta) {
+    do_copy = klass->transform_meta (decoder, frame, *meta);
+    GST_DEBUG_OBJECT (decoder, "transformed metadata %s: copy: %d",
+        g_type_name (info->api), do_copy);
+  }
+
+  /* we only copy metadata when the subclass implemented a transform_meta
+   * function and when it returns %TRUE */
+  if (do_copy) {
+    GstMetaTransformCopy copy_data = { FALSE, 0, -1 };
+    GST_DEBUG_OBJECT (decoder, "copy metadata %s", g_type_name (info->api));
+    /* simply copy then */
+    info->transform_func (frame->output_buffer, *meta, inbuf,
+        _gst_meta_transform_copy, &copy_data);
+  }
+  return TRUE;
+}
+
 /**
  * gst_video_decoder_finish_frame:
  * @decoder: a #GstVideoDecoder
@@ -2855,6 +2920,7 @@ gst_video_decoder_finish_frame (GstVideoDecoder * decoder,
     GstVideoCodecFrame * frame)
 {
   GstFlowReturn ret = GST_FLOW_OK;
+  GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_GET_CLASS (decoder);
   GstVideoDecoderPrivate *priv = decoder->priv;
   GstBuffer *output_buffer;
   gboolean needs_reconfigure = FALSE;
@@ -2908,6 +2974,19 @@ gst_video_decoder_finish_frame (GstVideoDecoder * decoder,
     priv->discont = FALSE;
   }
 
+  if (decoder_class->transform_meta) {
+    if (G_LIKELY (frame->input_buffer)) {
+      CopyMetaData data;
+
+      data.decoder = decoder;
+      data.frame = frame;
+      gst_buffer_foreach_meta (frame->input_buffer, foreach_metadata, &data);
+    } else {
+      GST_WARNING_OBJECT (decoder,
+          "Can't copy metadata because input frame disappeared");
+    }
+  }
+
   /* Get an additional ref to the buffer, which is going to be pushed
    * downstream, the original ref is owned by the frame
    *
@@ -2936,7 +3015,6 @@ done:
   return ret;
 }
 
-
 /* With stream lock, takes the frame reference */
 static GstFlowReturn
 gst_video_decoder_clip_and_push_buf (GstVideoDecoder * decoder, GstBuffer * buf)
index d9aa736..b2f531d 100644 (file)
@@ -265,6 +265,11 @@ struct _GstVideoDecoder
  *                  If not implemented, default returns
  *                  gst_video_decoder_proxy_getcaps
  *                  applied to sink template caps.
+ * @transform_meta: Optional. Transform the metadata on the input buffer to the
+ *                  output buffer. By default this method is copies all meta without
+ *                  tags and meta with only the "video" tag. subclasses can
+ *                  implement this method and return %TRUE if the metadata is to be
+ *                  copied. Since 1.6
  *
  * Subclasses can override any of the available virtual methods or not, as
  * needed. At minimum @handle_frame needs to be overridden, and @set_format
@@ -326,8 +331,12 @@ struct _GstVideoDecoderClass
 
   GstFlowReturn (*drain)          (GstVideoDecoder *decoder);
 
+  gboolean      (*transform_meta) (GstVideoDecoder *decoder,
+                                   GstVideoCodecFrame *frame,
+                                   GstMeta * meta);
+
   /*< private >*/
-  void         *padding[GST_PADDING_LARGE-5];
+  void         *padding[GST_PADDING_LARGE-6];
 };
 
 GType    gst_video_decoder_get_type (void);