[vlc-devel] [PATCH 2/6] mediacodec: Open/Close: separate JNI part from Decoder part

Jean-Baptiste Kempf jb at videolan.org
Tue May 19 21:41:57 CEST 2015


You do a bit too much in this patch, but OK.

On 19 May, Thomas Guillem wrote :
> Rename OpenMediaCodec to StartMediaCodec and CloseMediaCodec to StopMediaCodec.
> ---
>  modules/codec/omxil/mediacodec.c | 334 ++++++++++++++++++++-------------------
>  1 file changed, 173 insertions(+), 161 deletions(-)
> 
> diff --git a/modules/codec/omxil/mediacodec.c b/modules/codec/omxil/mediacodec.c
> index af2dfec..cb1500e 100644
> --- a/modules/codec/omxil/mediacodec.c
> +++ b/modules/codec/omxil/mediacodec.c
> @@ -150,6 +150,7 @@ struct decoder_sys_t
>      jobject input_buffers, output_buffers;
>      int pixel_format;
>      int stride, slice_height;
> +    const char *mime;
>      char *name;
>  
>      /* Codec Specific Data buffer: sent in PutInput after a start or a flush
> @@ -278,7 +279,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 void JniStopMediaCodec(decoder_t *p_dec, JNIEnv *env);
>  
>  static picture_t *DecodeVideo(decoder_t *, block_t **);
>  
> @@ -538,16 +539,13 @@ static int H264SetCSD(decoder_t *p_dec, void *p_buf, size_t i_size,
>  }
>  
>  static jstring GetMediaCodecName(decoder_t *p_dec, JNIEnv *env,
> -                                 const char *mime, jstring jmime)
> +                                 const char *mime, jstring jmime,
> +                                 size_t h264_profile)
>  {
>      decoder_sys_t *p_sys = p_dec->p_sys;
>      int num_codecs;
> -    size_t fmt_profile = 0;
>      jstring jcodec_name = NULL;
>  
> -    if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
> -        h264_get_profile_level(&p_dec->fmt_in, &fmt_profile, NULL, NULL);
> -
>      num_codecs = (*env)->CallStaticIntMethod(env,
>                                               jfields.media_codec_list_class,
>                                               jfields.get_codec_count);
> @@ -600,7 +598,7 @@ static jstring GetMediaCodecName(decoder_t *p_dec, JNIEnv *env,
>                  /* The mime type is matching for this component. We
>                     now check if the capabilities of the codec is
>                     matching the video format. */
> -                if (p_dec->fmt_in.i_codec == VLC_CODEC_H264 && fmt_profile) {
> +                if (h264_profile) {
>                      /* This decoder doesn't expose its profiles and is high
>                       * profile capable */
>                      if (!strncmp(name_ptr, "OMX.LUMEVideoDecoder", __MIN(20, name_len)))
> @@ -612,7 +610,7 @@ static jstring GetMediaCodecName(decoder_t *p_dec, JNIEnv *env,
>                          int omx_profile = (*env)->GetIntField(env, profile_level, jfields.profile_field);
>                          size_t codec_profile = convert_omx_to_profile_idc(omx_profile);
>                          (*env)->DeleteLocalRef(env, profile_level);
> -                        if (codec_profile != fmt_profile)
> +                        if (codec_profile != h264_profile)
>                              continue;
>                          /* Some encoders set the level too high, thus we ignore it for the moment.
>                             We could try to guess the actual profile based on the resolution. */
> @@ -652,13 +650,11 @@ loopclean:
>      return jcodec_name;
>  }
>  
> -/*****************************************************************************
> - * OpenMediaCodec: Create the mediacodec instance
> - *****************************************************************************/
> -static int OpenMediaCodec(decoder_t *p_dec, JNIEnv *env)
> +static int JniStartMediaCodec(decoder_t *p_dec, JNIEnv *env, jobject jsurface,
> +                              const char *mime, int i_width, int i_height,
> +                              size_t h264_profile, int i_angle)
>  {
>      decoder_sys_t *p_sys = p_dec->p_sys;
> -    const char *mime = NULL;
>      int i_ret = VLC_EGENERIC;
>      jstring jmime = NULL;
>      jstring jcodec_name = NULL;
> @@ -669,24 +665,11 @@ static int OpenMediaCodec(decoder_t *p_dec, JNIEnv *env)
>      jobject joutput_buffers = NULL;
>      jobject jbuffer_info = NULL;
>  
> -    switch (p_dec->fmt_in.i_codec) {
> -    case VLC_CODEC_HEVC: mime = "video/hevc"; break;
> -    case VLC_CODEC_H264: mime = "video/avc"; break;
> -    case VLC_CODEC_H263: mime = "video/3gpp"; break;
> -    case VLC_CODEC_MP4V: mime = "video/mp4v-es"; break;
> -    case VLC_CODEC_WMV3: mime = "video/x-ms-wmv"; break;
> -    case VLC_CODEC_VC1:  mime = "video/wvc1"; break;
> -    case VLC_CODEC_VP8:  mime = "video/x-vnd.on2.vp8"; break;
> -    case VLC_CODEC_VP9:  mime = "video/x-vnd.on2.vp9"; break;
> -    default:
> -        vlc_assert_unreachable();
> -    }
> -
>      jmime = (*env)->NewStringUTF(env, mime);
>      if (!jmime)
>          return VLC_EGENERIC;
>  
> -    jcodec_name = GetMediaCodecName(p_dec, env, mime, jmime);
> +    jcodec_name = GetMediaCodecName(p_dec, env, mime, jmime, h264_profile);
>      if (!jcodec_name) {
>          msg_Dbg(p_dec, "No suitable codec matching %s was found", mime);
>          goto error;
> @@ -705,122 +688,36 @@ static int OpenMediaCodec(decoder_t *p_dec, JNIEnv *env)
>      p_sys->allocated = true;
>      p_sys->codec = (*env)->NewGlobalRef(env, jcodec);
>  
> -    /* Either we use a "csd-0" buffer that is provided before codec
> -     * initialisation via the MediaFormat class, or use a CODEC_CONFIG buffer
> -     * that can be provided during playback (and must be provided after a flush
> -     * and a start). */
> -    if (p_dec->fmt_in.i_extra && !p_sys->p_csd)
> -    {
> -        if (p_dec->fmt_in.i_codec == VLC_CODEC_H264
> -         || p_dec->fmt_in.i_codec == VLC_CODEC_HEVC)
> -        {
> -            int buf_size = p_dec->fmt_in.i_extra + 20;
> -            uint32_t size = p_dec->fmt_in.i_extra;
> -            void *p_buf = malloc(buf_size);
> -
> -            if (!p_buf)
> -            {
> -                msg_Warn(p_dec, "extra buffer allocation failed");
> -                goto error;
> -            }
> -
> -            if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
> -            {
> -                if (((uint8_t*)p_dec->fmt_in.p_extra)[0] == 1
> -                 && convert_sps_pps(p_dec, p_dec->fmt_in.p_extra,
> -                                    p_dec->fmt_in.i_extra,
> -                                    p_buf, buf_size, &size,
> -                                    &p_sys->nal_size) == VLC_SUCCESS)
> -                    H264SetCSD(p_dec, p_buf, size, NULL);
> -            } else
> -            {
> -                if (convert_hevc_nal_units(p_dec, p_dec->fmt_in.p_extra,
> -                                           p_dec->fmt_in.i_extra,
> -                                           p_buf, buf_size, &size,
> -                                           &p_sys->nal_size) == VLC_SUCCESS)
> -                {
> -                    struct csd csd;
> -
> -                    csd.p_buf = p_buf;
> -                    csd.i_size = size;
> -                    CSDDup(p_dec, &csd, 1);
> -                }
> -            }
> -            free(p_buf);
> -        }
> -        if (!p_sys->p_csd)
> -        {
> -            struct csd csd;
> -
> -            csd.p_buf = p_dec->fmt_in.p_extra;
> -            csd.i_size = p_dec->fmt_in.i_extra;
> -            CSDDup(p_dec, &csd, 1);
> -        }
> -
> -        p_sys->i_csd_send = 0;
> -    }
> -
> -    if (!p_sys->i_width && !p_sys->i_height)
> -    {
> -        msg_Err(p_dec, "invalid size, abort MediaCodec");
> -        goto error;
> -    }
>      jformat = (*env)->CallStaticObjectMethod(env, jfields.media_format_class,
>                                               jfields.create_video_format, jmime,
> -                                             p_sys->i_width, p_sys->i_height);
> +                                             i_width, i_height);
>  
> -    p_sys->direct_rendering = var_InheritBool(p_dec, CFG_PREFIX "dr");
> +    p_sys->direct_rendering = !!jsurface;
>  
>      /* There is no way to rotate the video using direct rendering (and using a
>       * SurfaceView) before  API 21 (Lollipop). Therefore, we deactivate direct
>       * rendering if video doesn't have a normal rotation and if
>       * get_input_buffer method is not present (This method exists since API
>       * 21). */
> -    if (p_sys->direct_rendering
> -        && p_dec->fmt_in.video.orientation != ORIENT_NORMAL
> -        && !jfields.get_input_buffer)
> +    if (p_sys->direct_rendering && i_angle != 0 && !jfields.get_input_buffer)
>          p_sys->direct_rendering = false;
>  
>      if (p_sys->direct_rendering) {
> -        if (p_dec->fmt_in.video.orientation != ORIENT_NORMAL) {
> -            int i_angle;
> -
> -            switch (p_dec->fmt_in.video.orientation) {
> -                case ORIENT_ROTATED_90:
> -                    i_angle = 90;
> -                    break;
> -                case ORIENT_ROTATED_180:
> -                    i_angle = 180;
> -                    break;
> -                case ORIENT_ROTATED_270:
> -                    i_angle = 270;
> -                    break;
> -                default:
> -                    i_angle = 0;
> -            }
> +        if (i_angle != 0)
> +        {
>              jrotation_string = (*env)->NewStringUTF(env, "rotation-degrees");
>              (*env)->CallVoidMethod(env, jformat, jfields.set_integer,
>                                     jrotation_string, i_angle);
>          }
>  
> -        jobject surf = jni_LockAndGetAndroidJavaSurface();
> -        if (surf) {
> -            // Configure MediaCodec with the Android surface.
> -            (*env)->CallVoidMethod(env, p_sys->codec, jfields.configure,
> -                                   jformat, surf, NULL, 0);
> -            if (CHECK_EXCEPTION()) {
> -                msg_Warn(p_dec, "Exception occurred in MediaCodec.configure with an output surface.");
> -                jni_UnlockAndroidSurface();
> -                goto error;
> -            }
> -            p_dec->fmt_out.i_codec = VLC_CODEC_ANDROID_OPAQUE;
> -            jni_UnlockAndroidSurface();
> -        } else {
> -            msg_Warn(p_dec, "Failed to get the Android Surface, disabling direct rendering.");
> -            p_sys->direct_rendering = false;
> +        // Configure MediaCodec with the Android surface.
> +        (*env)->CallVoidMethod(env, p_sys->codec, jfields.configure,
> +                               jformat, jsurface, NULL, 0);
> +        if (CHECK_EXCEPTION()) {
> +            msg_Warn(p_dec, "Exception occurred in MediaCodec.configure with an output surface.");
> +            goto error;
>          }
> -    }
> -    if (!p_sys->direct_rendering) {
> +    } else {
>          (*env)->CallVoidMethod(env, p_sys->codec, jfields.configure,
>                                 jformat, NULL, NULL, 0);
>          if (CHECK_EXCEPTION()) {
> @@ -857,7 +754,6 @@ static int OpenMediaCodec(decoder_t *p_dec, JNIEnv *env)
>      jbuffer_info = (*env)->NewObject(env, jfields.buffer_info_class,
>                                       jfields.buffer_info_ctor);
>      p_sys->buffer_info = (*env)->NewGlobalRef(env, jbuffer_info);
> -    p_sys->b_update_format = true;
>  
>      i_ret = VLC_SUCCESS;
>  
> @@ -880,30 +776,119 @@ error:
>          (*env)->DeleteLocalRef(env, jbuffer_info);
>  
>      if (i_ret != VLC_SUCCESS)
> -        CloseMediaCodec(p_dec, env);
> +        JniStopMediaCodec(p_dec, env);
>      return i_ret;
>  }
>  
>  /*****************************************************************************
> - * CloseMediaCodec: Close the mediacodec instance
> + * StartMediaCodec: Create the mediacodec instance
>   *****************************************************************************/
> -static void CloseMediaCodec(decoder_t *p_dec, JNIEnv *env)
> +static int StartMediaCodec(decoder_t *p_dec, JNIEnv *env)
>  {
>      decoder_sys_t *p_sys = p_dec->p_sys;
> +    int i_angle = 0, i_ret;
> +    size_t h264_profile = 0;
> +    jobject jsurface = NULL;
>  
> -    if (!p_sys)
> -        return;
> +    if (p_dec->fmt_in.i_extra && !p_sys->p_csd)
> +    {
> +        if (p_dec->fmt_in.i_codec == VLC_CODEC_H264
> +         || p_dec->fmt_in.i_codec == VLC_CODEC_HEVC)
> +        {
> +            int buf_size = p_dec->fmt_in.i_extra + 20;
> +            uint32_t size = p_dec->fmt_in.i_extra;
> +            void *p_buf = malloc(buf_size);
>  
> -    free(p_sys->name);
> -    p_sys->name = NULL;
> +            if (!p_buf)
> +            {
> +                msg_Warn(p_dec, "extra buffer allocation failed");
> +                return VLC_EGENERIC;
> +            }
>  
> -    /* Invalidate all pictures that are currently in flight in order
> -     * to prevent the vout from using destroyed output buffers. */
> -    if (p_sys->direct_rendering) {
> -        InvalidateAllPictures(p_dec);
> -        p_sys->direct_rendering = false;
> +            if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
> +            {
> +                if (((uint8_t*)p_dec->fmt_in.p_extra)[0] == 1
> +                 && convert_sps_pps(p_dec, p_dec->fmt_in.p_extra,
> +                                    p_dec->fmt_in.i_extra,
> +                                    p_buf, buf_size, &size,
> +                                    &p_sys->nal_size) == VLC_SUCCESS)
> +                    H264SetCSD(p_dec, p_buf, size, NULL);
> +            } else
> +            {
> +                if (convert_hevc_nal_units(p_dec, p_dec->fmt_in.p_extra,
> +                                           p_dec->fmt_in.i_extra,
> +                                           p_buf, buf_size, &size,
> +                                           &p_sys->nal_size) == VLC_SUCCESS)
> +                {
> +                    struct csd csd;
> +
> +                    csd.p_buf = p_buf;
> +                    csd.i_size = size;
> +                    CSDDup(p_dec, &csd, 1);
> +                }
> +            }
> +            free(p_buf);
> +        }
> +        if (!p_sys->p_csd)
> +        {
> +            struct csd csd;
> +
> +            csd.p_buf = p_dec->fmt_in.p_extra;
> +            csd.i_size = p_dec->fmt_in.i_extra;
> +            CSDDup(p_dec, &csd, 1);
> +        }
> +
> +        p_sys->i_csd_send = 0;
> +    }
> +    if (!p_sys->i_width || !p_sys->i_height)
> +    {
> +        msg_Err(p_dec, "invalid size, abort MediaCodec");
> +        return VLC_EGENERIC;
> +    }
> +
> +    if ( p_dec->fmt_in.video.orientation != ORIENT_NORMAL)
> +    {
> +        switch (p_dec->fmt_in.video.orientation)
> +        {
> +            case ORIENT_ROTATED_90:
> +                i_angle = 90;
> +                break;
> +            case ORIENT_ROTATED_180:
> +                i_angle = 180;
> +                break;
> +            case ORIENT_ROTATED_270:
> +                i_angle = 270;
> +                break;
> +            default:
> +                i_angle = 0;
> +        }
>      }
>  
> +    if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
> +        h264_get_profile_level(&p_dec->fmt_in, &h264_profile, NULL, NULL);
> +
> +    if (var_InheritBool(p_dec, CFG_PREFIX "dr"))
> +        jsurface = jni_LockAndGetAndroidJavaSurface();
> +    i_ret = JniStartMediaCodec(p_dec, env, jsurface, p_sys->mime,
> +                               p_sys->i_width, p_sys->i_height, h264_profile,
> +                               i_angle);
> +    if (jsurface)
> +        jni_UnlockAndroidSurface();
> +
> +    if (i_ret == VLC_SUCCESS)
> +    {
> +        if (p_sys->direct_rendering)
> +            p_dec->fmt_out.i_codec = VLC_CODEC_ANDROID_OPAQUE;
> +        p_sys->b_update_format = true;
> +        return VLC_SUCCESS;
> +    } else
> +        return VLC_EGENERIC;
> +}
> +
> +static void JniStopMediaCodec(decoder_t *p_dec, JNIEnv *env)
> +{
> +    decoder_sys_t *p_sys = p_dec->p_sys;
> +
>      if (p_sys->input_buffers) {
>          (*env)->DeleteGlobalRef(env, p_sys->input_buffers);
>          p_sys->input_buffers = NULL;
> @@ -937,36 +922,63 @@ static void CloseMediaCodec(decoder_t *p_dec, JNIEnv *env)
>  }
>  
>  /*****************************************************************************
> + * StopMediaCodec: Close the mediacodec instance
> + *****************************************************************************/
> +static void StopMediaCodec(decoder_t *p_dec, JNIEnv *env)
> +{
> +    decoder_sys_t *p_sys = p_dec->p_sys;
> +
> +    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) {
> +        InvalidateAllPictures(p_dec);
> +        p_sys->direct_rendering = false;
> +    }
> +
> +    JniStopMediaCodec(p_dec, env);
> +}
> +
> +/*****************************************************************************
>   * OpenDecoder: Create the decoder instance
>   *****************************************************************************/
>  static int OpenDecoder(vlc_object_t *p_this)
>  {
>      decoder_t *p_dec = (decoder_t*)p_this;
>      JNIEnv* env = NULL;
> +    const char *mime;
>  
>      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_H264:
> -        /* We can handle h264 without a valid video size */
> -        break;
> -    case VLC_CODEC_HEVC:
> -    case VLC_CODEC_H263:
> -    case VLC_CODEC_MP4V:
> -    case VLC_CODEC_WMV3:
> -    case VLC_CODEC_VC1:
> -    case VLC_CODEC_VP8:
> -    case VLC_CODEC_VP9:
> -        if (p_dec->fmt_in.video.i_width && p_dec->fmt_in.video.i_height)
> -            break;
> +    case VLC_CODEC_HEVC: mime = "video/hevc"; break;
> +    case VLC_CODEC_H264: mime = "video/avc"; break;
> +    case VLC_CODEC_H263: mime = "video/3gpp"; break;
> +    case VLC_CODEC_MP4V: mime = "video/mp4v-es"; break;
> +    case VLC_CODEC_WMV3: mime = "video/x-ms-wmv"; break;
> +    case VLC_CODEC_VC1:  mime = "video/wvc1"; break;
> +    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 or resolution (%dx%d) not supported",
> -                (char *)&p_dec->fmt_in.i_codec,
> -                p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height);
> +        msg_Dbg(p_dec, "codec %4.4s not supported",
> +                (char *)&p_dec->fmt_in.i_codec);
>          return VLC_EGENERIC;
>      }
>  
> +    if (!p_dec->fmt_in.video.i_width || !p_dec->fmt_in.video.i_height)
> +    {
> +        /* We can handle h264 without a valid video size */
> +        if (p_dec->fmt_in.i_codec != VLC_CODEC_H264)
> +        {
> +            msg_Dbg(p_dec, "resolution (%dx%d) not supported",
> +                    p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height);
> +            return VLC_EGENERIC;
> +        }
> +    }
> +
>      if (!(env = jni_get_env(THREAD_NAME)))
>          goto error;
>  
> @@ -991,6 +1003,7 @@ static int OpenDecoder(vlc_object_t *p_this)
>      if (!p_dec->p_sys->timestamp_fifo)
>          goto error;
>  
> +    p_dec->p_sys->mime = mime;
>      p_dec->p_sys->b_new_block = true;
>  
>      switch (p_dec->fmt_in.i_codec)
> @@ -1011,7 +1024,7 @@ static int OpenDecoder(vlc_object_t *p_this)
>          }
>          break;
>      }
> -    return OpenMediaCodec(p_dec, env);
> +    return StartMediaCodec(p_dec, env);
>  
>   error:
>      CloseDecoder(p_this);
> @@ -1031,12 +1044,11 @@ static void CloseDecoder(vlc_object_t *p_this)
>          return;
>  
>      if ((env = jni_get_env(THREAD_NAME)))
> -        CloseMediaCodec(p_dec, env);
> +        StopMediaCodec(p_dec, env);
>      else
>          msg_Warn(p_dec, "Can't get a JNIEnv, can't close mediacodec !");
>  
>      CSDFree(p_dec);
> -    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)
> @@ -1422,7 +1434,7 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
>      int i_output_ret = 0;
>      int i_input_ret = 0;
>      bool b_error = false;
> -    bool b_delayed_open = false;
> +    bool b_delayed_start = false;
>      bool b_new_block = p_block ? p_sys->b_new_block : false;
>  
>      if (p_sys->error_state)
> @@ -1464,7 +1476,7 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
>              {
>                  msg_Err(p_dec, "SPS/PPS changed during playback and "
>                          "video size are different. Restart it !");
> -                CloseMediaCodec(p_dec, env);
> +                StopMediaCodec(p_dec, env);
>              } else
>              {
>                  msg_Err(p_dec, "SPS/PPS changed during playback. Flush it");
> @@ -1473,7 +1485,7 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
>              }
>          }
>          if (!p_sys->codec)
> -            b_delayed_open = true;
> +            b_delayed_start = true;
>      }
>  
>      /* try delayed opening if there is a new extra data */
> @@ -1483,11 +1495,11 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
>          {
>          case VLC_CODEC_VC1:
>              if (p_dec->fmt_in.i_extra)
> -                b_delayed_open = true;
> +                b_delayed_start = true;
>          default:
>              break;
>          }
> -        if (b_delayed_open && OpenMediaCodec(p_dec, env) != VLC_SUCCESS)
> +        if (b_delayed_start && StartMediaCodec(p_dec, env) != VLC_SUCCESS)
>          {
>              b_error = true;
>              goto endclean;
> -- 
> 2.1.4
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel

-- 
With my kindest regards,

-- 
Jean-Baptiste Kempf
http://www.jbkempf.com/ - +33 672 704 734
Sent from my Electronic Device



More information about the vlc-devel mailing list