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

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

Powered by Google App Engine
This is Rietveld 408576698