omxbufferpool: Copy buffers if the stride does not match and we can't use video meta

https://bugzilla.gnome.org/show_bug.cgi?id=731672
This commit is contained in:
Sebastian Dröge 2014-06-24 14:52:58 +02:00
parent b9238195dd
commit 4593f434a0
3 changed files with 95 additions and 29 deletions

View file

@ -380,46 +380,73 @@ gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool,
GST_VIDEO_INFO_HEIGHT (&pool->video_info));
}
}
pool->need_copy = FALSE;
} else {
GstMemory *mem;
const guint nstride = pool->port->port_def.format.video.nStride;
const guint nslice = pool->port->port_def.format.video.nSliceHeight;
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
mem = gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf);
buf = gst_buffer_new ();
gst_buffer_append_memory (buf, mem);
g_ptr_array_add (pool->buffers, buf);
if (pool->add_videometa) {
const guint nstride = pool->port->port_def.format.video.nStride;
const guint nslice = pool->port->port_def.format.video.nSliceHeight;
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
switch (GST_VIDEO_INFO_FORMAT (&pool->video_info)) {
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_RGB16:
case GST_VIDEO_FORMAT_BGR16:
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
case GST_VIDEO_FORMAT_YVYU:
case GST_VIDEO_FORMAT_GRAY8:
break;
case GST_VIDEO_FORMAT_I420:
stride[1] = nstride / 2;
offset[1] = offset[0] + stride[0] * nslice;
stride[2] = nstride / 2;
offset[2] = offset[1] + (stride[1] * nslice / 2);
break;
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV16:
stride[1] = nstride;
offset[1] = offset[0] + stride[0] * nslice;
break;
default:
g_assert_not_reached ();
break;
}
switch (GST_VIDEO_INFO_FORMAT (&pool->video_info)) {
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_RGB16:
case GST_VIDEO_FORMAT_BGR16:
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
case GST_VIDEO_FORMAT_YVYU:
case GST_VIDEO_FORMAT_GRAY8:
break;
case GST_VIDEO_FORMAT_I420:
stride[1] = nstride / 2;
offset[1] = offset[0] + stride[0] * nslice;
stride[2] = nstride / 2;
offset[2] = offset[1] + (stride[1] * nslice / 2);
break;
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV16:
stride[1] = nstride;
offset[1] = offset[0] + stride[0] * nslice;
break;
default:
g_assert_not_reached ();
if (pool->add_videometa) {
pool->need_copy = FALSE;
} else {
GstVideoInfo info;
gboolean need_copy = FALSE;
gint i;
gst_video_info_init (&info);
gst_video_info_set_format (&info,
GST_VIDEO_INFO_FORMAT (&pool->video_info),
GST_VIDEO_INFO_WIDTH (&pool->video_info),
GST_VIDEO_INFO_HEIGHT (&pool->video_info));
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&pool->video_info); i++) {
if (info.stride[i] != stride[i] || info.offset[i] != offset[i]) {
need_copy = TRUE;
break;
}
}
pool->need_copy = need_copy;
}
if (pool->need_copy || pool->add_videometa) {
/* We always add the videometa. It's the job of the user
* to copy the buffer if pool->need_copy is TRUE
*/
gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
GST_VIDEO_INFO_FORMAT (&pool->video_info),
GST_VIDEO_INFO_WIDTH (&pool->video_info),

View file

@ -51,6 +51,7 @@ struct _GstOMXBufferPool
GstCaps *caps;
gboolean add_videometa;
gboolean need_copy;
GstVideoInfo video_info;
/* Owned by element, element has to stop this pool before

View file

@ -1214,6 +1214,29 @@ gst_omx_video_dec_clean_older_frames (GstOMXVideoDec * self,
g_list_free (frames);
}
static GstBuffer *
copy_frame (const GstVideoInfo * info, GstBuffer * outbuf)
{
GstVideoInfo out_info, tmp_info;
GstBuffer *tmpbuf;
GstVideoFrame out_frame, tmp_frame;
out_info = *info;
tmp_info = *info;
tmpbuf = gst_buffer_new_and_alloc (out_info.size);
gst_video_frame_map (&out_frame, &out_info, outbuf, GST_MAP_READ);
gst_video_frame_map (&tmp_frame, &tmp_info, tmpbuf, GST_MAP_WRITE);
gst_video_frame_copy (&tmp_frame, &out_frame);
gst_video_frame_unmap (&out_frame);
gst_video_frame_unmap (&tmp_frame);
gst_buffer_unref (outbuf);
return tmpbuf;
}
static void
gst_omx_video_dec_loop (GstOMXVideoDec * self)
{
@ -1392,6 +1415,12 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
gst_omx_port_release_buffer (port, buf);
goto invalid_buffer;
}
if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy)
outbuf =
copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
outbuf);
buf = NULL;
} else {
outbuf =
@ -1407,6 +1436,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
} else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) {
if (self->out_port_pool) {
gint i, n;
GstBuffer *outbuf;
GstBufferPoolAcquireParams params = { 0, };
n = port->buffers->len;
@ -1421,7 +1451,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
flow_ret =
gst_buffer_pool_acquire_buffer (self->out_port_pool,
&frame->output_buffer, &params);
&outbuf, &params);
if (flow_ret != GST_FLOW_OK) {
flow_ret =
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
@ -1429,6 +1459,14 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
gst_omx_port_release_buffer (port, buf);
goto invalid_buffer;
}
if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy)
outbuf =
copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
outbuf);
frame->output_buffer = outbuf;
flow_ret =
gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
frame = NULL;