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

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: WebRTC impl on Chrome for TV 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) {
75 }
76
77 RTCDemuxerStream::~RTCDemuxerStream() {}
78
79 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() {
80 DCHECK(false) << "Does not support audio.";
ycheo (away) 2013/04/29 13:18:13 s/DCHECK(false)/NOTREACHED()/
wonsik 2013/05/01 14:15:38 Done.
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);
ycheo (away) 2013/04/29 13:18:13 indentation.
wonsik 2013/05/01 14:15:38 Done.
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) {
ycheo (away) 2013/04/29 13:18:13 indentation.
wonsik 2013/05/01 14:15:38 Done.
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_;
ycheo (away) 2013/04/29 13:18:13 who owns this?
wonsik 2013/05/01 14:15:38 RTCVideoDecoderBridgeTvImpl owns it now.
289 gfx::Size size_;
290 Status status_;
291 bool being_used_;
292 bool first_frame_;
293
294 DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderBridgeTvImpl);
295 };
296
297 RTCVideoDecoderBridgeTvImpl::RTCVideoDecoderBridgeTvImpl()
298 : decode_complete_callback_(NULL),
299 demuxer_(NULL),
300 status_(kNoInit),
301 being_used_(false),
302 first_frame_(true) {
303 }
304
305 RTCVideoDecoderBridgeTvImpl::~RTCVideoDecoderBridgeTvImpl() {
306 }
307
308 bool RTCVideoDecoderBridgeTvImpl::AcquireOwnership() {
309 if (being_used_) {
ycheo (away) 2013/04/29 13:18:13 Remove {} for the single line and apply this throu
wonsik 2013/05/01 14:15:38 Done.
310 return false;
311 }
312 being_used_ = true;
313 return true;
314 }
315
316 void RTCVideoDecoderBridgeTvImpl::ReleaseOwnership() {
317 DCHECK(being_used_);
318 being_used_ = false;
319 }
320
321 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::InitDecode(
322 const webrtc::VideoCodec* codecSettings,
323 WebRtc_Word32 numberOfCores) {
324 if (status_ != kNoInit) {
325 return WEBRTC_VIDEO_CODEC_ERROR;
326 }
327 if (codecSettings->codecType != webrtc::kVideoCodecVP8) {
328 return WEBRTC_VIDEO_CODEC_ERROR;
329 }
330 if (codecSettings->codecSpecific.VP8.feedbackModeOn) {
331 // We don't support feedback mode.
332 return WEBRTC_VIDEO_CODEC_ERROR;
333 }
334 size_ = gfx::Size(codecSettings->width, codecSettings->height);
335 status_ = kInitialized;
336 if (demuxer_)
337 demuxer_->UpdateSize(size_);
338
339 return WEBRTC_VIDEO_CODEC_OK;
340 }
341
342 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Decode(
343 const webrtc::EncodedImage& inputImage,
344 bool missingFrames,
345 const webrtc::RTPFragmentationHeader* fragmentation,
346 const webrtc::CodecSpecificInfo* codecSpecificInfo,
347 WebRtc_Word64 renderTimeMs) {
348 if (status_ == kNoInit || decode_complete_callback_ == NULL) {
349 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
350 }
351 if (!status_ == kInitialized) {
352 return WEBRTC_VIDEO_CODEC_ERROR;
353 }
354 if (missingFrames || !inputImage._completeFrame) {
355 // Unlike the SW decoder in libvpx, hw decoder can not handle broken frames.
356 // Here, we return an error in order to request a key frame.
357 return WEBRTC_VIDEO_CODEC_ERROR;
358 }
359 if (!demuxer_) {
360 // Drop frames until demuxer is up and running. We'll request key frame
361 // once demuxer is ready.
362 return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
363 }
364
365 if (first_frame_ && inputImage._frameType != webrtc::kKeyFrame) {
366 // If the first frame is not the key frame, return an error to request a key
367 // frame.
368 return WEBRTC_VIDEO_CODEC_ERROR;
369 }
370 first_frame_ = false;
371 if (inputImage._frameType == webrtc::kKeyFrame &&
372 inputImage._encodedWidth != 0 && inputImage._encodedHeight != 0) {
373 // Only key frame has the size.
374 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight);
375 if (size_ != new_size) {
376 size_ = new_size;
377 demuxer_->UpdateSize(new_size);
378 }
379 }
380 scoped_refptr<media::DecoderBuffer> buffer;
381 buffer = media::DecoderBuffer::CopyFrom(
382 inputImage._buffer, inputImage._length);
383 if (renderTimeMs != -1)
384 buffer->SetTimestamp(base::TimeDelta::FromMilliseconds(renderTimeMs));
385
386 demuxer_->QueueBuffer(
387 buffer,
388 base::Bind(&RTCVideoDecoderBridgeTvImpl::RunDecodeCompleteCallback,
389 decode_complete_callback_,
390 renderTimeMs));
391
392 return WEBRTC_VIDEO_CODEC_OK;
393 }
394
395 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::RegisterDecodeCompleteCallback(
396 webrtc::DecodedImageCallback* callback) {
397 decode_complete_callback_ = callback;
398 return WEBRTC_VIDEO_CODEC_OK;
399 }
400
401 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Release() {
402 demuxer_ = NULL;
403 status_ = kNoInit;
ycheo (away) 2013/04/29 13:18:13 How about |being_used_|? Reset the variable or nee
wonsik 2013/05/01 14:15:38 demuxer_'s life cycle changed. being_used_ is abou
404 return WEBRTC_VIDEO_CODEC_OK;
405 }
406
407 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Reset() {
408 return WEBRTC_VIDEO_CODEC_OK;
409 }
410
411 bool RTCVideoDecoderBridgeTvImpl::RegisterDemuxer(
412 RTCDemuxer* demuxer) {
413 if (demuxer_) {
414 return false;
415 }
416 demuxer_ = demuxer;
417 // If this is initialized before demuxer is set, update the demuxer with size
418 // information.
419 if (status_ == kInitialized)
420 demuxer_->UpdateSize(size_);
421 first_frame_ = true;
422 return true;
423 }
424
425 // static
426 void RTCVideoDecoderBridgeTvImpl::RunDecodeCompleteCallback(
427 webrtc::DecodedImageCallback* callback, WebRtc_Word64 timestamp) {
428 webrtc::I420VideoFrame dummy_video_frame;
429 dummy_video_frame.CreateEmptyFrame(2, 1, 2, 1, 1);
430 dummy_video_frame.set_timestamp(timestamp);
431 callback->Decoded(dummy_video_frame);
432 }
433
434 } // anonymous namespace
435
436 // RTCVideoDecoderBridgeTv -----------------------------------------------------
437
438 // static
439 RTCVideoDecoderBridgeTv* RTCVideoDecoderBridgeTv::Get() {
440 return RTCVideoDecoderBridgeTvImpl::GetInstance();
441 }
442
443 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698