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

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: Add comments and 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
22 namespace content {
23
24 class RTCDemuxerStream
25 : public media::DemuxerStream,
26 public base::SupportsWeakPtr<RTCDemuxerStream> {
27 public:
28 RTCDemuxerStream(const scoped_refptr<base::MessageLoopProxy>& message_loop);
29 // media::DemuxerStream implementation.
30 virtual void Read(const ReadCB& read_cb) OVERRIDE;
31 virtual const media::AudioDecoderConfig& audio_decoder_config() OVERRIDE;
32 virtual const media::VideoDecoderConfig& video_decoder_config() OVERRIDE;
33 virtual Type type() OVERRIDE;
34 virtual void EnableBitstreamConverter() OVERRIDE;
35
36 void UpdateSize(gfx::Size size);
37 void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer);
38 void ClearBuffer();
39
40 private:
41 media::DecoderBufferQueue buffer_queue_;
42 ReadCB read_cb_;
43 // Make sure all the methods are called by the same thread.
44 scoped_refptr<base::MessageLoopProxy> message_loop_;
45 media::VideoDecoderConfig video_decoder_config_;
46 };
47
48 RTCDemuxerStream::RTCDemuxerStream(
49 const scoped_refptr<base::MessageLoopProxy>& message_loop)
50 : message_loop_(message_loop) {
51 }
52
53 void RTCDemuxerStream::Read(const ReadCB& read_cb) {
54 DCHECK(message_loop_->BelongsToCurrentThread());
55 CHECK(read_cb_.is_null());
56 read_cb_ = read_cb;
57
58 if(!buffer_queue_.IsEmpty()) {
59 base::ResetAndReturn(&read_cb_).Run(
60 DemuxerStream::kOk, buffer_queue_.Pop());
61 }
62 }
63
64 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() {
65 LOG(FATAL) << "Audio is not supported.";
66 return *(new media::AudioDecoderConfig);
67 }
68
69 const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() {
70 DCHECK(message_loop_->BelongsToCurrentThread());
71 return video_decoder_config_;
72 }
73
74 media::DemuxerStream::Type RTCDemuxerStream::type() {
75 return media::DemuxerStream::VIDEO;
76 }
77
78 void RTCDemuxerStream::EnableBitstreamConverter() {
79 NOTREACHED();
80 }
81
82 void RTCDemuxerStream::UpdateSize(gfx::Size size) {
83 DCHECK(message_loop_->BelongsToCurrentThread());
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 weak_factory_(this),
121 decoding_error_occurred_(false) {
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() {
129 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
130 weak_this_ = weak_factory_.GetWeakPtr();
131 weak_stream_ = stream_->AsWeakPtr();
132 decoder_waiter_.Signal();
133 }
134
135 RTCVideoDecoder::~RTCVideoDecoder() {
136 }
137
138 // Called by WebRTC DecodingThread
139 int32_t RTCVideoDecoder::InitDecode(
140 const webrtc::VideoCodec* codecSettings,
141 int32_t /*numberOfCores*/) {
142 DVLOG(3) << "InitDecode";
143 if (state_ != kUninitialized) {
144 LOG(ERROR) << "state_ != kUninitialized!";
145 return WEBRTC_VIDEO_CODEC_ERROR;
146 }
147 if (codecSettings->codecType != webrtc::kVideoCodecVP8) {
148 LOG(ERROR) << "codec != VP8!";
149 return WEBRTC_VIDEO_CODEC_ERROR;
150 }
151 if (codecSettings->codecSpecific.VP8.feedbackModeOn) {
152 LOG(ERROR) << "Feedback mode not supported";
153 return WEBRTC_VIDEO_CODEC_ERROR;
154 }
155
156 decoder_message_loop_->PostTask(
157 FROM_HERE,
158 base::Bind(&RTCDemuxerStream::UpdateSize, weak_stream_,
159 gfx::Size(codecSettings->width, codecSettings->height)));
160 decoder_message_loop_->PostTask(
161 FROM_HERE,
162 base::Bind(&media::VideoDecoder::Initialize,
163 base::Unretained(video_decoder_.get()),
164 base::Unretained(stream_.get()),
165 base::Bind(&RTCVideoDecoder::OnUpdatePipelineStatus,
166 weak_this_),
167 base::Bind(&RTCVideoDecoder::OnUpdateStatistics, weak_this_)));
168 decoder_waiter_.Wait();
169 if (pipeline_status_ != media::PIPELINE_OK) {
170 LOG(ERROR) << "Initialize failed. pipeline_status_=" << pipeline_status_;
171 return WEBRTC_VIDEO_CODEC_ERROR;
172 }
173 state_ = kInitialized;
174 DVLOG(3) << "InitDecode end";
175 return WEBRTC_VIDEO_CODEC_OK;
176 }
177
178 // Called by WebRTC DecodingThread
179 int32_t RTCVideoDecoder::Decode(
180 const webrtc::EncodedImage& inputImage,
181 bool missingFrames,
182 const webrtc::RTPFragmentationHeader* /*fragmentation*/,
183 const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/,
184 int64_t /*renderTimeMs*/) {
185 DVLOG(3) << "Decode";
186
187 if (decoding_error_occurred_) {
188 LOG(ERROR) << "Decoding error occurred.";
189 return WEBRTC_VIDEO_CODEC_ERROR;
190 }
191 if (state_ == kUninitialized || decode_complete_callback_ == NULL) {
192 LOG(ERROR) << "WebRTC video codec unintialized.";
193 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
194 }
195 if (missingFrames || !inputImage._completeFrame) {
196 LOG(ERROR) << "Missing frames or not completed frames.";
197 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames.
198 // Return an error to request a key frame.
199 return WEBRTC_VIDEO_CODEC_ERROR;
200 }
201
202 if (inputImage._frameType == webrtc::kKeyFrame &&
203 inputImage._encodedWidth != 0 && inputImage._encodedHeight != 0) {
204 // Only key frame has the size.
205 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight);
206 if (size_ != new_size) {
207 size_ = new_size;
208 decoder_message_loop_->PostTask(
209 FROM_HERE,
210 base::Bind(&RTCDemuxerStream::UpdateSize, weak_stream_, new_size));
211 }
212 }
213 scoped_refptr<media::DecoderBuffer> buffer = media::DecoderBuffer::CopyFrom(
wuchengli 2013/05/10 15:57:15 Copy is necessary because the buffer will be relea
214 inputImage._buffer, inputImage._length);
215 buffer->SetTimestamp(base::TimeDelta::FromInternalValue(
216 inputImage._timeStamp));
217
218 decoder_message_loop_->PostTask(
219 FROM_HERE,
220 base::Bind(&RTCDemuxerStream::QueueBuffer, weak_stream_, buffer));
221
222 if (state_ == kInitialized) {
223 state_ = kDecoding;
224 decoder_message_loop_->PostTask(
225 FROM_HERE,
226 base::Bind(&RTCVideoDecoder::RequestFrame, weak_this_));
227 }
228
229 return WEBRTC_VIDEO_CODEC_OK;
230 }
231
232 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback(
233 webrtc::DecodedImageCallback* callback) {
234 decode_complete_callback_ = callback;
235 return WEBRTC_VIDEO_CODEC_OK;
236 }
237
238 int32_t RTCVideoDecoder::Release() {
239 DVLOG(3) << "Release";
240 if (state_ == kUninitialized) {
241 LOG(ERROR) << "Decoder not initialized.";
242 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
243 }
244 decoder_message_loop_->PostTask(
245 FROM_HERE,
246 base::Bind(&media::VideoDecoder::Stop,
247 base::Unretained(video_decoder_.get()),
248 base::Bind(&RTCVideoDecoder::ReleaseComplete, weak_this_)));
249 decoder_waiter_.Wait();
250 state_ = kUninitialized;
251 return WEBRTC_VIDEO_CODEC_OK;
252 }
253
254 int32_t RTCVideoDecoder::Reset() {
255 DVLOG(3) << "Reset";
256 if (state_ == kUninitialized) {
257 LOG(ERROR) << "Decoder not initialized.";
258 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
259 }
260 decoder_message_loop_->PostTask(
261 FROM_HERE,
262 base::Bind(&media::VideoDecoder::Reset,
263 base::Unretained(video_decoder_.get()),
264 base::Bind(&RTCVideoDecoder::ResetComplete, weak_this_)));
265 decoder_waiter_.Wait();
266 state_ = kInitialized;
267 DVLOG(3) << "Reset end";
268 return WEBRTC_VIDEO_CODEC_OK;
269 }
270
271 void RTCVideoDecoder::OnUpdateStatistics(
272 const media::PipelineStatistics& /*stats*/) {
273 // We don't use statistics for now.
274 }
275
276 void RTCVideoDecoder::OnUpdatePipelineStatus(
277 const media::PipelineStatus status) {
278 DVLOG(3) << "OnUpdatePipelineStatus. status=" << status;
279 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
280 pipeline_status_ = status;
281 decoder_waiter_.Signal();
282 }
283
284 void RTCVideoDecoder::ReleaseComplete() {
285 DVLOG(3) << "ReleaseComplete";
286 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
287 stream_->ClearBuffer();
288 decoder_waiter_.Signal();
289 }
290
291 void RTCVideoDecoder::ResetComplete() {
292 DVLOG(3) << "ResetComplete";
293 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
294 stream_->ClearBuffer();
295 decoder_waiter_.Signal();
296 }
297
298 void RTCVideoDecoder::FrameReady(
299 media::VideoDecoder::Status status,
300 const scoped_refptr<media::VideoFrame>& frame) {
301 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
302 DVLOG(3) << "FrameReady. status=" << status;
303
304 if (status != media::VideoDecoder::kOk) {
305 LOG(ERROR) << "FrameReady error. status=" << status;
306 decoding_error_occurred_ = true;
307 return;
308 }
309 gfx::Rect rect = frame->visible_rect();
310
311 webrtc::I420VideoFrame decoded_image;
312 decoded_image.CreateEmptyFrame(
313 rect.width(), rect.height(),
314 rect.width(), rect.width() / 2, rect.width() / 2);
315 webrtc::RefCountImpl<NativeHandleImpl>* handle =
316 new webrtc::RefCountImpl<NativeHandleImpl>();
317 handle->SetHandle(frame.get());
318 decoded_image.set_native_handle(handle);
319 decoded_image.set_timestamp(
320 static_cast<uint32_t>(frame->GetTimestamp().InMicroseconds()));
321 decode_complete_callback_->Decoded(decoded_image);
322
323 if (state_ == kDecoding) {
324 video_decoder_->Read(base::Bind(&RTCVideoDecoder::FrameReady, weak_this_));
325 }
326 }
327
328 void RTCVideoDecoder::RequestFrame() {
329 DCHECK(decoder_message_loop_->BelongsToCurrentThread());
330 video_decoder_->Read(
331 base::Bind(&RTCVideoDecoder::FrameReady, weak_this_));
332 }
333
334 } // namespace content
335
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