Commit 1285807f authored by Martin Storsjö's avatar Martin Storsjö

omxil: Retry getting an output buffer while waiting for a free input buffer

As soon as either the input packet has been written, or an output
buffer is available, we return from the function, allowing passing
the output frames down the pipeline as soon as possible. (For
direct rendering, a new output buffer only become available for
the codec to use once the picture is rendered or discarded.)

This fixes playback with IOMX direct rendering on Nexus S, which
only uses 2 output buffers in this mode (min_undequeued = 1,
nBufferCountMin = 1), and probably also for other devices with
a small number of output buffers.

(On the Nexus S, the number of output buffers can't be increased,
since this leads to blinking.)

This is similar to how available input/output buffers are checked
in the MediaCodec plugin.

This still isn't completely foolproof with respect to the case when
an input packet needs to be split up over multiple input buffers
though, but it wasn't completely correct previously either.

Also make sure we don't return from the function without consuming
the input packet or returning an output frame, which earlier would
lead to a skipped input packet and leaked memory. (This could
previously happen on reconfiguration, or on timeout while waiting for
an input buffer.)

Finally, make sure we don't block indefinitely in case the playback
is paused (causing the decoder to block while waiting for a free
output buffer). The same solution as in the android mediacodec
decoder is used here.
Signed-off-by: Martin Storsjö's avatarMartin Storsjö <martin@martin.st>
parent ef230f41
......@@ -1456,7 +1456,7 @@ static int DecodeVideoInput( decoder_t *p_dec, OmxPort *p_port, block_t **pp_blo
block_t *p_block = *pp_block;
/* Send the input buffer to the component */
OMX_FIFO_GET_TIMEOUT(&p_port->fifo, p_header, 200000);
OMX_FIFO_GET_TIMEOUT(&p_port->fifo, p_header, 10000);
if (p_header && p_header->nFlags & SENTINEL_FLAG) {
free(p_header);
......@@ -1532,7 +1532,6 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
picture_t *p_pic = NULL;
OMX_ERRORTYPE omx_error;
unsigned int i;
bool b_reconfig;
block_t *p_block;
if( !pp_block || !*pp_block )
......@@ -1578,29 +1577,64 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
if( DecodeVideoOutput( p_dec, &p_sys->out, &p_pic ) != 0 )
goto error;
if( DecodeVideoInput( p_dec, &p_sys->in, pp_block, 0, &b_reconfig ) != 0 )
goto error;
/* Loop as long as we haven't either got an input buffer (and cleared
* *pp_block) or got an output picture */
int max_polling_attempts = 100;
int attempts = 0;
while( *pp_block && !p_pic ) {
bool b_reconfig = false;
/* If we don't have a p_pic from the first try. Try again */
if( !b_reconfig && !p_pic &&
DecodeVideoOutput( p_dec, &p_sys->out, &p_pic ) != 0 )
goto error;
if( DecodeVideoInput( p_dec, &p_sys->in, pp_block, 0, &b_reconfig ) != 0 )
goto error;
/* Handle the PortSettingsChanged events */
for(i = 0; i < p_sys->ports; i++)
{
OmxPort *p_port = &p_sys->p_ports[i];
if(p_port->b_reconfigure)
/* If we don't have a p_pic from the first try. Try again */
if( !b_reconfig && !p_pic &&
DecodeVideoOutput( p_dec, &p_sys->out, &p_pic ) != 0 )
goto error;
/* Handle the PortSettingsChanged events */
for(i = 0; i < p_sys->ports; i++)
{
omx_error = PortReconfigure(p_dec, p_port);
p_port->b_reconfigure = 0;
CHECK_ERROR(omx_error, "PortReconfigure failed");
OmxPort *p_port = &p_sys->p_ports[i];
if(p_port->b_reconfigure)
{
omx_error = PortReconfigure(p_dec, p_port);
p_port->b_reconfigure = 0;
CHECK_ERROR(omx_error, "PortReconfigure failed");
}
if(p_port->b_update_def)
{
omx_error = GetPortDefinition(p_dec, p_port, p_port->p_fmt);
p_port->b_update_def = 0;
CHECK_ERROR(omx_error, "GetPortDefinition failed");
}
}
if(p_port->b_update_def)
{
omx_error = GetPortDefinition(p_dec, p_port, p_port->p_fmt);
p_port->b_update_def = 0;
CHECK_ERROR(omx_error, "GetPortDefinition failed");
attempts++;
/* With opaque DR the output buffers are released by the
vout therefore we implement a timeout for polling in
order to avoid being indefinitely stalled in this loop, if
playback is paused. */
if( p_sys->out.p_hwbuf && attempts == max_polling_attempts ) {
#ifdef USE_IOMX
picture_t *invalid_picture = decoder_NewPicture(p_dec);
if (invalid_picture) {
invalid_picture->date = VLC_TS_INVALID;
picture_sys_t *p_picsys = invalid_picture->p_sys;
p_picsys->pf_display_callback = NULL;
p_picsys->pf_unlock_callback = NULL;
p_picsys->p_dec = NULL;
p_picsys->i_index = -1;
p_picsys->b_valid = false;
} else {
/* If we cannot return a picture we must free the
block since the decoder will proceed with the
next block. */
block_Release(p_block);
*pp_block = NULL;
}
return invalid_picture;
#endif
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment