omxvideodec/enc: add hack updating nBufferCountActual before allocating

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
This commit is contained in:
Guillaume Desmottes 2018-04-27 16:26:36 +02:00
parent 338ff34e5e
commit 9a8e863862
4 changed files with 101 additions and 0 deletions

View 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++;

View 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);

View file

@ -2340,6 +2340,19 @@ gst_omx_video_dec_pick_input_allocation_mode (GstOMXVideoDec * self,
return GST_OMX_BUFFER_ALLOCATION_ALLOCATE_BUFFER;
}
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)
{
@ -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);

View 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;
@ -1874,6 +1890,19 @@ gst_omx_video_enc_configure_input_buffer (GstOMXVideoEnc * self,
return TRUE;
}
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)
{
@ -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);