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
This commit is contained in:
Sebastian Dröge 2015-06-29 15:58:38 +02:00
parent ceef2cc12d
commit d2cc76b228
2 changed files with 89 additions and 2 deletions

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

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