static int Audio_OnNewBlock(decoder_t *p_dec, block_t *p_block) { decoder_sys_t *p_sys = p_dec->p_sys; if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) { if (DecodeFlush(p_dec) != VLC_SUCCESS) return -1; date_Set(&p_sys->u.audio.i_end_date, VLC_TS_INVALID); return 0; } /* We've just started the stream, wait for the first PTS. */ if (!date_Get(&p_sys->u.audio.i_end_date)) { if (p_block->i_pts <= VLC_TS_INVALID) return 0; date_Set(&p_sys->u.audio.i_end_date, p_block->i_pts); } /* try delayed opening if there is a new extra data */ if (!p_sys->api->b_started) { bool b_delayed_start = false; switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_VORBIS: case VLC_CODEC_MP4A: if (p_dec->fmt_in.i_extra) b_delayed_start = true; default: break; } if (!p_dec->p_sys->u.audio.i_channels && p_dec->fmt_in.audio.i_channels) { p_dec->p_sys->u.audio.i_channels = p_dec->fmt_in.audio.i_channels; b_delayed_start = true; } if (b_delayed_start && !p_dec->p_sys->u.audio.i_channels && p_sys->u.audio.b_need_channels) b_delayed_start = false; if (b_delayed_start && StartMediaCodec(p_dec) != VLC_SUCCESS) return -1; if (!p_sys->api->b_started) return 0; } return 1; }
static int Video_OnNewBlock(decoder_t *p_dec, block_t *p_block) { decoder_sys_t *p_sys = p_dec->p_sys; bool b_csd_changed = false, b_size_changed = false; bool b_delayed_start = false; if (p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK && !p_sys->api->b_support_interlaced) return -1; if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) { if (p_sys->decoded) { timestamp_FifoEmpty(p_sys->u.video.timestamp_fifo); /* Invalidate all pictures that are currently in flight * since flushing make all previous indices returned by * MediaCodec invalid. */ if (p_sys->api->b_direct_rendering) InvalidateAllPictures(p_dec); } if (DecodeFlush(p_dec) != VLC_SUCCESS) return -1; return 0; } if (p_dec->fmt_in.i_codec == VLC_CODEC_H264) H264ProcessBlock(p_dec, p_block, &b_csd_changed, &b_size_changed); else if (p_dec->fmt_in.i_codec == VLC_CODEC_HEVC) HEVCProcessBlock(p_dec, p_block, &b_csd_changed, &b_size_changed); if (p_sys->api->b_started && b_csd_changed) { if (b_size_changed) { msg_Err(p_dec, "SPS/PPS changed during playback and " "video size are different. Restart it !"); StopMediaCodec(p_dec); } else { msg_Err(p_dec, "SPS/PPS changed during playback. Flush it"); if (DecodeFlush(p_dec) != VLC_SUCCESS) return -1; } } if (b_csd_changed) b_delayed_start = true; /* try delayed opening if there is a new extra data */ if (!p_sys->api->b_started) { switch (p_dec->fmt_in.i_codec) { case VLC_CODEC_VC1: if (p_dec->fmt_in.i_extra) b_delayed_start = true; default: break; } if (b_delayed_start && StartMediaCodec(p_dec) != VLC_SUCCESS) return -1; if (!p_sys->api->b_started) return 0; } timestamp_FifoPut(p_sys->u.video.timestamp_fifo, p_block->i_pts ? VLC_TS_INVALID : p_block->i_dts); return 1; }
/** * 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; }