[vlc-devel] [RFC PATCH 6/6] mediacodec: process output buffers in a separate thread

Thomas Guillem thomas at gllm.fr
Mon Nov 3 19:41:22 CET 2014


---
 modules/codec/omxil/android_mediacodec.c | 152 ++++++++++++++++++++-----------
 1 file changed, 97 insertions(+), 55 deletions(-)

diff --git a/modules/codec/omxil/android_mediacodec.c b/modules/codec/omxil/android_mediacodec.c
index 4029416..7cd29a4 100644
--- a/modules/codec/omxil/android_mediacodec.c
+++ b/modules/codec/omxil/android_mediacodec.c
@@ -133,6 +133,13 @@ static int64_t timestamp_FifoGet(timestamp_fifo_t *fifo)
     return result;
 }
 
+typedef struct queue_thread_elm_pic queue_thread_elm_pic;
+struct queue_thread_elm_pic
+{
+    uint32_t i_index;
+    bool b_render;
+};
+
 struct decoder_sys_t
 {
     jclass media_codec_list_class, media_codec_class, media_format_class;
@@ -177,6 +184,8 @@ struct decoder_sys_t
     bool            b_iqthread_decoded;
     queue_thread   *p_iqthread;
     JNIEnv         *p_iqthread_env;
+    queue_thread   *p_oqthread;
+    JNIEnv         *p_oqthread_env;
 };
 
 enum Types
@@ -264,6 +273,7 @@ static void CloseDecoder(vlc_object_t *);
 static picture_t *DecodeVideo(decoder_t *, block_t **);
 
 static int PutInput(decoder_t *p_dec, JNIEnv *env, block_t **pp_block, jlong timeout);
+static int GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong timeout);
 
 static void InvalidateAllPictures(decoder_t *);
 
@@ -305,7 +315,8 @@ static int QueueThreadCb_Init(queue_thread *p_qthread)
 {
     decoder_t *p_dec = (decoder_t*)p_qthread->p_owner;
     decoder_sys_t *p_sys = p_dec->p_sys;
-    JNIEnv **pp_env = &p_sys->p_iqthread_env;
+    JNIEnv **pp_env = p_qthread == p_sys->p_iqthread ?
+                        &p_sys->p_iqthread_env : &p_sys->p_oqthread_env;
 
     jni_attach_thread(pp_env, THREAD_NAME);
     if (!*pp_env)
@@ -318,7 +329,8 @@ static int QueueThreadCb_Destroy(queue_thread *p_qthread)
 {
     decoder_t *p_dec = (decoder_t*)p_qthread->p_owner;
     decoder_sys_t *p_sys = p_dec->p_sys;
-    JNIEnv **pp_env = &p_sys->p_iqthread_env;
+    JNIEnv **pp_env = p_qthread == p_sys->p_iqthread ?
+                        &p_sys->p_iqthread_env : &p_sys->p_oqthread_env;
 
     if (*pp_env)
         jni_detach_thread();
@@ -366,12 +378,58 @@ static int InputQueueThreadCb_Run(queue_thread *p_qthread, bool b_flushing)
         if (p_block == NULL) {
             p_sys->b_iqthread_decoded = true;
             QueueThread_FifoPop(p_qthread);
+            /* Wake the output thread. A new output buffer may be available if we
+             * got an input buffer */
+            QueueThread_Wake(p_sys->p_oqthread);
             return 1;
         } else
             return 0;
     }
 }
 
+static int OutputQueueThreadCb_Run(queue_thread *p_qthread, bool b_flushing)
+{
+    decoder_t *p_dec = (decoder_t*)p_qthread->p_owner;
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    JNIEnv *env = p_sys->p_oqthread_env;
+    queue_thread_elm *p_elm;
+    picture_t *p_pic = NULL;
+    bool b_render;
+
+    if (!env)
+        return -1;
+
+    while ((p_elm = QueueThread_FifoPop(p_qthread))) {
+        queue_thread_elm_pic *p_elm_pic = (queue_thread_elm_pic *)p_elm;
+        b_render = b_flushing ? false : p_elm_pic->b_render;
+
+        /* Release the MediaCodec buffer. */
+        (*env)->CallVoidMethod(env, p_sys->codec, p_sys->release_output_buffer,
+                               p_elm_pic->i_index, b_render);
+        if ((*env)->ExceptionOccurred(env)) {
+            msg_Err(p_dec, "Exception in MediaCodec.releaseOutputBuffer (DisplayBuffer)");
+            (*env)->ExceptionClear(env);
+            return -1;
+        }
+    }
+    if (b_flushing)
+        return 0;
+
+    if (GetOutput(p_dec, env, &p_pic, 0) != 0)
+        return -1;
+
+    if (p_pic) {
+        /* Wake the input thread. A new input buffer may be available if we got
+         * an output buffer */
+        QueueThread_Wake(p_sys->p_iqthread);
+
+        decoder_QueuePicture(p_dec, p_pic);
+        return 1;
+    }
+
+    return 0;
+}
+
 /*****************************************************************************
  * OpenDecoder: Create the decoder instance
  *****************************************************************************/
@@ -642,6 +700,16 @@ static int OpenDecoder(vlc_object_t *p_this)
     if (QueueThread_Start(p_sys->p_iqthread) != 0)
         goto error;
 
+    p_sys->p_oqthread = QueueThread_New(VLC_OBJECT(p_dec));
+    if (!p_sys->p_oqthread)
+        goto error;
+    p_sys->p_oqthread->p_owner = (queue_thread_owner_sys *)p_dec;
+    p_sys->p_oqthread->pf_init = QueueThreadCb_Init;
+    p_sys->p_oqthread->pf_destroy = QueueThreadCb_Destroy;
+    p_sys->p_oqthread->pf_run = OutputQueueThreadCb_Run;
+    if (QueueThread_Start(p_sys->p_oqthread) != 0)
+        goto error;
+
     const int timestamp_fifo_size = 32;
     p_sys->timestamp_fifo = timestamp_FifoNew(timestamp_fifo_size);
     if (!p_sys->timestamp_fifo)
@@ -666,6 +734,8 @@ static void CloseDecoder(vlc_object_t *p_this)
 
     if (p_sys->p_iqthread)
         QueueThread_Pause(p_sys->p_iqthread);
+    if (p_sys->p_oqthread)
+        QueueThread_Pause(p_sys->p_oqthread);
 
     /* Invalidate all pictures that are currently in flight in order
      * to prevent the vout from using destroyed output buffers. */
@@ -674,6 +744,8 @@ static void CloseDecoder(vlc_object_t *p_this)
 
     if (p_sys->p_iqthread)
         QueueThread_Delete(p_sys->p_iqthread);
+    if (p_sys->p_oqthread)
+        QueueThread_Delete(p_sys->p_oqthread);
 
     jni_attach_thread(&env, THREAD_NAME);
     if (p_sys->input_buffers)
@@ -718,33 +790,24 @@ static void DisplayBuffer(picture_sys_t* p_picsys, bool b_render)
 {
     decoder_t *p_dec = p_picsys->p_dec;
     decoder_sys_t *p_sys = p_dec->p_sys;
-
-    if (!p_picsys->b_valid)
-        return;
+    queue_thread_elm_pic *p_elm;
 
     vlc_mutex_lock(get_android_opaque_mutex());
 
-    /* Picture might have been invalidated while waiting on the mutex. */
-    if (!p_picsys->b_valid) {
-        vlc_mutex_unlock(get_android_opaque_mutex());
-        return;
-    }
+    if (!p_picsys->b_valid)
+        goto error;
 
-    uint32_t i_index = p_picsys->i_index;
-    p_sys->inflight_picture[i_index] = NULL;
+    p_picsys->b_valid = false;
 
-    /* Release the MediaCodec buffer. */
-    JNIEnv *env = NULL;
-    jni_attach_thread(&env, THREAD_NAME);
-    (*env)->CallVoidMethod(env, p_sys->codec, p_sys->release_output_buffer, i_index, b_render);
-    if ((*env)->ExceptionOccurred(env)) {
-        msg_Err(p_dec, "Exception in MediaCodec.releaseOutputBuffer (DisplayBuffer)");
-        (*env)->ExceptionClear(env);
-    }
+    p_elm = calloc(1, sizeof(queue_thread_elm_pic));
+    if (!p_elm)
+        goto error;
+    p_elm->i_index = p_picsys->i_index;
+    p_elm->b_render = b_render;
 
-    jni_detach_thread();
-    p_picsys->b_valid = false;
+    QueueThread_FifoPush(p_sys->p_oqthread, (queue_thread_elm *)p_elm);
 
+error:
     vlc_mutex_unlock(get_android_opaque_mutex());
 }
 
@@ -1031,10 +1094,9 @@ static int GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong ti
 static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    picture_t *p_pic = NULL;
-    JNIEnv *env = NULL;
 
-    if (QueueThread_GetErrorState(p_sys->p_iqthread))
+    if (QueueThread_GetErrorState(p_sys->p_iqthread) ||
+        QueueThread_GetErrorState(p_sys->p_oqthread))
         p_sys->error_state = true;
 
     if (p_sys->error_state) {
@@ -1043,7 +1105,12 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
             block_Release(*pp_block);
             *pp_block = NULL;
         }
-        goto endclean;
+        if (!p_sys->error_event_sent) {
+            /* Signal the error to the Java. */
+            jni_EventHardwareAccelerationError();
+            p_sys->error_event_sent = true;
+        }
+        return NULL;
     }
 
     if (pp_block && *pp_block) {
@@ -1053,6 +1120,7 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
             timestamp_FifoEmpty(p_sys->timestamp_fifo);
 
             QueueThread_Pause(p_sys->p_iqthread);
+            QueueThread_Pause(p_sys->p_oqthread);
 
             /* Invalidate all pictures that are currently in flight
              * since flushing make all previous indices returned by
@@ -1061,9 +1129,10 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
                 InvalidateAllPictures(p_dec);
 
             QueueThread_Flush(p_sys->p_iqthread);
+            QueueThread_Flush(p_sys->p_oqthread);
 
             QueueThread_Start(p_sys->p_iqthread);
-            return NULL;
+            QueueThread_Start(p_sys->p_oqthread);
         } else {
             QueueThread_FifoPush(p_sys->p_iqthread, (queue_thread_elm *)*pp_block);
             *pp_block = NULL;
@@ -1079,33 +1148,6 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
     }
 
     decoder_UpdateVideoFormat( p_dec );
-    
-    jni_attach_thread(&env, THREAD_NAME);
-
-    if (env == NULL || GetOutput(p_dec, env, &p_pic, 0) != 0)
-        p_sys->error_state = true;
-
-    if (env != NULL)
-        jni_detach_thread();
 
-    if (p_pic) {
-        /* Wake the input thread. A new input buffer may be available if we got
-         * an output buffer */
-        QueueThread_Wake(p_sys->p_iqthread);
-     }
-
-endclean:
-    if (p_sys->error_state) {
-        if (p_pic)
-            picture_Release(p_pic);
-        p_pic = NULL;
-
-        if (!p_sys->error_event_sent) {
-            /* Signal the error to the Java. */
-            jni_EventHardwareAccelerationError();
-            p_sys->error_event_sent = true;
-        }
-    }
- 
-    return p_pic;
+    return NULL;
 }
-- 
2.1.1




More information about the vlc-devel mailing list