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

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

Issue 13890012: Integrate VDA with WebRTC. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address some review comments Created 7 years, 7 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
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/media/rtc_video_decoder.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/message_loop_proxy.h"
12 #include "content/renderer/media/native_handle_impl.h"
13 #include "media/base/audio_decoder_config.h"
14 #include "media/base/bind_to_loop.h"
15 #include "media/base/decoder_buffer.h"
16 #include "media/base/decoder_buffer_queue.h"
17 #include "media/base/demuxer_stream.h"
18 #include "media/base/video_decoder_config.h"
19 #include "third_party/webrtc/system_wrappers/interface/ref_count.h"
20
21 namespace content {
22
23 class RTCDemuxerStream
24 : public media::DemuxerStream,
25 public base::SupportsWeakPtr<RTCDemuxerStream> {
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Exposing SupportsWeakPtr is a code smell. In this
wuchengli 2013/05/15 15:30:46 Removed SupportsWeakPtr. I added new methods in RT
26 public:
27 RTCDemuxerStream(const scoped_refptr<base::MessageLoopProxy>& message_loop);
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Missing (virtual) dtor. The dtor should maybe disp
28 // media::DemuxerStream implementation.
29 virtual void Read(const ReadCB& read_cb) OVERRIDE;
30 virtual const media::AudioDecoderConfig& audio_decoder_config() OVERRIDE;
31 virtual const media::VideoDecoderConfig& video_decoder_config() OVERRIDE;
32 virtual Type type() OVERRIDE;
33 virtual void EnableBitstreamConverter() OVERRIDE;
34
35 void UpdateSize(gfx::Size size);
36 void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer);
Pawel Osciak 2013/05/15 17:26:32 Documentation?
37 void ClearBuffer();
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Pluralize?
wuchengli 2013/05/15 15:30:46 Done.
38
39 private:
40 media::DecoderBufferQueue buffer_queue_;
41 ReadCB read_cb_;
42 // Make sure all the methods are called by the same thread.
43 scoped_refptr<base::MessageLoopProxy> message_loop_;
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Since this is all you use it for, you should drop
44 media::VideoDecoderConfig video_decoder_config_;
45 };
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 DISALLOW_COPY_AND_ASSIGN?
wuchengli 2013/05/15 15:30:46 Done.
46
47 RTCDemuxerStream::RTCDemuxerStream(
48 const scoped_refptr<base::MessageLoopProxy>& message_loop)
49 : message_loop_(message_loop) {
50 }
51
52 void RTCDemuxerStream::Read(const ReadCB& read_cb) {
53 DCHECK(message_loop_->BelongsToCurrentThread());
54 CHECK(read_cb_.is_null());
55 read_cb_ = read_cb;
56
57 if(!buffer_queue_.IsEmpty()) {
58 base::ResetAndReturn(&read_cb_).Run(
59 DemuxerStream::kOk, buffer_queue_.Pop());
60 }
61 }
62
63 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() {
64 LOG(FATAL) << "Audio is not supported.";
65 return *(new media::AudioDecoderConfig);
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 return media::AudioDecoderConfig(); doesn't work?
wuchengli 2013/05/15 15:30:46 Right. The compile error is "error: returning refe
Pawel Osciak 2013/05/15 17:26:32 Isn't this a leak? Isn't this class supposed to ma
wuchengli 2013/05/16 16:05:45 LOG(FATAL) will cause the program to terminate. Th
66 }
67
68 const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() {
69 DCHECK(message_loop_->BelongsToCurrentThread());
70 return video_decoder_config_;
71 }
72
73 media::DemuxerStream::Type RTCDemuxerStream::type() {
74 return media::DemuxerStream::VIDEO;
75 }
76
77 void RTCDemuxerStream::EnableBitstreamConverter() {
78 NOTREACHED();
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Why NOTREACHED here but LOG(FATAL) at l.64?
wuchengli 2013/05/15 15:30:46 Agree. I changed NOTREACHED to LOG(FATAL). I just
79 }
80
81 void RTCDemuxerStream::UpdateSize(gfx::Size size) {
82 DCHECK(message_loop_->BelongsToCurrentThread());
Pawel Osciak 2013/05/15 17:26:32 Did size update work for you with VDAs if posted f
wuchengli 2013/05/16 16:05:45 UpdateSize is posted from Decode() now. You mean i
83 DVLOG(2) << "Update config size to " << size.width() << "," << size.height();
84 gfx::Rect rect(size);
85 video_decoder_config_.Initialize(
86 media::kCodecVP8,
87 media::VP8PROFILE_MAIN,
88 media::VideoFrame::NATIVE_TEXTURE,
89 size, rect, size, NULL, 0, false, false);
90 }
91
92 void RTCDemuxerStream::QueueBuffer(
93 scoped_refptr<media::DecoderBuffer> buffer) {
94 DCHECK(message_loop_->BelongsToCurrentThread());
95 DVLOG(3) << "QueueBuffer";
96 buffer_queue_.Push(buffer);
97
98 if (!read_cb_.is_null()) {
99 base::ResetAndReturn(&read_cb_).Run(
100 DemuxerStream::kOk, buffer_queue_.Pop());
101 }
102 DVLOG(3) << "QueueBuffer end";
103 }
104
105 void RTCDemuxerStream::ClearBuffer() {
106 DCHECK(message_loop_->BelongsToCurrentThread());
107 buffer_queue_.Clear();
108 }
109
110 RTCVideoDecoder::RTCVideoDecoder(
111 media::VideoDecoder* video_decoder,
112 const scoped_refptr<base::MessageLoopProxy>& message_loop)
113 : video_decoder_(video_decoder),
114 decoder_message_loop_(message_loop),
115 decode_complete_callback_(NULL),
116 pipeline_status_(media::PIPELINE_OK),
117 decoder_waiter_(false, false),
118 stream_(new RTCDemuxerStream(message_loop)),
119 state_(kUninitialized),
120 decoding_error_occurred_(false),
121 weak_factory_(this) {
122 decoder_message_loop_->PostTask(
123 FROM_HERE,
124 base::Bind(&RTCVideoDecoder::InitWeakPtr, base::Unretained(this)));
125 decoder_waiter_.Wait();
126 }
127
128 void RTCVideoDecoder::InitWeakPtr() {
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 s/Ptr/Ptrs/
wuchengli 2013/05/15 15:30:46 Done.
129 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
130 weak_this_ = weak_factory_.GetWeakPtr();
131 weak_stream_ = stream_->AsWeakPtr();
132 decoder_waiter_.Signal();
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 What happens if the decoder thread is stopped befo
133 }
134
135 RTCVideoDecoder::~RTCVideoDecoder() {
136 }
137
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 You should DCHECK(decoder_message_loop_->BelongsT
wuchengli 2013/05/15 15:30:46 Done. Great suggestion.
138 int32_t RTCVideoDecoder::InitDecode(
139 const webrtc::VideoCodec* codecSettings,
140 int32_t /*numberOfCores*/) {
141 DVLOG(2) << "InitDecode";
142 {
143 base::AutoLock auto_lock(lock_);
144 if (state_ != kUninitialized) {
145 LOG(ERROR) << "state_ != kUninitialized!";
146 return WEBRTC_VIDEO_CODEC_ERROR;
147 }
148 }
149 DCHECK(codecSettings->codecType == webrtc::kVideoCodecVP8);
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 DCHECK_EQ
wuchengli 2013/05/15 15:30:46 Done.
150 if (codecSettings->codecSpecific.VP8.feedbackModeOn) {
151 LOG(ERROR) << "Feedback mode not supported";
152 return WEBRTC_VIDEO_CODEC_ERROR;
153 }
154
155 frame_size_.SetSize(codecSettings->width, codecSettings->height);
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Didn't the internal thread result in saying these
Pawel Osciak 2013/05/15 17:26:32 How does frame_size_ relate to visible size? Do we
wuchengli 2013/05/16 16:05:45 @Ami: UpdateSize is needed here because GpuVideoDe
156 decoder_message_loop_->PostTask(
157 FROM_HERE,
158 base::Bind(&RTCDemuxerStream::UpdateSize, weak_stream_, frame_size_));
159 decoder_message_loop_->PostTask(
160 FROM_HERE,
161 base::Bind(&media::VideoDecoder::Initialize,
162 base::Unretained(video_decoder_.get()),
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Why is this (and the next) Unretained safe?
wuchengli 2013/05/16 16:05:45 Unretained is safe because the WaitableEvent next
163 base::Unretained(stream_.get()),
164 base::Bind(&RTCVideoDecoder::OnUpdatePipelineStatus,
165 weak_this_),
166 base::Bind(&RTCVideoDecoder::OnUpdateStatistics, weak_this_)));
167 decoder_waiter_.Wait();
168 if (pipeline_status_ != media::PIPELINE_OK) {
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Shouldn't this be protected by lock_?
169 LOG(ERROR) << "Initialize failed. pipeline_status_=" << pipeline_status_;
170 return WEBRTC_VIDEO_CODEC_ERROR;
171 }
172 return WEBRTC_VIDEO_CODEC_OK;
173 }
174
175 int32_t RTCVideoDecoder::Decode(
176 const webrtc::EncodedImage& inputImage,
177 bool missingFrames,
178 const webrtc::RTPFragmentationHeader* /*fragmentation*/,
179 const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/,
180 int64_t /*renderTimeMs*/) {
181 DVLOG(3) << "Decode";
182
183 {
184 base::AutoLock auto_lock(lock_);
185 if (decoding_error_occurred_) {
186 LOG(ERROR) << "Decoding error occurred.";
187 return WEBRTC_VIDEO_CODEC_ERROR;
188 }
189 if (state_ == kUninitialized || decode_complete_callback_ == NULL) {
Pawel Osciak 2013/05/15 17:26:32 As Ami suggested, it'd probably be enough to combi
wuchengli 2013/05/23 16:50:47 I changed decoding_error_occurred_ to state_==kDec
190 LOG(ERROR) << "WebRTC video codec unintialized.";
191 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
192 }
193 }
194 if (missingFrames || !inputImage._completeFrame) {
195 LOG(ERROR) << "Missing frames or not completed frames.";
Pawel Osciak 2013/05/15 17:26:32 This is not a fatal error, iiuc we might be runnin
wuchengli 2013/05/23 16:50:47 Good point. Changed to DLOG.
196 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames.
197 // Return an error to request a key frame.
198 return WEBRTC_VIDEO_CODEC_ERROR;
199 }
200
201 // Only key frame has the size.
202 if (inputImage._frameType == webrtc::kKeyFrame) {
203 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight);
204 if (frame_size_ != new_size) {
205 frame_size_ = new_size;
206 decoder_message_loop_->PostTask(
207 FROM_HERE,
208 base::Bind(&RTCDemuxerStream::UpdateSize, weak_stream_, new_size));
209 }
210 }
211
212 scoped_refptr<media::DecoderBuffer> buffer = media::DecoderBuffer::CopyFrom(
213 inputImage._buffer, inputImage._length);
214 // EncodedImage uses 90KHz timestamp and DecoderBuffer uses microseconds.
215 // WebRTC uses the timestamp as key of a map. But conversion may lose
216 // precision. Here we use TimeDelta as a holder to preverse the exact same
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 s/preverse/preserve/
wuchengli 2013/05/15 15:30:46 Done.
217 // value.
218 buffer->SetTimestamp(base::TimeDelta::FromInternalValue(
219 inputImage._timeStamp));
220
221 decoder_message_loop_->PostTask(
222 FROM_HERE,
223 base::Bind(&RTCDemuxerStream::QueueBuffer, weak_stream_, buffer));
224
225 return WEBRTC_VIDEO_CODEC_OK;
226 }
227
228 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback(
229 webrtc::DecodedImageCallback* callback) {
230 decode_complete_callback_ = callback;
231 return WEBRTC_VIDEO_CODEC_OK;
232 }
233
234 int32_t RTCVideoDecoder::Release() {
235 DVLOG(2) << "Release";
236 {
237 base::AutoLock auto_lock(lock_);
238 if (state_ == kUninitialized) {
239 LOG(ERROR) << "Decoder not initialized.";
240 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
241 }
242 }
243 decoder_message_loop_->PostTask(
244 FROM_HERE,
245 base::Bind(&media::VideoDecoder::Stop,
246 base::Unretained(video_decoder_.get()),
247 base::Bind(&RTCVideoDecoder::ReleaseComplete, weak_this_)));
248 decoder_waiter_.Wait();
Pawel Osciak 2013/05/15 17:26:32 Would DCHECK(state_==kUninitialized) after this be
wuchengli 2013/05/23 16:50:47 Do you think state_ may not be updated? renderer_g
249 return WEBRTC_VIDEO_CODEC_OK;
250 }
251
252 int32_t RTCVideoDecoder::Reset() {
253 DVLOG(2) << "Reset";
254 {
255 base::AutoLock auto_lock(lock_);
256 if (state_ == kUninitialized) {
257 LOG(ERROR) << "Decoder not initialized.";
258 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
259 }
260 }
261 decoder_message_loop_->PostTask(
262 FROM_HERE,
263 base::Bind(&media::VideoDecoder::Reset,
264 base::Unretained(video_decoder_.get()),
265 base::Bind(&RTCVideoDecoder::ResetComplete, weak_this_)));
266 decoder_waiter_.Wait();
267 return WEBRTC_VIDEO_CODEC_OK;
268 }
269
270 void RTCVideoDecoder::OnUpdateStatistics(
271 const media::PipelineStatistics& /*stats*/) {
272 // We don't use statistics for now.
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 TODO to do this.
wuchengli 2013/05/15 15:30:46 Done.
273 }
274
275 void RTCVideoDecoder::OnUpdatePipelineStatus(
276 const media::PipelineStatus status) {
277 DVLOG(3) << "OnUpdatePipelineStatus. status=" << status;
278 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
279
280 pipeline_status_ = status;
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 This is accessed from more than one thread so it s
wuchengli 2013/05/15 15:30:46 This is accessed from two threads. But the sequenc
281 lock_.Acquire();
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 FWIW I think you can replace l.281-289 with: bool
wuchengli 2013/05/15 15:30:46 Done. Good suggestion.
282 decoding_error_occurred_ = false;
283 if (status == media::PIPELINE_OK) {
284 state_ = kInitialized;
285 lock_.Release();
286 video_decoder_->Read(base::Bind(&RTCVideoDecoder::FrameReady, weak_this_));
287 } else {
288 lock_.Release();
289 }
290 decoder_waiter_.Signal();
291 }
292
293 void RTCVideoDecoder::ReleaseComplete() {
294 DVLOG(2) << "ReleaseComplete";
295 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
296 stream_->ClearBuffer();
297
298 base::AutoLock auto_lock(lock_);
299 state_ = kUninitialized;
300 decoding_error_occurred_ = false;
301 decoder_waiter_.Signal();
302 }
303
304 void RTCVideoDecoder::ResetComplete() {
305 DVLOG(2) << "ResetComplete";
306 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
307 stream_->ClearBuffer();
308
309 base::AutoLock auto_lock(lock_);
310 state_ = kInitialized;
311 decoding_error_occurred_ = false;
312 decoder_waiter_.Signal();
313 }
314
315 void RTCVideoDecoder::FrameReady(
316 media::VideoDecoder::Status status,
317 const scoped_refptr<media::VideoFrame>& frame) {
318 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
319 DVLOG(3) << "FrameReady. status=" << status;
320
321 if (status != media::VideoDecoder::kOk) {
322 LOG(ERROR) << "FrameReady error. status=" << status;
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 FWIW this is not necessarily an _error_ per se, ju
wuchengli 2013/05/15 15:30:46 You are right. Changed to VLOG(1).
323 base::AutoLock auto_lock(lock_);
324 decoding_error_occurred_ = true;
325 return;
326 }
327 gfx::Rect rect = frame->visible_rect();
328
329 webrtc::I420VideoFrame decoded_image;
330 decoded_image.CreateEmptyFrame(
331 rect.width(), rect.height(),
332 rect.width(), rect.width() / 2, rect.width() / 2);
333 webrtc::RefCountImpl<NativeHandleImpl>* handle =
334 new webrtc::RefCountImpl<NativeHandleImpl>();
335 handle->SetHandle(frame.get());
336 decoded_image.set_native_handle(handle);
337 // No need to convert the timestamp because we use it as a holder. See
338 // RTCVideoDecoder::Decode() for more detail.
339 decoded_image.set_timestamp(
340 static_cast<uint32_t>(frame->GetTimestamp().InMicroseconds()));
341 decode_complete_callback_->Decoded(decoded_image);
342
343 lock_.Acquire();
344 if (state_ == kInitialized) {
345 lock_.Release();
346 video_decoder_->Read(base::Bind(&RTCVideoDecoder::FrameReady, weak_this_));
347 } else {
348 lock_.Release();
349 }
Ami GONE FROM CHROMIUM 2013/05/14 22:57:24 Ditto could reformat this.
wuchengli 2013/05/15 15:30:46 Done.
350 }
351
352 } // namespace content
353
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698