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

Thomas Guillem thomas at gllm.fr
Tue May 19 18:58:41 CEST 2015


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




More information about the vlc-devel mailing list