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

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: Created 7 years, 8 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) 2012 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 "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/singleton.h"
13 #include "base/message_loop_proxy.h"
14 #include "base/time.h"
15 #include "media/base/decoder_buffer.h"
16 #include "third_party/libjingle/source/talk/base/ratetracker.h"
17
18 namespace content {
19
20 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|.
21 static void RunOnMessageLoop(
22 const media::DemuxerStream::ReadCB& read_cb,
23 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
24 media::DemuxerStream::Status status,
25 const scoped_refptr<media::DecoderBuffer>& buffer) {
26 if (!message_loop_proxy->BelongsToCurrentThread()) {
27 message_loop_proxy->PostTask(FROM_HERE, base::Bind(
28 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer));
29 return;
30 }
31 read_cb.Run(status, buffer);
32 }
33
34 ////////////////////////////////////////////////////////////////////////////////
35
36 class RTCDemuxerStream : public media::DemuxerStream {
37 public:
38 explicit RTCDemuxerStream(const gfx::Size& size);
39 // media::DemuxerStream implementation.
40 virtual void Read(const ReadCB& read_cb) OVERRIDE;
41 virtual const media::AudioDecoderConfig& audio_decoder_config() OVERRIDE;
42 virtual const media::VideoDecoderConfig& video_decoder_config() OVERRIDE;
43 virtual Type type() OVERRIDE;
44 virtual void EnableBitstreamConverter() OVERRIDE;
45
46 void UpdateSize(const gfx::Size& size);
47 void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer);
48
49 protected:
50 friend class base::RefCountedThreadSafe<RTCDemuxerStream>;
51
52 virtual ~RTCDemuxerStream();
53
54 private:
55 media::DecoderBufferQueue buffer_queue_;
56 ReadCB read_cb_;
57
58 media::AudioDecoderConfig dummy_audio_decoder_config_;
59 media::VideoDecoderConfig video_decoder_config_;
60 talk_base::RateTracker frame_rate_tracker_;
61 };
62
63 RTCDemuxerStream::RTCDemuxerStream(const gfx::Size& size)
64 : video_decoder_config_(
65 media::kCodecVP8,
66 media::VP8PROFILE_MAIN,
67 media::VideoFrame::NATIVE_TEXTURE,
68 size, gfx::Rect(size), size, NULL, 0, false) {
69 }
70
71 RTCDemuxerStream::~RTCDemuxerStream() {}
72
73 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() {
74 DCHECK(false) << "Does not support audio.";
75 return dummy_audio_decoder_config_;
76 }
77
78 const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() {
79 return video_decoder_config_;
80 }
81
82 media::DemuxerStream::Type RTCDemuxerStream::type() {
83 return media::DemuxerStream::VIDEO;
84 }
85
86 void RTCDemuxerStream::EnableBitstreamConverter() {
87 }
88
89 void RTCDemuxerStream::UpdateSize(const gfx::Size& size) {
90 video_decoder_config_.Initialize(
91 media::kCodecVP8,
92 media::VP8PROFILE_MAIN,
93 media::VideoFrame::NATIVE_TEXTURE,
94 size, gfx::Rect(size), size, NULL, 0, false, false);
95 }
96
97 void RTCDemuxerStream::QueueBuffer(
98 scoped_refptr<media::DecoderBuffer> buffer) {
99 buffer_queue_.Push(buffer);
100 frame_rate_tracker_.Update(1);
101 DLOG(INFO) << "frame rate received : " << frame_rate_tracker_.units_second();
102
103 if (!read_cb_.is_null()) {
104 base::ResetAndReturn(&read_cb_).Run(
105 DemuxerStream::kOk, buffer_queue_.Pop());
106 }
107 }
108
109 ////////////////////////////////////////////////////////////////////////////////
110
111 RTCDemuxerProxy::RTCDemuxerProxy(
112 const scoped_refptr<base::MessageLoopProxy>& message_loop)
113 : loop_proxy_(message_loop),
114 stream_(NULL),
115 host_(NULL) {
116 }
117
118 RTCDemuxerProxy::~RTCDemuxerProxy() {}
119
120 void RTCDemuxerProxy::Initialize(media::DemuxerHost* host,
121 const media::PipelineStatusCB& cb) {
122 host_ = host;
123 init_cb_ = cb;
124 }
125
126 scoped_refptr<media::DemuxerStream> RTCDemuxerProxy::GetStream(
127 media::DemuxerStream::Type type) {
128 if (type == media::DemuxerStream::VIDEO)
129 return stream_;
130 return NULL;
131 }
132
133 base::TimeDelta RTCDemuxerProxy::GetStartTime() const {
134 return base::TimeDelta();
135 }
136
137 void RTCDemuxerProxy::UpdateSize(const gfx::Size& size) {
138 if (!loop_proxy_->BelongsToCurrentThread()) {
139 loop_proxy_->PostTask(FROM_HERE, base::Bind(
140 &RTCDemuxerProxy::UpdateSize, this, size));
141 return;
142 }
143 if (stream_) {
144 stream_->UpdateSize(size);
145 } else {
146 stream_ = new RTCDemuxerStream(size);
147 if (!init_cb_.is_null())
148 base::ResetAndReturn(&init_cb_).Run(media::PIPELINE_OK);
149 }
150 }
151
152 void RTCDemuxerProxy::QueueBuffer(
153 scoped_refptr<media::DecoderBuffer> buffer) {
154 if (!loop_proxy_->BelongsToCurrentThread()) {
155 loop_proxy_->PostTask(FROM_HERE, base::Bind(
156 &RTCDemuxerProxy::QueueBuffer, this, buffer));
157 return;
158 }
159 stream_->QueueBuffer(buffer);
160 }
161
162 void RTCDemuxerStream::Read(const ReadCB& read_cb) {
163 CHECK(read_cb_.is_null());
164 read_cb_ = base::Bind(&RunOnMessageLoop, read_cb,
165 base::MessageLoopProxy::current());
166
167 if(!buffer_queue_.IsEmpty()) {
168 base::ResetAndReturn(&read_cb_).Run(
169 DemuxerStream::kOk, buffer_queue_.Pop());
170 }
171 }
172
173 ////////////////////////////////////////////////////////////////////////////////
174
175 class RTCVideoDecoderBridgeTvImpl : public RTCVideoDecoderBridgeTv {
176 public:
177 static RTCVideoDecoderBridgeTvImpl* GetInstance() {
178 return Singleton<RTCVideoDecoderBridgeTvImpl>::get();
179 }
180 RTCVideoDecoderBridgeTvImpl();
181 virtual ~RTCVideoDecoderBridgeTvImpl();
182
183 // webrtc::VideoDecoder implementation.
184 virtual WebRtc_Word32 InitDecode(
185 const webrtc::VideoCodec* codecSettings,
186 WebRtc_Word32 numberOfCores) OVERRIDE;
187 virtual WebRtc_Word32 Decode(
188 const webrtc::EncodedImage& inputImage,
189 bool missingFrames,
190 const webrtc::RTPFragmentationHeader* fragmentation,
191 const webrtc::CodecSpecificInfo* codecSpecificInfo = NULL,
192 WebRtc_Word64 renderTimeMs = -1) OVERRIDE;
193 virtual WebRtc_Word32 RegisterDecodeCompleteCallback(
194 webrtc::DecodedImageCallback* callback) OVERRIDE;
195 virtual WebRtc_Word32 Release() OVERRIDE;
196 virtual WebRtc_Word32 Reset() OVERRIDE;
197
198 bool RegisterDemuxer(scoped_refptr<RTCDemuxerProxy> demuxer) OVERRIDE;
199 bool AcquireOwnership() OVERRIDE;
200 void ReleaseOwnership() OVERRIDE;
201
202 private:
203 friend struct DefaultSingletonTraits<RTCVideoDecoderBridgeTv>;
204
205 static const base::TimeDelta kDecoderTimeOut;
206 enum Status {
207 kNoInit,
208 kInitialized,
209 };
210
211 base::TimeDelta first_render_wall_time_;
212
213 webrtc::DecodedImageCallback* decode_complete_callback_;
214 scoped_refptr<RTCDemuxerProxy> demuxer_;
215 gfx::Size size_;
216 Status status_;
217 bool being_used_;
218 bool first_frame_;
219
220 DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderBridgeTvImpl);
221 };
222
223 RTCVideoDecoderBridgeTvImpl::RTCVideoDecoderBridgeTvImpl()
224 : decode_complete_callback_(NULL),
225 status_(kNoInit),
226 being_used_(false),
227 first_frame_(true) {
228 }
229
230 RTCVideoDecoderBridgeTvImpl::~RTCVideoDecoderBridgeTvImpl() {
231 }
232
233 bool RTCVideoDecoderBridgeTvImpl::AcquireOwnership() {
234 if (being_used_) {
235 return false;
236 }
237 being_used_ = true;
238 return true;
239 }
240
241 void RTCVideoDecoderBridgeTvImpl::ReleaseOwnership() {
242 DCHECK(being_used_);
243 being_used_ = false;
244 }
245
246 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::InitDecode(
247 const webrtc::VideoCodec* codecSettings,
248 WebRtc_Word32 numberOfCores) {
249 if (status_ != kNoInit) {
250 return WEBRTC_VIDEO_CODEC_ERROR;
251 }
252 if (codecSettings->codecType != webrtc::kVideoCodecVP8) {
253 return WEBRTC_VIDEO_CODEC_ERROR;
254 }
255 if (codecSettings->codecSpecific.VP8.feedbackModeOn) {
256 // We don't support feedback mode.
257 return WEBRTC_VIDEO_CODEC_ERROR;
258 }
259 size_ = gfx::Size(codecSettings->width, codecSettings->height);
260 status_ = kInitialized;
261 if (demuxer_)
262 demuxer_->UpdateSize(size_);
263
264 return WEBRTC_VIDEO_CODEC_OK;
265 }
266
267 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Decode(
268 const webrtc::EncodedImage& inputImage,
269 bool missingFrames,
270 const webrtc::RTPFragmentationHeader* fragmentation,
271 const webrtc::CodecSpecificInfo* codecSpecificInfo,
272 WebRtc_Word64 renderTimeMs) {
273 if (status_ == kNoInit || decode_complete_callback_ == NULL) {
274 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
275 }
276 if (!status_ == kInitialized) {
277 return WEBRTC_VIDEO_CODEC_ERROR;
278 }
279 if (missingFrames || !inputImage._completeFrame) {
280 // Unlike the SW decoder in libvpx, hw decoder can not handle broken frames.
281 // Here, we return an error in order to request a key frame.
282 return WEBRTC_VIDEO_CODEC_ERROR;
283 }
284 if (!demuxer_) {
285 // Drop frames until demuxer is up and running. We'll request key frame
286 // once demuxer is ready.
287 return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
288 }
289
290 if (first_frame_ && inputImage._frameType != webrtc::kKeyFrame) {
291 // If the first frame is not the key frame, return an error to request a key
292 // frame.
293 return WEBRTC_VIDEO_CODEC_ERROR;
294 }
295 first_frame_ = false;
296 if (inputImage._frameType == webrtc::kKeyFrame &&
297 inputImage._encodedWidth != 0 && inputImage._encodedHeight != 0) {
298 // Only key frame has the size.
299 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight);
300 if (size_ != new_size) {
301 size_ = new_size;
302 demuxer_->UpdateSize(new_size);
303 }
304 }
305 scoped_refptr<media::DecoderBuffer> buffer;
306 buffer = media::DecoderBuffer::CopyFrom(
307 inputImage._buffer, inputImage._length);
308
309 demuxer_->QueueBuffer(buffer);
310
311 return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
312 }
313
314 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::RegisterDecodeCompleteCallback(
315 webrtc::DecodedImageCallback* callback) {
316 decode_complete_callback_ = callback;
317 return WEBRTC_VIDEO_CODEC_OK;
318 }
319
320 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Release() {
321 demuxer_ = NULL;
322 status_ = kNoInit;
323 return WEBRTC_VIDEO_CODEC_OK;
324 }
325
326 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Reset() {
327 return WEBRTC_VIDEO_CODEC_OK;
328 }
329
330 bool RTCVideoDecoderBridgeTvImpl::RegisterDemuxer(
331 scoped_refptr<RTCDemuxerProxy> demuxer) {
332 if (demuxer_) {
333 return false;
334 }
335 demuxer_ = demuxer;
336 // If this is initialized before demuxer is set, update the demuxer with size
337 // information.
338 if (status_ == kInitialized)
339 demuxer_->UpdateSize(size_);
340 first_frame_ = true;
341 return true;
342 }
343
344 ////////////////////////////////////////////////////////////////////////////////
345
346 // static
347 RTCVideoDecoderBridgeTv* RTCVideoDecoderBridgeTv::Get() {
348 return RTCVideoDecoderBridgeTvImpl::GetInstance();
349 }
350
351 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698