From 5bad1eaa2446a0c393ce1c6b5e8fe90bb4bda0b3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 1 Mar 2012 17:29:37 +0100 Subject: [PATCH 1/3] theora: fix bufferpool negotiation Store the uncropped frame dimensions in the videoinfo. Always set the caps with the dimension of the cropped output. Don't negotiate the bufferpool multiple times. Remove the old crop feature, we always crop now. --- ext/theora/gsttheoradec.c | 86 +++++++++++++++++---------------------- ext/theora/gsttheoradec.h | 2 - 2 files changed, 37 insertions(+), 51 deletions(-) diff --git a/ext/theora/gsttheoradec.c b/ext/theora/gsttheoradec.c index d3f7dbd679..52d8f9599e 100644 --- a/ext/theora/gsttheoradec.c +++ b/ext/theora/gsttheoradec.c @@ -50,7 +50,6 @@ #define GST_CAT_DEFAULT theoradec_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); -#define THEORA_DEF_CROP TRUE #define THEORA_DEF_TELEMETRY_MV 0 #define THEORA_DEF_TELEMETRY_MBMODE 0 #define THEORA_DEF_TELEMETRY_QI 0 @@ -59,7 +58,6 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); enum { PROP_0, - PROP_CROP, PROP_TELEMETRY_MV, PROP_TELEMETRY_MBMODE, PROP_TELEMETRY_QI, @@ -128,11 +126,6 @@ gst_theora_dec_class_init (GstTheoraDecClass * klass) gobject_class->set_property = theora_dec_set_property; gobject_class->get_property = theora_dec_get_property; - g_object_class_install_property (gobject_class, PROP_CROP, - g_param_spec_boolean ("crop", "Crop", - "Crop the image to the visible region", THEORA_DEF_CROP, - (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MV)) { g_object_class_install_property (gobject_class, PROP_TELEMETRY_MV, g_param_spec_int ("visualize-motion-vectors", @@ -208,7 +201,6 @@ gst_theora_dec_init (GstTheoraDec * dec) gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); - dec->crop = THEORA_DEF_CROP; dec->telemetry_mv = THEORA_DEF_TELEMETRY_MV; dec->telemetry_mbmode = THEORA_DEF_TELEMETRY_MBMODE; dec->telemetry_qi = THEORA_DEF_TELEMETRY_QI; @@ -776,12 +768,16 @@ theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet) } static GstFlowReturn -theora_negotiate_pool (GstTheoraDec * dec, GstCaps * caps, GstVideoInfo * info) +theora_negotiate_pool (GstTheoraDec * dec) { GstQuery *query; - GstBufferPool *pool = NULL; + GstBufferPool *pool; guint size, min, max, prefix, alignment; GstStructure *config; + GstCaps *caps; + + /* find the caps of the output buffer */ + caps = gst_pad_get_current_caps (dec->srcpad); /* find a pool for the negotiated caps now */ query = gst_query_new_allocation (caps, TRUE); @@ -791,35 +787,45 @@ theora_negotiate_pool (GstTheoraDec * dec, GstCaps * caps, GstVideoInfo * info) /* we got configuration from our peer, parse them */ gst_query_parse_allocation_params (query, &size, &min, &max, &prefix, &alignment, &pool); - size = MAX (size, info->size); } else { GST_DEBUG_OBJECT (dec, "didn't get downstream ALLOCATION hints"); - size = info->size; + size = 0; min = max = 0; prefix = 0; alignment = 0; + pool = NULL; } if (pool == NULL) { /* we did not get a pool, make one ourselves then */ - pool = gst_buffer_pool_new (); + pool = gst_video_buffer_pool_new (); } if (dec->pool) gst_object_unref (dec->pool); dec->pool = pool; + /* check if downstream supports cropping */ + dec->has_cropping = + gst_query_has_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE); + + if (dec->has_cropping) { + /* we can crop, configure the pool with buffers of caps and size of the + * decoded picture size and then crop them with metadata */ + size = MAX (size, GST_VIDEO_INFO_SIZE (&dec->vinfo)); + gst_caps_unref (caps); + caps = gst_video_info_to_caps (&dec->vinfo); + } + config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set (config, caps, size, min, max, prefix, alignment); + gst_caps_unref (caps); + /* just set the option, if the pool can support it we will transparently use * it through the video info API. We could also see if the pool support this * option and only activate it then. */ gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); - /* check if downstream supports cropping */ - dec->has_cropping = - gst_query_has_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE); - GST_DEBUG_OBJECT (dec, "downstream cropping %d", dec->has_cropping); gst_buffer_pool_set_config (pool, config); @@ -836,10 +842,10 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) { GstCaps *caps; GstVideoFormat format; - gint width, height; gint par_num, par_den; GstFlowReturn ret = GST_FLOW_OK; GList *walk; + GstVideoInfo info; GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d", dec->info.fps_numerator, dec->info.fps_denominator, @@ -891,14 +897,6 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) goto invalid_format; } - if (dec->crop) { - width = dec->info.pic_width; - height = dec->info.pic_height; - } else { - /* no cropping, use the encoded dimensions */ - width = dec->info.frame_width; - height = dec->info.frame_height; - } if (dec->info.pic_width != dec->info.frame_width || dec->info.pic_height != dec->info.frame_height || dec->info.pic_x != 0 || dec->info.pic_y != 0) { @@ -929,7 +927,9 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) GST_WARNING_OBJECT (dec, "Could not enable BITS mode visualisation"); } - gst_video_info_set_format (&dec->vinfo, format, width, height); + /* our info contains the dimensions for the coded picture before cropping */ + gst_video_info_set_format (&dec->vinfo, format, dec->info.frame_width, + dec->info.frame_height); dec->vinfo.fps_n = dec->info.fps_numerator; dec->vinfo.fps_d = dec->info.fps_denominator; dec->vinfo.par_n = par_num; @@ -953,13 +953,16 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) break; } - caps = gst_video_info_to_caps (&dec->vinfo); + /* for the output caps we always take the cropped dimensions */ + info = dec->vinfo; + gst_video_info_set_format (&info, format, dec->info.pic_width, + dec->info.pic_height); + caps = gst_video_info_to_caps (&info); gst_pad_set_caps (dec->srcpad, caps); gst_caps_unref (caps); - /* negotiate a bufferpool */ - if ((ret = theora_negotiate_pool (dec, caps, &dec->vinfo)) != GST_FLOW_OK) - goto no_bufferpool; + /* make sure we negotiate a bufferpool */ + gst_pad_mark_reconfigure (dec->srcpad); dec->have_header = TRUE; @@ -983,10 +986,6 @@ invalid_format: GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt); return GST_FLOW_ERROR; } -no_bufferpool: - { - return ret; - } } static GstFlowReturn @@ -1113,13 +1112,8 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf, GstBuffer ** out) GstVideoCropMeta *crop; gint offset_x, offset_y; - if (gst_pad_check_reconfigure (dec->srcpad)) { - GstCaps *caps; - - caps = gst_pad_get_current_caps (dec->srcpad); - theora_negotiate_pool (dec, caps, &dec->vinfo); - gst_caps_unref (caps); - } + if (gst_pad_check_reconfigure (dec->srcpad)) + theora_negotiate_pool (dec); result = gst_buffer_pool_acquire_buffer (dec->pool, out, NULL); if (G_UNLIKELY (result != GST_FLOW_OK)) @@ -1128,7 +1122,7 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf, GstBuffer ** out) if (!gst_video_frame_map (&frame, &dec->vinfo, *out, GST_MAP_WRITE)) goto invalid_frame; - if (dec->crop && !dec->has_cropping) { + if (!dec->has_cropping) { /* we need to crop the hard way */ offset_x = dec->info.pic_x; offset_y = dec->info.pic_y; @@ -1650,9 +1644,6 @@ theora_dec_set_property (GObject * object, guint prop_id, GstTheoraDec *dec = GST_THEORA_DEC (object); switch (prop_id) { - case PROP_CROP: - dec->crop = g_value_get_boolean (value); - break; case PROP_TELEMETRY_MV: dec->telemetry_mv = g_value_get_int (value); break; @@ -1678,9 +1669,6 @@ theora_dec_get_property (GObject * object, guint prop_id, GstTheoraDec *dec = GST_THEORA_DEC (object); switch (prop_id) { - case PROP_CROP: - g_value_set_boolean (value, dec->crop); - break; case PROP_TELEMETRY_MV: g_value_set_int (value, dec->telemetry_mv); break; diff --git a/ext/theora/gsttheoradec.h b/ext/theora/gsttheoradec.h index 569fba0a93..e9fe1a8480 100644 --- a/ext/theora/gsttheoradec.h +++ b/ext/theora/gsttheoradec.h @@ -82,8 +82,6 @@ struct _GstTheoraDec gint telemetry_qi; gint telemetry_bits; - gboolean crop; - /* list of buffers that need timestamps */ GList *queued; /* list of raw output buffers */ From 91c587af228de91c2cddc73a8da311c0c16b08a5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 1 Mar 2012 17:34:28 +0100 Subject: [PATCH 2/3] videofilter: fix for decide_allocation changes Chain up to parent. --- gst-libs/gst/video/gstvideofilter.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/video/gstvideofilter.c b/gst-libs/gst/video/gstvideofilter.c index 97bda075bf..248c482eee 100644 --- a/gst-libs/gst/video/gstvideofilter.c +++ b/gst-libs/gst/video/gstvideofilter.c @@ -53,7 +53,7 @@ G_DEFINE_ABSTRACT_TYPE (GstVideoFilter, gst_video_filter, /* Answer the allocation query downstream. */ static gboolean gst_video_filter_propose_allocation (GstBaseTransform * trans, - gboolean passthrough, GstQuery * query) + GstQuery * decide_query, GstQuery * query) { GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); GstVideoInfo info; @@ -63,9 +63,9 @@ gst_video_filter_propose_allocation (GstBaseTransform * trans, guint size; /* we're passthrough, let the parent implementation hande things */ - if (passthrough) + if (decide_query == NULL) return GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans, - passthrough, query); + decide_query, query); gst_query_parse_allocation (query, &caps, &need_pool); @@ -124,7 +124,8 @@ gst_video_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query) GST_BUFFER_POOL_OPTION_VIDEO_META); gst_buffer_pool_set_config (pool, config); } - return TRUE; + return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans, + query); } From dcd277b9160f92e051097210889b969a059a162d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 1 Mar 2012 17:36:08 +0100 Subject: [PATCH 3/3] videoconvert: proxy allocation meta when we can Proxy all the metadata APIs in the allocation query. Remove all metadata that is dependent on the colorspace, copy others. --- gst/videoconvert/gstvideoconvert.c | 84 ++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/gst/videoconvert/gstvideoconvert.c b/gst/videoconvert/gstvideoconvert.c index d33779702c..b49239211e 100644 --- a/gst/videoconvert/gstvideoconvert.c +++ b/gst/videoconvert/gstvideoconvert.c @@ -49,6 +49,12 @@ GST_DEBUG_CATEGORY (videoconvert_debug); #define GST_CAT_DEFAULT videoconvert_debug GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE); +GType gst_video_convert_get_type (void); + +static GQuark _colorspace_quark; + +#define gst_video_convert_parent_class parent_class +G_DEFINE_TYPE (GstVideoConvert, gst_video_convert, GST_TYPE_VIDEO_FILTER); enum { @@ -72,8 +78,6 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS (CSP_VIDEO_CAPS) ); -GType gst_video_convert_get_type (void); - static void gst_video_convert_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec); static void gst_video_convert_get_property (GObject * object, @@ -305,8 +309,74 @@ invalid_palette: } } -#define gst_video_convert_parent_class parent_class -G_DEFINE_TYPE (GstVideoConvert, gst_video_convert, GST_TYPE_VIDEO_FILTER); +static gboolean +gst_video_convert_propose_allocation (GstBaseTransform * trans, + GstQuery * decide_query, GstQuery * query) +{ + gboolean ret; + guint i, n_metas; + + /* let parent handle */ + ret = GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans, + decide_query, query); + /* error or passthrough, we're done */ + if (!ret || decide_query == NULL) + return ret; + + /* non-passthrough, copy all metadata, decide_query does not contain the + * metadata anymore that depends on the buffer memory */ + n_metas = gst_query_get_n_allocation_metas (decide_query); + for (i = 0; i < n_metas; i++) { + GType api; + + api = gst_query_parse_nth_allocation_meta (decide_query, i); + gst_query_add_allocation_meta (query, api); + } + return ret; +} + +typedef struct +{ + GstBaseTransform *trans; + GstBuffer *outbuf; + GQuark tag; +} CopyMetaData; + +static gboolean +foreach_metadata (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data) +{ + CopyMetaData *data = user_data; + const GstMetaInfo *info = (*meta)->info; + + if (info->transform_func) { + if (gst_meta_api_type_has_tag (info->api, data->tag)) { + /* metadata depends on colorspace. FIXME discard for now until we + * have some transform data for it. */ + } else { + GstMetaTransformCopy copy_data = { 0, -1 }; + /* simply copy then */ + info->transform_func (data->outbuf, *meta, inbuf, + _gst_meta_transform_copy, ©_data); + } + } + return TRUE; +} + +static gboolean +gst_video_convert_copy_metadata (GstBaseTransform * trans, + GstBuffer * inbuf, GstBuffer * outbuf) +{ + CopyMetaData data; + + data.trans = trans; + data.outbuf = outbuf; + data.tag = _colorspace_quark; + + gst_buffer_foreach_meta (inbuf, foreach_metadata, &data); + + return GST_BASE_TRANSFORM_CLASS (parent_class)->copy_metadata (trans, inbuf, + outbuf); +} static void gst_video_convert_finalize (GObject * obj) @@ -347,6 +417,10 @@ gst_video_convert_class_init (GstVideoConvertClass * klass) GST_DEBUG_FUNCPTR (gst_video_convert_transform_caps); gstbasetransform_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_video_convert_fixate_caps); + gstbasetransform_class->propose_allocation = + GST_DEBUG_FUNCPTR (gst_video_convert_propose_allocation); + gstbasetransform_class->copy_metadata = + GST_DEBUG_FUNCPTR (gst_video_convert_copy_metadata); gstbasetransform_class->passthrough_on_same_caps = TRUE; @@ -428,6 +502,8 @@ plugin_init (GstPlugin * plugin) GST_DEBUG_CATEGORY_INIT (videoconvert_debug, "videoconvert", 0, "Colorspace Converter"); + _colorspace_quark = g_quark_from_static_string ("colorspace"); + return gst_element_register (plugin, "videoconvert", GST_RANK_NONE, GST_TYPE_VIDEO_CONVERT); }