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