| Index: media/base/android/media_decoder_job.cc
|
| diff --git a/media/base/android/media_decoder_job.cc b/media/base/android/media_decoder_job.cc
|
| index 41b74a08e5100dc69147db854f4c987d5157911e..90094439605c4380a35021bf59ab8daa763c06ce 100644
|
| --- a/media/base/android/media_decoder_job.cc
|
| +++ b/media/base/android/media_decoder_job.cc
|
| @@ -110,7 +110,7 @@ void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) {
|
| RequestData(prefetch_cb);
|
| }
|
|
|
| -bool MediaDecoderJob::Decode(
|
| +MediaDecoderJob::MediaDecoderJobStatus MediaDecoderJob::Decode(
|
| base::TimeTicks start_time_ticks,
|
| base::TimeDelta start_presentation_timestamp,
|
| const DecoderCallback& callback) {
|
| @@ -120,10 +120,11 @@ bool MediaDecoderJob::Decode(
|
| if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) {
|
| if (drain_decoder_)
|
| OnDecoderDrained();
|
| - need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge();
|
| + MediaDecoderJobStatus status = CreateMediaCodecBridge();
|
| + need_to_reconfig_decoder_job_ = (status != STATUS_SUCCESS);
|
| skip_eos_enqueue_ = true;
|
| if (need_to_reconfig_decoder_job_)
|
| - return false;
|
| + return status;
|
| }
|
|
|
| decode_cb_ = callback;
|
| @@ -133,11 +134,11 @@ bool MediaDecoderJob::Decode(
|
| base::Unretained(this),
|
| start_time_ticks,
|
| start_presentation_timestamp));
|
| - return true;
|
| + return STATUS_SUCCESS;
|
| }
|
|
|
| DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp);
|
| - return true;
|
| + return STATUS_SUCCESS;
|
| }
|
|
|
| void MediaDecoderJob::StopDecode() {
|
| @@ -205,6 +206,32 @@ base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() {
|
| return media_crypto;
|
| }
|
|
|
| +bool MediaDecoderJob::SetCurrentFrameToPreviouslyCachedKeyFrame() {
|
| + const std::vector<AccessUnit>& access_units =
|
| + received_data_[current_demuxer_data_index_].access_units;
|
| + // If the current data chunk is empty, the player must be in an initial or
|
| + // seek state. The next access unit will always be a key frame.
|
| + if (access_units.size() == 0)
|
| + return true;
|
| +
|
| + // Find key frame in all the access units the decoder have decoded,
|
| + // or is about to decode.
|
| + int i = std::min(access_unit_index_[current_demuxer_data_index_],
|
| + access_units.size() - 1);
|
| + for (; i >= 0; --i) {
|
| + // Config change is always the last access unit, and it always come with
|
| + // a key frame afterwards.
|
| + if (access_units[i].status == DemuxerStream::kConfigChanged)
|
| + return true;
|
| + if (access_units[i].is_key_frame) {
|
| + access_unit_index_[current_demuxer_data_index_] = i;
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| void MediaDecoderJob::Release() {
|
| DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
| DVLOG(1) << __FUNCTION__;
|
| @@ -518,11 +545,8 @@ void MediaDecoderJob::OnDecodeCompleted(
|
| case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
|
| case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
|
| case MEDIA_CODEC_OUTPUT_END_OF_STREAM:
|
| - if (!input_eos_encountered_) {
|
| - CurrentDataConsumed(
|
| - CurrentAccessUnit().status == DemuxerStream::kConfigChanged);
|
| + if (!input_eos_encountered_)
|
| access_unit_index_[current_demuxer_data_index_]++;
|
| - }
|
| break;
|
|
|
| case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
|
| @@ -589,7 +613,7 @@ void MediaDecoderJob::RequestCurrentChunkIfEmpty() {
|
|
|
| // Requests new data if the the last access unit of the next chunk is not EOS.
|
| current_demuxer_data_index_ = inactive_demuxer_data_index();
|
| - const AccessUnit last_access_unit =
|
| + const AccessUnit& last_access_unit =
|
| received_data_[current_demuxer_data_index_].access_units.back();
|
| if (!last_access_unit.is_end_of_stream &&
|
| last_access_unit.status != DemuxerStream::kAborted) {
|
| @@ -616,26 +640,26 @@ void MediaDecoderJob::OnDecoderDrained() {
|
| // Increase the access unit index so that the new decoder will not handle
|
| // the config change again.
|
| access_unit_index_[current_demuxer_data_index_]++;
|
| - CurrentDataConsumed(true);
|
| }
|
|
|
| -bool MediaDecoderJob::CreateMediaCodecBridge() {
|
| +MediaDecoderJob::MediaDecoderJobStatus
|
| + MediaDecoderJob::CreateMediaCodecBridge() {
|
| DVLOG(1) << __FUNCTION__;
|
| DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
| DCHECK(decode_cb_.is_null());
|
|
|
| if (!HasStream()) {
|
| ReleaseMediaCodecBridge();
|
| - return false;
|
| + return STATUS_FAILURE;
|
| }
|
|
|
| // Create |media_codec_bridge_| only if config changes.
|
| if (media_codec_bridge_ && !need_to_reconfig_decoder_job_)
|
| - return true;
|
| + return STATUS_SUCCESS;
|
|
|
| base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto();
|
| if (is_content_encrypted_ && media_crypto.is_null())
|
| - return false;
|
| + return STATUS_FAILURE;
|
|
|
| ReleaseMediaCodecBridge();
|
| DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge";
|
|
|