summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2013-03-22 15:49:18 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2013-03-22 15:53:08 +0100
commitdfa6c17de5921c30ba757f9e935449b6e8b7cbf9 (patch)
tree71028bd7457e85867fe0c851e8a6151fb6ad8320
parentc2966fce30b9b59e7f4e6506d5738fa15ca0b6d7 (diff)
downloadgstreamer-plugins-bad-dfa6c17de5921c30ba757f9e935449b6e8b7cbf9.tar.gz
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
-rw-r--r--gst/y4m/gsty4mdec.c171
-rw-r--r--gst/y4m/gsty4mdec.h3
2 files changed, 173 insertions, 1 deletions
diff --git a/gst/y4m/gsty4mdec.c b/gst/y4m/gsty4mdec.c
index 8c68a9f21..93c5c437a 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, &params);
+ } else {
+ allocator = NULL;
+ gst_allocation_params_init (&params);
+ }
+
+ 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, &params);
+ 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 eab23b54b..c2eb9b0c6 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