[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