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 "content/renderer/media/rtc_video_decoder.h" | 5 #include "content/renderer/media/rtc_video_decoder.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 timestamp(timestamp), | 61 timestamp(timestamp), |
62 width(width), | 62 width(width), |
63 height(height), | 63 height(height), |
64 size(size) {} | 64 size(size) {} |
65 | 65 |
66 RTCVideoDecoder::BufferData::BufferData() {} | 66 RTCVideoDecoder::BufferData::BufferData() {} |
67 | 67 |
68 RTCVideoDecoder::BufferData::~BufferData() {} | 68 RTCVideoDecoder::BufferData::~BufferData() {} |
69 | 69 |
70 RTCVideoDecoder::RTCVideoDecoder( | 70 RTCVideoDecoder::RTCVideoDecoder( |
| 71 const scoped_refptr<base::MessageLoopProxy>& vda_loop_proxy, |
71 const scoped_refptr<media::GpuVideoDecoder::Factories>& factories) | 72 const scoped_refptr<media::GpuVideoDecoder::Factories>& factories) |
72 : weak_factory_(this), | 73 : weak_factory_(this), |
73 weak_this_(weak_factory_.GetWeakPtr()), | 74 weak_this_(weak_factory_.GetWeakPtr()), |
74 factories_(factories), | 75 factories_(factories), |
75 vda_loop_proxy_(factories_->GetMessageLoop()), | 76 vda_loop_proxy_(vda_loop_proxy), |
76 create_shm_thread_("CreateSHMThread"), | |
77 decoder_texture_target_(0), | 77 decoder_texture_target_(0), |
78 next_picture_buffer_id_(0), | 78 next_picture_buffer_id_(0), |
79 state_(UNINITIALIZED), | 79 state_(UNINITIALIZED), |
80 decode_complete_callback_(NULL), | 80 decode_complete_callback_(NULL), |
81 num_shm_buffers_(0), | 81 num_shm_buffers_(0), |
82 next_bitstream_buffer_id_(0), | 82 next_bitstream_buffer_id_(0), |
83 reset_bitstream_buffer_id_(ID_INVALID) { | 83 reset_bitstream_buffer_id_(ID_INVALID) { |
84 create_shm_thread_.Start(); | 84 DCHECK(!vda_loop_proxy_->BelongsToCurrentThread()); |
85 // Initialize directly if |vda_loop_proxy_| is the renderer thread. | 85 DCHECK_EQ(vda_loop_proxy.get(), factories->GetMessageLoop().get()); |
86 base::WaitableEvent compositor_loop_async_waiter(false, false); | 86 base::WaitableEvent message_loop_async_waiter(false, false); |
87 if (vda_loop_proxy_->BelongsToCurrentThread()) { | 87 // Waiting here is safe. The media thread is stopped in the child thread and |
88 Initialize(&compositor_loop_async_waiter); | 88 // the child thread is blocked when VideoDecoderFactory::CreateVideoDecoder |
89 return; | 89 // runs. |
90 } | |
91 // Post the task if |vda_loop_proxy_| is the compositor thread. Waiting here | |
92 // is safe because the compositor thread will not be stopped until the | |
93 // renderer thread shuts down. | |
94 vda_loop_proxy_->PostTask(FROM_HERE, | 90 vda_loop_proxy_->PostTask(FROM_HERE, |
95 base::Bind(&RTCVideoDecoder::Initialize, | 91 base::Bind(&RTCVideoDecoder::Initialize, |
96 base::Unretained(this), | 92 base::Unretained(this), |
97 &compositor_loop_async_waiter)); | 93 &message_loop_async_waiter)); |
98 compositor_loop_async_waiter.Wait(); | 94 message_loop_async_waiter.Wait(); |
99 } | 95 } |
100 | 96 |
101 RTCVideoDecoder::~RTCVideoDecoder() { | 97 RTCVideoDecoder::~RTCVideoDecoder() { |
102 DVLOG(2) << "~RTCVideoDecoder"; | 98 DVLOG(2) << "~RTCVideoDecoder"; |
103 factories_->Abort(); | 99 // Remove |this| from the observer if vda thread is alive. |
104 create_shm_thread_.Stop(); | 100 if (vda_loop_proxy_->BelongsToCurrentThread()) |
105 // Delete vda and remove |this| from the observer if vda thread is alive. | |
106 if (vda_loop_proxy_->BelongsToCurrentThread()) { | |
107 base::MessageLoop::current()->RemoveDestructionObserver(this); | 101 base::MessageLoop::current()->RemoveDestructionObserver(this); |
108 DestroyVDA(); | 102 // VDA should have been destroyed. |
109 } else { | 103 DCHECK(!vda_); |
110 // VDA should have been destroyed in WillDestroyCurrentMessageLoop. | |
111 DCHECK(!vda_); | |
112 } | |
113 | 104 |
114 // Delete all shared memories. | 105 // Delete all shared memories. |
115 STLDeleteElements(&available_shm_segments_); | 106 STLDeleteElements(&available_shm_segments_); |
116 STLDeleteValues(&bitstream_buffers_in_decoder_); | 107 STLDeleteValues(&bitstream_buffers_in_decoder_); |
117 STLDeleteContainerPairFirstPointers(decode_buffers_.begin(), | 108 STLDeleteContainerPairFirstPointers(decode_buffers_.begin(), |
118 decode_buffers_.end()); | 109 decode_buffers_.end()); |
119 decode_buffers_.clear(); | 110 decode_buffers_.clear(); |
120 | 111 |
121 // Delete WebRTC input buffers. | 112 // Delete WebRTC input buffers. |
122 for (std::deque<std::pair<webrtc::EncodedImage, BufferData> >::iterator it = | 113 for (std::deque<std::pair<webrtc::EncodedImage, BufferData> >::iterator it = |
123 pending_buffers_.begin(); | 114 pending_buffers_.begin(); |
124 it != pending_buffers_.end(); | 115 it != pending_buffers_.end(); |
125 ++it) { | 116 ++it) { |
126 delete[] it->first._buffer; | 117 delete[] it->first._buffer; |
127 } | 118 } |
128 } | 119 } |
129 | 120 |
130 scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( | 121 scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( |
| 122 webrtc::VideoCodecType type, |
| 123 const scoped_refptr<base::MessageLoopProxy> vda_loop_proxy, |
131 const scoped_refptr<media::GpuVideoDecoder::Factories>& factories) { | 124 const scoped_refptr<media::GpuVideoDecoder::Factories>& factories) { |
132 scoped_ptr<RTCVideoDecoder> decoder(new RTCVideoDecoder(factories)); | 125 scoped_ptr<RTCVideoDecoder> decoder; |
133 decoder->vda_.reset(factories->CreateVideoDecodeAccelerator( | 126 // Convert WebRTC codec type to media codec profile. |
134 media::VP8PROFILE_MAIN, decoder.get())); | 127 media::VideoCodecProfile profile; |
| 128 switch (type) { |
| 129 case webrtc::kVideoCodecVP8: |
| 130 profile = media::VP8PROFILE_MAIN; |
| 131 break; |
| 132 default: |
| 133 DVLOG(2) << "Video codec not supported:" << type; |
| 134 return decoder.Pass(); |
| 135 } |
| 136 |
| 137 decoder.reset(new RTCVideoDecoder(vda_loop_proxy, factories)); |
| 138 decoder->vda_ |
| 139 .reset(factories->CreateVideoDecodeAccelerator(profile, decoder.get())); |
135 // vda can be NULL if VP8 is not supported. | 140 // vda can be NULL if VP8 is not supported. |
136 if (decoder->vda_ != NULL) { | 141 if (decoder->vda_ != NULL) { |
137 decoder->state_ = INITIALIZED; | 142 decoder->state_ = INITIALIZED; |
138 } else { | 143 } else { |
139 factories->GetMessageLoop()->DeleteSoon(FROM_HERE, decoder.release()); | 144 vda_loop_proxy->DeleteSoon(FROM_HERE, decoder.release()); |
140 } | 145 } |
141 return decoder.Pass(); | 146 return decoder.Pass(); |
142 } | 147 } |
143 | 148 |
144 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, | 149 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, |
145 int32_t /*numberOfCores*/) { | 150 int32_t /*numberOfCores*/) { |
146 DVLOG(2) << "InitDecode"; | 151 DVLOG(2) << "InitDecode"; |
147 DCHECK_EQ(codecSettings->codecType, webrtc::kVideoCodecVP8); | 152 DCHECK_EQ(codecSettings->codecType, webrtc::kVideoCodecVP8); |
148 if (codecSettings->codecSpecific.VP8.feedbackModeOn) { | 153 if (codecSettings->codecSpecific.VP8.feedbackModeOn) { |
149 LOG(ERROR) << "Feedback mode not supported"; | 154 LOG(ERROR) << "Feedback mode not supported"; |
150 return WEBRTC_VIDEO_CODEC_ERROR; | 155 return WEBRTC_VIDEO_CODEC_ERROR; |
151 } | 156 } |
152 | 157 |
153 base::AutoLock auto_lock(lock_); | 158 base::AutoLock auto_lock(lock_); |
154 if (state_ == UNINITIALIZED || state_ == DECODE_ERROR) { | 159 if (state_ == UNINITIALIZED || state_ == DECODE_ERROR) { |
155 LOG(ERROR) << "VDA is not initialized. state=" << state_; | 160 LOG(ERROR) << "VDA is not initialized. state=" << state_; |
156 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 161 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
157 } | 162 } |
158 // Create some shared memory if the queue is empty. | 163 // Create some shared memory if the queue is empty. |
159 if (available_shm_segments_.size() == 0) { | 164 if (available_shm_segments_.size() == 0) { |
160 // Unretained is safe because the destructor will wait until | 165 vda_loop_proxy_->PostTask(FROM_HERE, |
161 // |create_shm_thread_| stops. | 166 base::Bind(&RTCVideoDecoder::CreateSHM, |
162 create_shm_thread_.message_loop_proxy() | 167 weak_this_, |
163 ->PostTask(FROM_HERE, | 168 kMaxInFlightDecodes, |
164 base::Bind(&RTCVideoDecoder::CreateSHM, | 169 kSharedMemorySegmentBytes)); |
165 base::Unretained(this), | |
166 kMaxInFlightDecodes, | |
167 kSharedMemorySegmentBytes)); | |
168 } | 170 } |
169 return WEBRTC_VIDEO_CODEC_OK; | 171 return WEBRTC_VIDEO_CODEC_OK; |
170 } | 172 } |
171 | 173 |
172 int32_t RTCVideoDecoder::Decode( | 174 int32_t RTCVideoDecoder::Decode( |
173 const webrtc::EncodedImage& inputImage, | 175 const webrtc::EncodedImage& inputImage, |
174 bool missingFrames, | 176 bool missingFrames, |
175 const webrtc::RTPFragmentationHeader* /*fragmentation*/, | 177 const webrtc::RTPFragmentationHeader* /*fragmentation*/, |
176 const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/, | 178 const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/, |
177 int64_t /*renderTimeMs*/) { | 179 int64_t /*renderTimeMs*/) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback( | 226 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback( |
225 webrtc::DecodedImageCallback* callback) { | 227 webrtc::DecodedImageCallback* callback) { |
226 DVLOG(2) << "RegisterDecodeCompleteCallback"; | 228 DVLOG(2) << "RegisterDecodeCompleteCallback"; |
227 base::AutoLock auto_lock(lock_); | 229 base::AutoLock auto_lock(lock_); |
228 decode_complete_callback_ = callback; | 230 decode_complete_callback_ = callback; |
229 return WEBRTC_VIDEO_CODEC_OK; | 231 return WEBRTC_VIDEO_CODEC_OK; |
230 } | 232 } |
231 | 233 |
232 int32_t RTCVideoDecoder::Release() { | 234 int32_t RTCVideoDecoder::Release() { |
233 DVLOG(2) << "Release"; | 235 DVLOG(2) << "Release"; |
234 // Do not destroy VDA because the decoder will be recycled by | 236 base::AutoLock auto_lock(lock_); |
235 // RTCVideoDecoderFactory. Just reset VDA. | 237 if (state_ == UNINITIALIZED) { |
236 return Reset(); | 238 LOG(ERROR) << "Decoder not initialized."; |
| 239 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 240 } |
| 241 if (next_bitstream_buffer_id_ != 0) |
| 242 reset_bitstream_buffer_id_ = next_bitstream_buffer_id_ - 1; |
| 243 else |
| 244 reset_bitstream_buffer_id_ = ID_LAST; |
| 245 factories_->Abort(); |
| 246 vda_loop_proxy_->PostTask( |
| 247 FROM_HERE, base::Bind(&RTCVideoDecoder::ReleaseInternal, weak_this_)); |
| 248 return WEBRTC_VIDEO_CODEC_OK; |
237 } | 249 } |
238 | 250 |
239 int32_t RTCVideoDecoder::Reset() { | 251 int32_t RTCVideoDecoder::Reset() { |
240 DVLOG(2) << "Reset"; | 252 DVLOG(2) << "Reset"; |
241 base::AutoLock auto_lock(lock_); | 253 base::AutoLock auto_lock(lock_); |
242 if (state_ == UNINITIALIZED) { | 254 if (state_ == UNINITIALIZED) { |
243 LOG(ERROR) << "Decoder not initialized."; | 255 LOG(ERROR) << "Decoder not initialized."; |
244 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 256 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
245 } | 257 } |
246 if (next_bitstream_buffer_id_ != 0) | 258 if (next_bitstream_buffer_id_ != 0) |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
587 } | 599 } |
588 } | 600 } |
589 | 601 |
590 void RTCVideoDecoder::ResetInternal() { | 602 void RTCVideoDecoder::ResetInternal() { |
591 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 603 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); |
592 DVLOG(2) << "ResetInternal"; | 604 DVLOG(2) << "ResetInternal"; |
593 if (vda_) | 605 if (vda_) |
594 vda_->Reset(); | 606 vda_->Reset(); |
595 } | 607 } |
596 | 608 |
| 609 void RTCVideoDecoder::ReleaseInternal() { |
| 610 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); |
| 611 DVLOG(2) << "ReleaseInternal"; |
| 612 DestroyVDA(); |
| 613 } |
| 614 |
597 void RTCVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id, | 615 void RTCVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id, |
598 uint32 sync_point) { | 616 uint32 sync_point) { |
599 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 617 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); |
600 DVLOG(3) << "ReusePictureBuffer. id=" << picture_buffer_id; | 618 DVLOG(3) << "ReusePictureBuffer. id=" << picture_buffer_id; |
601 | 619 |
602 if (!vda_) | 620 if (!vda_) |
603 return; | 621 return; |
604 | 622 |
605 CHECK(!picture_buffers_at_display_.empty()); | 623 CHECK(!picture_buffers_at_display_.empty()); |
606 | 624 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 | 671 |
654 scoped_ptr<RTCVideoDecoder::SHMBuffer> RTCVideoDecoder::GetSHM_Locked( | 672 scoped_ptr<RTCVideoDecoder::SHMBuffer> RTCVideoDecoder::GetSHM_Locked( |
655 size_t min_size) { | 673 size_t min_size) { |
656 // Reuse a SHM if possible. | 674 // Reuse a SHM if possible. |
657 SHMBuffer* ret = NULL; | 675 SHMBuffer* ret = NULL; |
658 if (!available_shm_segments_.empty() && | 676 if (!available_shm_segments_.empty() && |
659 available_shm_segments_.back()->size >= min_size) { | 677 available_shm_segments_.back()->size >= min_size) { |
660 ret = available_shm_segments_.back(); | 678 ret = available_shm_segments_.back(); |
661 available_shm_segments_.pop_back(); | 679 available_shm_segments_.pop_back(); |
662 } | 680 } |
663 // Post to the child thread to create shared memory if SHM cannot be reused | 681 // Post to vda thread to create shared memory if SHM cannot be reused or the |
664 // or the queue is almost empty. | 682 // queue is almost empty. |
665 if (num_shm_buffers_ < kMaxNumSharedMemorySegments && | 683 if (num_shm_buffers_ < kMaxNumSharedMemorySegments && |
666 (ret == NULL || available_shm_segments_.size() <= 1)) { | 684 (ret == NULL || available_shm_segments_.size() <= 1)) { |
667 create_shm_thread_.message_loop_proxy()->PostTask( | 685 vda_loop_proxy_->PostTask( |
668 FROM_HERE, | 686 FROM_HERE, |
669 // Unretained is safe because the destructor will wait until | 687 base::Bind(&RTCVideoDecoder::CreateSHM, weak_this_, 1, min_size)); |
670 // |create_shm_thread_| stops. | |
671 base::Bind( | |
672 &RTCVideoDecoder::CreateSHM, base::Unretained(this), 1, min_size)); | |
673 } | 688 } |
674 return scoped_ptr<SHMBuffer>(ret); | 689 return scoped_ptr<SHMBuffer>(ret); |
675 } | 690 } |
676 | 691 |
677 void RTCVideoDecoder::PutSHM_Locked(scoped_ptr<SHMBuffer> shm_buffer) { | 692 void RTCVideoDecoder::PutSHM_Locked(scoped_ptr<SHMBuffer> shm_buffer) { |
678 available_shm_segments_.push_back(shm_buffer.release()); | 693 available_shm_segments_.push_back(shm_buffer.release()); |
679 } | 694 } |
680 | 695 |
681 void RTCVideoDecoder::CreateSHM(int number, size_t min_size) { | 696 void RTCVideoDecoder::CreateSHM(int number, size_t min_size) { |
682 DCHECK(create_shm_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 697 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); |
683 DVLOG(2) << "CreateSHM. size=" << min_size; | 698 DVLOG(2) << "CreateSHM. size=" << min_size; |
684 int number_to_allocate; | 699 int number_to_allocate; |
685 { | 700 { |
686 base::AutoLock auto_lock(lock_); | 701 base::AutoLock auto_lock(lock_); |
687 number_to_allocate = | 702 number_to_allocate = |
688 std::min(kMaxNumSharedMemorySegments - num_shm_buffers_, number); | 703 std::min(kMaxNumSharedMemorySegments - num_shm_buffers_, number); |
689 } | 704 } |
690 size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); | 705 size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); |
691 for (int i = 0; i < number_to_allocate; i++) { | 706 for (int i = 0; i < number_to_allocate; i++) { |
692 base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); | 707 base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); |
693 if (shm != NULL) { | 708 if (shm != NULL) { |
694 base::AutoLock auto_lock(lock_); | 709 base::AutoLock auto_lock(lock_); |
695 num_shm_buffers_++; | 710 num_shm_buffers_++; |
696 PutSHM_Locked( | 711 PutSHM_Locked( |
697 scoped_ptr<SHMBuffer>(new SHMBuffer(shm, size_to_allocate))); | 712 scoped_ptr<SHMBuffer>(new SHMBuffer(shm, size_to_allocate))); |
698 // Kick off the decoding. | |
699 vda_loop_proxy_->PostTask( | |
700 FROM_HERE, | |
701 base::Bind(&RTCVideoDecoder::RequestBufferDecode, weak_this_)); | |
702 } | 713 } |
703 } | 714 } |
| 715 // Kick off the decoding. |
| 716 RequestBufferDecode(); |
704 } | 717 } |
705 | 718 |
706 void RTCVideoDecoder::RecordBufferData(const BufferData& buffer_data) { | 719 void RTCVideoDecoder::RecordBufferData(const BufferData& buffer_data) { |
707 input_buffer_data_.push_front(buffer_data); | 720 input_buffer_data_.push_front(buffer_data); |
708 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but | 721 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but |
709 // that's too small for some pathological B-frame test videos. The cost of | 722 // that's too small for some pathological B-frame test videos. The cost of |
710 // using too-high a value is low (192 bits per extra slot). | 723 // using too-high a value is low (192 bits per extra slot). |
711 static const size_t kMaxInputBufferDataSize = 128; | 724 static const size_t kMaxInputBufferDataSize = 128; |
712 // Pop from the back of the list, because that's the oldest and least likely | 725 // Pop from the back of the list, because that's the oldest and least likely |
713 // to be useful in the future data. | 726 // to be useful in the future data. |
(...skipping 13 matching lines...) Expand all Loading... |
727 continue; | 740 continue; |
728 *timestamp = it->timestamp; | 741 *timestamp = it->timestamp; |
729 *width = it->width; | 742 *width = it->width; |
730 *height = it->height; | 743 *height = it->height; |
731 return; | 744 return; |
732 } | 745 } |
733 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; | 746 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; |
734 } | 747 } |
735 | 748 |
736 } // namespace content | 749 } // namespace content |
OLD | NEW |