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