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

Side by Side Diff: content/renderer/media/rtc_video_decoder_bridge.cc

Issue 13890012: Integrate VDA with WebRTC. (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.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/message_loop_proxy.h"
13 #include "base/time.h"
14 #include "content/renderer/media/native_handle_impl.h"
15 #include "media/base/decoder_buffer.h"
16 #include "media/base/yuv_convert.h"
17 #include "third_party/libjingle/source/talk/base/ratetracker.h" // XXX remove
18 #include "third_party/webrtc/system_wrappers/interface/ref_count.h"
19
20
21 namespace content {
22
23 #define LOG_LINE() VLOG(0) << __FILE__ << ":" << __FUNCTION__
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 Planning to remove before landing?
wuchengli 2013/05/08 15:58:56 Removed. On 2013/04/26 00:42:05, Ami Fischman wrot
24
25 // static
26 const base::TimeDelta RTCVideoDecoderBridge::kDecoderTimeOut =
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 Why is this a good idea?
wuchengli 2013/05/08 15:58:56 Removed. Now InitDecode waits for GpuVideoDecoder:
27 base::TimeDelta::FromMilliseconds(3000);
28
29 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|.
30 static void RunOnMessageLoop(
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 Any reason this can't be replaced by BindToLoop?
wuchengli 2013/05/08 15:58:56 Removed.
31 const media::DemuxerStream::ReadCB& read_cb,
32 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
33 media::DemuxerStream::Status status,
34 const scoped_refptr<media::DecoderBuffer>& buffer) {
35 if (!message_loop_proxy->BelongsToCurrentThread()) {
36 message_loop_proxy->PostTask(FROM_HERE, base::Bind(
37 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer));
38 return;
39 }
40
41 read_cb.Run(status, buffer);
42 }
43
44 void RTCDemuxerStream::Read(const ReadCB& read_cb) {
45 CHECK(read_cb_.is_null());
46 read_cb_ = base::Bind(&RunOnMessageLoop, read_cb,
47 base::MessageLoopProxy::current());
48
49 if(!buffer_queue_.IsEmpty()) {
50 base::ResetAndReturn(&read_cb_).Run(
51 DemuxerStream::kOk, buffer_queue_.Pop());
52 }
53 }
54
55 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() {
56 CHECK(false) << "Does not support audio.";
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 FWIW LOG(FATAL) reads slightly more clearly to me
wuchengli 2013/05/08 15:58:56 Done.
57 return dummy_audio_decoder_config_;
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 this is unreachable, and therefore the member is u
wuchengli 2013/05/08 15:58:56 Removed.
58 }
59
60 const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() {
61 return video_decoder_config_;
62 }
63
64 media::DemuxerStream::Type RTCDemuxerStream::type() {
65 return media::DemuxerStream::VIDEO;
66 }
67
68 void RTCDemuxerStream::EnableBitstreamConverter() {
69 }
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 LOG(FATAL) << "Unreachable!";
wuchengli 2013/05/08 15:58:56 Changed to NOTREACHED();
70
71 void RTCDemuxerStream::UpdateSize(gfx::Size size) {
72 gfx::Rect rect(size);
73 video_decoder_config_.Initialize(
74 media::kCodecVP8,
75 media::VP8PROFILE_MAIN,
76 media::VideoFrame::NATIVE_TEXTURE,
77 size, rect, size, NULL, 0, false, false);
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 Coded==visible==natural sizes/rects? I suspect the
wuchengli 2013/05/08 15:58:56 Can you explain more? I'm not sure what to put in
78 }
79
80 void RTCDemuxerStream::QueueBuffer(
81 scoped_refptr<media::DecoderBuffer> buffer) {
82 LOG_LINE();
83 LOG_LINE() << " end";
84 buffer_queue_.Push(buffer);
85
86 if (!read_cb_.is_null()) {
87 base::ResetAndReturn(&read_cb_).Run(
88 DemuxerStream::kOk, buffer_queue_.Pop());
89 }
90 }
91
92 RTCVideoDecoderBridge::RTCVideoDecoderBridge(
93 scoped_refptr<media::VideoDecoder> video_decoder,
94 const scoped_refptr<base::MessageLoopProxy>& message_loop)
95 : video_decoder_(video_decoder),
96 loop_proxy_(message_loop),
97 decode_complete_callback_(NULL),
98 pipeline_status_(media::PIPELINE_OK),
99 decoder_init_waiter_(false, false),
100 decoder_reset_waiter_(false, false),
101 stream_(new RTCDemuxerStream()),
102 status_(kNoInit),
103 decoding_error_occured_(false) {
104 LOG_LINE();
105 }
106
107 RTCVideoDecoderBridge::~RTCVideoDecoderBridge() {
108 LOG_LINE();
109 }
110
111 WebRtc_Word32 RTCVideoDecoderBridge::InitDecode(
112 const webrtc::VideoCodec* codecSettings,
113 WebRtc_Word32 numberOfCores) {
114 LOG_LINE();
115 if (status_ != kNoInit) {
116 return WEBRTC_VIDEO_CODEC_ERROR;
117 }
118 if (codecSettings->codecType != webrtc::kVideoCodecVP8) {
Pawel Osciak 2013/04/26 07:08:01 Can this happen if the check in RTCVideoDecoderFac
wuchengli 2013/05/08 15:58:56 All possible codecType are kVideoCodecVP8, kVideoC
119 return WEBRTC_VIDEO_CODEC_ERROR;
120 }
121 if (codecSettings->codecSpecific.VP8.feedbackModeOn) {
122 // We don't support feedback mode.
123 return WEBRTC_VIDEO_CODEC_ERROR;
124 }
125
126 loop_proxy_->PostTask(
127 FROM_HERE,
128 base::Bind(&RTCDemuxerStream::UpdateSize, stream_,
129 gfx::Size(codecSettings->width, codecSettings->height)));
130 loop_proxy_->PostTask(
131 FROM_HERE,
132 base::Bind(&media::VideoDecoder::Initialize,
133 video_decoder_,
134 stream_,
135 base::Bind(&RTCVideoDecoderBridge::OnUpdatePipelineStatus,
136 base::Unretained(this)),
137 base::Bind(&RTCVideoDecoderBridge::OnUpdateStatistics,
138 base::Unretained(this))));
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 why is this Unretained safe?
139 decoder_init_waiter_.TimedWait(kDecoderTimeOut);
140 if (pipeline_status_ != media::PIPELINE_OK) {
141 return WEBRTC_VIDEO_CODEC_ERROR;
142 }
Pawel Osciak 2013/04/26 07:08:01 No need for braces.
wuchengli 2013/05/08 15:58:56 I added one more line.
143 status_ = kInitialized;
144 LOG_LINE() << "OK";
145 return WEBRTC_VIDEO_CODEC_OK;
146 }
147
148 void RTCVideoDecoderBridge::OnUpdateStatistics(
149 const media::PipelineStatistics& stats) {
150 // We don't use statistics for now.
151 }
152
153 void RTCVideoDecoderBridge::OnUpdatePipelineStatus(
154 const media::PipelineStatus status) {
155 VLOG(0) << "RTCVideoDecoderBridge::OnUpdatePipelineStatus. status=" << status;
156 pipeline_status_ = status;
157 decoder_init_waiter_.Signal();
158 }
159
160 void RTCVideoDecoderBridge::ResetComplete() {
161 LOG_LINE();
162 decoder_reset_waiter_.Signal();
163 }
164
165
166 WebRtc_Word32 RTCVideoDecoderBridge::Decode(
167 const webrtc::EncodedImage& inputImage,
168 bool missingFrames,
169 const webrtc::RTPFragmentationHeader* fragmentation,
170 const webrtc::CodecSpecificInfo* codecSpecificInfo,
171 WebRtc_Word64 renderTimeMs) {
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 unused parameters can have their name omitted, whi
wuchengli 2013/05/08 15:58:56 Done.
172 VLOG(0) << "RTCVideoDecoderBridge::Decode. status=" << status_;
173 {
174 base::AutoLock auto_lock(lock_);
Pawel Osciak 2013/04/26 07:08:01 Lock usage is mysterious here, especially since th
wuchengli 2013/05/08 15:58:56 decoding_error_occurred_ is read by WebRTC Decodin
175 if (decoding_error_occured_) {
176 // TODO(dwkang): consider creating a SW decoder and falling back to it.
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 s/dwkang/wuchengli/g ? :)
wuchengli 2013/05/08 15:58:56 Removed the todo. This doesn't look like the right
177 return WEBRTC_VIDEO_CODEC_ERROR;
178 }
179 }
180 if (status_ == kNoInit || decode_complete_callback_ == NULL) {
181 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
182 }
Pawel Osciak 2013/04/26 07:08:01 Braces not needed and below too.
wuchengli 2013/05/08 15:58:56 Done.
183 if (!(status_ == kInitialized || status_ == kDecoding)) {
Pawel Osciak 2013/04/26 07:08:01 if (status_ != kInitialized && status_ != kDecodin
wuchengli 2013/05/08 15:58:56 Done.
184 return WEBRTC_VIDEO_CODEC_ERROR;
185 }
186 if (missingFrames || !inputImage._completeFrame) {
187 // Unlike the SW decoder in libvpx, hw decoder can not handle broken frames.
188 // Here, we return an error in order to request a key frame.
189 return WEBRTC_VIDEO_CODEC_ERROR;
190 }
191
192 if (inputImage._frameType == webrtc::kKeyFrame &&
193 inputImage._encodedWidth != 0 && inputImage._encodedHeight != 0) {
194 // Only key frame has the size.
195 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight);
196 if (size_ != new_size) {
197 size_ = new_size;
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 member never used; drop?
wuchengli 2013/05/08 15:58:56 This is used so that RTCDemuxerStream::UpdateSize
198 loop_proxy_->PostTask(
199 FROM_HERE,
200 base::Bind(&RTCDemuxerStream::UpdateSize, stream_, new_size));
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 In this case, you need to signal DemuxerStream::kC
201 }
202 }
203 scoped_refptr<media::DecoderBuffer> buffer;
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 I only got down to here but I think I see your pro
wuchengli 2013/04/26 05:08:08 GpuVideoDecoder::Read is called in RTCVideoDecoder
Ami GONE FROM CHROMIUM 2013/04/26 15:13:34 I see. IIUC the code will wait for each frame to
wuchengli 2013/05/09 15:43:14 The latest patchset does not wait from the GPU pro
204 buffer = media::DecoderBuffer::CopyFrom(
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 assign on prev line?
wuchengli 2013/05/08 15:58:56 Done.
205 inputImage._buffer, inputImage._length);
206 buffer->SetTimestamp(base::TimeDelta::FromInternalValue(
207 inputImage._timeStamp));
Ami GONE FROM CHROMIUM 2013/04/26 00:42:05 This looks strange; internalvalue is in microsecon
wuchengli 2013/05/09 15:43:14 inputImage._timeStamp is in 90KHz. We need to divi
208
209 loop_proxy_->PostTask(
210 FROM_HERE,
211 base::Bind(&RTCDemuxerStream::QueueBuffer, stream_, buffer));
212
213 {
214 base::AutoLock auto_lock(lock_);
215 for (VideoFrameList::iterator it = ready_video_frames_.begin();
216 it != ready_video_frames_.end(); ++it) {
217 gfx::Rect rect = (*it)->visible_rect();
218 decoded_image_.CreateEmptyFrame(
219 rect.width(), rect.height(),
220 rect.width(), rect.width() / 2, rect.width() / 2);
221 webrtc::RefCountImpl<media::NativeHandleImpl>* handle =
222 new webrtc::RefCountImpl<media::NativeHandleImpl>();
223 handle->SetHandle((*it).get());
224 decoded_image_.set_native_handle(handle);
225 decoded_image_.set_timestamp(
226 static_cast<uint32_t>((*it)->GetTimestamp().InMicroseconds()));
227 decode_complete_callback_->Decoded(decoded_image_);
228 decoded_image_.set_native_handle(NULL);
229 }
230 ready_video_frames_.clear();
231 }
232
233 if (status_ == kInitialized) {
234 status_ = kDecoding;
235 RequestFrame();
236 }
237
238 return WEBRTC_VIDEO_CODEC_OK;
239 }
240
241 void RTCVideoDecoderBridge::RequestFrame() {
242 loop_proxy_->PostTask(
243 FROM_HERE,
244 base::Bind(&media::VideoDecoder::Read,
245 video_decoder_,
246 base::Bind(&RTCVideoDecoderBridge::FrameReady,
247 base::AsWeakPtr(this))));
248 }
249
250 WebRtc_Word32 RTCVideoDecoderBridge::RegisterDecodeCompleteCallback(
251 webrtc::DecodedImageCallback* callback) {
252 decode_complete_callback_ = callback;
253 return WEBRTC_VIDEO_CODEC_OK;
254 }
255
256 WebRtc_Word32 RTCVideoDecoderBridge::Release() {
257 LOG_LINE();
258 /*if (status_ == kNoInit) {
259 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
260 }
261 base::WaitableEvent event(false, false);
262 loop_proxy_->PostTask(
263 FROM_HERE,
264 base::Bind(&media::VideoDecoder::Stop,
265 video_decoder_,
266 base::Bind(&base::WaitableEvent::Signal,
267 base::Unretained(&event))));
268 decoder_init_waiter_.Wait();
269 status_ = kReleased;*/
270 return WEBRTC_VIDEO_CODEC_OK;
271 }
272
273 WebRtc_Word32 RTCVideoDecoderBridge::Reset() {
274 LOG_LINE();
275 if (status_ == kNoInit) {
276 LOG(ERROR) << "RTCVideoDecoderBridge::Reset. status==kNoInit";
277 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
278 }
279 status_ = kReseting;
280 base::WaitableEvent event(false, false);
Pawel Osciak 2013/04/26 07:08:01 unused?
wuchengli 2013/05/08 15:58:56 Removed.
281 loop_proxy_->PostTask(
282 FROM_HERE,
283 base::Bind(&media::VideoDecoder::Reset,
284 video_decoder_,
285 base::Bind(&RTCVideoDecoderBridge::ResetComplete,
286 base::Unretained(this))));
287 decoder_reset_waiter_.Wait();
288 status_ = kInitialized;
289 LOG_LINE() << " OK";
290 return WEBRTC_VIDEO_CODEC_OK;
291 }
292
293 void RTCVideoDecoderBridge::FrameReady(
294 media::VideoDecoder::Status status,
295 const scoped_refptr<media::VideoFrame>& frame) {
296 VLOG(0) << "RTCVideoDecoderBridge::FrameReady. status=" << status
297 << ". status_=" << status_;
298 /*{
299 static talk_base::RateTracker frame_rate_tracker_;
300 static base::Time start_time = base::Time::Now();
301 base::Time diff = base::Time::Now() - start_time;
302 VLOG(1) << "RTCVideoDecoderBridge::FrameReady DeliverFrame framerate "
303 << frame_rate_tracker_.units_second()
304 << " avg framerate "
305 << frame_rate_tracker_.total_units() / diff.InSecondsF();
306 frame_rate_tracker_.Update(1);
307 }*/
308
309 {
310 base::AutoLock auto_lock(lock_);
311 if (status != media::VideoDecoder::kOk) {
312 LOG(ERROR) << "RTCVideoDecoderBridge::FrameReady. status!=kOk";
313 decoding_error_occured_ = true;
314 return;
315 }
316
317 ready_video_frames_.push_back(frame);
wuchengli 2013/04/25 12:38:54 How can I call decode_complete_callback_ using web
318 }
319 if (status_ == kDecoding) {
320 RequestFrame();
321 }
322 }
323
324 } // namespace content
325
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698