OLD | NEW |
---|---|
(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.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/callback_helpers.h" | |
9 #include "base/logging.h" | |
10 #include "base/memory/ref_counted.h" | |
11 #include "base/message_loop_proxy.h" | |
12 #include "content/renderer/media/native_handle_impl.h" | |
13 #include "media/base/audio_decoder_config.h" | |
14 #include "media/base/bind_to_loop.h" | |
15 #include "media/base/decoder_buffer.h" | |
16 #include "media/base/decoder_buffer_queue.h" | |
17 #include "media/base/demuxer_stream.h" | |
18 #include "media/base/video_decoder_config.h" | |
19 #include "third_party/webrtc/system_wrappers/interface/ref_count.h" | |
20 | |
21 | |
22 namespace content { | |
23 | |
24 class RTCDemuxerStream | |
25 : public media::DemuxerStream, | |
26 public base::SupportsWeakPtr<RTCDemuxerStream> { | |
27 public: | |
28 RTCDemuxerStream(const scoped_refptr<base::MessageLoopProxy>& message_loop); | |
29 // media::DemuxerStream implementation. | |
30 virtual void Read(const ReadCB& read_cb) OVERRIDE; | |
31 virtual const media::AudioDecoderConfig& audio_decoder_config() OVERRIDE; | |
32 virtual const media::VideoDecoderConfig& video_decoder_config() OVERRIDE; | |
33 virtual Type type() OVERRIDE; | |
34 virtual void EnableBitstreamConverter() OVERRIDE; | |
35 | |
36 void UpdateSize(gfx::Size size); | |
37 void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer); | |
38 void ClearBuffer(); | |
39 | |
40 private: | |
41 media::DecoderBufferQueue buffer_queue_; | |
42 ReadCB read_cb_; | |
43 // Make sure all the methods are called by the same thread. | |
44 scoped_refptr<base::MessageLoopProxy> message_loop_; | |
45 media::VideoDecoderConfig video_decoder_config_; | |
46 }; | |
47 | |
48 RTCDemuxerStream::RTCDemuxerStream( | |
49 const scoped_refptr<base::MessageLoopProxy>& message_loop) | |
50 : message_loop_(message_loop) { | |
51 } | |
52 | |
53 void RTCDemuxerStream::Read(const ReadCB& read_cb) { | |
54 DCHECK(message_loop_->BelongsToCurrentThread()); | |
55 CHECK(read_cb_.is_null()); | |
56 read_cb_ = read_cb; | |
57 | |
58 if(!buffer_queue_.IsEmpty()) { | |
59 base::ResetAndReturn(&read_cb_).Run( | |
60 DemuxerStream::kOk, buffer_queue_.Pop()); | |
61 } | |
62 } | |
63 | |
64 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() { | |
65 LOG(FATAL) << "Audio is not supported."; | |
66 return *(new media::AudioDecoderConfig); | |
67 } | |
68 | |
69 const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() { | |
70 DCHECK(message_loop_->BelongsToCurrentThread()); | |
71 return video_decoder_config_; | |
72 } | |
73 | |
74 media::DemuxerStream::Type RTCDemuxerStream::type() { | |
75 return media::DemuxerStream::VIDEO; | |
76 } | |
77 | |
78 void RTCDemuxerStream::EnableBitstreamConverter() { | |
79 NOTREACHED(); | |
80 } | |
81 | |
82 void RTCDemuxerStream::UpdateSize(gfx::Size size) { | |
83 DCHECK(message_loop_->BelongsToCurrentThread()); | |
84 gfx::Rect rect(size); | |
85 video_decoder_config_.Initialize( | |
86 media::kCodecVP8, | |
87 media::VP8PROFILE_MAIN, | |
88 media::VideoFrame::NATIVE_TEXTURE, | |
89 size, rect, size, NULL, 0, false, false); | |
90 } | |
91 | |
92 void RTCDemuxerStream::QueueBuffer( | |
93 scoped_refptr<media::DecoderBuffer> buffer) { | |
94 DCHECK(message_loop_->BelongsToCurrentThread()); | |
95 DVLOG(3) << "QueueBuffer"; | |
96 buffer_queue_.Push(buffer); | |
97 | |
98 if (!read_cb_.is_null()) { | |
99 base::ResetAndReturn(&read_cb_).Run( | |
100 DemuxerStream::kOk, buffer_queue_.Pop()); | |
101 } | |
102 DVLOG(3) << "QueueBuffer end"; | |
103 } | |
104 | |
105 void RTCDemuxerStream::ClearBuffer() { | |
106 DCHECK(message_loop_->BelongsToCurrentThread()); | |
107 buffer_queue_.Clear(); | |
108 } | |
109 | |
110 RTCVideoDecoder::RTCVideoDecoder( | |
111 media::VideoDecoder* video_decoder, | |
112 const scoped_refptr<base::MessageLoopProxy>& message_loop) | |
113 : video_decoder_(video_decoder), | |
114 decoder_message_loop_(message_loop), | |
115 decode_complete_callback_(NULL), | |
116 pipeline_status_(media::PIPELINE_OK), | |
117 decoder_waiter_(false, false), | |
118 stream_(new RTCDemuxerStream(message_loop)), | |
119 state_(kUninitialized), | |
120 weak_factory_(this), | |
121 decoding_error_occurred_(false) { | |
122 decoder_message_loop_->PostTask( | |
123 FROM_HERE, | |
124 base::Bind(&RTCVideoDecoder::InitWeakPtr, base::Unretained(this))); | |
125 decoder_waiter_.Wait(); | |
126 } | |
127 | |
128 void RTCVideoDecoder::InitWeakPtr() { | |
129 DCHECK(decoder_message_loop_->BelongsToCurrentThread()); | |
130 weak_this_ = weak_factory_.GetWeakPtr(); | |
131 weak_stream_ = stream_->AsWeakPtr(); | |
132 decoder_waiter_.Signal(); | |
133 } | |
134 | |
135 RTCVideoDecoder::~RTCVideoDecoder() { | |
136 } | |
137 | |
138 // Called by WebRTC DecodingThread | |
139 int32_t RTCVideoDecoder::InitDecode( | |
140 const webrtc::VideoCodec* codecSettings, | |
141 int32_t /*numberOfCores*/) { | |
142 DVLOG(3) << "InitDecode"; | |
143 if (state_ != kUninitialized) { | |
144 LOG(ERROR) << "state_ != kUninitialized!"; | |
145 return WEBRTC_VIDEO_CODEC_ERROR; | |
146 } | |
147 if (codecSettings->codecType != webrtc::kVideoCodecVP8) { | |
148 LOG(ERROR) << "codec != VP8!"; | |
149 return WEBRTC_VIDEO_CODEC_ERROR; | |
150 } | |
151 if (codecSettings->codecSpecific.VP8.feedbackModeOn) { | |
152 LOG(ERROR) << "Feedback mode not supported"; | |
153 return WEBRTC_VIDEO_CODEC_ERROR; | |
154 } | |
155 | |
156 decoder_message_loop_->PostTask( | |
157 FROM_HERE, | |
158 base::Bind(&RTCDemuxerStream::UpdateSize, weak_stream_, | |
159 gfx::Size(codecSettings->width, codecSettings->height))); | |
160 decoder_message_loop_->PostTask( | |
161 FROM_HERE, | |
162 base::Bind(&media::VideoDecoder::Initialize, | |
163 base::Unretained(video_decoder_.get()), | |
164 base::Unretained(stream_.get()), | |
165 base::Bind(&RTCVideoDecoder::OnUpdatePipelineStatus, | |
166 weak_this_), | |
167 base::Bind(&RTCVideoDecoder::OnUpdateStatistics, weak_this_))); | |
168 decoder_waiter_.Wait(); | |
169 if (pipeline_status_ != media::PIPELINE_OK) { | |
170 LOG(ERROR) << "Initialize failed. pipeline_status_=" << pipeline_status_; | |
171 return WEBRTC_VIDEO_CODEC_ERROR; | |
172 } | |
173 state_ = kInitialized; | |
174 DVLOG(3) << "InitDecode end"; | |
175 return WEBRTC_VIDEO_CODEC_OK; | |
176 } | |
177 | |
178 // Called by WebRTC DecodingThread | |
179 int32_t RTCVideoDecoder::Decode( | |
180 const webrtc::EncodedImage& inputImage, | |
181 bool missingFrames, | |
182 const webrtc::RTPFragmentationHeader* /*fragmentation*/, | |
183 const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/, | |
184 int64_t /*renderTimeMs*/) { | |
185 DVLOG(3) << "Decode"; | |
186 | |
187 if (decoding_error_occurred_) { | |
188 LOG(ERROR) << "Decoding error occurred."; | |
189 return WEBRTC_VIDEO_CODEC_ERROR; | |
190 } | |
191 if (state_ == kUninitialized || decode_complete_callback_ == NULL) { | |
192 LOG(ERROR) << "WebRTC video codec unintialized."; | |
193 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
194 } | |
195 if (missingFrames || !inputImage._completeFrame) { | |
196 LOG(ERROR) << "Missing frames or not completed frames."; | |
197 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. | |
198 // Return an error to request a key frame. | |
199 return WEBRTC_VIDEO_CODEC_ERROR; | |
200 } | |
201 | |
202 if (inputImage._frameType == webrtc::kKeyFrame && | |
203 inputImage._encodedWidth != 0 && inputImage._encodedHeight != 0) { | |
204 // Only key frame has the size. | |
205 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight); | |
206 if (size_ != new_size) { | |
207 size_ = new_size; | |
208 decoder_message_loop_->PostTask( | |
209 FROM_HERE, | |
210 base::Bind(&RTCDemuxerStream::UpdateSize, weak_stream_, new_size)); | |
211 } | |
212 } | |
213 scoped_refptr<media::DecoderBuffer> buffer = media::DecoderBuffer::CopyFrom( | |
wuchengli
2013/05/10 15:57:15
Copy is necessary because the buffer will be relea
| |
214 inputImage._buffer, inputImage._length); | |
215 buffer->SetTimestamp(base::TimeDelta::FromInternalValue( | |
216 inputImage._timeStamp)); | |
217 | |
218 decoder_message_loop_->PostTask( | |
219 FROM_HERE, | |
220 base::Bind(&RTCDemuxerStream::QueueBuffer, weak_stream_, buffer)); | |
221 | |
222 if (state_ == kInitialized) { | |
223 state_ = kDecoding; | |
224 decoder_message_loop_->PostTask( | |
225 FROM_HERE, | |
226 base::Bind(&RTCVideoDecoder::RequestFrame, weak_this_)); | |
227 } | |
228 | |
229 return WEBRTC_VIDEO_CODEC_OK; | |
230 } | |
231 | |
232 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback( | |
233 webrtc::DecodedImageCallback* callback) { | |
234 decode_complete_callback_ = callback; | |
235 return WEBRTC_VIDEO_CODEC_OK; | |
236 } | |
237 | |
238 int32_t RTCVideoDecoder::Release() { | |
239 DVLOG(3) << "Release"; | |
240 if (state_ == kUninitialized) { | |
241 LOG(ERROR) << "Decoder not initialized."; | |
242 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
243 } | |
244 decoder_message_loop_->PostTask( | |
245 FROM_HERE, | |
246 base::Bind(&media::VideoDecoder::Stop, | |
247 base::Unretained(video_decoder_.get()), | |
248 base::Bind(&RTCVideoDecoder::ReleaseComplete, weak_this_))); | |
249 decoder_waiter_.Wait(); | |
250 state_ = kUninitialized; | |
251 return WEBRTC_VIDEO_CODEC_OK; | |
252 } | |
253 | |
254 int32_t RTCVideoDecoder::Reset() { | |
255 DVLOG(3) << "Reset"; | |
256 if (state_ == kUninitialized) { | |
257 LOG(ERROR) << "Decoder not initialized."; | |
258 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
259 } | |
260 decoder_message_loop_->PostTask( | |
261 FROM_HERE, | |
262 base::Bind(&media::VideoDecoder::Reset, | |
263 base::Unretained(video_decoder_.get()), | |
264 base::Bind(&RTCVideoDecoder::ResetComplete, weak_this_))); | |
265 decoder_waiter_.Wait(); | |
266 state_ = kInitialized; | |
267 DVLOG(3) << "Reset end"; | |
268 return WEBRTC_VIDEO_CODEC_OK; | |
269 } | |
270 | |
271 void RTCVideoDecoder::OnUpdateStatistics( | |
272 const media::PipelineStatistics& /*stats*/) { | |
273 // We don't use statistics for now. | |
274 } | |
275 | |
276 void RTCVideoDecoder::OnUpdatePipelineStatus( | |
277 const media::PipelineStatus status) { | |
278 DVLOG(3) << "OnUpdatePipelineStatus. status=" << status; | |
279 DCHECK(decoder_message_loop_->BelongsToCurrentThread()); | |
280 pipeline_status_ = status; | |
281 decoder_waiter_.Signal(); | |
282 } | |
283 | |
284 void RTCVideoDecoder::ReleaseComplete() { | |
285 DVLOG(3) << "ReleaseComplete"; | |
286 DCHECK(decoder_message_loop_->BelongsToCurrentThread()); | |
287 stream_->ClearBuffer(); | |
288 decoder_waiter_.Signal(); | |
289 } | |
290 | |
291 void RTCVideoDecoder::ResetComplete() { | |
292 DVLOG(3) << "ResetComplete"; | |
293 DCHECK(decoder_message_loop_->BelongsToCurrentThread()); | |
294 stream_->ClearBuffer(); | |
295 decoder_waiter_.Signal(); | |
296 } | |
297 | |
298 void RTCVideoDecoder::FrameReady( | |
299 media::VideoDecoder::Status status, | |
300 const scoped_refptr<media::VideoFrame>& frame) { | |
301 DCHECK(decoder_message_loop_->BelongsToCurrentThread()); | |
302 DVLOG(3) << "FrameReady. status=" << status; | |
303 | |
304 if (status != media::VideoDecoder::kOk) { | |
305 LOG(ERROR) << "FrameReady error. status=" << status; | |
306 decoding_error_occurred_ = true; | |
307 return; | |
308 } | |
309 gfx::Rect rect = frame->visible_rect(); | |
310 | |
311 webrtc::I420VideoFrame decoded_image; | |
312 decoded_image.CreateEmptyFrame( | |
313 rect.width(), rect.height(), | |
314 rect.width(), rect.width() / 2, rect.width() / 2); | |
315 webrtc::RefCountImpl<NativeHandleImpl>* handle = | |
316 new webrtc::RefCountImpl<NativeHandleImpl>(); | |
317 handle->SetHandle(frame.get()); | |
318 decoded_image.set_native_handle(handle); | |
319 decoded_image.set_timestamp( | |
320 static_cast<uint32_t>(frame->GetTimestamp().InMicroseconds())); | |
321 decode_complete_callback_->Decoded(decoded_image); | |
322 | |
323 if (state_ == kDecoding) { | |
324 video_decoder_->Read(base::Bind(&RTCVideoDecoder::FrameReady, weak_this_)); | |
325 } | |
326 } | |
327 | |
328 void RTCVideoDecoder::RequestFrame() { | |
329 DCHECK(decoder_message_loop_->BelongsToCurrentThread()); | |
330 video_decoder_->Read( | |
331 base::Bind(&RTCVideoDecoder::FrameReady, weak_this_)); | |
332 } | |
333 | |
334 } // namespace content | |
335 | |
OLD | NEW |