omxvideoenc: implement dmabuf import on zynqultrascaleplus
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Thu, 27 Jul 2017 09:21:59 +0000 (11:21 +0200)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Mon, 29 Jan 2018 15:21:02 +0000 (15:21 +0000)
The Zynq UltraScale+ encoder implements a custom OMX extension to
directly import dmabuf saving the need of mapping input buffers.

This can be use with either 'v4l2src io-mode=dmabuf' or an OMX video
decoder upstream.

https://bugzilla.gnome.org/show_bug.cgi?id=792361

omx/gstomx.c
omx/gstomx.h
omx/gstomxvideoenc.c
omx/gstomxvideoenc.h

index 8754599..01718de 100644 (file)
@@ -25,6 +25,7 @@
 #endif
 
 #include <gst/gst.h>
+#include <gst/allocators/gstdmabuf.h>
 #include <string.h>
 
 #include "gstomx.h"
@@ -617,14 +618,18 @@ gst_omx_buffer_unmap (GstOMXBuffer * buffer)
   if (buffer->input_frame_mapped) {
     g_assert (!buffer->input_mem);
     g_assert (!buffer->input_buffer);
+    g_assert (!buffer->input_buffer_mapped);
     gst_video_frame_unmap (&buffer->input_frame);
     buffer->input_frame_mapped = FALSE;
   } else if (buffer->input_mem) {
     g_assert (!buffer->input_buffer);
+    g_assert (!buffer->input_buffer_mapped);
     gst_memory_unmap (buffer->input_mem, &buffer->map);
     g_clear_pointer (&buffer->input_mem, gst_memory_unref);
   } else if (buffer->input_buffer) {
-    gst_buffer_unmap (buffer->input_buffer, &buffer->map);
+    if (buffer->input_buffer_mapped)
+      gst_buffer_unmap (buffer->input_buffer, &buffer->map);
+    buffer->input_buffer_mapped = FALSE;
     g_clear_pointer (&buffer->input_buffer, gst_buffer_unref);
   }
 }
@@ -1863,6 +1868,7 @@ gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input,
   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
   g_return_val_if_fail (!buffer->input_mem, FALSE);
   g_return_val_if_fail (!buffer->input_buffer, FALSE);
+  g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
 
   if (!gst_video_frame_map (&buffer->input_frame, info, input, GST_MAP_READ))
     return FALSE;
@@ -1884,6 +1890,7 @@ gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
   g_return_val_if_fail (!buffer->input_mem, FALSE);
   g_return_val_if_fail (!buffer->input_buffer, FALSE);
+  g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
 
   if (!gst_memory_map (mem, &buffer->map, GST_MAP_READ))
     return FALSE;
@@ -1897,6 +1904,32 @@ gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem)
 }
 
 gboolean
+gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input)
+{
+  gint fd;
+  GstMemory *mem;
+
+  g_return_val_if_fail (buffer != NULL, FALSE);
+  g_return_val_if_fail (input != NULL, FALSE);
+  g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
+  g_return_val_if_fail (!buffer->input_mem, FALSE);
+  g_return_val_if_fail (!buffer->input_buffer, FALSE);
+  g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
+
+  mem = gst_buffer_peek_memory (input, 0);
+  g_return_val_if_fail (gst_is_dmabuf_memory (mem), FALSE);
+
+  fd = gst_dmabuf_memory_get_fd (mem);
+
+  buffer->input_buffer = gst_buffer_ref (input);
+  buffer->omx_buf->pBuffer = GUINT_TO_POINTER (fd);
+  buffer->omx_buf->nAllocLen = gst_memory_get_sizes (mem, NULL, NULL);
+  buffer->omx_buf->nFilledLen = buffer->omx_buf->nAllocLen;
+
+  return TRUE;
+}
+
+gboolean
 gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
 {
   g_return_val_if_fail (buffer != NULL, FALSE);
@@ -1904,10 +1937,12 @@ gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input)
   g_return_val_if_fail (!buffer->input_frame_mapped, FALSE);
   g_return_val_if_fail (!buffer->input_mem, FALSE);
   g_return_val_if_fail (!buffer->input_buffer, FALSE);
+  g_return_val_if_fail (!buffer->input_buffer_mapped, FALSE);
 
   if (!gst_buffer_map (input, &buffer->map, GST_MAP_READ))
     return FALSE;
 
+  buffer->input_buffer_mapped = TRUE;
   buffer->input_buffer = gst_buffer_ref (input);
   buffer->omx_buf->pBuffer = buffer->map.data;
   buffer->omx_buf->nAllocLen = buffer->map.size;
index e197c96..bf53444 100644 (file)
@@ -339,6 +339,7 @@ struct _GstOMXBuffer {
   gboolean input_frame_mapped; /* TRUE if input_frame is valid */
   GstMemory *input_mem;
   GstBuffer *input_buffer;
+  gboolean input_buffer_mapped;
   GstMapInfo map;
 };
 
@@ -420,6 +421,7 @@ OMX_ERRORTYPE     gst_omx_port_use_dynamic_buffers (GstOMXPort * port);
 gboolean          gst_omx_buffer_map_frame (GstOMXBuffer * buffer, GstBuffer * input, GstVideoInfo * info);
 gboolean          gst_omx_buffer_map_memory (GstOMXBuffer * buffer, GstMemory * mem);
 gboolean          gst_omx_buffer_map_buffer (GstOMXBuffer * buffer, GstBuffer * input);
+gboolean          gst_omx_buffer_import_fd (GstOMXBuffer * buffer, GstBuffer * input);
 
 void              gst_omx_set_default_role (GstOMXClassData *class_data, const gchar *default_role);
 
index 7a55feb..5f8046d 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <gst/gst.h>
 #include <gst/video/gstvideometa.h>
+#include <gst/allocators/gstdmabuf.h>
+
 #include <string.h>
 
 #include "gstomxvideo.h"
@@ -1222,6 +1224,36 @@ gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
 
   self->input_allocation = gst_omx_video_enc_pick_input_allocation_mode (self,
       input);
+  self->input_dmabuf = FALSE;
+
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+  if (gst_is_dmabuf_memory (gst_buffer_peek_memory (input, 0))) {
+    if (self->input_allocation == GST_OMX_BUFFER_ALLOCATION_USE_BUFFER_DYNAMIC) {
+      OMX_ALG_PORT_PARAM_BUFFER_MODE buffer_mode;
+      OMX_ERRORTYPE err;
+
+      GST_OMX_INIT_STRUCT (&buffer_mode);
+      buffer_mode.nPortIndex = self->enc_in_port->index;
+      buffer_mode.eMode = OMX_ALG_BUF_DMA;
+
+      GST_DEBUG_OBJECT (self, "Configure encoder to import dmabuf");
+
+      err =
+          gst_omx_component_set_parameter (self->enc,
+          (OMX_INDEXTYPE) OMX_ALG_IndexPortParamBufferMode, &buffer_mode);
+      if (err != OMX_ErrorNone)
+        GST_WARNING_OBJECT (self,
+            "Failed to set output buffer mode: %s (0x%08x)",
+            gst_omx_error_to_string (err), err);
+    } else {
+      GST_DEBUG_OBJECT (self,
+          "Wrong input allocation mode (%d); dynamic buffers are required to use dmabuf import",
+          self->input_allocation);
+    }
+
+    self->input_dmabuf = TRUE;
+  }
+#endif
 
   GST_DEBUG_OBJECT (self, "Enabling component");
   if (self->disabled) {
@@ -1529,22 +1561,34 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf,
       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 (!self->input_dmabuf) {
+      /* 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;
-    }
+      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));
+      GST_LOG_OBJECT (self, "Transfer buffer of %" G_GSIZE_FORMAT " bytes",
+          gst_buffer_get_size (inbuf));
+    } else {
+      /* dmabuf input */
+      if (!gst_omx_buffer_import_fd (outbuf, inbuf)) {
+        GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
+            ("failed to import dmabuf"));
+        return FALSE;
+      }
+
+      GST_LOG_OBJECT (self, "Import dmabuf of %" G_GSIZE_FORMAT " bytes",
+          gst_buffer_get_size (inbuf));
+    }
 
     ret = TRUE;
     goto done;
index 345b9d1..705441e 100644 (file)
@@ -79,6 +79,8 @@ struct _GstOMXVideoEnc
   GstFlowReturn downstream_flow_ret;
 
   GstOMXBufferAllocation input_allocation;
+  /* TRUE if encoder is passing dmabuf's fd directly to the OMX component */
+  gboolean input_dmabuf;
 };
 
 struct _GstOMXVideoEncClass