OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/base/android/media_decoder_job.h" | 5 #include "media/base/android/media_decoder_job.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/single_thread_task_runner.h" | 9 #include "base/single_thread_task_runner.h" |
10 #include "base/threading/thread_task_runner_handle.h" | 10 #include "base/threading/thread_task_runner_handle.h" |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 | 81 |
82 base::Closure done_cb = base::ResetAndReturn(&data_received_cb_); | 82 base::Closure done_cb = base::ResetAndReturn(&data_received_cb_); |
83 | 83 |
84 // If this data request is for the inactive chunk, or |data_received_cb_| | 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. | 85 // was set to null by Flush() or Release(), do nothing. |
86 if (done_cb.is_null()) | 86 if (done_cb.is_null()) |
87 return; | 87 return; |
88 | 88 |
89 if (stop_decode_pending_) { | 89 if (stop_decode_pending_) { |
90 DCHECK(is_decoding()); | 90 DCHECK(is_decoding()); |
91 OnDecodeCompleted(MEDIA_CODEC_ABORT, false, kNoTimestamp(), kNoTimestamp()); | 91 OnDecodeCompleted(MEDIA_CODEC_ABORT, false, kNoTimestamp, kNoTimestamp); |
92 return; | 92 return; |
93 } | 93 } |
94 | 94 |
95 done_cb.Run(); | 95 done_cb.Run(); |
96 } | 96 } |
97 | 97 |
98 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { | 98 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { |
99 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 99 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
100 DCHECK(data_received_cb_.is_null()); | 100 DCHECK(data_received_cb_.is_null()); |
101 DCHECK(decode_cb_.is_null()); | 101 DCHECK(decode_cb_.is_null()); |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 bool reconfigure_needed = IsCodecReconfigureNeeded(configs); | 345 bool reconfigure_needed = IsCodecReconfigureNeeded(configs); |
346 SetDemuxerConfigs(configs); | 346 SetDemuxerConfigs(configs); |
347 if (!drain_decoder_) { | 347 if (!drain_decoder_) { |
348 // If we haven't decoded any data yet, just skip the current access unit | 348 // If we haven't decoded any data yet, just skip the current access unit |
349 // and request the MediaCodec to be recreated on next Decode(). | 349 // and request the MediaCodec to be recreated on next Decode(). |
350 if (skip_eos_enqueue_ || !reconfigure_needed) { | 350 if (skip_eos_enqueue_ || !reconfigure_needed) { |
351 need_to_reconfig_decoder_job_ = | 351 need_to_reconfig_decoder_job_ = |
352 need_to_reconfig_decoder_job_ || reconfigure_needed; | 352 need_to_reconfig_decoder_job_ || reconfigure_needed; |
353 // Report MEDIA_CODEC_OK status so decoder will continue decoding and | 353 // Report MEDIA_CODEC_OK status so decoder will continue decoding and |
354 // MEDIA_CODEC_OUTPUT_FORMAT_CHANGED status will come later. | 354 // MEDIA_CODEC_OUTPUT_FORMAT_CHANGED status will come later. |
355 ui_task_runner_->PostTask(FROM_HERE, base::Bind( | 355 ui_task_runner_->PostTask( |
356 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this), | 356 FROM_HERE, base::Bind(&MediaDecoderJob::OnDecodeCompleted, |
357 MEDIA_CODEC_OK, false, kNoTimestamp(), kNoTimestamp())); | 357 base::Unretained(this), MEDIA_CODEC_OK, false, |
| 358 kNoTimestamp, kNoTimestamp)); |
358 return; | 359 return; |
359 } | 360 } |
360 // Start draining the decoder so that all the remaining frames are | 361 // Start draining the decoder so that all the remaining frames are |
361 // rendered. | 362 // rendered. |
362 drain_decoder_ = true; | 363 drain_decoder_ = true; |
363 } | 364 } |
364 } | 365 } |
365 | 366 |
366 DCHECK(!(needs_flush_ && drain_decoder_)); | 367 DCHECK(!(needs_flush_ && drain_decoder_)); |
367 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( | 368 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( |
(...skipping 15 matching lines...) Expand all Loading... |
383 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); | 384 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); |
384 TRACE_EVENT0("media", __FUNCTION__); | 385 TRACE_EVENT0("media", __FUNCTION__); |
385 | 386 |
386 if (needs_flush) { | 387 if (needs_flush) { |
387 DVLOG(1) << "DecodeInternal needs flush."; | 388 DVLOG(1) << "DecodeInternal needs flush."; |
388 input_eos_encountered_ = false; | 389 input_eos_encountered_ = false; |
389 output_eos_encountered_ = false; | 390 output_eos_encountered_ = false; |
390 input_buf_index_ = -1; | 391 input_buf_index_ = -1; |
391 MediaCodecStatus flush_status = media_codec_bridge_->Flush(); | 392 MediaCodecStatus flush_status = media_codec_bridge_->Flush(); |
392 if (flush_status != MEDIA_CODEC_OK) { | 393 if (flush_status != MEDIA_CODEC_OK) { |
393 callback.Run(flush_status, false, kNoTimestamp(), kNoTimestamp()); | 394 callback.Run(flush_status, false, kNoTimestamp, kNoTimestamp); |
394 return; | 395 return; |
395 } | 396 } |
396 } | 397 } |
397 | 398 |
398 // Once output EOS has occurred, we should not be asked to decode again. | 399 // Once output EOS has occurred, we should not be asked to decode again. |
399 // MediaCodec has undefined behavior if similarly asked to decode after output | 400 // MediaCodec has undefined behavior if similarly asked to decode after output |
400 // EOS. | 401 // EOS. |
401 DCHECK(!output_eos_encountered_); | 402 DCHECK(!output_eos_encountered_); |
402 | 403 |
403 // For aborted access unit, just skip it and inform the player. | 404 // For aborted access unit, just skip it and inform the player. |
404 if (unit.status == DemuxerStream::kAborted) { | 405 if (unit.status == DemuxerStream::kAborted) { |
405 callback.Run(MEDIA_CODEC_ABORT, false, kNoTimestamp(), kNoTimestamp()); | 406 callback.Run(MEDIA_CODEC_ABORT, false, kNoTimestamp, kNoTimestamp); |
406 return; | 407 return; |
407 } | 408 } |
408 | 409 |
409 if (skip_eos_enqueue_) { | 410 if (skip_eos_enqueue_) { |
410 if (unit.is_end_of_stream || unit.data.empty()) { | 411 if (unit.is_end_of_stream || unit.data.empty()) { |
411 input_eos_encountered_ = true; | 412 input_eos_encountered_ = true; |
412 output_eos_encountered_ = true; | 413 output_eos_encountered_ = true; |
413 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, false, kNoTimestamp(), | 414 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, false, kNoTimestamp, |
414 kNoTimestamp()); | 415 kNoTimestamp); |
415 return; | 416 return; |
416 } | 417 } |
417 | 418 |
418 skip_eos_enqueue_ = false; | 419 skip_eos_enqueue_ = false; |
419 } | 420 } |
420 | 421 |
421 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; | 422 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; |
422 if (!input_eos_encountered_) { | 423 if (!input_eos_encountered_) { |
423 input_status = QueueInputBuffer(unit); | 424 input_status = QueueInputBuffer(unit); |
424 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { | 425 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { |
425 input_eos_encountered_ = true; | 426 input_eos_encountered_ = true; |
426 } else if (input_status == MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER) { | 427 } else if (input_status == MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER) { |
427 // In some cases, all buffers must be released to codec before format | 428 // In some cases, all buffers must be released to codec before format |
428 // change can be resolved. Context: b/21786703 | 429 // change can be resolved. Context: b/21786703 |
429 DVLOG(1) << "dequeueInputBuffer gave AGAIN_LATER, dequeue output buffers"; | 430 DVLOG(1) << "dequeueInputBuffer gave AGAIN_LATER, dequeue output buffers"; |
430 } else if (input_status != MEDIA_CODEC_OK) { | 431 } else if (input_status != MEDIA_CODEC_OK) { |
431 callback.Run(input_status, false, kNoTimestamp(), kNoTimestamp()); | 432 callback.Run(input_status, false, kNoTimestamp, kNoTimestamp); |
432 return; | 433 return; |
433 } | 434 } |
434 } | 435 } |
435 | 436 |
436 int buffer_index = 0; | 437 int buffer_index = 0; |
437 size_t offset = 0; | 438 size_t offset = 0; |
438 size_t size = 0; | 439 size_t size = 0; |
439 base::TimeDelta presentation_timestamp; | 440 base::TimeDelta presentation_timestamp; |
440 | 441 |
441 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( | 442 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( |
(...skipping 17 matching lines...) Expand all Loading... |
459 // dequeued, post a task on the UI thread to signal the format change. | 460 // dequeued, post a task on the UI thread to signal the format change. |
460 if (OnOutputFormatChanged()) | 461 if (OnOutputFormatChanged()) |
461 has_format_change = true; | 462 has_format_change = true; |
462 else | 463 else |
463 status = MEDIA_CODEC_ERROR; | 464 status = MEDIA_CODEC_ERROR; |
464 } | 465 } |
465 } while (status != MEDIA_CODEC_OK && status != MEDIA_CODEC_ERROR && | 466 } while (status != MEDIA_CODEC_OK && status != MEDIA_CODEC_ERROR && |
466 status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); | 467 status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); |
467 | 468 |
468 if (status != MEDIA_CODEC_OK) { | 469 if (status != MEDIA_CODEC_OK) { |
469 callback.Run(status, false, kNoTimestamp(), kNoTimestamp()); | 470 callback.Run(status, false, kNoTimestamp, kNoTimestamp); |
470 return; | 471 return; |
471 } | 472 } |
472 | 473 |
473 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. | 474 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. |
474 if (output_eos_encountered_) | 475 if (output_eos_encountered_) |
475 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; | 476 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; |
476 else if (has_format_change) | 477 else if (has_format_change) |
477 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED; | 478 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED; |
478 | 479 |
479 bool render_output = presentation_timestamp >= preroll_timestamp_ && | 480 bool render_output = presentation_timestamp >= preroll_timestamp_ && |
(...skipping 20 matching lines...) Expand all Loading... |
500 // |start_presentation_timestamp_| and |start_time_ticks_| in | 501 // |start_presentation_timestamp_| and |start_time_ticks_| in |
501 // media_source_player.cc. | 502 // media_source_player.cc. |
502 DVLOG(1) << "codec is lagging behind :" << time_to_render.InMicroseconds(); | 503 DVLOG(1) << "codec is lagging behind :" << time_to_render.InMicroseconds(); |
503 if (render_output) { | 504 if (render_output) { |
504 // The player won't expect a timestamp smaller than the | 505 // The player won't expect a timestamp smaller than the |
505 // |start_presentation_timestamp|. However, this could happen due to decoder | 506 // |start_presentation_timestamp|. However, this could happen due to decoder |
506 // errors. | 507 // errors. |
507 presentation_timestamp = std::max( | 508 presentation_timestamp = std::max( |
508 presentation_timestamp, start_presentation_timestamp); | 509 presentation_timestamp, start_presentation_timestamp); |
509 } else { | 510 } else { |
510 presentation_timestamp = kNoTimestamp(); | 511 presentation_timestamp = kNoTimestamp; |
511 } | 512 } |
512 | 513 |
513 const bool is_late_frame = (time_to_render < base::TimeDelta()); | 514 const bool is_late_frame = (time_to_render < base::TimeDelta()); |
514 ReleaseOutputBuffer(buffer_index, offset, size, render_output, is_late_frame, | 515 ReleaseOutputBuffer(buffer_index, offset, size, render_output, is_late_frame, |
515 presentation_timestamp, status, callback); | 516 presentation_timestamp, status, callback); |
516 } | 517 } |
517 | 518 |
518 void MediaDecoderJob::OnDecodeCompleted( | 519 void MediaDecoderJob::OnDecodeCompleted( |
519 MediaCodecStatus status, | 520 MediaCodecStatus status, |
520 bool is_late_frame, | 521 bool is_late_frame, |
521 base::TimeDelta current_presentation_timestamp, | 522 base::TimeDelta current_presentation_timestamp, |
522 base::TimeDelta max_presentation_timestamp) { | 523 base::TimeDelta max_presentation_timestamp) { |
523 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 524 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
524 | 525 |
525 if (destroy_pending_) { | 526 if (destroy_pending_) { |
526 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; | 527 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; |
527 delete this; | 528 delete this; |
528 return; | 529 return; |
529 } | 530 } |
530 | 531 |
531 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) | 532 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) |
532 output_eos_encountered_ = true; | 533 output_eos_encountered_ = true; |
533 | 534 |
534 DCHECK(!decode_cb_.is_null()); | 535 DCHECK(!decode_cb_.is_null()); |
535 | 536 |
536 // If output was queued for rendering, then we have completed prerolling. | 537 // If output was queued for rendering, then we have completed prerolling. |
537 if (current_presentation_timestamp != kNoTimestamp() || | 538 if (current_presentation_timestamp != kNoTimestamp || |
538 status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { | 539 status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { |
539 prerolling_ = false; | 540 prerolling_ = false; |
540 } | 541 } |
541 | 542 |
542 switch (status) { | 543 switch (status) { |
543 case MEDIA_CODEC_OK: | 544 case MEDIA_CODEC_OK: |
544 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: | 545 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: |
545 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: | 546 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: |
546 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: | 547 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: |
547 if (!input_eos_encountered_) | 548 if (!input_eos_encountered_) |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
683 | 684 |
684 void MediaDecoderJob::ReleaseMediaCodecBridge() { | 685 void MediaDecoderJob::ReleaseMediaCodecBridge() { |
685 if (!media_codec_bridge_) | 686 if (!media_codec_bridge_) |
686 return; | 687 return; |
687 | 688 |
688 media_codec_bridge_.reset(); | 689 media_codec_bridge_.reset(); |
689 input_buf_index_ = -1; | 690 input_buf_index_ = -1; |
690 } | 691 } |
691 | 692 |
692 } // namespace media | 693 } // namespace media |
OLD | NEW |