[vlc-devel] [RFC PATCH 4/6] mediacodec: process input buffers in a separate thread
Thomas Guillem
thomas at gllm.fr
Mon Nov 3 19:41:20 CET 2014
DecodeVideo will now send input blocks to a FIFO that will be processed by a
separate thread. This function will return instantaneously, either a valid
pic or NULL if there was no output buffers available. "invalid_picture hack" is
not needed anymore.
Fix a deadlock when a slow video was flushed, due to a seek.
(fixes #12397)
---
modules/codec/omxil/android_mediacodec.c | 195 +++++++++++++++++++++----------
1 file changed, 133 insertions(+), 62 deletions(-)
diff --git a/modules/codec/omxil/android_mediacodec.c b/modules/codec/omxil/android_mediacodec.c
index e9d0b4e..4029416 100644
--- a/modules/codec/omxil/android_mediacodec.c
+++ b/modules/codec/omxil/android_mediacodec.c
@@ -42,6 +42,7 @@
#include <OMX_Component.h>
#include "omxil_utils.h"
#include "android_opaque.h"
+#include "queue_thread.h"
#define INFO_OUTPUT_BUFFERS_CHANGED -3
#define INFO_OUTPUT_FORMAT_CHANGED -2
@@ -161,7 +162,6 @@ struct decoder_sys_t
bool allocated;
bool started;
- bool decoded;
bool error_state;
bool error_event_sent;
@@ -173,6 +173,10 @@ struct decoder_sys_t
picture_t** inflight_picture; /**< stores the inflight picture for each output buffer or NULL */
timestamp_fifo_t *timestamp_fifo;
+
+ bool b_iqthread_decoded;
+ queue_thread *p_iqthread;
+ JNIEnv *p_iqthread_env;
};
enum Types
@@ -259,6 +263,8 @@ 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 void InvalidateAllPictures(decoder_t *);
/*****************************************************************************
@@ -293,6 +299,80 @@ static int jstrcmp(JNIEnv* env, jobject str, const char* str2)
}
/*****************************************************************************
+ * QueueThread callbacks
+ *****************************************************************************/
+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;
+
+ jni_attach_thread(pp_env, THREAD_NAME);
+ if (!*pp_env)
+ return -1;
+
+ return 0;
+}
+
+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;
+
+ if (*pp_env)
+ jni_detach_thread();
+ *pp_env = NULL;
+
+ return 0;
+}
+
+static int InputQueueThreadCb_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_iqthread_env;
+ queue_thread_elm *p_elm;
+ block_t *p_block;
+
+ if (!env)
+ return -1;
+
+ if (b_flushing) {
+ while ((p_elm = QueueThread_FifoPop(p_qthread))) {
+ block_t *p_block = (block_t *) p_elm;
+ block_Release( p_block );
+ }
+ if (p_sys->b_iqthread_decoded) {
+ (*env)->CallVoidMethod(env, p_sys->codec, p_sys->flush);
+ if ((*env)->ExceptionOccurred(env)) {
+ msg_Warn(p_dec, "Exception occurred in MediaCodec.flush");
+ (*env)->ExceptionClear(env);
+ return -1;
+ }
+ p_sys->b_iqthread_decoded = false;
+ }
+ return 0;
+ } else {
+ p_elm = QueueThread_FifoPeek(p_qthread);
+ p_block = (block_t *)p_elm;
+
+ if (!p_block)
+ return 0;
+
+ if (PutInput(p_dec, env, &p_block, 0) != 0)
+ return -1;
+
+ if (p_block == NULL) {
+ p_sys->b_iqthread_decoded = true;
+ QueueThread_FifoPop(p_qthread);
+ return 1;
+ } else
+ return 0;
+ }
+}
+
+/*****************************************************************************
* OpenDecoder: Create the decoder instance
*****************************************************************************/
static int OpenDecoder(vlc_object_t *p_this)
@@ -552,6 +632,16 @@ static int OpenDecoder(vlc_object_t *p_this)
jni_detach_thread();
+ p_sys->p_iqthread = QueueThread_New(VLC_OBJECT(p_dec));
+ if (!p_sys->p_iqthread)
+ goto error;
+ p_sys->p_iqthread->p_owner = (queue_thread_owner_sys *)p_dec;
+ p_sys->p_iqthread->pf_init = QueueThreadCb_Init;
+ p_sys->p_iqthread->pf_destroy = QueueThreadCb_Destroy;
+ p_sys->p_iqthread->pf_run = InputQueueThreadCb_Run;
+ if (QueueThread_Start(p_sys->p_iqthread) != 0)
+ goto error;
+
const int timestamp_fifo_size = 32;
p_sys->timestamp_fifo = timestamp_FifoNew(timestamp_fifo_size);
if (!p_sys->timestamp_fifo)
@@ -574,10 +664,17 @@ static void CloseDecoder(vlc_object_t *p_this)
if (!p_sys)
return;
+ if (p_sys->p_iqthread)
+ QueueThread_Pause(p_sys->p_iqthread);
+
/* 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);
+
+ if (p_sys->p_iqthread)
+ QueueThread_Delete(p_sys->p_iqthread);
+
jni_attach_thread(&env, THREAD_NAME);
if (p_sys->input_buffers)
(*env)->DeleteGlobalRef(env, p_sys->input_buffers);
@@ -722,7 +819,6 @@ static int PutInput(decoder_t *p_dec, JNIEnv *env, block_t **pp_block, jlong tim
}
block_Release(p_block);
*pp_block = NULL;
- p_sys->decoded = true;
return 0;
}
@@ -938,37 +1034,40 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
picture_t *p_pic = NULL;
JNIEnv *env = NULL;
- if (!pp_block || !*pp_block)
- return NULL;
+ if (QueueThread_GetErrorState(p_sys->p_iqthread))
+ p_sys->error_state = true;
if (p_sys->error_state) {
- block_Release(*pp_block);
- *pp_block = NULL;
+ if( pp_block && *pp_block )
+ {
+ block_Release(*pp_block);
+ *pp_block = NULL;
+ }
goto endclean;
}
- jni_attach_thread(&env, THREAD_NAME);
+ if (pp_block && *pp_block) {
+ if ((*pp_block)->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
+ block_Release(*pp_block);
+ *pp_block = NULL;
+ timestamp_FifoEmpty(p_sys->timestamp_fifo);
+
+ QueueThread_Pause(p_sys->p_iqthread);
- if ((*pp_block)->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
- block_Release(*pp_block);
- *pp_block = NULL;
- timestamp_FifoEmpty(p_sys->timestamp_fifo);
- if (p_sys->decoded) {
/* Invalidate all pictures that are currently in flight
* since flushing make all previous indices returned by
* MediaCodec invalid. */
if (p_sys->direct_rendering)
InvalidateAllPictures(p_dec);
- (*env)->CallVoidMethod(env, p_sys->codec, p_sys->flush);
- if ((*env)->ExceptionOccurred(env)) {
- msg_Warn(p_dec, "Exception occurred in MediaCodec.flush");
- (*env)->ExceptionClear(env);
- p_sys->error_state = true;
- }
+ QueueThread_Flush(p_sys->p_iqthread);
+
+ QueueThread_Start(p_sys->p_iqthread);
+ return NULL;
+ } else {
+ QueueThread_FifoPush(p_sys->p_iqthread, (queue_thread_elm *)*pp_block);
+ *pp_block = NULL;
}
- p_sys->decoded = false;
- goto endclean;
}
/* Use the aspect ratio provided by the input (ie read from packetizer).
@@ -979,47 +1078,21 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
p_dec->fmt_out.video.i_sar_den = p_dec->fmt_in.video.i_sar_den;
}
- jlong timeout = 0;
- const int max_polling_attempts = 50;
- int attempts = 0;
- while (*pp_block != NULL && p_pic == NULL) {
- if (PutInput(p_dec, env, pp_block, (jlong) 0) != 0) {
- p_sys->error_state = true;
- break;
- }
+ decoder_UpdateVideoFormat( p_dec );
+
+ jni_attach_thread(&env, THREAD_NAME);
- if (GetOutput(p_dec, env, &p_pic, timeout) != 0) {
- p_sys->error_state = true;
- break;
- }
+ if (env == NULL || GetOutput(p_dec, env, &p_pic, 0) != 0)
+ p_sys->error_state = true;
- if (p_pic == NULL && *pp_block != NULL) {
- timeout = 30 * 1000;
- ++attempts;
- /* With opaque DR the output buffers are released by the
- vout therefore we implement a timeout for polling in
- order to avoid being indefinitely stalled in this loop. */
- if (p_sys->direct_rendering && attempts == max_polling_attempts) {
- p_pic = decoder_NewPicture(p_dec);
- if (p_pic) {
- p_pic->date = VLC_TS_INVALID;
- picture_sys_t *p_picsys = p_pic->p_sys;
- p_picsys->pf_display_callback = NULL;
- p_picsys->pf_unlock_callback = NULL;
- p_picsys->p_dec = NULL;
- p_picsys->i_index = -1;
- p_picsys->b_valid = false;
- }
- else {
- /* If we cannot return a picture we must free the
- block since the decoder will proceed with the
- next block. */
- block_Release(*pp_block);
- *pp_block = NULL;
- }
- }
- }
- }
+ 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) {
@@ -1033,8 +1106,6 @@ endclean:
p_sys->error_event_sent = true;
}
}
- if (env != NULL)
- jni_detach_thread();
-
+
return p_pic;
}
--
2.1.1
More information about the vlc-devel
mailing list