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

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

Issue 14247018: Implement WebRTC in Chrome for TV (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed some 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_bridge_tv.h"
6
7 #include <queue>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/singleton.h"
15 #include "base/message_loop_proxy.h"
16 #include "base/synchronization/lock.h"
17 #include "base/time.h"
18 #include "media/base/decoder_buffer.h"
19 #include "third_party/libjingle/source/talk/base/ratetracker.h"
20
21 namespace content {
22
23 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|.
24 static void RunOnMessageLoop(
25 media::DemuxerStream::ReadCB read_cb,
26 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
27 media::DemuxerStream::Status status,
28 const scoped_refptr<media::DecoderBuffer>& buffer) {
29 if (!message_loop_proxy->BelongsToCurrentThread()) {
30 message_loop_proxy->PostTask(FROM_HERE, base::Bind(
31 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer));
32 return;
33 }
34 read_cb.Run(status, buffer);
35 }
36
37 // RTCDemuxerStream ------------------------------------------------------------
38
39 namespace {
40
41 class RTCDemuxerStream : public media::DemuxerStream {
42 public:
43 explicit RTCDemuxerStream(const gfx::Size& size);
44 virtual ~RTCDemuxerStream();
45 // media::DemuxerStream implementation.
46 virtual void Read(const ReadCB& read_cb) OVERRIDE;
47 virtual const media::AudioDecoderConfig& audio_decoder_config() OVERRIDE;
48 virtual const media::VideoDecoderConfig& video_decoder_config() OVERRIDE;
49 virtual Type type() OVERRIDE;
50 virtual void EnableBitstreamConverter() OVERRIDE;
51
52 void UpdateSize(const gfx::Size& size);
53 void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer,
54 const base::Closure& done_cb);
55
56 void RunDoneCallback();
ycheo (away) 2013/05/02 02:45:21 private?
wonsik 2013/05/02 15:22:00 Done.
57
58 private:
59 void RunReadCallback();
60
61 media::DecoderBufferQueue buffer_queue_;
62 std::queue<base::Closure> done_cb_queue_;
63 ReadCB read_cb_;
64
65 media::AudioDecoderConfig dummy_audio_decoder_config_;
66 media::VideoDecoderConfig video_decoder_config_;
67 talk_base::RateTracker frame_rate_tracker_;
68 };
69
70 RTCDemuxerStream::RTCDemuxerStream(const gfx::Size& size)
71 : video_decoder_config_(
72 media::kCodecVP8,
73 media::VP8PROFILE_MAIN,
74 media::VideoFrame::NATIVE_TEXTURE,
75 size, gfx::Rect(size), size, NULL, 0, false) {
76 }
77
78 RTCDemuxerStream::~RTCDemuxerStream() {}
79
80 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() {
81 NOTREACHED() << "Does not support audio.";
82 return dummy_audio_decoder_config_;
83 }
84
85 const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() {
86 return video_decoder_config_;
87 }
88
89 media::DemuxerStream::Type RTCDemuxerStream::type() {
90 return media::DemuxerStream::VIDEO;
91 }
92
93 void RTCDemuxerStream::EnableBitstreamConverter() {
94 }
95
96 void RTCDemuxerStream::UpdateSize(const gfx::Size& size) {
97 video_decoder_config_.Initialize(
98 media::kCodecVP8,
99 media::VP8PROFILE_MAIN,
100 media::VideoFrame::NATIVE_TEXTURE,
101 size, gfx::Rect(size), size, NULL, 0, false, false);
102 }
103
104 void RTCDemuxerStream::QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer,
105 const base::Closure& done_cb) {
106 buffer_queue_.Push(buffer);
107 done_cb_queue_.push(done_cb);
108 frame_rate_tracker_.Update(1);
109 DLOG(INFO) << "frame rate received : " << frame_rate_tracker_.units_second();
110 RunReadCallback();
111 }
112
113 void RTCDemuxerStream::Read(const ReadCB& read_cb) {
114 CHECK(read_cb_.is_null());
115 // A call to |Read| operation means that |MediaSourceDelegate| is done with
116 // the previous buffer.
117 if (!done_cb_queue_.empty())
118 RunDoneCallback();
119 read_cb_ = base::Bind(&RunOnMessageLoop, read_cb,
120 base::MessageLoopProxy::current());
121 RunReadCallback();
122 }
123
124 void RTCDemuxerStream::RunReadCallback() {
125 if (!read_cb_.is_null() && !buffer_queue_.IsEmpty()) {
126 base::ResetAndReturn(&read_cb_).Run(
127 DemuxerStream::kOk, buffer_queue_.Pop());
128 }
129 }
130
131 void RTCDemuxerStream::RunDoneCallback() {
132 DCHECK(!done_cb_queue_.empty());
133 done_cb_queue_.front().Run();
134 done_cb_queue_.pop();
135 }
136
137 // RTCDemuxerProxy -------------------------------------------------------------
138
139 class RTCDemuxerProxy : public base::RefCountedThreadSafe<RTCDemuxerProxy> {
140 public:
141 RTCDemuxerProxy(const scoped_refptr<base::MessageLoopProxy>& message_loop);
142
143 void Initialize(media::DemuxerHost* host, const media::PipelineStatusCB& cb);
144 media::DemuxerStream* GetStream(media::DemuxerStream::Type type);
145 void UpdateSize(const gfx::Size& size);
146 void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer,
147 const base::Closure& done_cb);
148
149 protected:
150 friend class base::RefCountedThreadSafe<RTCDemuxerProxy>;
151
152 virtual ~RTCDemuxerProxy();
153
154 private:
155 scoped_refptr<base::MessageLoopProxy> loop_proxy_;
156 scoped_ptr<RTCDemuxerStream> stream_;
157 media::DemuxerHost* host_;
158 media::PipelineStatusCB init_cb_;
159 };
160
161 RTCDemuxerProxy::RTCDemuxerProxy(
162 const scoped_refptr<base::MessageLoopProxy>& message_loop)
163 : loop_proxy_(message_loop),
164 host_(NULL) {
165 }
166
167 RTCDemuxerProxy::~RTCDemuxerProxy() {}
168
169 void RTCDemuxerProxy::Initialize(media::DemuxerHost* host,
170 const media::PipelineStatusCB& cb) {
171 host_ = host;
172 init_cb_ = cb;
173 }
174
175 media::DemuxerStream* RTCDemuxerProxy::GetStream(
176 media::DemuxerStream::Type type) {
177 if (type == media::DemuxerStream::VIDEO)
178 return stream_.get();
179 return NULL;
180 }
181
182 void RTCDemuxerProxy::UpdateSize(const gfx::Size& size) {
183 if (!loop_proxy_->BelongsToCurrentThread()) {
184 loop_proxy_->PostTask(FROM_HERE, base::Bind(
185 &RTCDemuxerProxy::UpdateSize, this, size));
186 return;
187 }
188 if (stream_) {
189 stream_->UpdateSize(size);
190 } else {
191 stream_.reset(new RTCDemuxerStream(size));
192 if (!init_cb_.is_null())
193 base::ResetAndReturn(&init_cb_).Run(media::PIPELINE_OK);
194 }
195 }
196
197 void RTCDemuxerProxy::QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer,
198 const base::Closure& done_cb) {
199 if (!loop_proxy_->BelongsToCurrentThread()) {
200 loop_proxy_->PostTask(FROM_HERE, base::Bind(
201 &RTCDemuxerProxy::QueueBuffer, this, buffer, done_cb));
202 return;
203 }
204 if (stream_)
205 stream_->QueueBuffer(buffer, done_cb);
206 else
207 done_cb.Run();
208 }
209
210 // RTCDemuxer ------------------------------------------------------------------
211
212 class RTCDemuxer : public media::Demuxer {
213 public:
214 RTCDemuxer(const scoped_refptr<base::MessageLoopProxy>& message_loop);
215 virtual ~RTCDemuxer();
216
217 // media::Demuxer implementation.
218 virtual void Initialize(media::DemuxerHost* host,
219 const media::PipelineStatusCB& cb) OVERRIDE;
220 virtual media::DemuxerStream* GetStream(
221 media::DemuxerStream::Type type) OVERRIDE;
222 virtual base::TimeDelta GetStartTime() const OVERRIDE;
223
224 void UpdateSize(const gfx::Size& size);
225 void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer,
226 const base::Closure& done_cb);
227
228 private:
229 friend class RTCVideoDecoderBridgeTv;
230
231 scoped_refptr<RTCDemuxerProxy> proxy_;
232 };
233
234 RTCDemuxer::RTCDemuxer(
235 const scoped_refptr<base::MessageLoopProxy>& message_loop)
236 : proxy_(new RTCDemuxerProxy(message_loop)) {}
237
238 RTCDemuxer::~RTCDemuxer() {}
239
240 void RTCDemuxer::Initialize(media::DemuxerHost* host,
241 const media::PipelineStatusCB& cb) {
242 proxy_->Initialize(host, cb);
243 }
244
245 media::DemuxerStream* RTCDemuxer::GetStream(media::DemuxerStream::Type type) {
246 return proxy_->GetStream(type);
247 }
248
249 base::TimeDelta RTCDemuxer::GetStartTime() const {
250 return base::TimeDelta();
251 }
252
253 void RTCDemuxer::UpdateSize(const gfx::Size& size) {
254 proxy_->UpdateSize(size);
255 }
256
257 void RTCDemuxer::QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer,
258 const base::Closure& done_cb) {
259 proxy_->QueueBuffer(buffer, done_cb);
260 }
261
262 // RTCVideoDecoderBridgeTvImpl -------------------------------------------------
263
264 class RTCVideoDecoderBridgeTvImpl : public RTCVideoDecoderBridgeTv {
265 public:
266 static RTCVideoDecoderBridgeTvImpl* GetInstance() {
267 return Singleton<RTCVideoDecoderBridgeTvImpl>::get();
268 }
269 RTCVideoDecoderBridgeTvImpl();
270 virtual ~RTCVideoDecoderBridgeTvImpl();
271
272 // webrtc::VideoDecoder implementation.
273 virtual WebRtc_Word32 InitDecode(
274 const webrtc::VideoCodec* codecSettings,
275 WebRtc_Word32 numberOfCores) OVERRIDE;
276 virtual WebRtc_Word32 Decode(
277 const webrtc::EncodedImage& inputImage,
278 bool missingFrames,
279 const webrtc::RTPFragmentationHeader* fragmentation,
280 const webrtc::CodecSpecificInfo* codecSpecificInfo = NULL,
281 WebRtc_Word64 renderTimeMs = -1) OVERRIDE;
282 virtual WebRtc_Word32 RegisterDecodeCompleteCallback(
283 webrtc::DecodedImageCallback* callback) OVERRIDE;
284 virtual WebRtc_Word32 Release() OVERRIDE;
285 virtual WebRtc_Word32 Reset() OVERRIDE;
286
287 virtual media::Demuxer* CreateDemuxer(
288 const scoped_refptr<base::MessageLoopProxy>& message_loop) OVERRIDE;
289 bool AcquireOwnership() OVERRIDE;
290 void ReleaseOwnership() OVERRIDE;
291
292 static void RunDecodeCompleteCallback(webrtc::DecodedImageCallback* callback,
293 WebRtc_Word64 timestamp);
294
295 private:
296 friend struct DefaultSingletonTraits<RTCVideoDecoderBridgeTv>;
297
298 static const base::TimeDelta kDecoderTimeOut;
299 enum Status {
300 kNoInit,
301 kInitialized,
302 };
303
304 // Lock protected, since these can be accessed in CreateDemuxer,
305 // AcquireOwnership, and ReleaseOwnership. No guarantee of calling thread for
306 // these methods.
307 base::Lock lock_;
308 scoped_ptr<RTCDemuxer> demuxer_;
309 int generation_;
310 int demuxer_generation_;
311 bool being_used_;
312 bool first_frame_;
313
314 // Only used by DecoderThread, after AcquireOwnership() is successful.
315 webrtc::DecodedImageCallback* decode_complete_callback_;
316 gfx::Size size_;
317 Status status_;
318 WebRtc_Word64 timestamp_offset_;
319
320 DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderBridgeTvImpl);
321 };
322
323 RTCVideoDecoderBridgeTvImpl::RTCVideoDecoderBridgeTvImpl()
324 : demuxer_(NULL),
325 generation_(0),
326 demuxer_generation_(-1),
327 being_used_(false),
328 first_frame_(true),
329 decode_complete_callback_(NULL),
330 status_(kNoInit) {}
331
332 RTCVideoDecoderBridgeTvImpl::~RTCVideoDecoderBridgeTvImpl() {}
333
334 media::Demuxer* RTCVideoDecoderBridgeTvImpl::CreateDemuxer(
335 const scoped_refptr<base::MessageLoopProxy>& message_loop) {
336 base::AutoLock lock(lock_);
337 if (generation_ == demuxer_generation_)
338 return NULL;
339 demuxer_generation_ = generation_;
340 demuxer_.reset(new RTCDemuxer(message_loop));
341 // If this is initialized before demuxer is set, update the demuxer with size
342 // information.
343 if (status_ == kInitialized)
344 demuxer_->UpdateSize(size_);
345 first_frame_ = true;
346 return demuxer_.get();
347 }
348
349 bool RTCVideoDecoderBridgeTvImpl::AcquireOwnership() {
350 base::AutoLock lock(lock_);
351 if (being_used_)
352 return false;
353
354 being_used_ = true;
355 return true;
356 }
357
358 void RTCVideoDecoderBridgeTvImpl::ReleaseOwnership() {
359 base::AutoLock lock(lock_);
360 DCHECK(being_used_);
361 being_used_ = false;
362 ++generation_;
363 }
364
365 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::InitDecode(
366 const webrtc::VideoCodec* codecSettings,
367 WebRtc_Word32 numberOfCores) {
368 if (status_ != kNoInit)
369 return WEBRTC_VIDEO_CODEC_ERROR;
370 if (codecSettings->codecType != webrtc::kVideoCodecVP8)
371 return WEBRTC_VIDEO_CODEC_ERROR;
372 // We don't support feedback mode.
373 if (codecSettings->codecSpecific.VP8.feedbackModeOn)
374 return WEBRTC_VIDEO_CODEC_ERROR;
375 size_ = gfx::Size(codecSettings->width, codecSettings->height);
376 status_ = kInitialized;
377 base::AutoLock lock(lock_);
378 if (demuxer_ && demuxer_generation_ == generation_)
ycheo (away) 2013/05/02 02:45:21 You may want to add some warning message if the ge
wonsik 2013/05/03 18:31:19 N/A
379 demuxer_->UpdateSize(size_);
380
381 return WEBRTC_VIDEO_CODEC_OK;
382 }
383
384 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Decode(
385 const webrtc::EncodedImage& inputImage,
386 bool missingFrames,
387 const webrtc::RTPFragmentationHeader* fragmentation,
388 const webrtc::CodecSpecificInfo* codecSpecificInfo,
389 WebRtc_Word64 renderTimeMs) {
390 if (status_ == kNoInit || decode_complete_callback_ == NULL)
391 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
392 if (!status_ == kInitialized)
393 return WEBRTC_VIDEO_CODEC_ERROR;
394 // Unlike the SW decoder in libvpx, hw decoder can not handle broken frames.
395 // Here, we return an error in order to request a key frame.
396 if (missingFrames || !inputImage._completeFrame)
397 return WEBRTC_VIDEO_CODEC_ERROR;
398 base::AutoLock lock(lock_);
399 // Drop frames until demuxer is up and running. We'll request key frame
400 // once demuxer is ready.
401 if (!demuxer_ || demuxer_generation_ != generation_)
402 return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
403
404 if (first_frame_) {
405 // If the first frame is not the key frame, return an error to request a key
406 // frame.
407 if (inputImage._frameType != webrtc::kKeyFrame)
408 return WEBRTC_VIDEO_CODEC_ERROR;
409
410 // Google TV expects timestamp from 0.
411 timestamp_offset_ = renderTimeMs;
412 }
413 first_frame_ = false;
414 if (inputImage._frameType == webrtc::kKeyFrame &&
415 inputImage._encodedWidth != 0 && inputImage._encodedHeight != 0) {
416 // Only key frame has the size.
417 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight);
418 if (size_ != new_size) {
419 size_ = new_size;
420 demuxer_->UpdateSize(new_size);
421 }
422 }
423 scoped_refptr<media::DecoderBuffer> buffer;
424 buffer = media::DecoderBuffer::CopyFrom(
425 inputImage._buffer, inputImage._length);
426 if (renderTimeMs != -1) {
427 buffer->SetTimestamp(
428 base::TimeDelta::FromMilliseconds(renderTimeMs - timestamp_offset_));
429 }
430
431 demuxer_->QueueBuffer(
432 buffer,
433 base::Bind(&RTCVideoDecoderBridgeTvImpl::RunDecodeCompleteCallback,
434 decode_complete_callback_,
435 renderTimeMs));
436
437 return WEBRTC_VIDEO_CODEC_OK;
438 }
439
440 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::RegisterDecodeCompleteCallback(
441 webrtc::DecodedImageCallback* callback) {
442 decode_complete_callback_ = callback;
443 return WEBRTC_VIDEO_CODEC_OK;
444 }
445
446 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Release() {
447 status_ = kNoInit;
448 return WEBRTC_VIDEO_CODEC_OK;
449 }
450
451 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Reset() {
452 return WEBRTC_VIDEO_CODEC_OK;
453 }
454
455 // static
456 void RTCVideoDecoderBridgeTvImpl::RunDecodeCompleteCallback(
457 webrtc::DecodedImageCallback* callback, WebRtc_Word64 timestamp) {
458 webrtc::I420VideoFrame dummy_video_frame;
459 dummy_video_frame.CreateEmptyFrame(2, 1, 2, 1, 1);
460 dummy_video_frame.set_timestamp(timestamp);
461 callback->Decoded(dummy_video_frame);
462 }
463
464 } // anonymous namespace
465
466 // RTCVideoDecoderBridgeTv -----------------------------------------------------
467
468 // static
469 RTCVideoDecoderBridgeTv* RTCVideoDecoderBridgeTv::Get() {
470 return RTCVideoDecoderBridgeTvImpl::GetInstance();
471 }
472
473 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698