From dfa6c17de5921c30ba757f9e935449b6e8b7cbf9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 22 Mar 2013 15:49:18 +0100 Subject: [PATCH] y4mdec: Use the correct strides as used by y4m and convert to GStreamer strides if necessary https://bugzilla.gnome.org/show_bug.cgi?id=696361 --- gst/y4m/gsty4mdec.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++- gst/y4m/gsty4mdec.h | 3 + 2 files changed, 173 insertions(+), 1 deletion(-) diff --git a/gst/y4m/gsty4mdec.c b/gst/y4m/gsty4mdec.c index 8c68a9f..93c5c43 100644 --- a/gst/y4m/gsty4mdec.c +++ b/gst/y4m/gsty4mdec.c @@ -196,10 +196,13 @@ gst_y4m_dec_finalize (GObject * object) static GstStateChangeReturn gst_y4m_dec_change_state (GstElement * element, GstStateChange transition) { + GstY4mDec *y4mdec; GstStateChangeReturn ret; g_return_val_if_fail (GST_IS_Y4M_DEC (element), GST_STATE_CHANGE_FAILURE); + y4mdec = GST_Y4M_DEC (element); + switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; @@ -217,6 +220,11 @@ gst_y4m_dec_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: + if (y4mdec->pool) { + gst_buffer_pool_set_active (y4mdec->pool, FALSE); + gst_object_unref (y4mdec->pool); + } + y4mdec->pool = NULL; break; case GST_STATE_CHANGE_READY_TO_NULL: break; @@ -392,7 +400,49 @@ gst_y4m_dec_parse_header (GstY4mDec * y4mdec, char *header) } gst_video_info_init (&y4mdec->info); - gst_video_info_set_format (&y4mdec->info, format, width, height); + gst_video_info_set_format (&y4mdec->out_info, format, width, height); + y4mdec->info = y4mdec->out_info; + + switch (y4mdec->info.finfo->format) { + case GST_VIDEO_FORMAT_I420: + y4mdec->info.offset[0] = 0; + y4mdec->info.stride[0] = width; + y4mdec->info.offset[1] = y4mdec->info.stride[0] * height; + y4mdec->info.stride[1] = GST_ROUND_UP_2 (width) / 2; + y4mdec->info.offset[2] = + y4mdec->info.offset[1] + + y4mdec->info.stride[1] * (GST_ROUND_UP_2 (height) / 2); + y4mdec->info.stride[2] = GST_ROUND_UP_2 (width) / 2; + y4mdec->info.size = + y4mdec->info.offset[2] + + y4mdec->info.stride[2] * (GST_ROUND_UP_2 (height) / 2); + break; + case GST_VIDEO_FORMAT_Y42B: + y4mdec->info.offset[0] = 0; + y4mdec->info.stride[0] = width; + y4mdec->info.offset[1] = y4mdec->info.stride[0] * height; + y4mdec->info.stride[1] = GST_ROUND_UP_2 (width) / 2; + y4mdec->info.offset[2] = + y4mdec->info.offset[1] + y4mdec->info.stride[1] * height; + y4mdec->info.stride[2] = GST_ROUND_UP_2 (width) / 2; + y4mdec->info.size = + y4mdec->info.offset[2] + y4mdec->info.stride[2] * height; + break; + case GST_VIDEO_FORMAT_Y444: + y4mdec->info.offset[0] = 0; + y4mdec->info.stride[0] = width; + y4mdec->info.offset[1] = y4mdec->info.stride[0] * height; + y4mdec->info.stride[1] = width; + y4mdec->info.offset[2] = + y4mdec->info.offset[1] + y4mdec->info.stride[1] * height; + y4mdec->info.stride[2] = width; + y4mdec->info.size = + y4mdec->info.offset[2] + y4mdec->info.stride[2] * height; + break; + default: + g_assert_not_reached (); + break; + } switch (interlaced_char) { case 0: @@ -457,6 +507,7 @@ gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) if (!y4mdec->have_header) { gboolean ret; GstCaps *caps; + GstQuery *query; if (n_avail < MAX_HEADER_LENGTH) return GST_FLOW_OK; @@ -481,6 +532,78 @@ gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) caps = gst_video_info_to_caps (&y4mdec->info); ret = gst_pad_set_caps (y4mdec->srcpad, caps); + + query = gst_query_new_allocation (caps, FALSE); + y4mdec->video_meta = FALSE; + + if (y4mdec->pool) { + gst_buffer_pool_set_active (y4mdec->pool, FALSE); + gst_object_unref (y4mdec->pool); + } + y4mdec->pool = NULL; + + if (gst_pad_peer_query (y4mdec->srcpad, query)) { + y4mdec->video_meta = + gst_query_find_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, + NULL); + + /* We only need a pool if we need to do stride conversion for downstream */ + if (!y4mdec->video_meta && memcmp (&y4mdec->info, &y4mdec->out_info, + sizeof (y4mdec->info)) != 0) { + GstBufferPool *pool = NULL; + GstAllocator *allocator = NULL; + GstAllocationParams params; + GstStructure *config; + guint size, min, max; + + if (gst_query_get_n_allocation_params (query) > 0) { + gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms); + } else { + allocator = NULL; + gst_allocation_params_init (¶ms); + } + + if (gst_query_get_n_allocation_pools (query) > 0) { + gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, + &max); + size = MAX (size, y4mdec->out_info.size); + } else { + pool = NULL; + size = y4mdec->out_info.size; + min = max = 0; + } + + if (pool == NULL) { + pool = gst_video_buffer_pool_new (); + } + + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_set_params (config, caps, size, min, max); + gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); + gst_buffer_pool_set_config (pool, config); + + if (allocator) + gst_object_unref (allocator); + + y4mdec->pool = pool; + } + } else if (memcmp (&y4mdec->info, &y4mdec->out_info, + sizeof (y4mdec->info)) != 0) { + GstBufferPool *pool; + GstStructure *config; + + /* No pool, create our own if we need to do stride conversion */ + pool = gst_video_buffer_pool_new (); + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_set_params (config, caps, y4mdec->out_info.size, 0, + 0); + gst_buffer_pool_set_config (pool, config); + y4mdec->pool = pool; + } + if (y4mdec->pool) { + gst_buffer_pool_set_active (y4mdec->pool, TRUE); + } + gst_query_unref (query); gst_caps_unref (caps); if (!ret) { GST_DEBUG_OBJECT (y4mdec, "Couldn't set caps on src pad"); @@ -554,6 +677,52 @@ gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) y4mdec->frame_index++; + if (y4mdec->video_meta) { + gst_buffer_add_video_meta_full (buffer, 0, y4mdec->info.finfo->format, + y4mdec->info.width, y4mdec->info.height, y4mdec->info.finfo->n_planes, + y4mdec->info.offset, y4mdec->info.stride); + } else if (memcmp (&y4mdec->info, &y4mdec->out_info, + sizeof (y4mdec->info)) != 0) { + GstBuffer *outbuf; + GstVideoFrame iframe, oframe; + gint i, j; + gint w, h, istride, ostride; + guint8 *src, *dest; + + /* Allocate a new buffer and do stride conversion */ + g_assert (y4mdec->pool != NULL); + + flow_ret = gst_buffer_pool_acquire_buffer (y4mdec->pool, &outbuf, NULL); + if (flow_ret != GST_FLOW_OK) { + gst_buffer_unref (buffer); + break; + } + + gst_video_frame_map (&iframe, &y4mdec->info, buffer, GST_MAP_READ); + gst_video_frame_map (&oframe, &y4mdec->out_info, outbuf, GST_MAP_WRITE); + + for (i = 0; i < 3; i++) { + w = GST_VIDEO_FRAME_COMP_WIDTH (&iframe, i);; + h = GST_VIDEO_FRAME_COMP_HEIGHT (&iframe, i);; + istride = GST_VIDEO_FRAME_COMP_STRIDE (&iframe, i);; + ostride = GST_VIDEO_FRAME_COMP_STRIDE (&oframe, i);; + src = GST_VIDEO_FRAME_COMP_DATA (&iframe, i); + dest = GST_VIDEO_FRAME_COMP_DATA (&oframe, i); + + for (j = 0; j < h; j++) { + memcpy (dest, src, w); + + dest += ostride; + src += istride; + } + } + + gst_video_frame_unmap (&iframe); + gst_video_frame_unmap (&oframe); + gst_buffer_unref (buffer); + buffer = outbuf; + } + flow_ret = gst_pad_push (y4mdec->srcpad, buffer); if (flow_ret != GST_FLOW_OK) break; diff --git a/gst/y4m/gsty4mdec.h b/gst/y4m/gsty4mdec.h index eab23b5..c2eb9b0 100644 --- a/gst/y4m/gsty4mdec.h +++ b/gst/y4m/gsty4mdec.h @@ -51,6 +51,9 @@ struct _GstY4mDec GstSegment segment; GstVideoInfo info; + GstVideoInfo out_info; + gboolean video_meta; + GstBufferPool *pool; }; struct _GstY4mDecClass -- 2.7.4