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
This commit is contained in:
Sebastian Dröge 2013-03-22 15:49:18 +01:00
parent c2966fce30
commit dfa6c17de5
2 changed files with 173 additions and 1 deletions

View file

@ -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;

View file

@ -51,6 +51,9 @@ struct _GstY4mDec
GstSegment segment;
GstVideoInfo info;
GstVideoInfo out_info;
gboolean video_meta;
GstBufferPool *pool;
};
struct _GstY4mDecClass