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

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

Powered by Google App Engine
This is Rietveld 408576698