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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 decode_threads = std::max(decode_threads, 0); | 54 decode_threads = std::max(decode_threads, 0); |
55 decode_threads = std::min(decode_threads, kMaxDecodeThreads); | 55 decode_threads = std::min(decode_threads, kMaxDecodeThreads); |
56 return decode_threads; | 56 return decode_threads; |
57 } | 57 } |
58 | 58 |
59 VpxVideoDecoder::VpxVideoDecoder( | 59 VpxVideoDecoder::VpxVideoDecoder( |
60 const scoped_refptr<base::MessageLoopProxy>& message_loop) | 60 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
61 : message_loop_(message_loop), | 61 : message_loop_(message_loop), |
62 weak_factory_(this), | 62 weak_factory_(this), |
63 state_(kUninitialized), | 63 state_(kUninitialized), |
64 demuxer_stream_(NULL), | |
65 vpx_codec_(NULL), | 64 vpx_codec_(NULL), |
66 vpx_codec_alpha_(NULL) { | 65 vpx_codec_alpha_(NULL) { |
67 } | 66 } |
68 | 67 |
69 VpxVideoDecoder::~VpxVideoDecoder() { | 68 VpxVideoDecoder::~VpxVideoDecoder() { |
70 DCHECK_EQ(kUninitialized, state_); | 69 DCHECK_EQ(kUninitialized, state_); |
71 CloseDecoder(); | 70 CloseDecoder(); |
72 } | 71 } |
73 | 72 |
74 void VpxVideoDecoder::Initialize( | 73 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, |
75 DemuxerStream* stream, | 74 const PipelineStatusCB& status_cb, |
76 const PipelineStatusCB& status_cb, | 75 const StatisticsCB& statistics_cb) { |
77 const StatisticsCB& statistics_cb) { | |
78 DCHECK(message_loop_->BelongsToCurrentThread()); | 76 DCHECK(message_loop_->BelongsToCurrentThread()); |
79 DCHECK(stream); | 77 DCHECK(config.IsValidConfig()); |
| 78 DCHECK(!config.is_encrypted()); |
80 DCHECK(read_cb_.is_null()); | 79 DCHECK(read_cb_.is_null()); |
81 DCHECK(reset_cb_.is_null()); | 80 DCHECK(reset_cb_.is_null()); |
82 | 81 |
83 weak_this_ = weak_factory_.GetWeakPtr(); | 82 weak_this_ = weak_factory_.GetWeakPtr(); |
84 | 83 |
85 demuxer_stream_ = stream; | 84 if (!ConfigureDecoder(config)) { |
86 statistics_cb_ = statistics_cb; | |
87 | |
88 if (!ConfigureDecoder()) { | |
89 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 85 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
90 return; | 86 return; |
91 } | 87 } |
92 | 88 |
93 // Success! | 89 // Success! |
| 90 config_ = config; |
| 91 statistics_cb_ = statistics_cb; |
94 state_ = kNormal; | 92 state_ = kNormal; |
95 status_cb.Run(PIPELINE_OK); | 93 status_cb.Run(PIPELINE_OK); |
96 } | 94 } |
97 | 95 |
98 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context, | 96 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context, |
99 const VideoDecoderConfig& config) { | 97 const VideoDecoderConfig& config) { |
100 context = new vpx_codec_ctx(); | 98 context = new vpx_codec_ctx(); |
101 vpx_codec_dec_cfg_t vpx_config = {0}; | 99 vpx_codec_dec_cfg_t vpx_config = {0}; |
102 vpx_config.w = config.coded_size().width(); | 100 vpx_config.w = config.coded_size().width(); |
103 vpx_config.h = config.coded_size().height(); | 101 vpx_config.h = config.coded_size().height(); |
104 vpx_config.threads = GetThreadCount(); | 102 vpx_config.threads = GetThreadCount(); |
105 | 103 |
106 vpx_codec_err_t status = vpx_codec_dec_init(context, | 104 vpx_codec_err_t status = vpx_codec_dec_init(context, |
107 config.codec() == kCodecVP9 ? | 105 config.codec() == kCodecVP9 ? |
108 vpx_codec_vp9_dx() : | 106 vpx_codec_vp9_dx() : |
109 vpx_codec_vp8_dx(), | 107 vpx_codec_vp8_dx(), |
110 &vpx_config, | 108 &vpx_config, |
111 0); | 109 0); |
112 if (status != VPX_CODEC_OK) { | 110 if (status != VPX_CODEC_OK) { |
113 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; | 111 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; |
114 delete context; | 112 delete context; |
115 return NULL; | 113 return NULL; |
116 } | 114 } |
117 return context; | 115 return context; |
118 } | 116 } |
119 | 117 |
120 bool VpxVideoDecoder::ConfigureDecoder() { | 118 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) { |
121 const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config(); | |
122 DCHECK(config.IsValidConfig()); | |
123 | |
124 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 119 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
125 bool can_handle = false; | 120 bool can_handle = false; |
126 if (cmd_line->HasSwitch(switches::kEnableVp9Playback) && | 121 if (cmd_line->HasSwitch(switches::kEnableVp9Playback) && |
127 config.codec() == kCodecVP9) { | 122 config.codec() == kCodecVP9) { |
128 can_handle = true; | 123 can_handle = true; |
129 } | 124 } |
130 if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) && | 125 if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) && |
131 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) { | 126 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) { |
132 can_handle = true; | 127 can_handle = true; |
133 } | 128 } |
(...skipping 21 matching lines...) Expand all Loading... |
155 delete vpx_codec_; | 150 delete vpx_codec_; |
156 vpx_codec_ = NULL; | 151 vpx_codec_ = NULL; |
157 } | 152 } |
158 if (vpx_codec_alpha_) { | 153 if (vpx_codec_alpha_) { |
159 vpx_codec_destroy(vpx_codec_alpha_); | 154 vpx_codec_destroy(vpx_codec_alpha_); |
160 delete vpx_codec_alpha_; | 155 delete vpx_codec_alpha_; |
161 vpx_codec_alpha_ = NULL; | 156 vpx_codec_alpha_ = NULL; |
162 } | 157 } |
163 } | 158 } |
164 | 159 |
165 void VpxVideoDecoder::Read(const ReadCB& read_cb) { | 160 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| 161 const ReadCB& read_cb) { |
166 DCHECK(message_loop_->BelongsToCurrentThread()); | 162 DCHECK(message_loop_->BelongsToCurrentThread()); |
167 DCHECK(!read_cb.is_null()); | 163 DCHECK(!read_cb.is_null()); |
168 CHECK_NE(state_, kUninitialized); | 164 CHECK_NE(state_, kUninitialized); |
169 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 165 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; |
| 166 |
170 read_cb_ = BindToCurrentLoop(read_cb); | 167 read_cb_ = BindToCurrentLoop(read_cb); |
171 | 168 |
172 if (state_ == kError) { | 169 if (state_ == kError) { |
173 read_cb.Run(kDecodeError, NULL); | 170 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
174 return; | 171 return; |
175 } | 172 } |
176 | 173 |
177 // Return empty frames if decoding has finished. | 174 // Return empty frames if decoding has finished. |
178 if (state_ == kDecodeFinished) { | 175 if (state_ == kDecodeFinished) { |
179 read_cb.Run(kOk, VideoFrame::CreateEmptyFrame()); | 176 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); |
180 return; | 177 return; |
181 } | 178 } |
182 | 179 |
183 ReadFromDemuxerStream(); | 180 DecodeBuffer(buffer); |
184 } | 181 } |
185 | 182 |
186 void VpxVideoDecoder::Reset(const base::Closure& closure) { | 183 void VpxVideoDecoder::Reset(const base::Closure& closure) { |
187 DCHECK(message_loop_->BelongsToCurrentThread()); | 184 DCHECK(message_loop_->BelongsToCurrentThread()); |
188 DCHECK(reset_cb_.is_null()); | 185 DCHECK(reset_cb_.is_null()); |
189 reset_cb_ = BindToCurrentLoop(closure); | 186 reset_cb_ = BindToCurrentLoop(closure); |
190 | 187 |
191 // Defer the reset if a read is pending. | 188 // Defer the reset if a read is pending. |
192 if (!read_cb_.is_null()) | 189 if (!read_cb_.is_null()) |
193 return; | 190 return; |
194 | 191 |
195 DoReset(); | 192 DoReset(); |
196 } | 193 } |
197 | 194 |
198 void VpxVideoDecoder::Stop(const base::Closure& closure) { | 195 void VpxVideoDecoder::Stop(const base::Closure& closure) { |
199 DCHECK(message_loop_->BelongsToCurrentThread()); | 196 DCHECK(message_loop_->BelongsToCurrentThread()); |
200 | 197 |
201 if (state_ == kUninitialized) { | 198 if (state_ == kUninitialized) { |
202 closure.Run(); | 199 closure.Run(); |
203 return; | 200 return; |
204 } | 201 } |
205 | 202 |
206 if (!read_cb_.is_null()) | 203 if (!read_cb_.is_null()) |
207 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); | 204 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); |
208 | 205 |
209 state_ = kUninitialized; | 206 state_ = kUninitialized; |
210 closure.Run(); | 207 closure.Run(); |
211 } | 208 } |
212 | 209 |
213 void VpxVideoDecoder::ReadFromDemuxerStream() { | 210 void VpxVideoDecoder::DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) { |
214 DCHECK_NE(state_, kUninitialized); | |
215 DCHECK_NE(state_, kDecodeFinished); | |
216 DCHECK_NE(state_, kError); | |
217 DCHECK(!read_cb_.is_null()); | |
218 | |
219 demuxer_stream_->Read(base::Bind( | |
220 &VpxVideoDecoder::DoDecryptOrDecodeBuffer, weak_this_)); | |
221 } | |
222 | |
223 void VpxVideoDecoder::DoDecryptOrDecodeBuffer( | |
224 DemuxerStream::Status status, | |
225 const scoped_refptr<DecoderBuffer>& buffer) { | |
226 DCHECK(message_loop_->BelongsToCurrentThread()); | |
227 DCHECK_NE(state_, kDecodeFinished); | |
228 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; | |
229 | |
230 if (state_ == kUninitialized) | |
231 return; | |
232 | |
233 DCHECK(!read_cb_.is_null()); | |
234 | |
235 if (!reset_cb_.is_null()) { | |
236 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); | |
237 DoReset(); | |
238 return; | |
239 } | |
240 | |
241 if (status == DemuxerStream::kAborted) { | |
242 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); | |
243 return; | |
244 } | |
245 | |
246 // VideoFrameStream ensures no kConfigChanged is passed to VideoDecoders. | |
247 DCHECK_EQ(status, DemuxerStream::kOk) << status; | |
248 DecodeBuffer(buffer); | |
249 } | |
250 | |
251 void VpxVideoDecoder::DecodeBuffer( | |
252 const scoped_refptr<DecoderBuffer>& buffer) { | |
253 DCHECK(message_loop_->BelongsToCurrentThread()); | 211 DCHECK(message_loop_->BelongsToCurrentThread()); |
254 DCHECK_NE(state_, kUninitialized); | 212 DCHECK_NE(state_, kUninitialized); |
255 DCHECK_NE(state_, kDecodeFinished); | 213 DCHECK_NE(state_, kDecodeFinished); |
256 DCHECK_NE(state_, kError); | 214 DCHECK_NE(state_, kError); |
257 DCHECK(reset_cb_.is_null()); | 215 DCHECK(reset_cb_.is_null()); |
258 DCHECK(!read_cb_.is_null()); | 216 DCHECK(!read_cb_.is_null()); |
259 DCHECK(buffer); | |
260 | 217 |
261 // Transition to kDecodeFinished on the first end of stream buffer. | 218 // Transition to kDecodeFinished on the first end of stream buffer. |
262 if (state_ == kNormal && buffer->IsEndOfStream()) { | 219 if (state_ == kNormal && buffer->IsEndOfStream()) { |
263 state_ = kDecodeFinished; | 220 state_ = kDecodeFinished; |
264 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); | 221 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); |
265 return; | 222 return; |
266 } | 223 } |
267 | 224 |
268 scoped_refptr<VideoFrame> video_frame; | 225 scoped_refptr<VideoFrame> video_frame; |
269 if (!Decode(buffer, &video_frame)) { | 226 if (!VpxDecode(buffer, &video_frame)) { |
270 state_ = kError; | 227 state_ = kError; |
271 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 228 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
272 return; | 229 return; |
273 } | 230 } |
274 | 231 |
275 // Any successful decode counts! | 232 // Any successful decode counts! |
276 if (buffer->GetDataSize() && buffer->GetSideDataSize()) { | 233 if (buffer->GetDataSize() && buffer->GetSideDataSize()) { |
277 PipelineStatistics statistics; | 234 PipelineStatistics statistics; |
278 statistics.video_bytes_decoded = buffer->GetDataSize(); | 235 statistics.video_bytes_decoded = buffer->GetDataSize(); |
279 statistics_cb_.Run(statistics); | 236 statistics_cb_.Run(statistics); |
280 } | 237 } |
281 | 238 |
282 // If we didn't get a frame we need more data. | |
283 if (!video_frame) { | 239 if (!video_frame) { |
284 ReadFromDemuxerStream(); | 240 base::ResetAndReturn(&read_cb_).Run(kNotEnoughData, NULL); |
285 return; | 241 return; |
286 } | 242 } |
287 | 243 |
288 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); | 244 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); |
289 } | 245 } |
290 | 246 |
291 bool VpxVideoDecoder::Decode( | 247 bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer, |
292 const scoped_refptr<DecoderBuffer>& buffer, | 248 scoped_refptr<VideoFrame>* video_frame) { |
293 scoped_refptr<VideoFrame>* video_frame) { | |
294 DCHECK(video_frame); | 249 DCHECK(video_frame); |
295 DCHECK(!buffer->IsEndOfStream()); | 250 DCHECK(!buffer->IsEndOfStream()); |
296 | 251 |
297 // Pass |buffer| to libvpx. | 252 // Pass |buffer| to libvpx. |
298 int64 timestamp = buffer->GetTimestamp().InMicroseconds(); | 253 int64 timestamp = buffer->GetTimestamp().InMicroseconds(); |
299 void* user_priv = reinterpret_cast<void*>(×tamp); | 254 void* user_priv = reinterpret_cast<void*>(×tamp); |
300 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, | 255 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, |
301 buffer->GetData(), | 256 buffer->GetData(), |
302 buffer->GetDataSize(), | 257 buffer->GetDataSize(), |
303 user_priv, | 258 user_priv, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 } | 318 } |
364 | 319 |
365 void VpxVideoDecoder::DoReset() { | 320 void VpxVideoDecoder::DoReset() { |
366 DCHECK(read_cb_.is_null()); | 321 DCHECK(read_cb_.is_null()); |
367 | 322 |
368 state_ = kNormal; | 323 state_ = kNormal; |
369 reset_cb_.Run(); | 324 reset_cb_.Run(); |
370 reset_cb_.Reset(); | 325 reset_cb_.Reset(); |
371 } | 326 } |
372 | 327 |
373 void VpxVideoDecoder::CopyVpxImageTo( | 328 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, |
374 const vpx_image* vpx_image, | 329 const struct vpx_image* vpx_image_alpha, |
375 const struct vpx_image* vpx_image_alpha, | 330 scoped_refptr<VideoFrame>* video_frame) { |
376 scoped_refptr<VideoFrame>* video_frame) { | |
377 CHECK(vpx_image); | 331 CHECK(vpx_image); |
378 CHECK_EQ(vpx_image->d_w % 2, 0U); | 332 CHECK_EQ(vpx_image->d_w % 2, 0U); |
379 CHECK_EQ(vpx_image->d_h % 2, 0U); | 333 CHECK_EQ(vpx_image->d_h % 2, 0U); |
380 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || | 334 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || |
381 vpx_image->fmt == VPX_IMG_FMT_YV12); | 335 vpx_image->fmt == VPX_IMG_FMT_YV12); |
382 | 336 |
383 gfx::Size size(vpx_image->d_w, vpx_image->d_h); | 337 gfx::Size size(vpx_image->d_w, vpx_image->d_h); |
384 gfx::Size natural_size = | |
385 demuxer_stream_->video_decoder_config().natural_size(); | |
386 | 338 |
387 *video_frame = VideoFrame::CreateFrame(vpx_codec_alpha_ ? | 339 *video_frame = VideoFrame::CreateFrame( |
388 VideoFrame::YV12A : | 340 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, |
389 VideoFrame::YV12, | 341 size, |
390 size, | 342 gfx::Rect(size), |
391 gfx::Rect(size), | 343 config_.natural_size(), |
392 natural_size, | 344 kNoTimestamp()); |
393 kNoTimestamp()); | |
394 | 345 |
395 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], | 346 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], |
396 vpx_image->stride[VPX_PLANE_Y], | 347 vpx_image->stride[VPX_PLANE_Y], |
397 vpx_image->d_h, | 348 vpx_image->d_h, |
398 *video_frame); | 349 *video_frame); |
399 CopyUPlane(vpx_image->planes[VPX_PLANE_U], | 350 CopyUPlane(vpx_image->planes[VPX_PLANE_U], |
400 vpx_image->stride[VPX_PLANE_U], | 351 vpx_image->stride[VPX_PLANE_U], |
401 vpx_image->d_h / 2, | 352 vpx_image->d_h / 2, |
402 *video_frame); | 353 *video_frame); |
403 CopyVPlane(vpx_image->planes[VPX_PLANE_V], | 354 CopyVPlane(vpx_image->planes[VPX_PLANE_V], |
404 vpx_image->stride[VPX_PLANE_V], | 355 vpx_image->stride[VPX_PLANE_V], |
405 vpx_image->d_h / 2, | 356 vpx_image->d_h / 2, |
406 *video_frame); | 357 *video_frame); |
| 358 |
407 if (!vpx_codec_alpha_) | 359 if (!vpx_codec_alpha_) |
408 return; | 360 return; |
| 361 |
409 if (!vpx_image_alpha) { | 362 if (!vpx_image_alpha) { |
410 MakeOpaqueAPlane(vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, | 363 MakeOpaqueAPlane( |
411 *video_frame); | 364 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, *video_frame); |
412 return; | 365 return; |
413 } | 366 } |
| 367 |
414 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], | 368 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], |
415 vpx_image->stride[VPX_PLANE_Y], | 369 vpx_image->stride[VPX_PLANE_Y], |
416 vpx_image->d_h, | 370 vpx_image->d_h, |
417 *video_frame); | 371 *video_frame); |
418 } | 372 } |
419 | 373 |
420 } // namespace media | 374 } // namespace media |
OLD | NEW |