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 "webkit/media/crypto/ppapi/ffmpeg_cdm_video_decoder.h" | 5 #include "webkit/media/crypto/ppapi/ffmpeg_cdm_video_decoder.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "media/base/buffers.h" | 9 #include "media/base/buffers.h" |
10 #include "media/base/limits.h" | 10 #include "media/base/limits.h" |
11 #include "webkit/media/crypto/ppapi/content_decryption_module.h" | 11 #include "webkit/media/crypto/ppapi/content_decryption_module.h" |
12 | 12 |
13 // Include FFmpeg header files. | 13 // Include FFmpeg header files. |
14 extern "C" { | 14 extern "C" { |
15 // Temporarily disable possible loss of data warning. | 15 // Temporarily disable possible loss of data warning. |
16 MSVC_PUSH_DISABLE_WARNING(4244); | 16 MSVC_PUSH_DISABLE_WARNING(4244); |
17 #include <libavcodec/avcodec.h> | 17 #include <libavcodec/avcodec.h> |
18 MSVC_POP_WARNING(); | 18 MSVC_POP_WARNING(); |
19 } // extern "C" | 19 } // extern "C" |
20 | 20 |
21 // TODO(tomfinegan): Move libvpx decode support somewhere else. Another ifdef | |
22 // is a crime against humanity etc etc... | |
23 #define USE_LIBVPX 1 | |
24 | |
25 #if defined (USE_LIBVPX) | |
26 // Include libvpx header files. | |
27 extern "C" { | |
28 #define VPX_CODEC_DISABLE_COMPAT 1 | |
29 #include "third_party/libvpx/libvpx.h" | |
30 } | |
31 #endif | |
32 | |
33 // TODO(tomfinegan): I'm seeing bad video output, so I put in code w/memcpy's | |
34 // instead of using |CopyPlane()| to try to figure out what was going on. Turns | |
35 // out video output is bad with or without libvpx in the mix. I've left this | |
36 // mess here because full plane copies are what the stuff we're comparing | |
37 // against does, so maybe it's of some use... | |
xhwang
2012/11/16 17:33:02
Is this what you are seeing? http://code.google.co
Tom Finegan
2012/11/16 19:36:51
Yeah, that's the problem. Things look fine with --
| |
38 // #define USE_COPYPLANE_WITH_LIBVPX 1 | |
39 | |
21 namespace webkit_media { | 40 namespace webkit_media { |
22 | 41 |
23 static const int kDecodeThreads = 1; | 42 static const int kDecodeThreads = 1; |
24 | 43 |
25 static cdm::VideoFormat PixelFormatToCdmVideoFormat(PixelFormat pixel_format) { | 44 static cdm::VideoFormat PixelFormatToCdmVideoFormat(PixelFormat pixel_format) { |
26 switch (pixel_format) { | 45 switch (pixel_format) { |
27 case PIX_FMT_YUV420P: | 46 case PIX_FMT_YUV420P: |
28 return cdm::kYv12; | 47 return cdm::kYv12; |
29 default: | 48 default: |
30 DVLOG(1) << "Unsupported PixelFormat: " << pixel_format; | 49 DVLOG(1) << "Unsupported PixelFormat: " << pixel_format; |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 memcpy(target + target_offset, | 145 memcpy(target + target_offset, |
127 source + source_offset, | 146 source + source_offset, |
128 copy_bytes_per_row); | 147 copy_bytes_per_row); |
129 } | 148 } |
130 } | 149 } |
131 | 150 |
132 FFmpegCdmVideoDecoder::FFmpegCdmVideoDecoder(cdm::Allocator* allocator) | 151 FFmpegCdmVideoDecoder::FFmpegCdmVideoDecoder(cdm::Allocator* allocator) |
133 : codec_context_(NULL), | 152 : codec_context_(NULL), |
134 av_frame_(NULL), | 153 av_frame_(NULL), |
135 is_initialized_(false), | 154 is_initialized_(false), |
136 allocator_(allocator) { | 155 allocator_(allocator), |
156 vpx_codec_(NULL), | |
157 vpx_image_(NULL) { | |
137 } | 158 } |
138 | 159 |
139 FFmpegCdmVideoDecoder::~FFmpegCdmVideoDecoder() { | 160 FFmpegCdmVideoDecoder::~FFmpegCdmVideoDecoder() { |
140 ReleaseFFmpegResources(); | 161 ReleaseFFmpegResources(); |
141 } | 162 } |
142 | 163 |
143 bool FFmpegCdmVideoDecoder::Initialize(const cdm::VideoDecoderConfig& config) { | 164 bool FFmpegCdmVideoDecoder::Initialize(const cdm::VideoDecoderConfig& config) { |
144 DVLOG(1) << "Initialize()"; | 165 DVLOG(1) << "Initialize()"; |
145 | 166 |
146 if (!IsValidOutputConfig(config.format, config.coded_size)) { | 167 if (!IsValidOutputConfig(config.format, config.coded_size)) { |
147 LOG(ERROR) << "Initialize(): invalid video decoder configuration."; | 168 LOG(ERROR) << "Initialize(): invalid video decoder configuration."; |
148 return false; | 169 return false; |
149 } | 170 } |
150 | 171 |
151 if (is_initialized_) { | 172 if (is_initialized_) { |
152 LOG(ERROR) << "Initialize(): Already initialized."; | 173 LOG(ERROR) << "Initialize(): Already initialized."; |
153 return false; | 174 return false; |
154 } | 175 } |
155 | 176 |
156 // Initialize AVCodecContext structure. | 177 // TODO(tomfinegan): Move libvpx decode support somewhere else. |
157 codec_context_ = avcodec_alloc_context3(NULL); | 178 #if defined(USE_LIBVPX) |
158 CdmVideoDecoderConfigToAVCodecContext(config, codec_context_); | 179 if (config.codec == cdm::VideoDecoderConfig::kCodecVp8) { |
180 return InitializeLibvpx(config); | |
181 } | |
182 #endif | |
159 | 183 |
160 // Enable motion vector search (potentially slow), strong deblocking filter | 184 return InitializeFFmpeg(config); |
161 // for damaged macroblocks, and set our error detection sensitivity. | |
162 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; | |
163 codec_context_->err_recognition = AV_EF_CAREFUL; | |
164 codec_context_->thread_count = kDecodeThreads; | |
165 codec_context_->opaque = this; | |
166 codec_context_->flags |= CODEC_FLAG_EMU_EDGE; | |
167 | |
168 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); | |
169 if (!codec) { | |
170 LOG(ERROR) << "Initialize(): avcodec_find_decoder failed."; | |
171 return false; | |
172 } | |
173 | |
174 int status; | |
175 if ((status = avcodec_open2(codec_context_, codec, NULL)) < 0) { | |
176 LOG(ERROR) << "Initialize(): avcodec_open2 failed: " << status; | |
177 return false; | |
178 } | |
179 | |
180 av_frame_ = avcodec_alloc_frame(); | |
181 is_initialized_ = true; | |
182 | |
183 return true; | |
184 } | 185 } |
185 | 186 |
186 void FFmpegCdmVideoDecoder::Deinitialize() { | 187 void FFmpegCdmVideoDecoder::Deinitialize() { |
187 DVLOG(1) << "Deinitialize()"; | 188 DVLOG(1) << "Deinitialize()"; |
188 ReleaseFFmpegResources(); | 189 ReleaseFFmpegResources(); |
190 | |
191 if (vpx_codec_) { | |
192 vpx_codec_destroy(vpx_codec_); | |
193 vpx_codec_ = NULL; | |
194 } | |
195 | |
189 is_initialized_ = false; | 196 is_initialized_ = false; |
190 } | 197 } |
191 | 198 |
192 void FFmpegCdmVideoDecoder::Reset() { | 199 void FFmpegCdmVideoDecoder::Reset() { |
193 DVLOG(1) << "Reset()"; | 200 DVLOG(1) << "Reset()"; |
194 avcodec_flush_buffers(codec_context_); | 201 |
202 if (codec_context_) | |
203 avcodec_flush_buffers(codec_context_); | |
195 } | 204 } |
196 | 205 |
197 // static | 206 // static |
198 bool FFmpegCdmVideoDecoder::IsValidOutputConfig(cdm::VideoFormat format, | 207 bool FFmpegCdmVideoDecoder::IsValidOutputConfig(cdm::VideoFormat format, |
199 const cdm::Size& data_size) { | 208 const cdm::Size& data_size) { |
200 return ((format == cdm::kYv12 || format == cdm::kI420) && | 209 return ((format == cdm::kYv12 || format == cdm::kI420) && |
201 (data_size.width % 2) == 0 && (data_size.height % 2) == 0 && | 210 (data_size.width % 2) == 0 && (data_size.height % 2) == 0 && |
202 data_size.width > 0 && data_size.height > 0 && | 211 data_size.width > 0 && data_size.height > 0 && |
203 data_size.width <= media::limits::kMaxDimension && | 212 data_size.width <= media::limits::kMaxDimension && |
204 data_size.height <= media::limits::kMaxDimension && | 213 data_size.height <= media::limits::kMaxDimension && |
205 data_size.width * data_size.height <= media::limits::kMaxCanvas); | 214 data_size.width * data_size.height <= media::limits::kMaxCanvas); |
206 } | 215 } |
207 | 216 |
208 cdm::Status FFmpegCdmVideoDecoder::DecodeFrame( | 217 cdm::Status FFmpegCdmVideoDecoder::DecodeFrame( |
209 const uint8_t* compressed_frame, | 218 const uint8_t* compressed_frame, |
210 int32_t compressed_frame_size, | 219 int32_t compressed_frame_size, |
211 int64_t timestamp, | 220 int64_t timestamp, |
212 cdm::VideoFrame* decoded_frame) { | 221 cdm::VideoFrame* decoded_frame) { |
213 DVLOG(1) << "DecodeFrame()"; | |
214 DCHECK(decoded_frame); | 222 DCHECK(decoded_frame); |
215 | 223 |
216 // Create a packet for input data. | 224 // TODO(tomfinegan): Move libvpx decode support somewhere else. |
217 AVPacket packet; | 225 #if defined(USE_LIBVPX) |
218 av_init_packet(&packet); | 226 if (vpx_codec_) { |
227 return DecodeFrameLibvpx(compressed_frame, compressed_frame_size, | |
228 timestamp, | |
229 decoded_frame); | |
230 } | |
231 #endif | |
219 | 232 |
220 // The FFmpeg API does not allow us to have const read-only pointers. | 233 return DecodeFrameFFmpeg(compressed_frame, compressed_frame_size, timestamp, |
221 packet.data = const_cast<uint8_t*>(compressed_frame); | 234 decoded_frame); |
222 packet.size = compressed_frame_size; | |
223 | |
224 // Let FFmpeg handle presentation timestamp reordering. | |
225 codec_context_->reordered_opaque = timestamp; | |
226 | |
227 // Reset frame to default values. | |
228 avcodec_get_frame_defaults(av_frame_); | |
229 | |
230 // This is for codecs not using get_buffer to initialize | |
231 // |av_frame_->reordered_opaque| | |
232 av_frame_->reordered_opaque = codec_context_->reordered_opaque; | |
233 | |
234 int frame_decoded = 0; | |
235 int result = avcodec_decode_video2(codec_context_, | |
236 av_frame_, | |
237 &frame_decoded, | |
238 &packet); | |
239 // Log the problem when we can't decode a video frame and exit early. | |
240 if (result < 0) { | |
241 LOG(ERROR) << "DecodeFrame(): Error decoding video frame with timestamp: " | |
242 << timestamp << " us, packet size: " << packet.size << " bytes"; | |
243 return cdm::kDecodeError; | |
244 } | |
245 | |
246 // If no frame was produced then signal that more data is required to produce | |
247 // more frames. | |
248 if (frame_decoded == 0) | |
249 return cdm::kNeedMoreData; | |
250 | |
251 // The decoder is in a bad state and not decoding correctly. | |
252 // Checking for NULL avoids a crash. | |
253 if (!av_frame_->data[cdm::VideoFrame::kYPlane] || | |
254 !av_frame_->data[cdm::VideoFrame::kUPlane] || | |
255 !av_frame_->data[cdm::VideoFrame::kVPlane]) { | |
256 LOG(ERROR) << "DecodeFrame(): Video frame has invalid frame data."; | |
257 return cdm::kDecodeError; | |
258 } | |
259 | |
260 if (!CopyAvFrameTo(decoded_frame)) { | |
261 LOG(ERROR) << "DecodeFrame() could not copy video frame to output buffer."; | |
262 return cdm::kDecodeError; | |
263 } | |
264 | |
265 return cdm::kSuccess; | |
266 } | 235 } |
267 | 236 |
268 bool FFmpegCdmVideoDecoder::CopyAvFrameTo(cdm::VideoFrame* cdm_video_frame) { | 237 bool FFmpegCdmVideoDecoder::CopyAvFrameTo(cdm::VideoFrame* cdm_video_frame) { |
269 DCHECK(cdm_video_frame); | 238 DCHECK(cdm_video_frame); |
270 DCHECK_EQ(av_frame_->format, PIX_FMT_YUV420P); | 239 DCHECK_EQ(av_frame_->format, PIX_FMT_YUV420P); |
271 DCHECK_EQ(av_frame_->width % 2, 0); | 240 DCHECK_EQ(av_frame_->width % 2, 0); |
272 DCHECK_EQ(av_frame_->height % 2, 0); | 241 DCHECK_EQ(av_frame_->height % 2, 0); |
273 | 242 |
274 const int y_size = av_frame_->width * av_frame_->height; | 243 const int y_size = av_frame_->width * av_frame_->height; |
275 const int uv_size = y_size / 2; | 244 const int uv_size = y_size / 2; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 | 289 |
321 cdm_video_frame->set_stride(cdm::VideoFrame::kYPlane, av_frame_->width); | 290 cdm_video_frame->set_stride(cdm::VideoFrame::kYPlane, av_frame_->width); |
322 cdm_video_frame->set_stride(cdm::VideoFrame::kUPlane, uv_stride); | 291 cdm_video_frame->set_stride(cdm::VideoFrame::kUPlane, uv_stride); |
323 cdm_video_frame->set_stride(cdm::VideoFrame::kVPlane, uv_stride); | 292 cdm_video_frame->set_stride(cdm::VideoFrame::kVPlane, uv_stride); |
324 | 293 |
325 cdm_video_frame->set_timestamp(av_frame_->reordered_opaque); | 294 cdm_video_frame->set_timestamp(av_frame_->reordered_opaque); |
326 | 295 |
327 return true; | 296 return true; |
328 } | 297 } |
329 | 298 |
299 bool FFmpegCdmVideoDecoder::CopyVpxImageTo(cdm::VideoFrame* cdm_video_frame) { | |
300 DCHECK(cdm_video_frame); | |
301 DCHECK_EQ(vpx_image_->fmt, VPX_IMG_FMT_I420); | |
302 DCHECK_EQ(vpx_image_->d_w % 2, 0U); | |
303 DCHECK_EQ(vpx_image_->d_h % 2, 0U); | |
304 | |
305 #if defined(USE_COPYPLANE_WITH_LIBVPX) | |
306 const int y_size = vpx_image_->d_w * vpx_image_->d_h; | |
307 const int uv_size = y_size / 2; | |
308 const int space_required = y_size + (uv_size * 2); | |
309 | |
310 DCHECK(!cdm_video_frame->frame_buffer()); | |
311 cdm_video_frame->set_frame_buffer(allocator_->Allocate(space_required)); | |
312 if (!cdm_video_frame->frame_buffer()) { | |
313 LOG(ERROR) << "CopyVpxImageTo() cdm::Allocator::Allocate failed."; | |
314 return false; | |
315 } | |
316 | |
317 CopyPlane(vpx_image_->planes[VPX_PLANE_Y], | |
318 vpx_image_->stride[VPX_PLANE_Y], | |
319 vpx_image_->d_w, | |
320 vpx_image_->d_h, | |
321 vpx_image_->d_w, | |
322 cdm_video_frame->frame_buffer()->data()); | |
323 | |
324 const int uv_stride = vpx_image_->d_w / 2; | |
325 const int uv_rows = vpx_image_->d_h / 2; | |
326 CopyPlane(vpx_image_->planes[VPX_PLANE_U], | |
327 vpx_image_->stride[VPX_PLANE_U], | |
328 uv_stride, | |
329 uv_rows, | |
330 uv_stride, | |
331 cdm_video_frame->frame_buffer()->data() + y_size); | |
332 | |
333 CopyPlane(vpx_image_->planes[VPX_PLANE_V], | |
334 vpx_image_->stride[VPX_PLANE_V], | |
335 uv_stride, | |
336 uv_rows, | |
337 uv_stride, | |
338 cdm_video_frame->frame_buffer()->data() + y_size + uv_size); | |
339 | |
340 cdm_video_frame->set_format(cdm::kYv12); | |
341 | |
342 cdm::Size video_frame_size; | |
343 video_frame_size.width = vpx_image_->d_w; | |
344 video_frame_size.height = vpx_image_->d_h; | |
345 cdm_video_frame->set_size(video_frame_size); | |
346 | |
347 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kYPlane, 0); | |
348 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kUPlane, y_size); | |
349 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kVPlane, | |
350 y_size + uv_size); | |
351 | |
352 cdm_video_frame->set_stride(cdm::VideoFrame::kYPlane, vpx_image_->d_w); | |
353 cdm_video_frame->set_stride(cdm::VideoFrame::kUPlane, uv_stride); | |
354 cdm_video_frame->set_stride(cdm::VideoFrame::kVPlane, uv_stride); | |
355 #else | |
356 const int y_size = vpx_image_->stride[VPX_PLANE_Y] * vpx_image_->d_h; | |
357 const int uv_rows = vpx_image_->d_h / 2; | |
358 const int u_size = vpx_image_->stride[VPX_PLANE_U] * uv_rows; | |
359 const int v_size = vpx_image_->stride[VPX_PLANE_V] * uv_rows; | |
360 const int space_required = y_size + u_size + v_size; | |
361 | |
362 DCHECK(!cdm_video_frame->frame_buffer()); | |
363 cdm_video_frame->set_frame_buffer(allocator_->Allocate(space_required)); | |
364 if (!cdm_video_frame->frame_buffer()) { | |
365 LOG(ERROR) << "CopyVpxImageTo() cdm::Allocator::Allocate failed."; | |
366 return false; | |
367 } | |
368 | |
369 memcpy(cdm_video_frame->frame_buffer()->data(), | |
370 vpx_image_->planes[VPX_PLANE_Y], | |
371 y_size); | |
372 memcpy(cdm_video_frame->frame_buffer()->data() + y_size, | |
373 vpx_image_->planes[VPX_PLANE_U], | |
374 u_size); | |
375 memcpy(cdm_video_frame->frame_buffer()->data() + y_size + u_size, | |
376 vpx_image_->planes[VPX_PLANE_V], | |
377 v_size); | |
378 | |
379 cdm_video_frame->set_format(cdm::kYv12); | |
380 | |
381 cdm::Size video_frame_size; | |
382 video_frame_size.width = vpx_image_->d_w; | |
383 video_frame_size.height = vpx_image_->d_h; | |
384 cdm_video_frame->set_size(video_frame_size); | |
385 | |
386 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kYPlane, 0); | |
387 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kUPlane, y_size); | |
388 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kVPlane, | |
389 y_size + u_size); | |
390 | |
391 cdm_video_frame->set_stride(cdm::VideoFrame::kYPlane, | |
392 vpx_image_->stride[VPX_PLANE_Y]); | |
393 cdm_video_frame->set_stride(cdm::VideoFrame::kUPlane, | |
394 vpx_image_->stride[VPX_PLANE_U]); | |
395 cdm_video_frame->set_stride(cdm::VideoFrame::kVPlane, | |
396 vpx_image_->stride[VPX_PLANE_V]); | |
397 #endif // USE_COPYPLANE_WITH_LIBVPX | |
398 | |
399 return true; | |
400 } | |
401 | |
330 void FFmpegCdmVideoDecoder::ReleaseFFmpegResources() { | 402 void FFmpegCdmVideoDecoder::ReleaseFFmpegResources() { |
331 DVLOG(1) << "ReleaseFFmpegResources()"; | 403 DVLOG(1) << "ReleaseFFmpegResources()"; |
332 | 404 |
333 if (codec_context_) { | 405 if (codec_context_) { |
334 av_free(codec_context_->extradata); | 406 av_free(codec_context_->extradata); |
335 avcodec_close(codec_context_); | 407 avcodec_close(codec_context_); |
336 av_free(codec_context_); | 408 av_free(codec_context_); |
337 codec_context_ = NULL; | 409 codec_context_ = NULL; |
338 } | 410 } |
339 if (av_frame_) { | 411 if (av_frame_) { |
340 av_free(av_frame_); | 412 av_free(av_frame_); |
341 av_frame_ = NULL; | 413 av_frame_ = NULL; |
342 } | 414 } |
343 } | 415 } |
344 | 416 |
417 bool FFmpegCdmVideoDecoder::InitializeFFmpeg( | |
418 const cdm::VideoDecoderConfig& config) { | |
419 // Initialize AVCodecContext structure. | |
420 codec_context_ = avcodec_alloc_context3(NULL); | |
421 CdmVideoDecoderConfigToAVCodecContext(config, codec_context_); | |
422 | |
423 // Enable motion vector search (potentially slow), strong deblocking filter | |
424 // for damaged macroblocks, and set our error detection sensitivity. | |
425 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; | |
426 codec_context_->err_recognition = AV_EF_CAREFUL; | |
427 codec_context_->thread_count = kDecodeThreads; | |
428 codec_context_->opaque = this; | |
429 codec_context_->flags |= CODEC_FLAG_EMU_EDGE; | |
430 | |
431 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); | |
432 if (!codec) { | |
433 LOG(ERROR) << "InitializeFFmpeg(): avcodec_find_decoder failed."; | |
434 return false; | |
435 } | |
436 | |
437 int status; | |
438 if ((status = avcodec_open2(codec_context_, codec, NULL)) < 0) { | |
439 LOG(ERROR) << "InitializeFFmpeg(): avcodec_open2 failed: " << status; | |
440 return false; | |
441 } | |
442 | |
443 av_frame_ = avcodec_alloc_frame(); | |
444 is_initialized_ = true; | |
445 | |
446 return true; | |
447 } | |
448 | |
449 bool FFmpegCdmVideoDecoder::InitializeLibvpx( | |
450 const cdm::VideoDecoderConfig& config) { | |
451 vpx_codec_ = new vpx_codec_ctx_t(); | |
452 vpx_codec_dec_cfg_t vpx_config = {0}; | |
453 vpx_config.w = config.coded_size.width; | |
454 vpx_config.h = config.coded_size.height; | |
455 vpx_config.threads = kDecodeThreads; | |
456 | |
457 vpx_codec_err_t status = vpx_codec_dec_init(vpx_codec_, | |
458 vpx_codec_vp8_dx(), | |
459 &vpx_config, | |
460 0); | |
461 if (status != VPX_CODEC_OK) { | |
462 LOG(ERROR) << "InitializeLibvpx(): vpx_codec_dec_init failed, ret=" | |
463 << status; | |
464 delete vpx_codec_; | |
465 vpx_codec_ = NULL; | |
466 } | |
467 | |
468 is_initialized_ = true; | |
469 return true; | |
470 } | |
471 | |
472 cdm::Status FFmpegCdmVideoDecoder::DecodeFrameFFmpeg( | |
473 const uint8_t* compressed_frame, | |
474 int32_t compressed_frame_size, | |
475 int64_t timestamp, | |
476 cdm::VideoFrame* decoded_frame) { | |
477 DVLOG(1) << "DecodeFrameFFmpeg()"; | |
478 | |
479 // Create a packet for input data. | |
480 AVPacket packet; | |
481 av_init_packet(&packet); | |
482 | |
483 // The FFmpeg API does not allow us to have const read-only pointers. | |
484 packet.data = const_cast<uint8_t*>(compressed_frame); | |
485 packet.size = compressed_frame_size; | |
486 | |
487 // Let FFmpeg handle presentation timestamp reordering. | |
488 codec_context_->reordered_opaque = timestamp; | |
489 | |
490 // Reset frame to default values. | |
491 avcodec_get_frame_defaults(av_frame_); | |
492 | |
493 // This is for codecs not using get_buffer to initialize | |
494 // |av_frame_->reordered_opaque| | |
495 av_frame_->reordered_opaque = codec_context_->reordered_opaque; | |
496 | |
497 int frame_decoded = 0; | |
498 int result = avcodec_decode_video2(codec_context_, | |
499 av_frame_, | |
500 &frame_decoded, | |
501 &packet); | |
502 // Log the problem when we can't decode a video frame and exit early. | |
503 if (result < 0) { | |
504 LOG(ERROR) << "DecodeFrameFFmpeg(): Error decoding video frame with " | |
505 << "timestamp: " << timestamp << " us, packet size: " | |
506 << packet.size << " bytes"; | |
507 return cdm::kDecodeError; | |
508 } | |
509 | |
510 // If no frame was produced then signal that more data is required to produce | |
511 // more frames. | |
512 if (frame_decoded == 0) | |
513 return cdm::kNeedMoreData; | |
514 | |
515 // The decoder is in a bad state and not decoding correctly. | |
516 // Checking for NULL avoids a crash. | |
517 if (!av_frame_->data[cdm::VideoFrame::kYPlane] || | |
518 !av_frame_->data[cdm::VideoFrame::kUPlane] || | |
519 !av_frame_->data[cdm::VideoFrame::kVPlane]) { | |
520 LOG(ERROR) << "DecodeFrameFFmpeg(): Video frame has invalid frame data."; | |
521 return cdm::kDecodeError; | |
522 } | |
523 | |
524 if (!CopyAvFrameTo(decoded_frame)) { | |
525 LOG(ERROR) << "DecodeFrameFFmpeg() could not copy video frame to output " | |
526 << "buffer."; | |
527 return cdm::kDecodeError; | |
528 } | |
529 | |
530 return cdm::kSuccess; | |
531 } | |
532 | |
533 cdm::Status FFmpegCdmVideoDecoder::DecodeFrameLibvpx( | |
534 const uint8_t* compressed_frame, | |
535 int32_t compressed_frame_size, | |
536 int64_t timestamp, | |
537 cdm::VideoFrame* decoded_frame) { | |
538 DVLOG(1) << "DecodeFrameLibvpx()"; | |
539 | |
540 // Pass |compressed_frame| to libvpx. | |
541 void* user_priv = reinterpret_cast<void*>(×tamp); | |
542 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, | |
543 compressed_frame, | |
544 compressed_frame_size, | |
545 user_priv, | |
546 0); | |
547 if (status != VPX_CODEC_OK) { | |
548 LOG(ERROR) << "DecodeFrameLibvpx(): vpx_codec_decode failed, status=" | |
549 << status; | |
550 return cdm::kDecodeError; | |
551 } | |
552 | |
553 // Gets pointer to decoded data. | |
554 vpx_codec_iter_t iter = NULL; | |
555 vpx_image_ = vpx_codec_get_frame(vpx_codec_, &iter); | |
556 if (!vpx_image_) | |
557 return cdm::kNeedMoreData; | |
558 | |
559 if (vpx_image_->user_priv != reinterpret_cast<void*>(×tamp)) { | |
560 LOG(ERROR) << "DecodeFrameLibvpx() invalid output timestamp."; | |
561 return cdm::kDecodeError; | |
562 } | |
563 decoded_frame->set_timestamp(timestamp); | |
564 | |
565 if (!CopyVpxImageTo(decoded_frame)) { | |
566 LOG(ERROR) << "DecodeFrameLibvpx() could not copy vpx image to output " | |
567 << "buffer."; | |
568 return cdm::kDecodeError; | |
569 } | |
570 | |
Tom Finegan
2012/11/16 10:29:54
Oops... I'll fix this whitespace.
| |
571 | |
572 | |
573 | |
574 | |
575 return cdm::kSuccess; | |
576 } | |
577 | |
345 } // namespace webkit_media | 578 } // namespace webkit_media |
OLD | NEW |