| 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 |