OLD | NEW |
---|---|
(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 | |
OLD | NEW |