Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(395)

Side by Side Diff: content/renderer/media/rtc_video_decoder.cc

Issue 19534002: Make RendererGpuVideoDecoderFactories live on arbitrary threads. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/renderer/media/rtc_video_decoder.h ('k') | content/renderer/media/rtc_video_decoder_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698