X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fomxil%2Fandroid_mediacodec.c;h=21bd9a17aabc00e1f0b1409e3218c821eef11333;hb=9d997cdf5e68f11b70b08af53a8246bbd21c50ea;hp=7ccffb22c440d9a98a3ccd4a4bcb893022b389b8;hpb=42cc2df680d9987137b5725243a118da4253b184;p=vlc diff --git a/modules/codec/omxil/android_mediacodec.c b/modules/codec/omxil/android_mediacodec.c index 7ccffb22c4..21bd9a17aa 100644 --- a/modules/codec/omxil/android_mediacodec.c +++ b/modules/codec/omxil/android_mediacodec.c @@ -709,6 +709,23 @@ static void CloseDecoder(vlc_object_t *p_this) free(p_sys); } +/***************************************************************************** + * ReleaseOutputBuffer + *****************************************************************************/ +static int ReleaseOutputBuffer(decoder_t *p_dec, JNIEnv *env, int i_index, + bool b_render) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + + (*env)->CallVoidMethod(env, p_sys->codec, p_sys->release_output_buffer, + i_index, b_render); + if (CHECK_EXCEPTION()) { + msg_Err(p_dec, "Exception in MediaCodec.releaseOutputBuffer"); + return -1; + } + return 0; +} + /***************************************************************************** * vout callbacks *****************************************************************************/ @@ -716,7 +733,6 @@ static void UnlockPicture(picture_t* p_pic, bool b_render) { picture_sys_t *p_picsys = p_pic->p_sys; decoder_t *p_dec = p_picsys->priv.hw.p_dec; - decoder_sys_t *p_sys = p_dec->p_sys; if (!p_picsys->priv.hw.b_valid) return; @@ -735,10 +751,7 @@ static void UnlockPicture(picture_t* p_pic, bool b_render) /* 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 (CHECK_EXCEPTION()) - msg_Err(p_dec, "Exception in MediaCodec.releaseOutputBuffer (DisplayBuffer)"); - + ReleaseOutputBuffer(p_dec, env, i_index, b_render); jni_detach_thread(); p_picsys->priv.hw.b_valid = false; @@ -781,7 +794,59 @@ static int InsertInflightPicture(decoder_t *p_dec, picture_t *p_pic, return 0; } -static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong timeout) +static int PutInput(decoder_t *p_dec, JNIEnv *env, block_t **pp_block, jlong timeout) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + block_t *p_block = *pp_block; + int index; + jobject buf; + jsize size; + uint8_t *bufptr; + struct H264ConvertState convert_state = { 0, 0 }; + + index = (*env)->CallIntMethod(env, p_sys->codec, + p_sys->dequeue_input_buffer, timeout); + if (CHECK_EXCEPTION()) { + msg_Err(p_dec, "Exception occurred in MediaCodec.dequeueInputBuffer"); + return -1; + } + if (index < 0) + return 0; + + if (p_sys->get_input_buffers) + buf = (*env)->GetObjectArrayElement(env, p_sys->input_buffers, index); + else + buf = (*env)->CallObjectMethod(env, p_sys->codec, p_sys->get_input_buffer, index); + size = (*env)->GetDirectBufferCapacity(env, buf); + bufptr = (*env)->GetDirectBufferAddress(env, buf); + if (size < 0) { + msg_Err(p_dec, "Java buffer has invalid size"); + return -1; + } + if ((size_t) size > p_block->i_buffer) + size = p_block->i_buffer; + memcpy(bufptr, p_block->p_buffer, size); + + convert_h264_to_annexb(bufptr, size, p_sys->nal_size, &convert_state); + + int64_t ts = p_block->i_pts; + if (!ts && p_block->i_dts) + ts = p_block->i_dts; + timestamp_FifoPut(p_sys->timestamp_fifo, p_block->i_pts ? VLC_TS_INVALID : p_block->i_dts); + (*env)->CallVoidMethod(env, p_sys->codec, p_sys->queue_input_buffer, index, 0, size, ts, 0); + (*env)->DeleteLocalRef(env, buf); + if (CHECK_EXCEPTION()) { + msg_Err(p_dec, "Exception in MediaCodec.queueInputBuffer"); + return -1; + } + block_Release(p_block); + *pp_block = NULL; + p_sys->decoded = true; + + return 0; +} + +static int GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong timeout) { decoder_sys_t *p_sys = p_dec->p_sys; while (1) { @@ -789,19 +854,14 @@ static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong t p_sys->buffer_info, timeout); if (CHECK_EXCEPTION()) { msg_Err(p_dec, "Exception in MediaCodec.dequeueOutputBuffer (GetOutput)"); - p_sys->error_state = true; - return; + return -1; } if (index >= 0) { if (!p_sys->pixel_format) { msg_Warn(p_dec, "Buffers returned before output format is set, dropping frame"); - (*env)->CallVoidMethod(env, p_sys->codec, p_sys->release_output_buffer, index, false); - if (CHECK_EXCEPTION()) { - msg_Err(p_dec, "Exception in MediaCodec.releaseOutputBuffer"); - p_sys->error_state = true; - return; - } + if (ReleaseOutputBuffer(p_dec, env, index, false) != 0) + return -1; continue; } @@ -811,13 +871,8 @@ static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong t picture_t *p_pic = *pp_pic; picture_sys_t *p_picsys = p_pic->p_sys; int i_prev_index = p_picsys->priv.hw.i_index; - (*env)->CallVoidMethod(env, p_sys->codec, p_sys->release_output_buffer, i_prev_index, false); - if (CHECK_EXCEPTION()) { - msg_Err(p_dec, "Exception in MediaCodec.releaseOutputBuffer " \ - "(GetOutput, overwriting previous picture)"); - p_sys->error_state = true; - return; - } + if (ReleaseOutputBuffer(p_dec, env, i_prev_index, false) != 0) + return -1; // No need to lock here since the previous picture was not sent. InsertInflightPicture(p_dec, NULL, i_prev_index); @@ -873,20 +928,18 @@ static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong t msg_Err(p_dec, "Codec error (IllegalStateException) in MediaCodec.releaseOutputBuffer"); (*env)->ExceptionClear(env); (*env)->DeleteLocalRef(env, illegalStateException); - p_sys->error_state = true; + (*env)->DeleteLocalRef(env, buf); + return -1; } } (*env)->DeleteLocalRef(env, buf); } } else { msg_Warn(p_dec, "NewPicture failed"); - (*env)->CallVoidMethod(env, p_sys->codec, p_sys->release_output_buffer, index, false); - if (CHECK_EXCEPTION()) { - msg_Err(p_dec, "Exception in MediaCodec.releaseOutputBuffer (GetOutput)"); - p_sys->error_state = true; - } + if (ReleaseOutputBuffer(p_dec, env, index, false) != 0) + return -1; } - return; + return 0; } else if (index == INFO_OUTPUT_BUFFERS_CHANGED) { msg_Dbg(p_dec, "output buffers changed"); @@ -899,8 +952,7 @@ static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong t if (CHECK_EXCEPTION()) { msg_Err(p_dec, "Exception in MediaCodec.getOutputBuffer (GetOutput)"); p_sys->output_buffers = NULL; - p_sys->error_state = true; - return; + return -1; } p_sys->output_buffers = (*env)->NewGlobalRef(env, p_sys->output_buffers); @@ -908,8 +960,7 @@ static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong t jobject format = (*env)->CallObjectMethod(env, p_sys->codec, p_sys->get_output_format); if (CHECK_EXCEPTION()) { msg_Err(p_dec, "Exception in MediaCodec.getOutputFormat (GetOutput)"); - p_sys->error_state = true; - return; + return -1; } jobject format_string = (*env)->CallObjectMethod(env, format, p_sys->tostring); @@ -936,8 +987,7 @@ static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong t if (!GetVlcChromaFormat(p_sys->pixel_format, &p_dec->fmt_out.i_codec, &name)) { msg_Err(p_dec, "color-format not recognized"); - p_sys->error_state = true; - return; + return -1; } } @@ -971,9 +1021,10 @@ static void GetOutput(decoder_t *p_dec, JNIEnv *env, picture_t **pp_pic, jlong t } } else { - return; + return 0; } } + return 0; } static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block) @@ -981,27 +1032,20 @@ 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; - struct H264ConvertState convert_state = { 0, 0 }; if (!pp_block || !*pp_block) return NULL; - block_t *p_block = *pp_block; - - if (p_sys->error_state) { - block_Release(p_block); - if (!p_sys->error_event_sent) { - /* Signal the error to the Java. */ - jni_EventHardwareAccelerationError(); - p_sys->error_event_sent = true; - } - return NULL; - } + if (p_sys->error_state) + goto endclean; jni_attach_thread(&env, THREAD_NAME); + if (!env) + goto endclean; - if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) { - block_Release(p_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); if (p_sys->decoded) { /* Invalidate all pictures that are currently in flight @@ -1017,8 +1061,7 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block) } } p_sys->decoded = false; - jni_detach_thread(); - return NULL; + goto endclean; } /* Use the aspect ratio provided by the input (ie read from packetizer). @@ -1032,37 +1075,29 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block) jlong timeout = 0; const int max_polling_attempts = 50; int attempts = 0; - while (true) { - int index = (*env)->CallIntMethod(env, p_sys->codec, p_sys->dequeue_input_buffer, (jlong) 0); - if (CHECK_EXCEPTION()) { - msg_Err(p_dec, "Exception occurred in MediaCodec.dequeueInputBuffer"); + /* return when pp_block is processed */ + while (*pp_block != NULL) { + if (*pp_block != NULL && PutInput(p_dec, env, pp_block, (jlong) 0) != 0) { p_sys->error_state = true; break; } - if (index < 0) { - GetOutput(p_dec, env, &p_pic, timeout); - if (p_sys->error_state) - break; - if (p_pic) { - /* If we couldn't get an available input buffer but a - * decoded frame is available, we return the frame - * without assigning NULL to *pp_block. The next call - * to DecodeVideo will try to send the input packet again. - */ - jni_detach_thread(); - return p_pic; - } + if (p_pic == NULL && GetOutput(p_dec, env, &p_pic, timeout) != 0) { + p_sys->error_state = true; + break; + } + + 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) { - picture_t *invalid_picture = decoder_NewPicture(p_dec); - if (invalid_picture) { - invalid_picture->date = VLC_TS_INVALID; - picture_sys_t *p_picsys = invalid_picture->p_sys; + 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_lock_pic = NULL; p_picsys->pf_unlock_pic = NULL; p_picsys->priv.hw.p_dec = NULL; @@ -1073,59 +1108,32 @@ static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block) /* If we cannot return a picture we must free the block since the decoder will proceed with the next block. */ - block_Release(p_block); + block_Release(*pp_block); *pp_block = NULL; } - jni_detach_thread(); - return invalid_picture; } - continue; } - - jobject buf; - if (p_sys->get_input_buffers) - buf = (*env)->GetObjectArrayElement(env, p_sys->input_buffers, index); - else - buf = (*env)->CallObjectMethod(env, p_sys->codec, p_sys->get_input_buffer, index); - jsize size = (*env)->GetDirectBufferCapacity(env, buf); - uint8_t *bufptr = (*env)->GetDirectBufferAddress(env, buf); - if (size < 0) { - msg_Err(p_dec, "Java buffer has invalid size"); - p_sys->error_state = true; - break; - } - if ((size_t) size > p_block->i_buffer) - size = p_block->i_buffer; - memcpy(bufptr, p_block->p_buffer, size); - - convert_h264_to_annexb(bufptr, size, p_sys->nal_size, &convert_state); - - int64_t ts = p_block->i_pts; - if (!ts && p_block->i_dts) - ts = p_block->i_dts; - timestamp_FifoPut(p_sys->timestamp_fifo, p_block->i_pts ? VLC_TS_INVALID : p_block->i_dts); - (*env)->CallVoidMethod(env, p_sys->codec, p_sys->queue_input_buffer, index, 0, size, ts, 0); - (*env)->DeleteLocalRef(env, buf); - if (CHECK_EXCEPTION()) { - msg_Err(p_dec, "Exception in MediaCodec.queueInputBuffer"); - p_sys->error_state = true; - break; - } - p_sys->decoded = true; - break; } + +endclean: if (p_sys->error_state) { + if( pp_block && *pp_block ) + { + block_Release(*pp_block); + *pp_block = NULL; + } if (p_pic) picture_Release(p_pic); - jni_detach_thread(); - return NULL; - } - if (!p_pic) - GetOutput(p_dec, env, &p_pic, 0); - jni_detach_thread(); + p_pic = NULL; - block_Release(p_block); - *pp_block = NULL; + if (!p_sys->error_event_sent) { + /* Signal the error to the Java. */ + jni_EventHardwareAccelerationError(); + p_sys->error_event_sent = true; + } + } + if (env != NULL) + jni_detach_thread(); return p_pic; }