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);