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
16namespace 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.
21static const int kMediaCodecTimeoutInMilliseconds = 250;
22
23MediaDecoderJob::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
51MediaDecoderJob::~MediaDecoderJob() {
52  ReleaseMediaCodecBridge();
53}
54
55void 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
98void 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
113bool 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
149void MediaDecoderJob::StopDecode() {
150  DCHECK(ui_task_runner_->BelongsToCurrentThread());
151  DCHECK(is_decoding());
152  stop_decode_pending_ = true;
153}
154
155bool MediaDecoderJob::OutputEOSReached() const {
156  return !drain_decoder_ && output_eos_encountered_;
157}
158
159void MediaDecoderJob::SetDrmBridge(MediaDrmBridge* drm_bridge) {
160  drm_bridge_ = drm_bridge;
161  need_to_reconfig_decoder_job_ = true;
162}
163
164void 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
183void 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
192void 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
207base::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
214void 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
233MediaCodecStatus 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
283bool 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
294void 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
320void 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
362void 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
503void 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
571const 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
578size_t MediaDecoderJob::CurrentReceivedDataChunkIndex() const {
579  return NoAccessUnitsRemainingInChunk(true) ?
580      inactive_demuxer_data_index() : current_demuxer_data_index_;
581}
582
583bool 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
591void 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
607void 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
614void 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
629bool 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
653bool MediaDecoderJob::IsCodecReconfigureNeeded(
654    const DemuxerConfigs& configs) const {
655  if (!AreDemuxerConfigsChanged(configs))
656    return false;
657  return true;
658}
659
660bool MediaDecoderJob::UpdateOutputFormat() {
661  return false;
662}
663
664void 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