summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2017-07-20 16:35:31 +0200
committerJulien Isorce <jisorce@oblong.com>2017-12-14 09:00:31 +0000
commit533ee7fadcd167b92f263c1676ef7468c0ac2959 (patch)
tree775fc9f1d84d0ddf137527fccb7a07558482ee5c
parente55675b7ceb92286d539752c2c83939226304c7e (diff)
downloadgst-omx-533ee7fadcd167b92f263c1676ef7468c0ac2959.tar.gz
omxvideoenc: use dynamic buffer mode on input if possible
If the OMX component supports dynamic buffer mode and the input buffers are properly aligned avoid copying each input frame between OMX and GStreamer. Tested on zynqultrascaleplus and rpi (without dynamic buffers). https://bugzilla.gnome.org/show_bug.cgi?id=787093
-rw-r--r--omx/gstomxvideoenc.c115
-rw-r--r--omx/gstomxvideoenc.h2
2 files changed, 116 insertions, 1 deletions
diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c
index 37fd4ac..ce3d55a 100644
--- a/omx/gstomxvideoenc.c
+++ b/omx/gstomxvideoenc.c
@@ -1123,12 +1123,93 @@ gst_omx_video_enc_configure_input_buffer (GstOMXVideoEnc * self,
static gboolean
gst_omx_video_enc_allocate_in_buffers (GstOMXVideoEnc * self)
{
- if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
+ switch (self->input_allocation) {
+ case GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER:
+ if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
+ return FALSE;
+ break;
+ case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC:
+ if (gst_omx_port_use_dynamic_buffers (self->enc_in_port) != OMX_ErrorNone)
+ return FALSE;
+ break;
+ case GST_OMX_BUFFER_ALLOCATION_USE_BUFFER:
+ default:
+ /* Not supported */
+ g_return_val_if_reached (FALSE);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+check_input_alignment (GstOMXVideoEnc * self, GstMapInfo * map)
+{
+ OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->enc_in_port->port_def;
+
+ if (map->size != port_def->nBufferSize) {
+ GST_DEBUG_OBJECT (self,
+ "input buffer has wrong size/stride (%" G_GSIZE_FORMAT
+ " expected: %u), can't use dynamic allocation",
+ map->size, (guint32) port_def->nBufferSize);
return FALSE;
+ }
+
+ if (port_def->nBufferAlignment &&
+ (GPOINTER_TO_UINT (map->data) & (port_def->nBufferAlignment - 1)) != 0) {
+ GST_DEBUG_OBJECT (self,
+ "input buffer is not properly aligned (address: %p alignment: %u bytes), can't use dynamic allocation",
+ map->data, (guint32) port_def->nBufferAlignment);
+ return FALSE;
+ }
return TRUE;
}
+/* Check if @inbuf's alignment and stride matches the requirements to use the
+ * dynamic buffer mode. */
+static gboolean
+can_use_dynamic_buffer_mode (GstOMXVideoEnc * self, GstBuffer * inbuf)
+{
+ GstMapInfo map;
+ gboolean result = FALSE;
+
+ if (gst_buffer_n_memory (inbuf) > 1) {
+ GST_DEBUG_OBJECT (self,
+ "input buffer contains more than one memory, can't use dynamic allocation");
+ return FALSE;
+ }
+
+ if (!gst_buffer_map (inbuf, &map, GST_MAP_READ)) {
+ GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
+ ("failed to map input buffer"));
+ return FALSE;
+ }
+
+ result = check_input_alignment (self, &map);
+
+ gst_buffer_unmap (inbuf, &map);
+ return result;
+}
+
+/* Choose the allocation mode for input buffers depending of what's supported by
+ * the component and the size/alignment of the input buffer. */
+static GstOMXBufferAllocation
+gst_omx_video_enc_pick_input_allocation_mode (GstOMXVideoEnc * self,
+ GstBuffer * inbuf)
+{
+ if (!gst_omx_is_dynamic_allocation_supported ())
+ return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
+
+ if (can_use_dynamic_buffer_mode (self, inbuf)) {
+ GST_DEBUG_OBJECT (self,
+ "input buffer is properly aligned, use dynamic allocation");
+ return GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC;
+ }
+
+ GST_DEBUG_OBJECT (self, "let input buffer allocate its buffers");
+ return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
+}
+
static gboolean
gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
{
@@ -1139,6 +1220,9 @@ gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
if (!gst_omx_video_enc_configure_input_buffer (self, input))
return FALSE;
+ self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self,
+ input);
+
GST_DEBUG_OBJECT (self, "Enabling component");
if (self->disabled) {
if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
@@ -1437,6 +1521,35 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
goto done;
}
+ if (self->enc_in_port->allocation ==
+ GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
+ if (gst_buffer_n_memory (inbuf) > 1) {
+ GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
+ ("input buffer now has more than one memory, can't use dynamic allocation any more"));
+ return FALSE;
+ }
+
+ /* Map and keep a ref on the buffer while it's being processed
+ * by the OMX component. */
+ if (!gst_omx_buffer_map_frame (outbuf, inbuf, info)) {
+ GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
+ ("failed to map input buffer"));
+ return FALSE;
+ }
+
+ if (!check_input_alignment (self, &outbuf->input_frame.map[0])) {
+ GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
+ ("input buffer now has wrong alignment/stride, can't use dynamic allocation any more"));
+ return FALSE;
+ }
+
+ GST_LOG_OBJECT (self, "Transfer buffer of %" G_GSIZE_FORMAT " bytes",
+ gst_buffer_get_size (inbuf));
+
+ ret = TRUE;
+ goto done;
+ }
+
/* Same strides and everything */
if (gst_buffer_get_size (inbuf) ==
outbuf->omx_buf->nAllocLen - outbuf->omx_buf->nOffset) {
diff --git a/omx/gstomxvideoenc.h b/omx/gstomxvideoenc.h
index 265d4fe..345b9d1 100644
--- a/omx/gstomxvideoenc.h
+++ b/omx/gstomxvideoenc.h
@@ -77,6 +77,8 @@ struct _GstOMXVideoEnc
guint32 quant_b_frames;
GstFlowReturn downstream_flow_ret;
+
+ GstOMXBufferAllocation input_allocation;
};
struct _GstOMXVideoEncClass