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