/** * DecodeCommon called from DecodeVideo or DecodeAudio. * It returns -1 in case of error, 0 otherwise. The output buffer is returned * in pp_out_pic for Video, and pp_out_block for Audio. */ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block, dec_on_new_block_cb pf_on_new_block, dec_get_output_cb pf_get_out, picture_t **pp_out_pic, block_t **pp_out_block) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block = pp_block ? *pp_block : NULL; unsigned int i_attempts = 0; jlong timeout = 0; int i_output_ret = 0; int i_input_ret = 0; bool b_abort = false; bool b_error = false; bool b_new_block = p_block ? p_sys->b_new_block : false; if (p_sys->error_state) goto endclean; if (b_new_block) { int i_ret; p_sys->b_new_block = false; i_ret = pf_on_new_block(p_dec, p_block); if (i_ret != 1) { if (i_ret == -1) b_error = true; goto endclean; } } do { if ((p_sys->i_csd_send < p_sys->i_csd_count || p_block) && i_input_ret == 0) { i_input_ret = PutInput(p_dec, p_block, timeout); if (!p_sys->decoded) continue; } if (i_input_ret != -1 && p_sys->decoded && i_output_ret == 0) { i_output_ret = pf_get_out(p_dec, pp_out_pic, pp_out_block, &b_abort, timeout); if (!p_sys->b_has_format && i_output_ret == 0 && i_input_ret == 0 && ++i_attempts > 100) { /* No output and no format, thereforce mediacodec didn't * produce any output or events yet. Don't wait indefinitely * and abort after 2seconds (100 * 2 * 10ms) without any data. * Indeed, MediaCodec can fail without throwing any exception * or error returns... */ msg_Err(p_dec, "No output/input for %lld ms, abort", i_attempts * timeout); b_error = true; break; } } timeout = 10 * 1000; // 10 ms /* loop until either the input or the output are processed (i_input_ret * or i_output_ret == 1 ) or caused an error (i_input_ret or * i_output_ret == -1 )*/ } while (p_block && i_input_ret == 0 && i_output_ret == 0 && !b_abort); if (i_input_ret == -1 || i_output_ret == -1) { msg_Err(p_dec, "%s failed", i_input_ret == -1 ? "PutInput" : "GetOutput"); b_error = true; } endclean: /* If pf_decode returns NULL, we'll get a new p_block from the next * pf_decode call. Therefore we need to release the current one even if we * couldn't process it (it happens in case or error or if MediaCodec is * still not opened). We also must release the current p_block if we were * able to process it. */ if (p_block && (i_output_ret != 1 || i_input_ret != 0)) { block_Release(p_block); *pp_block = NULL; p_sys->b_new_block = true; } if (b_error && !p_sys->error_state) { /* Signal the error to the Java. */ jni_EventHardwareAccelerationError(); p_sys->error_state = true; } return b_error ? -1 : 0; }
/** * DecodeCommon called from DecodeVideo or DecodeAudio. * It returns -1 in case of error, 0 otherwise. The output buffer is returned * in pp_out_pic for Video, and pp_out_block for Audio. */ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block, picture_t **pp_out_pic, block_t **pp_out_block) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block = pp_block ? *pp_block : NULL; unsigned int i_attempts = 0; jlong timeout = 0; int i_output_ret = 0; int i_input_ret = 0; bool b_abort = false; bool b_error = false; bool b_new_block = p_block ? p_sys->b_new_block : false; if (p_sys->error_state) goto endclean; if (b_new_block) { int i_ret, i_flags = 0; p_sys->b_new_block = false; if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) { if (DecodeFlush(p_dec) != VLC_SUCCESS) b_error = true; goto endclean; } i_ret = p_sys->pf_on_new_block(p_dec, p_block, &i_flags); if (i_ret != 1) { if (i_ret == -1) b_error = true; goto endclean; } if (i_flags & NEWBLOCK_FLAG_FLUSH) { if (DecodeFlush(p_dec) != VLC_SUCCESS) { b_error = true; goto endclean; } } if (i_flags & NEWBLOCK_FLAG_RESTART) { StopMediaCodec(p_dec); if (StartMediaCodec(p_dec) != VLC_SUCCESS) { b_error = true; goto endclean; } } } if (!p_sys->api->b_started) goto endclean; do { if ((p_sys->i_csd_send < p_sys->i_csd_count || p_block) && i_input_ret == 0) { int i_index = p_sys->api->dequeue_in(p_sys->api, timeout); if (i_index >= 0) { block_t *p_in_block; mtime_t i_ts; if (p_sys->i_csd_send < p_sys->i_csd_count) { p_in_block = p_sys->pp_csd[p_sys->i_csd_send]; i_ts = 0; } else { p_in_block = p_block; i_ts = p_block->i_pts; if (!i_ts && p_block->i_dts) i_ts = p_block->i_dts; } i_input_ret = p_sys->api->queue_in(p_sys->api, i_index, p_in_block->p_buffer, p_in_block->i_buffer, i_ts, p_in_block->i_flags & BLOCK_FLAG_CSD) == 0 ? 1 : -1; if (i_input_ret == 1) { if (p_sys->i_csd_send < p_sys->i_csd_count) { p_sys->i_csd_send++; i_input_ret = 0; } else { p_sys->decoded = true; if (p_block->i_flags & BLOCK_FLAG_PREROLL ) p_sys->i_preroll_end = i_ts; } } } else if (i_index == MC_API_INFO_TRYAGAIN) i_input_ret = 0; else i_input_ret = -1; /* No need to try output if no input buffer is decoded */ if (!p_sys->decoded) continue; } if (i_input_ret != -1 && p_sys->decoded && i_output_ret == 0) { i_output_ret = GetAndProcessOutput(p_dec, pp_out_pic, pp_out_block, timeout); if (i_output_ret == 0 && i_input_ret == 0) { if (++i_attempts == 20) { /* HACK: When direct rendering is enabled, there is a * possible deadlock between the Decoder and the Vout. It * happens when the Vout is paused and when the Decoder is * flushing. In that case, the Vout won't release any * output buffers, therefore MediaCodec won't dequeue any * input buffers. To work around this issue, release all * output buffers if DecodeCommon is waiting more than 400 * msec for a new input buffer. */ msg_Warn(p_dec, "Decoder stuck: invalidate all buffers"); InvalidateAllPictures(p_dec); } if (!p_sys->b_has_format && ++i_attempts > 100) { /* No output and no format, thereforce mediacodec didn't * produce any output or events yet. Don't wait * indefinitely and abort after 2seconds (100 * 2 * 10ms) * without any data. Indeed, MediaCodec can fail without * throwing any exception or error returns... */ msg_Err(p_dec, "No output/input for %lld ms, abort", i_attempts * timeout); b_error = true; break; } } } timeout = 10 * 1000; // 10 ms /* loop until either the input or the output are processed (i_input_ret * or i_output_ret == 1 ) or caused an error (i_input_ret or * i_output_ret == -1 )*/ } while (p_block && i_input_ret == 0 && i_output_ret == 0 && !b_abort); if (i_input_ret == -1 || i_output_ret == -1) { msg_Err(p_dec, "%s failed", i_input_ret == -1 ? "PutInput" : "GetOutput"); b_error = true; } endclean: /* If pf_decode returns NULL, we'll get a new p_block from the next * pf_decode call. Therefore we need to release the current one even if we * couldn't process it (it happens in case or error or if MediaCodec is * still not opened). We also must release the current p_block if we were * able to process it. */ if (p_block && (i_output_ret != 1 || i_input_ret != 0)) { block_Release(p_block); *pp_block = NULL; p_sys->b_new_block = true; } if (b_error && !p_sys->error_state) { /* Signal the error to the Java. */ jni_EventHardwareAccelerationError(); p_sys->error_state = true; } return b_error ? -1 : 0; }