From ceef2cc12da884edfc172aa2a5dc09fc8cdc8edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 29 Jun 2015 13:59:25 +0200 Subject: [PATCH] videoencoder: 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. https://bugzilla.gnome.org/show_bug.cgi?id=742385 --- gst-libs/gst/video/gstvideoencoder.c | 78 ++++++++++++++++++++++++++++ gst-libs/gst/video/gstvideoencoder.h | 12 ++++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/video/gstvideoencoder.c b/gst-libs/gst/video/gstvideoencoder.c index ebeaa7a7d4..d9bc4e2d1e 100644 --- a/gst-libs/gst/video/gstvideoencoder.c +++ b/gst-libs/gst/video/gstvideoencoder.c @@ -244,6 +244,9 @@ static gboolean gst_video_encoder_sink_query_default (GstVideoEncoder * encoder, static gboolean gst_video_encoder_src_query_default (GstVideoEncoder * encoder, GstQuery * query); +static gboolean gst_video_encoder_transform_meta_default (GstVideoEncoder * + encoder, 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 @@ -307,6 +310,7 @@ gst_video_encoder_class_init (GstVideoEncoderClass * klass) klass->negotiate = gst_video_encoder_negotiate_default; klass->sink_query = gst_video_encoder_sink_query_default; klass->src_query = gst_video_encoder_src_query_default; + klass->transform_meta = gst_video_encoder_transform_meta_default; } static GList * @@ -1800,6 +1804,67 @@ gst_video_encoder_release_frame (GstVideoEncoder * enc, gst_video_codec_frame_unref (frame); } +static gboolean +gst_video_encoder_transform_meta_default (GstVideoEncoder * + encoder, 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 +{ + GstVideoEncoder *encoder; + GstVideoCodecFrame *frame; +} CopyMetaData; + +static gboolean +foreach_metadata (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data) +{ + CopyMetaData *data = user_data; + GstVideoEncoder *encoder = data->encoder; + GstVideoEncoderClass *klass = GST_VIDEO_ENCODER_GET_CLASS (encoder); + 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 (encoder, "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 (encoder, "not copying memory specific metadata %s", + g_type_name (info->api)); + do_copy = FALSE; + } else if (klass->transform_meta) { + do_copy = klass->transform_meta (encoder, frame, *meta); + GST_DEBUG_OBJECT (encoder, "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 (encoder, "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_encoder_finish_frame: * @encoder: a #GstVideoEncoder @@ -2046,6 +2111,19 @@ gst_video_encoder_finish_frame (GstVideoEncoder * encoder, if (encoder_class->pre_push) ret = encoder_class->pre_push (encoder, frame); + if (encoder_class->transform_meta) { + if (G_LIKELY (frame->input_buffer)) { + CopyMetaData data; + + data.encoder = encoder; + data.frame = frame; + gst_buffer_foreach_meta (frame->input_buffer, foreach_metadata, &data); + } else { + GST_WARNING_OBJECT (encoder, + "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 */ buffer = gst_buffer_ref (frame->output_buffer); diff --git a/gst-libs/gst/video/gstvideoencoder.h b/gst-libs/gst/video/gstvideoencoder.h index 52990624c6..3573d464dc 100644 --- a/gst-libs/gst/video/gstvideoencoder.h +++ b/gst-libs/gst/video/gstvideoencoder.h @@ -225,6 +225,12 @@ struct _GstVideoEncoder * should chain up to the parent implementation to invoke the * default handler. Since 1.4 * + * @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 * and @get_caps are likely needed as well. @@ -281,8 +287,12 @@ struct _GstVideoEncoderClass gboolean (*src_query) (GstVideoEncoder *encoder, GstQuery *query); + gboolean (*transform_meta) (GstVideoEncoder *encoder, + GstVideoCodecFrame *frame, + GstMeta * meta); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-3]; + gpointer _gst_reserved[GST_PADDING_LARGE-4]; }; GType gst_video_encoder_get_type (void);