[vlc-devel] [RFC PATCH] mediacodec: fix a deadlock when seeking on pause

Thomas Guillem tom at gllm.fr
Tue Oct 28 17:05:26 CET 2014


If you are OK, I have to do the same patch for iomx-dr.

On Tue, Oct 28, 2014, at 17:01, Thomas Guillem wrote:
> MediaCodec with direct rendering can be stuck waiting for an input buffer
> when
> video is paused. Indeed, input buffers availability depends on output
> buffers.
> When the video is paused, output buffers are not released or displayed
> anymore,
> therefore, no more input buffers are available.
> 
> A previous hack was made in order to fix a deadlock when mediacodec was
> stuck
> and when exit was requested. Mediacodec returned an invalid picture after
> a
> small delay, then DecoderIsExitRequested in DecoderDecodeVideo was
> checked and
> this decoder could be exited without blocking.
> 
> This previous hack didn't fix a deadlock when a paused video was flushed,
> due
> to a seek. Indeed, when stuck, mediacodec is feed with the same block.
> Therefore it won't receive a new block containing the FLUSH flags and it
> will
> be stuck returning an invalid picture.
> 
> One (ugly) way to fix this deadlock is, when you return an
> invalid_picture, to
> put the block in an internal FIFO and tell the core decoder that the
> block is
> processed. This way, new blocks will be given on next Decode calls and
> the
> Decoder will be able to handle a flush block. If the decoder is stuck
> when
> paused and resumed again, the Decode function will first process the
> block that
> come from the internal FIFO. There will be no discontinuity at all.
> 
> (fixes #12397)
> ---
>  modules/codec/omxil/android_mediacodec.c | 40
>  +++++++++++++++++++++++++++++---
>  1 file changed, 37 insertions(+), 3 deletions(-)
> 
> diff --git a/modules/codec/omxil/android_mediacodec.c
> b/modules/codec/omxil/android_mediacodec.c
> index 6d204d7..0673887 100644
> --- a/modules/codec/omxil/android_mediacodec.c
> +++ b/modules/codec/omxil/android_mediacodec.c
> @@ -173,6 +173,7 @@ struct decoder_sys_t
>      picture_t** inflight_picture; /**< stores the inflight picture for
>      each output buffer or NULL */
>  
>      timestamp_fifo_t *timestamp_fifo;
> +    block_fifo_t *p_extra_input_fifo;
>  };
>  
>  enum Types
> @@ -536,6 +537,9 @@ static int OpenDecoder(vlc_object_t *p_this)
>          (*env)->ExceptionClear(env);
>          goto error;
>      }
> +    p_sys->p_extra_input_fifo = block_FifoNew();
> +    if (!p_sys->p_extra_input_fifo)
> +        goto error;
>      p_sys->started = true;
>  
>      p_sys->input_buffers = (*env)->CallObjectMethod(env, p_sys->codec,
>      p_sys->get_input_buffers);
> @@ -606,6 +610,9 @@ static void CloseDecoder(vlc_object_t *p_this)
>          (*env)->DeleteGlobalRef(env, p_sys->buffer_info);
>      jni_detach_thread();
>  
> +    if (p_sys->p_extra_input_fifo)
> +        block_FifoRelease(p_sys->p_extra_input_fifo);
> +
>      free(p_sys->name);
>      ArchitectureSpecificCopyHooksDestroy(p_sys->pixel_format,
>      &p_sys->architecture_specific_data);
>      free(p_sys->inflight_picture);
> @@ -909,8 +916,10 @@ static picture_t *DecodeVideo(decoder_t *p_dec,
> block_t **pp_block)
>  
>      jni_attach_thread(&env, THREAD_NAME);
>  
> +    /* First check if the block in arguments has any flush flags */
>      if (p_block->i_flags &
>      (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
>          block_Release(p_block);
> +        block_FifoEmpty(p_sys->p_extra_input_fifo);
>          timestamp_FifoEmpty(p_sys->timestamp_fifo);
>          if (p_sys->decoded) {
>              /* Invalidate all pictures that are currently in flight
> @@ -931,6 +940,12 @@ static picture_t *DecodeVideo(decoder_t *p_dec,
> block_t **pp_block)
>          return NULL;
>      }
>  
> +    if (block_FifoCount(p_sys->p_extra_input_fifo) > 0) {
> +        /* Don't dequeue the first block, but just peek it. The dequeue
> is done
> +         * at the end if the block has been processed */
> +        p_block = block_FifoShow(p_sys->p_extra_input_fifo);
> +    }
> +
>      /* Use the aspect ratio provided by the input (ie read from
>      packetizer).
>       * Don't check the current value of the aspect ratio in fmt_out,
>       since we
>       * want to allow changes in it to propagate. */
> @@ -972,6 +987,14 @@ static picture_t *DecodeVideo(decoder_t *p_dec,
> block_t **pp_block)
>              if (p_sys->direct_rendering && attempts ==
>              max_polling_attempts) {
>                  picture_t *invalid_picture = decoder_NewPicture(p_dec);
>                  if (invalid_picture) {
> +                    /* HACK: Assign NULL to *pp_block in order to get a
> new
> +                     * pp_block for the next call and put this block in
> an
> +                     * internal fifo in order to not lost it. That way,
> the
> +                     * decoder won't be stuck in case of seek since it
> will
> +                     * receive a new block with the flush flag. */
> +                    block_FifoPut(p_sys->p_extra_input_fifo, *pp_block);
> +                    *pp_block = NULL;
> +
>                      invalid_picture->date = VLC_TS_INVALID;
>                      picture_sys_t *p_picsys = invalid_picture->p_sys;
>                      p_picsys->pf_display_callback = NULL;
> @@ -984,8 +1007,10 @@ static picture_t *DecodeVideo(decoder_t *p_dec,
> block_t **pp_block)
>                      /* 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;
> +                    if (p_block == *pp_block) {
> +                        block_Release(p_block);
> +                        *pp_block = NULL;
> +                    }
>                  }
>                  jni_detach_thread();
>                  return invalid_picture;
> @@ -1032,7 +1057,16 @@ static picture_t *DecodeVideo(decoder_t *p_dec,
> block_t **pp_block)
>          GetOutput(p_dec, env, &p_pic, 0);
>      jni_detach_thread();
>  
> -    block_Release(p_block);
> +    if (p_block == *pp_block) {
> +        /* Normal way: the block comes from arguments */
> +        block_Release(p_block);
> +    } else {
> +        /* Hack way: the block comes from the internal fifo */
> +        /* Dequeue the first block since it has been processed */
> +        p_block = block_FifoGet(p_sys->p_extra_input_fifo);
> +        /* The pp_block in arguments was not processed, so put it in the
> FIFO */
> +        block_FifoPut(p_sys->p_extra_input_fifo, *pp_block);
> +    }
>      *pp_block = NULL;
>  
>      return p_pic;
> -- 
> 2.1.0
> 



More information about the vlc-devel mailing list