| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/gpu/android_video_decode_accelerator.h" | 5 #include "media/gpu/android_video_decode_accelerator.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 H264PROFILE_SCALABLEHIGH, | 75 H264PROFILE_SCALABLEHIGH, |
| 76 H264PROFILE_STEREOHIGH, | 76 H264PROFILE_STEREOHIGH, |
| 77 H264PROFILE_MULTIVIEWHIGH}; | 77 H264PROFILE_MULTIVIEWHIGH}; |
| 78 | 78 |
| 79 // Because MediaCodec is thread-hostile (must be poked on a single thread) and | 79 // Because MediaCodec is thread-hostile (must be poked on a single thread) and |
| 80 // has no callback mechanism (b/11990118), we must drive it by polling for | 80 // has no callback mechanism (b/11990118), we must drive it by polling for |
| 81 // complete frames (and available input buffers, when the codec is fully | 81 // complete frames (and available input buffers, when the codec is fully |
| 82 // saturated). This function defines the polling delay. The value used is an | 82 // saturated). This function defines the polling delay. The value used is an |
| 83 // arbitrary choice that trades off CPU utilization (spinning) against latency. | 83 // arbitrary choice that trades off CPU utilization (spinning) against latency. |
| 84 // Mirrors android_video_encode_accelerator.cc:EncodePollDelay(). | 84 // Mirrors android_video_encode_accelerator.cc:EncodePollDelay(). |
| 85 static inline const base::TimeDelta DecodePollDelay() { | 85 // |
| 86 // An alternative to this polling scheme could be to dedicate a new thread | 86 // An alternative to this polling scheme could be to dedicate a new thread |
| 87 // (instead of using the ChildThread) to run the MediaCodec, and make that | 87 // (instead of using the ChildThread) to run the MediaCodec, and make that |
| 88 // thread use the timeout-based flavor of MediaCodec's dequeue methods when it | 88 // thread use the timeout-based flavor of MediaCodec's dequeue methods when it |
| 89 // believes the codec should complete "soon" (e.g. waiting for an input | 89 // believes the codec should complete "soon" (e.g. waiting for an input |
| 90 // buffer, or waiting for a picture when it knows enough complete input | 90 // buffer, or waiting for a picture when it knows enough complete input |
| 91 // pictures have been fed to saturate any internal buffering). This is | 91 // pictures have been fed to saturate any internal buffering). This is |
| 92 // speculative and it's unclear that this would be a win (nor that there's a | 92 // speculative and it's unclear that this would be a win (nor that there's a |
| 93 // reasonably device-agnostic way to fill in the "believes" above). | 93 // reasonably device-agnostic way to fill in the "believes" above). |
| 94 return base::TimeDelta::FromMilliseconds(10); | 94 constexpr base::TimeDelta DecodePollDelay = |
| 95 } | 95 base::TimeDelta::FromMilliseconds(10); |
| 96 | 96 |
| 97 static inline const base::TimeDelta NoWaitTimeOut() { | 97 constexpr base::TimeDelta NoWaitTimeOut = base::TimeDelta::FromMicroseconds(0); |
| 98 return base::TimeDelta::FromMicroseconds(0); | |
| 99 } | |
| 100 | 98 |
| 101 static inline const base::TimeDelta IdleTimerTimeOut() { | 99 constexpr base::TimeDelta IdleTimerTimeOut = base::TimeDelta::FromSeconds(1); |
| 102 return base::TimeDelta::FromSeconds(1); | |
| 103 } | |
| 104 | 100 |
| 105 // Time between when we notice an error, and when we actually notify somebody. | 101 // Time between when we notice an error, and when we actually notify somebody. |
| 106 // This is to prevent codec errors caused by SurfaceView fullscreen transitions | 102 // This is to prevent codec errors caused by SurfaceView fullscreen transitions |
| 107 // from breaking the pipeline, if we're about to be reset anyway. | 103 // from breaking the pipeline, if we're about to be reset anyway. |
| 108 static inline const base::TimeDelta ErrorPostingDelay() { | 104 constexpr base::TimeDelta ErrorPostingDelay = base::TimeDelta::FromSeconds(2); |
| 109 return base::TimeDelta::FromSeconds(2); | |
| 110 } | |
| 111 | 105 |
| 112 // For RecordFormatChangedMetric. | 106 // For RecordFormatChangedMetric. |
| 113 enum FormatChangedValue { | 107 enum FormatChangedValue { |
| 114 CodecInitialized = false, | 108 CodecInitialized = false, |
| 115 MissingFormatChanged = true | 109 MissingFormatChanged = true |
| 116 }; | 110 }; |
| 117 | 111 |
| 118 // Maximum number of concurrent, incomplete codec creations that we'll allow | 112 // Maximum number of concurrent, incomplete codec creations that we'll allow |
| 119 // before turning off autodection of codec type. | 113 // before turning off autodection of codec type. |
| 120 enum { kMaxConcurrentCodecAutodetections = 4 }; | 114 enum { kMaxConcurrentCodecAutodetections = 4 }; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 // will stay running until we try to shut it down again. | 211 // will stay running until we try to shut it down again. |
| 218 base::AutoLock auto_lock(autodetection_info_.lock_); | 212 base::AutoLock auto_lock(autodetection_info_.lock_); |
| 219 if (autodetection_info_.outstanding_) | 213 if (autodetection_info_.outstanding_) |
| 220 return; | 214 return; |
| 221 | 215 |
| 222 construction_thread_.Stop(); | 216 construction_thread_.Stop(); |
| 223 } | 217 } |
| 224 | 218 |
| 225 // Request periodic callback of |avda_instance|->DoIOTask(). Does nothing if | 219 // Request periodic callback of |avda_instance|->DoIOTask(). Does nothing if |
| 226 // the instance is already registered and the timer started. The first request | 220 // the instance is already registered and the timer started. The first request |
| 227 // will start the repeating timer on an interval of DecodePollDelay(). | 221 // will start the repeating timer on an interval of DecodePollDelay. |
| 228 void StartTimer(AndroidVideoDecodeAccelerator* avda_instance) { | 222 void StartTimer(AndroidVideoDecodeAccelerator* avda_instance) { |
| 229 DCHECK(thread_checker_.CalledOnValidThread()); | 223 DCHECK(thread_checker_.CalledOnValidThread()); |
| 230 | 224 |
| 231 timer_avda_instances_.insert(avda_instance); | 225 timer_avda_instances_.insert(avda_instance); |
| 232 | 226 |
| 233 // If the timer is running, StopTimer() might have been called earlier, if | 227 // If the timer is running, StopTimer() might have been called earlier, if |
| 234 // so remove the instance from the pending erasures. | 228 // so remove the instance from the pending erasures. |
| 235 if (timer_running_) | 229 if (timer_running_) |
| 236 pending_erase_.erase(avda_instance); | 230 pending_erase_.erase(avda_instance); |
| 237 | 231 |
| 238 if (io_timer_.IsRunning()) | 232 if (io_timer_.IsRunning()) |
| 239 return; | 233 return; |
| 240 io_timer_.Start(FROM_HERE, DecodePollDelay(), this, | 234 io_timer_.Start(FROM_HERE, DecodePollDelay, this, |
| 241 &AVDATimerManager::RunTimer); | 235 &AVDATimerManager::RunTimer); |
| 242 } | 236 } |
| 243 | 237 |
| 244 // Stop callbacks to |avda_instance|->DoIOTask(). Does nothing if the instance | 238 // Stop callbacks to |avda_instance|->DoIOTask(). Does nothing if the instance |
| 245 // is not registered. If there are no instances left, the repeating timer will | 239 // is not registered. If there are no instances left, the repeating timer will |
| 246 // be stopped. | 240 // be stopped. |
| 247 void StopTimer(AndroidVideoDecodeAccelerator* avda_instance) { | 241 void StopTimer(AndroidVideoDecodeAccelerator* avda_instance) { |
| 248 DCHECK(thread_checker_.CalledOnValidThread()); | 242 DCHECK(thread_checker_.CalledOnValidThread()); |
| 249 | 243 |
| 250 // If the timer is running, defer erasures to avoid iterator invalidation. | 244 // If the timer is running, defer erasures to avoid iterator invalidation. |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 if (pending_bitstream_records_.empty()) | 635 if (pending_bitstream_records_.empty()) |
| 642 return false; | 636 return false; |
| 643 | 637 |
| 644 int input_buf_index = pending_input_buf_index_; | 638 int input_buf_index = pending_input_buf_index_; |
| 645 | 639 |
| 646 // Do not dequeue a new input buffer if we failed with MEDIA_CODEC_NO_KEY. | 640 // Do not dequeue a new input buffer if we failed with MEDIA_CODEC_NO_KEY. |
| 647 // That status does not return this buffer back to the pool of | 641 // That status does not return this buffer back to the pool of |
| 648 // available input buffers. We have to reuse it in QueueSecureInputBuffer(). | 642 // available input buffers. We have to reuse it in QueueSecureInputBuffer(). |
| 649 if (input_buf_index == -1) { | 643 if (input_buf_index == -1) { |
| 650 MediaCodecStatus status = | 644 MediaCodecStatus status = |
| 651 media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index); | 645 media_codec_->DequeueInputBuffer(NoWaitTimeOut, &input_buf_index); |
| 652 switch (status) { | 646 switch (status) { |
| 653 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: | 647 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: |
| 654 return false; | 648 return false; |
| 655 case MEDIA_CODEC_ERROR: | 649 case MEDIA_CODEC_ERROR: |
| 656 POST_ERROR(PLATFORM_FAILURE, "Failed to DequeueInputBuffer"); | 650 POST_ERROR(PLATFORM_FAILURE, "Failed to DequeueInputBuffer"); |
| 657 return false; | 651 return false; |
| 658 case MEDIA_CODEC_OK: | 652 case MEDIA_CODEC_OK: |
| 659 break; | 653 break; |
| 660 default: | 654 default: |
| 661 NOTREACHED() << "Unknown DequeueInputBuffer status " << status; | 655 NOTREACHED() << "Unknown DequeueInputBuffer status " << status; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 685 shm = std::move(pending_bitstream_records_.front().memory); | 679 shm = std::move(pending_bitstream_records_.front().memory); |
| 686 | 680 |
| 687 if (!shm->Map()) { | 681 if (!shm->Map()) { |
| 688 POST_ERROR(UNREADABLE_INPUT, "Failed to SharedMemoryRegion::Map()"); | 682 POST_ERROR(UNREADABLE_INPUT, "Failed to SharedMemoryRegion::Map()"); |
| 689 return false; | 683 return false; |
| 690 } | 684 } |
| 691 } | 685 } |
| 692 | 686 |
| 693 const base::TimeDelta presentation_timestamp = | 687 const base::TimeDelta presentation_timestamp = |
| 694 bitstream_buffer.presentation_timestamp(); | 688 bitstream_buffer.presentation_timestamp(); |
| 695 DCHECK(presentation_timestamp != kNoTimestamp()) | 689 DCHECK(presentation_timestamp != kNoTimestamp) |
| 696 << "Bitstream buffers must have valid presentation timestamps"; | 690 << "Bitstream buffers must have valid presentation timestamps"; |
| 697 | 691 |
| 698 // There may already be a bitstream buffer with this timestamp, e.g., VP9 alt | 692 // There may already be a bitstream buffer with this timestamp, e.g., VP9 alt |
| 699 // ref frames, but it's OK to overwrite it because we only expect a single | 693 // ref frames, but it's OK to overwrite it because we only expect a single |
| 700 // output frame to have that timestamp. AVDA clients only use the bitstream | 694 // output frame to have that timestamp. AVDA clients only use the bitstream |
| 701 // buffer id in the returned Pictures to map a bitstream buffer back to a | 695 // buffer id in the returned Pictures to map a bitstream buffer back to a |
| 702 // timestamp on their side, so either one of the bitstream buffer ids will | 696 // timestamp on their side, so either one of the bitstream buffer ids will |
| 703 // result in them finding the right timestamp. | 697 // result in them finding the right timestamp. |
| 704 bitstream_buffers_in_decoder_[presentation_timestamp] = bitstream_buffer.id(); | 698 bitstream_buffers_in_decoder_[presentation_timestamp] = bitstream_buffer.id(); |
| 705 | 699 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 775 | 769 |
| 776 bool eos = false; | 770 bool eos = false; |
| 777 base::TimeDelta presentation_timestamp; | 771 base::TimeDelta presentation_timestamp; |
| 778 int32_t buf_index = 0; | 772 int32_t buf_index = 0; |
| 779 do { | 773 do { |
| 780 size_t offset = 0; | 774 size_t offset = 0; |
| 781 size_t size = 0; | 775 size_t size = 0; |
| 782 | 776 |
| 783 TRACE_EVENT_BEGIN0("media", "AVDA::DequeueOutput"); | 777 TRACE_EVENT_BEGIN0("media", "AVDA::DequeueOutput"); |
| 784 MediaCodecStatus status = media_codec_->DequeueOutputBuffer( | 778 MediaCodecStatus status = media_codec_->DequeueOutputBuffer( |
| 785 NoWaitTimeOut(), &buf_index, &offset, &size, &presentation_timestamp, | 779 NoWaitTimeOut, &buf_index, &offset, &size, &presentation_timestamp, |
| 786 &eos, NULL); | 780 &eos, NULL); |
| 787 TRACE_EVENT_END2("media", "AVDA::DequeueOutput", "status", status, | 781 TRACE_EVENT_END2("media", "AVDA::DequeueOutput", "status", status, |
| 788 "presentation_timestamp (ms)", | 782 "presentation_timestamp (ms)", |
| 789 presentation_timestamp.InMilliseconds()); | 783 presentation_timestamp.InMilliseconds()); |
| 790 | 784 |
| 791 switch (status) { | 785 switch (status) { |
| 792 case MEDIA_CODEC_ERROR: | 786 case MEDIA_CODEC_ERROR: |
| 793 // Do not post an error if we are draining for reset and destroy. | 787 // Do not post an error if we are draining for reset and destroy. |
| 794 // Instead, run the drain completion task. | 788 // Instead, run the drain completion task. |
| 795 if (IsDrainingForResetOrDestroy()) { | 789 if (IsDrainingForResetOrDestroy()) { |
| (...skipping 730 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1526 strategy_->OnFrameAvailable(); | 1520 strategy_->OnFrameAvailable(); |
| 1527 } | 1521 } |
| 1528 | 1522 |
| 1529 void AndroidVideoDecodeAccelerator::PostError( | 1523 void AndroidVideoDecodeAccelerator::PostError( |
| 1530 const ::tracked_objects::Location& from_here, | 1524 const ::tracked_objects::Location& from_here, |
| 1531 VideoDecodeAccelerator::Error error) { | 1525 VideoDecodeAccelerator::Error error) { |
| 1532 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 1526 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 1533 from_here, | 1527 from_here, |
| 1534 base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, | 1528 base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, |
| 1535 weak_this_factory_.GetWeakPtr(), error, error_sequence_token_), | 1529 weak_this_factory_.GetWeakPtr(), error, error_sequence_token_), |
| 1536 (defer_errors_ ? ErrorPostingDelay() : base::TimeDelta())); | 1530 (defer_errors_ ? ErrorPostingDelay : base::TimeDelta())); |
| 1537 state_ = ERROR; | 1531 state_ = ERROR; |
| 1538 } | 1532 } |
| 1539 | 1533 |
| 1540 void AndroidVideoDecodeAccelerator::InitializeCdm() { | 1534 void AndroidVideoDecodeAccelerator::InitializeCdm() { |
| 1541 DVLOG(2) << __FUNCTION__ << ": " << config_.cdm_id; | 1535 DVLOG(2) << __FUNCTION__ << ": " << config_.cdm_id; |
| 1542 | 1536 |
| 1543 #if !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | 1537 #if !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) |
| 1544 NOTIMPLEMENTED(); | 1538 NOTIMPLEMENTED(); |
| 1545 NotifyInitializationComplete(false); | 1539 NotifyInitializationComplete(false); |
| 1546 #else | 1540 #else |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1646 if (client_) | 1640 if (client_) |
| 1647 client_->NotifyError(error); | 1641 client_->NotifyError(error); |
| 1648 } | 1642 } |
| 1649 | 1643 |
| 1650 void AndroidVideoDecodeAccelerator::ManageTimer(bool did_work) { | 1644 void AndroidVideoDecodeAccelerator::ManageTimer(bool did_work) { |
| 1651 bool should_be_running = true; | 1645 bool should_be_running = true; |
| 1652 | 1646 |
| 1653 base::TimeTicks now = base::TimeTicks::Now(); | 1647 base::TimeTicks now = base::TimeTicks::Now(); |
| 1654 if (!did_work && !most_recent_work_.is_null()) { | 1648 if (!did_work && !most_recent_work_.is_null()) { |
| 1655 // Make sure that we have done work recently enough, else stop the timer. | 1649 // Make sure that we have done work recently enough, else stop the timer. |
| 1656 if (now - most_recent_work_ > IdleTimerTimeOut()) { | 1650 if (now - most_recent_work_ > IdleTimerTimeOut) { |
| 1657 most_recent_work_ = base::TimeTicks(); | 1651 most_recent_work_ = base::TimeTicks(); |
| 1658 should_be_running = false; | 1652 should_be_running = false; |
| 1659 } | 1653 } |
| 1660 } else { | 1654 } else { |
| 1661 most_recent_work_ = now; | 1655 most_recent_work_ = now; |
| 1662 } | 1656 } |
| 1663 | 1657 |
| 1664 if (should_be_running) | 1658 if (should_be_running) |
| 1665 g_avda_timer.Pointer()->StartTimer(this); | 1659 g_avda_timer.Pointer()->StartTimer(this); |
| 1666 else | 1660 else |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1780 | 1774 |
| 1781 bool AndroidVideoDecodeAccelerator::IsMediaCodecSoftwareDecodingForbidden() | 1775 bool AndroidVideoDecodeAccelerator::IsMediaCodecSoftwareDecodingForbidden() |
| 1782 const { | 1776 const { |
| 1783 // Prevent MediaCodec from using its internal software decoders when we have | 1777 // Prevent MediaCodec from using its internal software decoders when we have |
| 1784 // more secure and up to date versions in the renderer process. | 1778 // more secure and up to date versions in the renderer process. |
| 1785 return !config_.is_encrypted && (codec_config_->codec_ == media::kCodecVP8 || | 1779 return !config_.is_encrypted && (codec_config_->codec_ == media::kCodecVP8 || |
| 1786 codec_config_->codec_ == media::kCodecVP9); | 1780 codec_config_->codec_ == media::kCodecVP9); |
| 1787 } | 1781 } |
| 1788 | 1782 |
| 1789 } // namespace media | 1783 } // namespace media |
| OLD | NEW |