diff --git a/omx/gstomxbufferpool.c b/omx/gstomxbufferpool.c index 65f4a411d6..b57612d16c 100644 --- a/omx/gstomxbufferpool.c +++ b/omx/gstomxbufferpool.c @@ -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), diff --git a/omx/gstomxbufferpool.h b/omx/gstomxbufferpool.h index f2c008d495..76f96802a2 100644 --- a/omx/gstomxbufferpool.h +++ b/omx/gstomxbufferpool.h @@ -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 diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c index eb52d13a15..8590301f66 100644 --- a/omx/gstomxvideodec.c +++ b/omx/gstomxvideodec.c @@ -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, ¶ms); + &outbuf, ¶ms); 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;