[vlc-devel] [PATCH 2/2] mediacodec: handle vc1/h264/hevc opening if there is no extradata

Thomas Guillem thomas at gllm.fr
Tue Apr 21 19:06:17 CEST 2015


On Tue, Apr 21, 2015, at 19:04, Thomas Guillem wrote:
> For h264/vc1: do a delayed opening from DecodeVideo if there is no
> extradata in
> OpenDecoder.
> 
> For hevc: abort mediacodec if there is no extradata. This a temporary
> workaround waiting for a better hevc packetizer.

Same patch, but I added a temporary workaround for HEVC.

> 
> Fixes #14429
> ---
>  modules/codec/omxil/android_mediacodec.c | 177
>  +++++++++++++++++++++++--------
>  1 file changed, 135 insertions(+), 42 deletions(-)
> 
> diff --git a/modules/codec/omxil/android_mediacodec.c
> b/modules/codec/omxil/android_mediacodec.c
> index 5d78953..6314107 100644
> --- a/modules/codec/omxil/android_mediacodec.c
> +++ b/modules/codec/omxil/android_mediacodec.c
> @@ -29,6 +29,7 @@
>  
>  #include <jni.h>
>  #include <stdint.h>
> +#include <assert.h>
>  
>  #include <vlc_common.h>
>  #include <vlc_plugin.h>
> @@ -264,6 +265,7 @@ static const struct member members[] = {
>   *****************************************************************************/
>  static int  OpenDecoder(vlc_object_t *);
>  static void CloseDecoder(vlc_object_t *);
> +static void CloseMediaCodec(decoder_t *p_dec, JNIEnv *env);
>  
>  static picture_t *DecodeVideo(decoder_t *, block_t **);
>  
> @@ -390,17 +392,14 @@ end:
>  }
>  
>  /*****************************************************************************
> - * OpenDecoder: Create the decoder instance
> + * OpenMediaCodec: Create the mediacodec instance
>   *****************************************************************************/
> -static int OpenDecoder(vlc_object_t *p_this)
> +static int OpenMediaCodec(decoder_t *p_dec, JNIEnv* env)
>  {
> -    decoder_t *p_dec = (decoder_t*)p_this;
> -    decoder_sys_t *p_sys;
> -
> -    if (p_dec->fmt_in.i_cat != VIDEO_ES && !p_dec->b_force)
> -        return VLC_EGENERIC;
> -
> +    decoder_sys_t *p_sys = p_dec->p_sys;
>      const char *mime = NULL;
> +    size_t fmt_profile = 0;
> +
>      switch (p_dec->fmt_in.i_codec) {
>      case VLC_CODEC_HEVC: mime = "video/hevc"; break;
>      case VLC_CODEC_H264: mime = "video/avc"; break;
> @@ -411,32 +410,12 @@ static int OpenDecoder(vlc_object_t *p_this)
>      case VLC_CODEC_VP8:  mime = "video/x-vnd.on2.vp8"; break;
>      case VLC_CODEC_VP9:  mime = "video/x-vnd.on2.vp9"; break;
>      default:
> -        msg_Dbg(p_dec, "codec %4.4s not supported", (char
> *)&p_dec->fmt_in.i_codec);
> -        return VLC_EGENERIC;
> +        vlc_assert_unreachable();
>      }
>  
> -    size_t fmt_profile = 0;
>      if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
>          h264_get_profile_level(&p_dec->fmt_in, &fmt_profile, NULL,
>          NULL);
>  
> -    /* Allocate the memory needed to store the decoder's structure */
> -    if ((p_dec->p_sys = p_sys = calloc(1, sizeof(*p_sys))) == NULL)
> -        return VLC_ENOMEM;
> -
> -    p_dec->pf_decode_video = DecodeVideo;
> -
> -    p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;
> -    p_dec->fmt_out.video = p_dec->fmt_in.video;
> -    p_dec->fmt_out.audio = p_dec->fmt_in.audio;
> -    p_dec->b_need_packetized = true;
> -
> -    JNIEnv* env = NULL;
> -    if (!(env = jni_get_env(THREAD_NAME)))
> -        goto error;
> -
> -    if (!InitJNIFields(p_dec, env))
> -        goto error;
> -
>      int num_codecs = (*env)->CallStaticIntMethod(env,
>      jfields.media_codec_list_class,
>                                                   jfields.get_codec_count);
>      jobject codec_name = NULL;
> @@ -671,51 +650,145 @@ loopclean:
>      return VLC_SUCCESS;
>  
>   error:
> -    CloseDecoder(p_this);
> +    CloseMediaCodec(p_dec, env);
>      return VLC_EGENERIC;
>  }
>  
> -static void CloseDecoder(vlc_object_t *p_this)
> +/*****************************************************************************
> + * CloseMediaCodec: Close the mediacodec instance
> +
> *****************************************************************************/
> +static void CloseMediaCodec(decoder_t *p_dec, JNIEnv *env)
>  {
> -    decoder_t *p_dec = (decoder_t *)p_this;
>      decoder_sys_t *p_sys = p_dec->p_sys;
> -    JNIEnv *env = NULL;
>  
>      if (!p_sys)
>          return;
>  
> +    free(p_sys->name);
> +    p_sys->name = NULL;
> +
>      /* Invalidate all pictures that are currently in flight in order
>       * to prevent the vout from using destroyed output buffers. */
> -    if (p_sys->direct_rendering)
> +    if (p_sys->direct_rendering) {
>          InvalidateAllPictures(p_dec);
> +        p_sys->direct_rendering = false;
> +    }
>  
> -    if (!(env = jni_get_env(THREAD_NAME)))
> -        goto cleanup;
> -
> -    if (p_sys->input_buffers)
> +    if (p_sys->input_buffers) {
>          (*env)->DeleteGlobalRef(env, p_sys->input_buffers);
> -    if (p_sys->output_buffers)
> +        p_sys->input_buffers = NULL;
> +    }
> +    if (p_sys->output_buffers) {
>          (*env)->DeleteGlobalRef(env, p_sys->output_buffers);
> +        p_sys->output_buffers = NULL;
> +    }
>      if (p_sys->codec) {
>          if (p_sys->started)
>          {
>              (*env)->CallVoidMethod(env, p_sys->codec, jfields.stop);
>              if (CHECK_EXCEPTION())
>                  msg_Err(p_dec, "Exception in MediaCodec.stop");
> +            p_sys->started = false;
>          }
>          if (p_sys->allocated)
>          {
>              (*env)->CallVoidMethod(env, p_sys->codec, jfields.release);
>              if (CHECK_EXCEPTION())
>                  msg_Err(p_dec, "Exception in MediaCodec.release");
> +            p_sys->allocated = false;
>          }
>          (*env)->DeleteGlobalRef(env, p_sys->codec);
> +        p_sys->codec = NULL;
>      }
> -    if (p_sys->buffer_info)
> +    if (p_sys->buffer_info) {
>          (*env)->DeleteGlobalRef(env, p_sys->buffer_info);
> +        p_sys->buffer_info = NULL;
> +    }
> +}
> +
> +/*****************************************************************************
> + * OpenDecoder: Create the decoder instance
> +
> *****************************************************************************/
> +static int OpenDecoder(vlc_object_t *p_this)
> +{
> +    decoder_t *p_dec = (decoder_t*)p_this;
> +    JNIEnv* env = NULL;
> +
> +    if (p_dec->fmt_in.i_cat != VIDEO_ES && !p_dec->b_force)
> +        return VLC_EGENERIC;
> +
> +    switch (p_dec->fmt_in.i_codec) {
> +    case VLC_CODEC_HEVC:
> +    case VLC_CODEC_H264:
> +    case VLC_CODEC_H263:
> +    case VLC_CODEC_MP4V:
> +    case VLC_CODEC_WMV3:
> +    case VLC_CODEC_VC1:
> +    case VLC_CODEC_VP8:
> +    case VLC_CODEC_VP9:
> +        break;
> +    default:
> +        msg_Dbg(p_dec, "codec %4.4s not supported", (char
> *)&p_dec->fmt_in.i_codec);
> +        return VLC_EGENERIC;
> +    }
> +
> +    /* Allocate the memory needed to store the decoder's structure */
> +    if ((p_dec->p_sys = calloc(1, sizeof(*p_dec->p_sys))) == NULL)
> +        return VLC_ENOMEM;
> +
> +    p_dec->pf_decode_video = DecodeVideo;
> +
> +    p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;
> +    p_dec->fmt_out.video = p_dec->fmt_in.video;
> +    p_dec->fmt_out.audio = p_dec->fmt_in.audio;
> +    p_dec->b_need_packetized = true;
> +
> +    if (!(env = jni_get_env(THREAD_NAME)))
> +        goto error;
> +
> +    if (!InitJNIFields(p_dec, env))
> +        goto error;
> +
> +    if (!p_dec->fmt_in.i_extra
> +     && (p_dec->fmt_in.i_codec == VLC_CODEC_VC1
> +      || p_dec->fmt_in.i_codec == VLC_CODEC_H264
> +      || p_dec->fmt_in.i_codec == VLC_CODEC_HEVC))
> +    {
> +        /* TODO:
> +         * remove this workaround when hevc packetizer can send
> extradata */
> +        if(p_dec->fmt_in.i_codec == VLC_CODEC_HEVC)
> +        {
> +            msg_Err(p_dec, "Can't open hevc without extradata");
> +            return VLC_EGENERIC;
> +        }
> +        msg_Warn(p_dec, "waiting for extra data for codec %4.4s",
> +                p_dec->fmt_in.i_extra);
> +        return VLC_SUCCESS;
> +    } else
> +        return OpenMediaCodec(p_dec, env);
> +
> + error:
> +    CloseDecoder(p_this);
> +    return VLC_EGENERIC;
> +}
> +
> +/*****************************************************************************
> + * CloseDecoder: Close the decoder instance
> +
> *****************************************************************************/
> +static void CloseDecoder(vlc_object_t *p_this)
> +{
> +    decoder_t *p_dec = (decoder_t *)p_this;
> +    decoder_sys_t *p_sys = p_dec->p_sys;
> +    JNIEnv *env = NULL;
> +
> +    if (!p_sys)
> +        return;
> +
> +    if ((env = jni_get_env(THREAD_NAME)))
> +        CloseMediaCodec(p_dec, env);
> +    else
> +        msg_Warn(p_dec, "Can't get a JNIEnv, can't close mediacodec !");
>  
> -cleanup:
> -    free(p_sys->name);
>      ArchitectureSpecificCopyHooksDestroy(p_sys->pixel_format,
>      &p_sys->architecture_specific_data);
>      free(p_sys->pp_inflight_pictures);
>      if (p_sys->timestamp_fifo)
> @@ -1032,6 +1105,26 @@ static picture_t *DecodeVideo(decoder_t *p_dec,
> block_t **pp_block)
>      if (!(env = jni_get_env(THREAD_NAME)))
>          goto endclean;
>  
> +    /* try delayed opening if there is a new extra data */
> +    if (!p_sys->codec && p_dec->fmt_in.i_extra)
> +    {
> +        if (OpenMediaCodec(p_dec, env) != VLC_SUCCESS)
> +        {
> +            p_sys->error_state = true;
> +            goto endclean;
> +        }
> +    }
> +
> +    if (!p_sys->codec)
> +    {
> +        if (p_block)
> +        {
> +            block_Release(p_block);
> +            *pp_block = NULL;
> +        }
> +        return NULL;
> +    }
> +
>      if (p_block && p_block->i_flags &
>      (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
>          block_Release(p_block);
>          *pp_block = NULL;
> -- 
> 2.1.3
> 



More information about the vlc-devel mailing list