OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/filters/vpx_video_decoder.h" | 5 #include "media/filters/vpx_video_decoder.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 VpxVideoDecoder::~VpxVideoDecoder() { | 71 VpxVideoDecoder::~VpxVideoDecoder() { |
72 DCHECK_EQ(kUninitialized, state_); | 72 DCHECK_EQ(kUninitialized, state_); |
73 CloseDecoder(); | 73 CloseDecoder(); |
74 } | 74 } |
75 | 75 |
76 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, | 76 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, |
77 const PipelineStatusCB& status_cb) { | 77 const PipelineStatusCB& status_cb) { |
78 DCHECK(message_loop_->BelongsToCurrentThread()); | 78 DCHECK(message_loop_->BelongsToCurrentThread()); |
79 DCHECK(config.IsValidConfig()); | 79 DCHECK(config.IsValidConfig()); |
80 DCHECK(!config.is_encrypted()); | 80 DCHECK(!config.is_encrypted()); |
81 DCHECK(read_cb_.is_null()); | 81 DCHECK(decode_cb_.is_null()); |
82 DCHECK(reset_cb_.is_null()); | 82 DCHECK(reset_cb_.is_null()); |
83 | 83 |
84 weak_this_ = weak_factory_.GetWeakPtr(); | 84 weak_this_ = weak_factory_.GetWeakPtr(); |
85 | 85 |
86 if (!ConfigureDecoder(config)) { | 86 if (!ConfigureDecoder(config)) { |
87 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 87 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
88 return; | 88 return; |
89 } | 89 } |
90 | 90 |
91 // Success! | 91 // Success! |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 vpx_codec_ = NULL; | 150 vpx_codec_ = NULL; |
151 } | 151 } |
152 if (vpx_codec_alpha_) { | 152 if (vpx_codec_alpha_) { |
153 vpx_codec_destroy(vpx_codec_alpha_); | 153 vpx_codec_destroy(vpx_codec_alpha_); |
154 delete vpx_codec_alpha_; | 154 delete vpx_codec_alpha_; |
155 vpx_codec_alpha_ = NULL; | 155 vpx_codec_alpha_ = NULL; |
156 } | 156 } |
157 } | 157 } |
158 | 158 |
159 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 159 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
160 const ReadCB& read_cb) { | 160 const DecodeCB& decode_cb) { |
161 DCHECK(message_loop_->BelongsToCurrentThread()); | 161 DCHECK(message_loop_->BelongsToCurrentThread()); |
162 DCHECK(!read_cb.is_null()); | 162 DCHECK(!decode_cb.is_null()); |
163 CHECK_NE(state_, kUninitialized); | 163 CHECK_NE(state_, kUninitialized); |
164 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 164 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported."; |
165 | 165 |
166 read_cb_ = BindToCurrentLoop(read_cb); | 166 decode_cb_ = BindToCurrentLoop(decode_cb); |
167 | 167 |
168 if (state_ == kError) { | 168 if (state_ == kError) { |
169 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 169 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); |
170 return; | 170 return; |
171 } | 171 } |
172 | 172 |
173 // Return empty frames if decoding has finished. | 173 // Return empty frames if decoding has finished. |
174 if (state_ == kDecodeFinished) { | 174 if (state_ == kDecodeFinished) { |
175 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); | 175 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); |
176 return; | 176 return; |
177 } | 177 } |
178 | 178 |
179 DecodeBuffer(buffer); | 179 DecodeBuffer(buffer); |
180 } | 180 } |
181 | 181 |
182 void VpxVideoDecoder::Reset(const base::Closure& closure) { | 182 void VpxVideoDecoder::Reset(const base::Closure& closure) { |
183 DCHECK(message_loop_->BelongsToCurrentThread()); | 183 DCHECK(message_loop_->BelongsToCurrentThread()); |
184 DCHECK(reset_cb_.is_null()); | 184 DCHECK(reset_cb_.is_null()); |
185 reset_cb_ = BindToCurrentLoop(closure); | 185 reset_cb_ = BindToCurrentLoop(closure); |
186 | 186 |
187 // Defer the reset if a read is pending. | 187 // Defer the reset if a decode is pending. |
188 if (!read_cb_.is_null()) | 188 if (!decode_cb_.is_null()) |
189 return; | 189 return; |
190 | 190 |
191 DoReset(); | 191 DoReset(); |
192 } | 192 } |
193 | 193 |
194 void VpxVideoDecoder::Stop(const base::Closure& closure) { | 194 void VpxVideoDecoder::Stop(const base::Closure& closure) { |
195 DCHECK(message_loop_->BelongsToCurrentThread()); | 195 DCHECK(message_loop_->BelongsToCurrentThread()); |
196 base::ScopedClosureRunner runner(BindToCurrentLoop(closure)); | 196 base::ScopedClosureRunner runner(BindToCurrentLoop(closure)); |
197 | 197 |
198 if (state_ == kUninitialized) | 198 if (state_ == kUninitialized) |
199 return; | 199 return; |
200 | 200 |
201 if (!read_cb_.is_null()) { | 201 if (!decode_cb_.is_null()) { |
202 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); | 202 base::ResetAndReturn(&decode_cb_).Run(kOk, NULL); |
203 // Reset is pending only when read is pending. | 203 // Reset is pending only when decode is pending. |
204 if (!reset_cb_.is_null()) | 204 if (!reset_cb_.is_null()) |
205 base::ResetAndReturn(&reset_cb_).Run(); | 205 base::ResetAndReturn(&reset_cb_).Run(); |
206 } | 206 } |
207 | 207 |
208 state_ = kUninitialized; | 208 state_ = kUninitialized; |
209 } | 209 } |
210 | 210 |
211 bool VpxVideoDecoder::HasAlpha() const { | 211 bool VpxVideoDecoder::HasAlpha() const { |
212 return vpx_codec_alpha_ != NULL; | 212 return vpx_codec_alpha_ != NULL; |
213 } | 213 } |
214 | 214 |
215 void VpxVideoDecoder::DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) { | 215 void VpxVideoDecoder::DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) { |
216 DCHECK(message_loop_->BelongsToCurrentThread()); | 216 DCHECK(message_loop_->BelongsToCurrentThread()); |
217 DCHECK_NE(state_, kUninitialized); | 217 DCHECK_NE(state_, kUninitialized); |
218 DCHECK_NE(state_, kDecodeFinished); | 218 DCHECK_NE(state_, kDecodeFinished); |
219 DCHECK_NE(state_, kError); | 219 DCHECK_NE(state_, kError); |
220 DCHECK(reset_cb_.is_null()); | 220 DCHECK(reset_cb_.is_null()); |
221 DCHECK(!read_cb_.is_null()); | 221 DCHECK(!decode_cb_.is_null()); |
222 DCHECK(buffer); | 222 DCHECK(buffer); |
223 | 223 |
224 // Transition to kDecodeFinished on the first end of stream buffer. | 224 // Transition to kDecodeFinished on the first end of stream buffer. |
225 if (state_ == kNormal && buffer->end_of_stream()) { | 225 if (state_ == kNormal && buffer->end_of_stream()) { |
226 state_ = kDecodeFinished; | 226 state_ = kDecodeFinished; |
227 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); | 227 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); |
228 return; | 228 return; |
229 } | 229 } |
230 | 230 |
231 scoped_refptr<VideoFrame> video_frame; | 231 scoped_refptr<VideoFrame> video_frame; |
232 if (!VpxDecode(buffer, &video_frame)) { | 232 if (!VpxDecode(buffer, &video_frame)) { |
233 state_ = kError; | 233 state_ = kError; |
234 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 234 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); |
235 return; | 235 return; |
236 } | 236 } |
237 | 237 |
238 // If we didn't get a frame we need more data. | 238 // If we didn't get a frame we need more data. |
239 if (!video_frame.get()) { | 239 if (!video_frame.get()) { |
240 base::ResetAndReturn(&read_cb_).Run(kNotEnoughData, NULL); | 240 base::ResetAndReturn(&decode_cb_).Run(kNotEnoughData, NULL); |
241 return; | 241 return; |
242 } | 242 } |
243 | 243 |
244 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); | 244 base::ResetAndReturn(&decode_cb_).Run(kOk, video_frame); |
245 } | 245 } |
246 | 246 |
247 bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer, | 247 bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer, |
248 scoped_refptr<VideoFrame>* video_frame) { | 248 scoped_refptr<VideoFrame>* video_frame) { |
249 DCHECK(video_frame); | 249 DCHECK(video_frame); |
250 DCHECK(!buffer->end_of_stream()); | 250 DCHECK(!buffer->end_of_stream()); |
251 | 251 |
252 // Pass |buffer| to libvpx. | 252 // Pass |buffer| to libvpx. |
253 int64 timestamp = buffer->timestamp().InMicroseconds(); | 253 int64 timestamp = buffer->timestamp().InMicroseconds(); |
254 void* user_priv = reinterpret_cast<void*>(×tamp); | 254 void* user_priv = reinterpret_cast<void*>(×tamp); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 } | 311 } |
312 } | 312 } |
313 } | 313 } |
314 | 314 |
315 CopyVpxImageTo(vpx_image, vpx_image_alpha, video_frame); | 315 CopyVpxImageTo(vpx_image, vpx_image_alpha, video_frame); |
316 (*video_frame)->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp)); | 316 (*video_frame)->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp)); |
317 return true; | 317 return true; |
318 } | 318 } |
319 | 319 |
320 void VpxVideoDecoder::DoReset() { | 320 void VpxVideoDecoder::DoReset() { |
321 DCHECK(read_cb_.is_null()); | 321 DCHECK(decode_cb_.is_null()); |
322 | 322 |
323 state_ = kNormal; | 323 state_ = kNormal; |
324 reset_cb_.Run(); | 324 reset_cb_.Run(); |
325 reset_cb_.Reset(); | 325 reset_cb_.Reset(); |
326 } | 326 } |
327 | 327 |
328 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, | 328 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, |
329 const struct vpx_image* vpx_image_alpha, | 329 const struct vpx_image* vpx_image_alpha, |
330 scoped_refptr<VideoFrame>* video_frame) { | 330 scoped_refptr<VideoFrame>* video_frame) { |
331 CHECK(vpx_image); | 331 CHECK(vpx_image); |
(...skipping 30 matching lines...) Expand all Loading... |
362 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); | 362 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); |
363 return; | 363 return; |
364 } | 364 } |
365 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], | 365 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], |
366 vpx_image->stride[VPX_PLANE_Y], | 366 vpx_image->stride[VPX_PLANE_Y], |
367 vpx_image->d_h, | 367 vpx_image->d_h, |
368 video_frame->get()); | 368 video_frame->get()); |
369 } | 369 } |
370 | 370 |
371 } // namespace media | 371 } // namespace media |
OLD | NEW |