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