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

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

Powered by Google App Engine
This is Rietveld 408576698