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

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

Powered by Google App Engine
This is Rietveld 408576698