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)); GST_VIDEO_INFO_HEIGHT (&pool->video_info));
} }
} }
pool->need_copy = FALSE;
} else { } else {
GstMemory *mem; 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); mem = gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf);
buf = gst_buffer_new (); buf = gst_buffer_new ();
gst_buffer_append_memory (buf, mem); gst_buffer_append_memory (buf, mem);
g_ptr_array_add (pool->buffers, buf); g_ptr_array_add (pool->buffers, buf);
if (pool->add_videometa) { switch (GST_VIDEO_INFO_FORMAT (&pool->video_info)) {
const guint nstride = pool->port->port_def.format.video.nStride; case GST_VIDEO_FORMAT_ABGR:
const guint nslice = pool->port->port_def.format.video.nSliceHeight; case GST_VIDEO_FORMAT_ARGB:
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, }; case GST_VIDEO_FORMAT_RGB16:
gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, }; 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)) { if (pool->add_videometa) {
case GST_VIDEO_FORMAT_ABGR: pool->need_copy = FALSE;
case GST_VIDEO_FORMAT_ARGB: } else {
case GST_VIDEO_FORMAT_RGB16: GstVideoInfo info;
case GST_VIDEO_FORMAT_BGR16: gboolean need_copy = FALSE;
case GST_VIDEO_FORMAT_YUY2: gint i;
case GST_VIDEO_FORMAT_UYVY:
case GST_VIDEO_FORMAT_YVYU: gst_video_info_init (&info);
case GST_VIDEO_FORMAT_GRAY8: gst_video_info_set_format (&info,
break; GST_VIDEO_INFO_FORMAT (&pool->video_info),
case GST_VIDEO_FORMAT_I420: GST_VIDEO_INFO_WIDTH (&pool->video_info),
stride[1] = nstride / 2; GST_VIDEO_INFO_HEIGHT (&pool->video_info));
offset[1] = offset[0] + stride[0] * nslice;
stride[2] = nstride / 2; for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&pool->video_info); i++) {
offset[2] = offset[1] + (stride[1] * nslice / 2); if (info.stride[i] != stride[i] || info.offset[i] != offset[i]) {
break; need_copy = TRUE;
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; 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_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
GST_VIDEO_INFO_FORMAT (&pool->video_info), GST_VIDEO_INFO_FORMAT (&pool->video_info),
GST_VIDEO_INFO_WIDTH (&pool->video_info), GST_VIDEO_INFO_WIDTH (&pool->video_info),

View file

@ -51,6 +51,7 @@ struct _GstOMXBufferPool
GstCaps *caps; GstCaps *caps;
gboolean add_videometa; gboolean add_videometa;
gboolean need_copy;
GstVideoInfo video_info; GstVideoInfo video_info;
/* Owned by element, element has to stop this pool before /* 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); 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 static void
gst_omx_video_dec_loop (GstOMXVideoDec * self) 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); gst_omx_port_release_buffer (port, buf);
goto invalid_buffer; 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; buf = NULL;
} else { } else {
outbuf = outbuf =
@ -1407,6 +1436,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
} else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) { } else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) {
if (self->out_port_pool) { if (self->out_port_pool) {
gint i, n; gint i, n;
GstBuffer *outbuf;
GstBufferPoolAcquireParams params = { 0, }; GstBufferPoolAcquireParams params = { 0, };
n = port->buffers->len; 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; GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
flow_ret = flow_ret =
gst_buffer_pool_acquire_buffer (self->out_port_pool, gst_buffer_pool_acquire_buffer (self->out_port_pool,
&frame->output_buffer, &params); &outbuf, &params);
if (flow_ret != GST_FLOW_OK) { if (flow_ret != GST_FLOW_OK) {
flow_ret = flow_ret =
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); 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); gst_omx_port_release_buffer (port, buf);
goto invalid_buffer; 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 = flow_ret =
gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
frame = NULL; frame = NULL;