omxvideodec/enc: add hack updating nBufferCountActual before allocating
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Fri, 27 Apr 2018 14:26:36 +0000 (16:26 +0200)
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Fri, 8 Jun 2018 07:44:49 +0000 (09:44 +0200)
The OMX specs states that the nBufferCountActual of a port has to default
to its nBufferCountMin. If we don't change nBufferCountActual we purely rely
on this default. But in some cases, OMX may change nBufferCountMin before we
allocate buffers. Like for example when configuring the input ports with the
actual format, it may decrease the number of minimal buffers required.
This method checks this and update nBufferCountActual if needed so we'll use
less buffers than the worst case in such scenarios.

SetParameter() needs to be called when the port is either disabled or
the component in the Loaded state.

Don't do this for the decoder output as
gst_omx_video_dec_allocate_output_buffers() already check
nBufferCountMin when computing the number of output buffers.

On some platform, like rpi, the default nBufferCountActual is much
higher than nBufferCountMin so only enable this using a specific gst-omx
hack.

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

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

index 6276fea..94bc014 100644 (file)
@@ -2543,6 +2543,34 @@ done:
   return err;
 }
 
+/* The OMX specs states that the nBufferCountActual of a port has to default
+ * to its nBufferCountMin. If we don't change nBufferCountActual we purely rely
+ * on this default. But in some cases, OMX may change nBufferCountMin before we
+ * allocate buffers. Like for example when configuring the input ports with the
+ * actual format, it may decrease the number of minimal buffers required.
+ * This method checks this and update nBufferCountActual if needed so we'll use
+ * less buffers than the worst case in such scenarios.
+ */
+gboolean
+gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port)
+{
+  OMX_PARAM_PORTDEFINITIONTYPE port_def;
+
+  gst_omx_port_get_port_definition (port, &port_def);
+  if (port_def.nBufferCountActual != port_def.nBufferCountMin) {
+    port_def.nBufferCountActual = port_def.nBufferCountMin;
+
+    GST_DEBUG_OBJECT (port->comp->parent,
+        "set port %d nBufferCountActual to %d",
+        (guint) port->index, (guint) port_def.nBufferCountActual);
+
+    if (gst_omx_port_update_port_definition (port, &port_def) != OMX_ErrorNone)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
 typedef GType (*GGetTypeFunction) (void);
 
 static const GGetTypeFunction types[] = {
@@ -2858,6 +2886,8 @@ gst_omx_parse_hacks (gchar ** hacks)
       hacks_flags |= GST_OMX_HACK_PASS_PROFILE_TO_DECODER;
     else if (g_str_equal (*hacks, "pass-color-format-to-decoder"))
       hacks_flags |= GST_OMX_HACK_PASS_COLOR_FORMAT_TO_DECODER;
+    else if (g_str_equal (*hacks, "ensure-buffer-count-actual"))
+      hacks_flags |= GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL;
     else
       GST_WARNING ("Unknown hack: %s", *hacks);
     hacks++;
index e1ea76b..4600833 100644 (file)
@@ -200,6 +200,13 @@ G_BEGIN_DECLS
  */
 #define GST_OMX_HACK_PASS_COLOR_FORMAT_TO_DECODER        G_GUINT64_CONSTANT (0x0000000000001000)
 
+/* If set, automatically update nBufferCountActual to nBufferCountMin before
+ * allocating buffers. This can be used on OMX implementation decreasing
+ * nBufferCountMin depending of the format and so can reduce the number
+ * of allocated buffers.
+ */
+#define GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL          G_GUINT64_CONSTANT (0x0000000000002000)
+
 typedef struct _GstOMXCore GstOMXCore;
 typedef struct _GstOMXPort GstOMXPort;
 typedef enum _GstOMXPortDirection GstOMXPortDirection;
@@ -448,6 +455,7 @@ OMX_ERRORTYPE     gst_omx_port_mark_reconfigured (GstOMXPort * port);
 OMX_ERRORTYPE     gst_omx_port_set_enabled (GstOMXPort * port, gboolean enabled);
 OMX_ERRORTYPE     gst_omx_port_wait_enabled (GstOMXPort * port, GstClockTime timeout);
 gboolean          gst_omx_port_is_enabled (GstOMXPort * port);
+gboolean          gst_omx_port_ensure_buffer_count_actual (GstOMXPort * port);
 
 /* OMX 1.2.0 dynamic allocation mode */
 gboolean          gst_omx_is_dynamic_allocation_supported (void);
index 1d94cce..1428ef8 100644 (file)
@@ -2341,6 +2341,19 @@ gst_omx_video_dec_pick_input_allocation_mode (GstOMXVideoDec * self,
 }
 
 static gboolean
+gst_omx_video_dec_ensure_nb_in_buffers (GstOMXVideoDec * self)
+{
+  GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
+
+  if ((klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL)) {
+    if (!gst_omx_port_ensure_buffer_count_actual (self->dec_in_port))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
 gst_omx_video_dec_enable (GstOMXVideoDec * self, GstBuffer * input)
 {
   GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
@@ -2351,6 +2364,8 @@ gst_omx_video_dec_enable (GstOMXVideoDec * self, GstBuffer * input)
       input);
 
   if (self->disabled) {
+    if (!gst_omx_video_dec_ensure_nb_in_buffers (self))
+      return FALSE;
     if (gst_omx_port_set_enabled (self->dec_in_port, TRUE) != OMX_ErrorNone)
       return FALSE;
     if (!gst_omx_video_dec_allocate_in_buffers (self))
@@ -2376,6 +2391,9 @@ gst_omx_video_dec_enable (GstOMXVideoDec * self, GstBuffer * input)
     if (!gst_omx_video_dec_negotiate (self))
       GST_LOG_OBJECT (self, "Negotiation failed, will get output format later");
 
+    if (!gst_omx_video_dec_ensure_nb_in_buffers (self))
+      return FALSE;
+
     if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
       /* Disable output port */
       if (gst_omx_port_set_enabled (self->dec_out_port, FALSE) != OMX_ErrorNone)
@@ -2802,6 +2820,11 @@ gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
         goto reconfigure_error;
       }
 
+      if (!gst_omx_video_dec_ensure_nb_in_buffers (self)) {
+        GST_VIDEO_DECODER_STREAM_LOCK (self);
+        goto reconfigure_error;
+      }
+
       err = gst_omx_port_set_enabled (port, TRUE);
       if (err != OMX_ErrorNone) {
         GST_VIDEO_DECODER_STREAM_LOCK (self);
index 8a0ed3f..56e2651 100644 (file)
@@ -1368,6 +1368,19 @@ gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port,
   return flow_ret;
 }
 
+static gboolean
+gst_omx_video_enc_ensure_nb_out_buffers (GstOMXVideoEnc * self)
+{
+  GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
+
+  if ((klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL)) {
+    if (!gst_omx_port_ensure_buffer_count_actual (self->enc_out_port))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
 static void
 gst_omx_video_enc_loop (GstOMXVideoEnc * self)
 {
@@ -1444,6 +1457,9 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self)
     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
 
     if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
+      if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
+        goto reconfigure_error;
+
       err = gst_omx_port_set_enabled (port, TRUE);
       if (err != OMX_ErrorNone)
         goto reconfigure_error;
@@ -1875,6 +1891,19 @@ gst_omx_video_enc_configure_input_buffer (GstOMXVideoEnc * self,
 }
 
 static gboolean
+gst_omx_video_enc_ensure_nb_in_buffers (GstOMXVideoEnc * self)
+{
+  GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
+
+  if ((klass->cdata.hacks & GST_OMX_HACK_ENSURE_BUFFER_COUNT_ACTUAL)) {
+    if (!gst_omx_port_ensure_buffer_count_actual (self->enc_in_port))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
 gst_omx_video_enc_allocate_in_buffers (GstOMXVideoEnc * self)
 {
   switch (self->input_allocation) {
@@ -2008,6 +2037,12 @@ gst_omx_video_enc_enable (GstOMXVideoEnc * self, GstBuffer * input)
 #endif
 
   GST_DEBUG_OBJECT (self, "Enabling component");
+
+  if (!gst_omx_video_enc_ensure_nb_in_buffers (self))
+    return FALSE;
+  if (!gst_omx_video_enc_ensure_nb_out_buffers (self))
+    return FALSE;
+
   if (self->disabled) {
     if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
       return FALSE;
@@ -2650,6 +2685,11 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder,
         goto reconfigure_error;
       }
 
+      if (!gst_omx_video_enc_ensure_nb_in_buffers (self)) {
+        GST_VIDEO_ENCODER_STREAM_LOCK (self);
+        goto reconfigure_error;
+      }
+
       err = gst_omx_port_set_enabled (port, TRUE);
       if (err != OMX_ErrorNone) {
         GST_VIDEO_ENCODER_STREAM_LOCK (self);