Home | History | Annotate | Download | only in android
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/base/android/media_decoder_job.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback_helpers.h"
      9 #include "base/debug/trace_event.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "media/base/android/media_codec_bridge.h"
     12 #include "media/base/android/media_drm_bridge.h"
     13 #include "media/base/bind_to_current_loop.h"
     14 #include "media/base/buffers.h"
     15 
     16 namespace media {
     17 
     18 // Timeout value for media codec operations. Because the first
     19 // DequeInputBuffer() can take about 150 milliseconds, use 250 milliseconds
     20 // here. See http://b/9357571.
     21 static const int kMediaCodecTimeoutInMilliseconds = 250;
     22 
     23 MediaDecoderJob::MediaDecoderJob(
     24     const scoped_refptr<base::SingleThreadTaskRunner>& decoder_task_runner,
     25     const base::Closure& request_data_cb,
     26     const base::Closure& config_changed_cb)
     27     : need_to_reconfig_decoder_job_(false),
     28       ui_task_runner_(base::MessageLoopProxy::current()),
     29       decoder_task_runner_(decoder_task_runner),
     30       needs_flush_(false),
     31       input_eos_encountered_(false),
     32       output_eos_encountered_(false),
     33       skip_eos_enqueue_(true),
     34       prerolling_(true),
     35       request_data_cb_(request_data_cb),
     36       config_changed_cb_(config_changed_cb),
     37       current_demuxer_data_index_(0),
     38       input_buf_index_(-1),
     39       is_content_encrypted_(false),
     40       stop_decode_pending_(false),
     41       destroy_pending_(false),
     42       is_requesting_demuxer_data_(false),
     43       is_incoming_data_invalid_(false),
     44       release_resources_pending_(false),
     45       drm_bridge_(NULL),
     46       drain_decoder_(false) {
     47   InitializeReceivedData();
     48   eos_unit_.end_of_stream = true;
     49 }
     50 
     51 MediaDecoderJob::~MediaDecoderJob() {
     52   ReleaseMediaCodecBridge();
     53 }
     54 
     55 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) {
     56   DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units";
     57   DCHECK(ui_task_runner_->BelongsToCurrentThread());
     58   DCHECK(NoAccessUnitsRemainingInChunk(false));
     59 
     60   TRACE_EVENT_ASYNC_END2(
     61       "media", "MediaDecoderJob::RequestData", this,
     62       "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO",
     63       "Units read", data.access_units.size());
     64 
     65   if (is_incoming_data_invalid_) {
     66     is_incoming_data_invalid_ = false;
     67 
     68     // If there is a pending callback, need to request the data again to get
     69     // valid data.
     70     if (!data_received_cb_.is_null())
     71       request_data_cb_.Run();
     72     else
     73       is_requesting_demuxer_data_ = false;
     74     return;
     75   }
     76 
     77   size_t next_demuxer_data_index = inactive_demuxer_data_index();
     78   received_data_[next_demuxer_data_index] = data;
     79   access_unit_index_[next_demuxer_data_index] = 0;
     80   is_requesting_demuxer_data_ = false;
     81 
     82   base::Closure done_cb = base::ResetAndReturn(&data_received_cb_);
     83 
     84   // If this data request is for the inactive chunk, or |data_received_cb_|
     85   // was set to null by Flush() or Release(), do nothing.
     86   if (done_cb.is_null())
     87     return;
     88 
     89   if (stop_decode_pending_) {
     90     DCHECK(is_decoding());
     91     OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp());
     92     return;
     93   }
     94 
     95   done_cb.Run();
     96 }
     97 
     98 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) {
     99   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    100   DCHECK(data_received_cb_.is_null());
    101   DCHECK(decode_cb_.is_null());
    102 
    103   if (HasData()) {
    104     DVLOG(1) << __FUNCTION__ << " : using previously received data";
    105     ui_task_runner_->PostTask(FROM_HERE, prefetch_cb);
    106     return;
    107   }
    108 
    109   DVLOG(1) << __FUNCTION__ << " : requesting data";
    110   RequestData(prefetch_cb);
    111 }
    112 
    113 bool MediaDecoderJob::Decode(
    114     base::TimeTicks start_time_ticks,
    115     base::TimeDelta start_presentation_timestamp,
    116     const DecoderCallback& callback) {
    117   DCHECK(decode_cb_.is_null());
    118   DCHECK(data_received_cb_.is_null());
    119   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    120 
    121   if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) {
    122     need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge();
    123     if (drain_decoder_) {
    124       // Decoder has been recreated, stop draining.
    125       drain_decoder_ = false;
    126       input_eos_encountered_ = false;
    127       output_eos_encountered_ = false;
    128       access_unit_index_[current_demuxer_data_index_]++;
    129     }
    130     skip_eos_enqueue_ = true;
    131     if (need_to_reconfig_decoder_job_)
    132       return false;
    133   }
    134 
    135   decode_cb_ = callback;
    136 
    137   if (!HasData()) {
    138     RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit,
    139                            base::Unretained(this),
    140                            start_time_ticks,
    141                            start_presentation_timestamp));
    142     return true;
    143   }
    144 
    145   DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp);
    146   return true;
    147 }
    148 
    149 void MediaDecoderJob::StopDecode() {
    150   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    151   DCHECK(is_decoding());
    152   stop_decode_pending_ = true;
    153 }
    154 
    155 bool MediaDecoderJob::OutputEOSReached() const {
    156   return !drain_decoder_ && output_eos_encountered_;
    157 }
    158 
    159 void MediaDecoderJob::SetDrmBridge(MediaDrmBridge* drm_bridge) {
    160   drm_bridge_ = drm_bridge;
    161   need_to_reconfig_decoder_job_ = true;
    162 }
    163 
    164 void MediaDecoderJob::Flush() {
    165   DVLOG(1) << __FUNCTION__;
    166   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    167   DCHECK(data_received_cb_.is_null());
    168   DCHECK(decode_cb_.is_null());
    169 
    170   // Clean up the received data.
    171   current_demuxer_data_index_ = 0;
    172   InitializeReceivedData();
    173   if (is_requesting_demuxer_data_)
    174     is_incoming_data_invalid_ = true;
    175   input_eos_encountered_ = false;
    176   output_eos_encountered_ = false;
    177   drain_decoder_ = false;
    178 
    179   // Do nothing, flush when the next Decode() happens.
    180   needs_flush_ = true;
    181 }
    182 
    183 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) {
    184   DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")";
    185   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    186   DCHECK(!is_decoding());
    187 
    188   preroll_timestamp_ = preroll_timestamp;
    189   prerolling_ = true;
    190 }
    191 
    192 void MediaDecoderJob::ReleaseDecoderResources() {
    193   DVLOG(1) << __FUNCTION__;
    194   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    195   if (decode_cb_.is_null()) {
    196     DCHECK(!drain_decoder_);
    197     // Since the decoder job is not decoding data, we can safely destroy
    198     // |media_codec_bridge_|.
    199     ReleaseMediaCodecBridge();
    200     return;
    201   }
    202 
    203   // Release |media_codec_bridge_| once decoding is completed.
    204   release_resources_pending_ = true;
    205 }
    206 
    207 base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() {
    208   base::android::ScopedJavaLocalRef<jobject> media_crypto;
    209   if (drm_bridge_)
    210     media_crypto = drm_bridge_->GetMediaCrypto();
    211   return media_crypto;
    212 }
    213 
    214 void MediaDecoderJob::Release() {
    215   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    216   DVLOG(1) << __FUNCTION__;
    217 
    218   // If the decoder job is still decoding, we cannot delete the job immediately.
    219   destroy_pending_ = is_decoding();
    220 
    221   request_data_cb_.Reset();
    222   data_received_cb_.Reset();
    223   decode_cb_.Reset();
    224 
    225   if (destroy_pending_) {
    226     DVLOG(1) << __FUNCTION__ << " : delete is pending decode completion";
    227     return;
    228   }
    229 
    230   delete this;
    231 }
    232 
    233 MediaCodecStatus MediaDecoderJob::QueueInputBuffer(const AccessUnit& unit) {
    234   DVLOG(1) << __FUNCTION__;
    235   DCHECK(decoder_task_runner_->BelongsToCurrentThread());
    236   TRACE_EVENT0("media", __FUNCTION__);
    237 
    238   int input_buf_index = input_buf_index_;
    239   input_buf_index_ = -1;
    240 
    241   // TODO(xhwang): Hide DequeueInputBuffer() and the index in MediaCodecBridge.
    242   if (input_buf_index == -1) {
    243     base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
    244         kMediaCodecTimeoutInMilliseconds);
    245     MediaCodecStatus status =
    246         media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index);
    247     if (status != MEDIA_CODEC_OK) {
    248       DVLOG(1) << "DequeueInputBuffer fails: " << status;
    249       return status;
    250     }
    251   }
    252 
    253   // TODO(qinmin): skip frames if video is falling far behind.
    254   DCHECK_GE(input_buf_index, 0);
    255   if (unit.end_of_stream || unit.data.empty()) {
    256     media_codec_bridge_->QueueEOS(input_buf_index);
    257     return MEDIA_CODEC_INPUT_END_OF_STREAM;
    258   }
    259 
    260   if (unit.key_id.empty() || unit.iv.empty()) {
    261     DCHECK(unit.iv.empty() || !unit.key_id.empty());
    262     return media_codec_bridge_->QueueInputBuffer(
    263         input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
    264   }
    265 
    266   MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer(
    267       input_buf_index,
    268       &unit.data[0], unit.data.size(),
    269       reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(),
    270       reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
    271       unit.subsamples.empty() ? NULL : &unit.subsamples[0],
    272       unit.subsamples.size(),
    273       unit.timestamp);
    274 
    275   // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|.
    276   // Otherwise MediaDrm will report errors.
    277   if (status == MEDIA_CODEC_NO_KEY)
    278     input_buf_index_ = input_buf_index;
    279 
    280   return status;
    281 }
    282 
    283 bool MediaDecoderJob::HasData() const {
    284   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    285   // When |input_eos_encountered_| is set, |access_unit_index_| and
    286   // |current_demuxer_data_index_| must be pointing to an EOS unit,
    287   // or a |kConfigChanged| unit if |drain_decoder_| is true. In both cases,
    288   // we'll feed an EOS input unit to drain the decoder until we hit output EOS.
    289   DCHECK(!input_eos_encountered_ || !NoAccessUnitsRemainingInChunk(true));
    290   return !NoAccessUnitsRemainingInChunk(true) ||
    291       !NoAccessUnitsRemainingInChunk(false);
    292 }
    293 
    294 void MediaDecoderJob::RequestData(const base::Closure& done_cb) {
    295   DVLOG(1) << __FUNCTION__;
    296   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    297   DCHECK(data_received_cb_.is_null());
    298   DCHECK(!input_eos_encountered_);
    299   DCHECK(NoAccessUnitsRemainingInChunk(false));
    300 
    301   TRACE_EVENT_ASYNC_BEGIN0("media", "MediaDecoderJob::RequestData", this);
    302 
    303   data_received_cb_ = done_cb;
    304 
    305   // If we are already expecting new data, just set the callback and do
    306   // nothing.
    307   if (is_requesting_demuxer_data_)
    308     return;
    309 
    310   // The new incoming data will be stored as the next demuxer data chunk, since
    311   // the decoder might still be decoding the current one.
    312   size_t next_demuxer_data_index = inactive_demuxer_data_index();
    313   received_data_[next_demuxer_data_index] = DemuxerData();
    314   access_unit_index_[next_demuxer_data_index] = 0;
    315   is_requesting_demuxer_data_ = true;
    316 
    317   request_data_cb_.Run();
    318 }
    319 
    320 void MediaDecoderJob::DecodeCurrentAccessUnit(
    321     base::TimeTicks start_time_ticks,
    322     base::TimeDelta start_presentation_timestamp) {
    323   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    324   DCHECK(!decode_cb_.is_null());
    325 
    326   RequestCurrentChunkIfEmpty();
    327   const AccessUnit& access_unit = CurrentAccessUnit();
    328   if (CurrentAccessUnit().status == DemuxerStream::kConfigChanged) {
    329     int index = CurrentReceivedDataChunkIndex();
    330     const DemuxerConfigs& configs = received_data_[index].demuxer_configs[0];
    331     bool reconfigure_needed = IsCodecReconfigureNeeded(configs);
    332     SetDemuxerConfigs(configs);
    333     if (!drain_decoder_) {
    334       // If we haven't decoded any data yet, just skip the current access unit
    335       // and request the MediaCodec to be recreated on next Decode().
    336       if (skip_eos_enqueue_ || !reconfigure_needed) {
    337         need_to_reconfig_decoder_job_ =
    338             need_to_reconfig_decoder_job_ || reconfigure_needed;
    339         // Report MEDIA_CODEC_OK status so decoder will continue decoding and
    340         // MEDIA_CODEC_OUTPUT_FORMAT_CHANGED status will come later.
    341         ui_task_runner_->PostTask(FROM_HERE, base::Bind(
    342             &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this),
    343             MEDIA_CODEC_OK, kNoTimestamp(), kNoTimestamp()));
    344         return;
    345       }
    346       // Start draining the decoder so that all the remaining frames are
    347       // rendered.
    348       drain_decoder_ = true;
    349     }
    350   }
    351 
    352   DCHECK(!(needs_flush_ && drain_decoder_));
    353   decoder_task_runner_->PostTask(FROM_HERE, base::Bind(
    354       &MediaDecoderJob::DecodeInternal, base::Unretained(this),
    355       drain_decoder_ ? eos_unit_ : access_unit,
    356       start_time_ticks, start_presentation_timestamp, needs_flush_,
    357       media::BindToCurrentLoop(base::Bind(
    358           &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this)))));
    359   needs_flush_ = false;
    360 }
    361 
    362 void MediaDecoderJob::DecodeInternal(
    363     const AccessUnit& unit,
    364     base::TimeTicks start_time_ticks,
    365     base::TimeDelta start_presentation_timestamp,
    366     bool needs_flush,
    367     const MediaDecoderJob::DecoderCallback& callback) {
    368   DVLOG(1) << __FUNCTION__;
    369   DCHECK(decoder_task_runner_->BelongsToCurrentThread());
    370   TRACE_EVENT0("media", __FUNCTION__);
    371 
    372   if (needs_flush) {
    373     DVLOG(1) << "DecodeInternal needs flush.";
    374     input_eos_encountered_ = false;
    375     output_eos_encountered_ = false;
    376     MediaCodecStatus reset_status = media_codec_bridge_->Reset();
    377     if (MEDIA_CODEC_OK != reset_status) {
    378       callback.Run(reset_status, kNoTimestamp(), kNoTimestamp());
    379       return;
    380     }
    381   }
    382 
    383   // Once output EOS has occurred, we should not be asked to decode again.
    384   // MediaCodec has undefined behavior if similarly asked to decode after output
    385   // EOS.
    386   DCHECK(!output_eos_encountered_);
    387 
    388   // For aborted access unit, just skip it and inform the player.
    389   if (unit.status == DemuxerStream::kAborted) {
    390     // TODO(qinmin): use a new enum instead of MEDIA_CODEC_STOPPED.
    391     callback.Run(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp());
    392     return;
    393   }
    394 
    395   if (skip_eos_enqueue_) {
    396     if (unit.end_of_stream || unit.data.empty()) {
    397       input_eos_encountered_ = true;
    398       output_eos_encountered_ = true;
    399       callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(),
    400                    kNoTimestamp());
    401       return;
    402     }
    403 
    404     skip_eos_enqueue_ = false;
    405   }
    406 
    407   MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM;
    408   if (!input_eos_encountered_) {
    409     input_status = QueueInputBuffer(unit);
    410     if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) {
    411       input_eos_encountered_ = true;
    412     } else if (input_status != MEDIA_CODEC_OK) {
    413       callback.Run(input_status, kNoTimestamp(), kNoTimestamp());
    414       return;
    415     }
    416   }
    417 
    418   int buffer_index = 0;
    419   size_t offset = 0;
    420   size_t size = 0;
    421   base::TimeDelta presentation_timestamp;
    422 
    423   base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
    424       kMediaCodecTimeoutInMilliseconds);
    425 
    426   MediaCodecStatus status = MEDIA_CODEC_OK;
    427   bool has_format_change = false;
    428   // Dequeue the output buffer until a MEDIA_CODEC_OK, MEDIA_CODEC_ERROR or
    429   // MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER is received.
    430   do {
    431     status = media_codec_bridge_->DequeueOutputBuffer(
    432         timeout,
    433         &buffer_index,
    434         &offset,
    435         &size,
    436         &presentation_timestamp,
    437         &output_eos_encountered_,
    438         NULL);
    439     if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED &&
    440         !media_codec_bridge_->GetOutputBuffers()) {
    441       status = MEDIA_CODEC_ERROR;
    442     } else if (status == MEDIA_CODEC_OUTPUT_FORMAT_CHANGED) {
    443       // TODO(qinmin): instead of waiting for the next output buffer to be
    444       // dequeued, post a task on the UI thread to signal the format change.
    445       has_format_change = true;
    446     }
    447   } while (status != MEDIA_CODEC_OK && status != MEDIA_CODEC_ERROR &&
    448            status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER);
    449 
    450   if (status != MEDIA_CODEC_OK) {
    451     callback.Run(status, kNoTimestamp(), kNoTimestamp());
    452     return;
    453   }
    454 
    455   // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up.
    456   if (output_eos_encountered_)
    457     status = MEDIA_CODEC_OUTPUT_END_OF_STREAM;
    458   else if (has_format_change)
    459     status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED;
    460 
    461   bool render_output  = presentation_timestamp >= preroll_timestamp_ &&
    462       (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u);
    463   base::TimeDelta time_to_render;
    464   DCHECK(!start_time_ticks.is_null());
    465   if (render_output && ComputeTimeToRender()) {
    466     time_to_render = presentation_timestamp - (base::TimeTicks::Now() -
    467         start_time_ticks + start_presentation_timestamp);
    468   }
    469 
    470   if (time_to_render > base::TimeDelta()) {
    471     decoder_task_runner_->PostDelayedTask(
    472         FROM_HERE,
    473         base::Bind(&MediaDecoderJob::ReleaseOutputBuffer,
    474                    base::Unretained(this),
    475                    buffer_index,
    476                    size,
    477                    render_output,
    478                    presentation_timestamp,
    479                    base::Bind(callback, status)),
    480         time_to_render);
    481     return;
    482   }
    483 
    484   // TODO(qinmin): The codec is lagging behind, need to recalculate the
    485   // |start_presentation_timestamp_| and |start_time_ticks_| in
    486   // media_source_player.cc.
    487   DVLOG(1) << "codec is lagging behind :" << time_to_render.InMicroseconds();
    488   if (render_output) {
    489     // The player won't expect a timestamp smaller than the
    490     // |start_presentation_timestamp|. However, this could happen due to decoder
    491     // errors.
    492     presentation_timestamp = std::max(
    493         presentation_timestamp, start_presentation_timestamp);
    494   } else {
    495     presentation_timestamp = kNoTimestamp();
    496   }
    497   ReleaseOutputCompletionCallback completion_callback = base::Bind(
    498       callback, status);
    499   ReleaseOutputBuffer(buffer_index, size, render_output, presentation_timestamp,
    500                       completion_callback);
    501 }
    502 
    503 void MediaDecoderJob::OnDecodeCompleted(
    504     MediaCodecStatus status, base::TimeDelta current_presentation_timestamp,
    505     base::TimeDelta max_presentation_timestamp) {
    506   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    507 
    508   if (destroy_pending_) {
    509     DVLOG(1) << __FUNCTION__ << " : completing pending deletion";
    510     delete this;
    511     return;
    512   }
    513 
    514   if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM)
    515     output_eos_encountered_ = true;
    516 
    517   DCHECK(!decode_cb_.is_null());
    518 
    519   // If output was queued for rendering, then we have completed prerolling.
    520   if (current_presentation_timestamp != kNoTimestamp())
    521     prerolling_ = false;
    522 
    523   switch (status) {
    524     case MEDIA_CODEC_OK:
    525     case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
    526     case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
    527     case MEDIA_CODEC_OUTPUT_END_OF_STREAM:
    528       if (!input_eos_encountered_) {
    529         CurrentDataConsumed(
    530             CurrentAccessUnit().status == DemuxerStream::kConfigChanged);
    531         access_unit_index_[current_demuxer_data_index_]++;
    532       }
    533       break;
    534 
    535     case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
    536     case MEDIA_CODEC_INPUT_END_OF_STREAM:
    537     case MEDIA_CODEC_NO_KEY:
    538     case MEDIA_CODEC_STOPPED:
    539     case MEDIA_CODEC_ERROR:
    540       // Do nothing.
    541       break;
    542 
    543     case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
    544       DCHECK(false) << "Invalid output status";
    545       break;
    546   };
    547 
    548   if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM && drain_decoder_) {
    549     OnDecoderDrained();
    550     status = MEDIA_CODEC_OK;
    551   }
    552 
    553   if (status == MEDIA_CODEC_OUTPUT_FORMAT_CHANGED) {
    554     if (UpdateOutputFormat())
    555       config_changed_cb_.Run();
    556     status = MEDIA_CODEC_OK;
    557   }
    558 
    559   if (release_resources_pending_) {
    560     ReleaseMediaCodecBridge();
    561     release_resources_pending_ = false;
    562     if (drain_decoder_)
    563       OnDecoderDrained();
    564   }
    565 
    566   stop_decode_pending_ = false;
    567   base::ResetAndReturn(&decode_cb_).Run(
    568       status, current_presentation_timestamp, max_presentation_timestamp);
    569 }
    570 
    571 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const {
    572   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    573   DCHECK(HasData());
    574   size_t index = CurrentReceivedDataChunkIndex();
    575   return received_data_[index].access_units[access_unit_index_[index]];
    576 }
    577 
    578 size_t MediaDecoderJob::CurrentReceivedDataChunkIndex() const {
    579   return NoAccessUnitsRemainingInChunk(true) ?
    580       inactive_demuxer_data_index() : current_demuxer_data_index_;
    581 }
    582 
    583 bool MediaDecoderJob::NoAccessUnitsRemainingInChunk(
    584     bool is_active_chunk) const {
    585   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    586   size_t index = is_active_chunk ? current_demuxer_data_index_ :
    587       inactive_demuxer_data_index();
    588   return received_data_[index].access_units.size() <= access_unit_index_[index];
    589 }
    590 
    591 void MediaDecoderJob::RequestCurrentChunkIfEmpty() {
    592   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    593   DCHECK(HasData());
    594   if (!NoAccessUnitsRemainingInChunk(true))
    595     return;
    596 
    597   // Requests new data if the the last access unit of the next chunk is not EOS.
    598   current_demuxer_data_index_ = inactive_demuxer_data_index();
    599   const AccessUnit last_access_unit =
    600       received_data_[current_demuxer_data_index_].access_units.back();
    601   if (!last_access_unit.end_of_stream &&
    602       last_access_unit.status != DemuxerStream::kAborted) {
    603     RequestData(base::Closure());
    604   }
    605 }
    606 
    607 void MediaDecoderJob::InitializeReceivedData() {
    608   for (size_t i = 0; i < 2; ++i) {
    609     received_data_[i] = DemuxerData();
    610     access_unit_index_[i] = 0;
    611   }
    612 }
    613 
    614 void MediaDecoderJob::OnDecoderDrained() {
    615   DVLOG(1) << __FUNCTION__;
    616   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    617   DCHECK(drain_decoder_);
    618 
    619   input_eos_encountered_ = false;
    620   output_eos_encountered_ = false;
    621   drain_decoder_ = false;
    622   ReleaseMediaCodecBridge();
    623   // Increase the access unit index so that the new decoder will not handle
    624   // the config change again.
    625   access_unit_index_[current_demuxer_data_index_]++;
    626   CurrentDataConsumed(true);
    627 }
    628 
    629 bool MediaDecoderJob::CreateMediaCodecBridge() {
    630   DVLOG(1) << __FUNCTION__;
    631   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    632   DCHECK(decode_cb_.is_null());
    633 
    634   if (!HasStream()) {
    635     ReleaseMediaCodecBridge();
    636     return false;
    637   }
    638 
    639   // Create |media_codec_bridge_| only if config changes.
    640   if (media_codec_bridge_ && !need_to_reconfig_decoder_job_)
    641     return true;
    642 
    643   base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto();
    644   if (is_content_encrypted_ && media_crypto.is_null())
    645     return false;
    646 
    647   ReleaseMediaCodecBridge();
    648   DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge";
    649 
    650   return CreateMediaCodecBridgeInternal();
    651 }
    652 
    653 bool MediaDecoderJob::IsCodecReconfigureNeeded(
    654     const DemuxerConfigs& configs) const {
    655   if (!AreDemuxerConfigsChanged(configs))
    656     return false;
    657   return true;
    658 }
    659 
    660 bool MediaDecoderJob::UpdateOutputFormat() {
    661   return false;
    662 }
    663 
    664 void MediaDecoderJob::ReleaseMediaCodecBridge() {
    665   if (!media_codec_bridge_)
    666     return;
    667 
    668   media_codec_bridge_.reset();
    669   input_buf_index_ = -1;
    670 }
    671 
    672 }  // namespace media
    673