From d2cc76b228f5309ad66a510914ca0febfa4f03e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 29 Jun 2015 15:58:38 +0200 Subject: [PATCH] videodecoder: Add transform_meta() vfunc with default implementation 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 | 80 +++++++++++++++++++++++++++- gst-libs/gst/video/gstvideodecoder.h | 11 +++- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/video/gstvideodecoder.c b/gst-libs/gst/video/gstvideodecoder.c index fc7b8b7aa5..7128580b1a 100644 --- a/gst-libs/gst/video/gstvideodecoder.c +++ b/gst-libs/gst/video/gstvideodecoder.c @@ -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, ©_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) diff --git a/gst-libs/gst/video/gstvideodecoder.h b/gst-libs/gst/video/gstvideodecoder.h index d9aa736216..b2f531d4e7 100644 --- a/gst-libs/gst/video/gstvideodecoder.h +++ b/gst-libs/gst/video/gstvideodecoder.h @@ -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);