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/ffmpeg_video_decoder.h" | 5 #include "media/filters/ffmpeg_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/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 : message_loop_factory_cb_(message_loop_cb), | 54 : message_loop_factory_cb_(message_loop_cb), |
55 message_loop_(NULL), | 55 message_loop_(NULL), |
56 state_(kUninitialized), | 56 state_(kUninitialized), |
57 codec_context_(NULL), | 57 codec_context_(NULL), |
58 av_frame_(NULL), | 58 av_frame_(NULL), |
59 frame_rate_numerator_(0), | 59 frame_rate_numerator_(0), |
60 frame_rate_denominator_(0), | 60 frame_rate_denominator_(0), |
61 decryptor_(NULL) { | 61 decryptor_(NULL) { |
62 } | 62 } |
63 | 63 |
64 int FFmpegVideoDecoder::GetVideoBuffer(AVFrame* frame) { | |
65 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); | |
66 if (format == VideoFrame::INVALID) | |
67 return AVERROR(EINVAL); | |
68 DCHECK(format == VideoFrame::YV12 || format == VideoFrame::YV16); | |
69 | |
70 int width = codec_context_->width; | |
71 int height = codec_context_->height; | |
72 int ret; | |
73 if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) | |
74 return ret; | |
75 | |
76 scoped_refptr<VideoFrame> video_frame = | |
77 VideoFrame::CreateFrame(format, width, height, 16u, | |
scherkus (not reviewing)
2012/06/14 19:21:20
fix indent (4 spaces from current indent level = 6
rbultje1
2012/06/14 19:26:25
Done.
| |
78 kNoTimestamp(), kNoTimestamp()); | |
79 | |
80 for (int i = 0; i < 3; i++) { | |
81 frame->base[i] = video_frame->data(i); | |
82 frame->data[i] = video_frame->data(i); | |
83 frame->linesize[i] = video_frame->stride(i); | |
84 } | |
85 | |
86 frame->opaque = video_frame.release(); | |
87 frame->type = FF_BUFFER_TYPE_USER; | |
88 frame->pkt_pts = codec_context_->pkt ? codec_context_->pkt->pts : | |
89 AV_NOPTS_VALUE; | |
90 frame->width = codec_context_->width; | |
91 frame->height = codec_context_->height; | |
92 frame->format = codec_context_->pix_fmt; | |
93 | |
94 return 0; | |
95 } | |
96 | |
97 static int GetVideoBufferImpl(AVCodecContext* s, AVFrame* frame) { | |
98 FFmpegVideoDecoder* vd = static_cast<FFmpegVideoDecoder*>(s->opaque); | |
99 return vd->GetVideoBuffer(frame); | |
100 } | |
101 | |
102 static void ReleaseVideoBuffer(AVCodecContext* s, AVFrame* frame) { | |
scherkus (not reviewing)
2012/06/14 19:21:20
nit: append Impl to fn name for parity
rbultje1
2012/06/14 19:26:25
Done.
| |
103 // We're releasing the refenence to the buffer allocated in | |
104 // GetVideoBuffer() here, so the explicit Release() here is | |
105 // intentional. | |
106 scoped_refptr<VideoFrame> video_frame = | |
107 static_cast<VideoFrame*>(frame->opaque); | |
scherkus (not reviewing)
2012/06/14 19:21:20
fix indent here (4 spaces from current indent leve
rbultje1
2012/06/14 19:26:25
Done.
| |
108 video_frame->Release(); | |
109 memset(frame->data, 0, sizeof(frame->data)); | |
110 frame->opaque = NULL; | |
111 } | |
112 | |
64 void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, | 113 void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, |
65 const PipelineStatusCB& status_cb, | 114 const PipelineStatusCB& status_cb, |
66 const StatisticsCB& statistics_cb) { | 115 const StatisticsCB& statistics_cb) { |
67 if (!message_loop_) { | 116 if (!message_loop_) { |
68 message_loop_ = message_loop_factory_cb_.Run(); | 117 message_loop_ = message_loop_factory_cb_.Run(); |
69 message_loop_factory_cb_.Reset(); | 118 message_loop_factory_cb_.Reset(); |
70 | 119 |
71 message_loop_->PostTask(FROM_HERE, base::Bind( | 120 message_loop_->PostTask(FROM_HERE, base::Bind( |
72 &FFmpegVideoDecoder::Initialize, this, | 121 &FFmpegVideoDecoder::Initialize, this, |
73 stream, status_cb, statistics_cb)); | 122 stream, status_cb, statistics_cb)); |
(...skipping 23 matching lines...) Expand all Loading... | |
97 | 146 |
98 // Initialize AVCodecContext structure. | 147 // Initialize AVCodecContext structure. |
99 codec_context_ = avcodec_alloc_context(); | 148 codec_context_ = avcodec_alloc_context(); |
100 VideoDecoderConfigToAVCodecContext(config, codec_context_); | 149 VideoDecoderConfigToAVCodecContext(config, codec_context_); |
101 | 150 |
102 // Enable motion vector search (potentially slow), strong deblocking filter | 151 // Enable motion vector search (potentially slow), strong deblocking filter |
103 // for damaged macroblocks, and set our error detection sensitivity. | 152 // for damaged macroblocks, and set our error detection sensitivity. |
104 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; | 153 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; |
105 codec_context_->err_recognition = AV_EF_CAREFUL; | 154 codec_context_->err_recognition = AV_EF_CAREFUL; |
106 codec_context_->thread_count = GetThreadCount(codec_context_->codec_id); | 155 codec_context_->thread_count = GetThreadCount(codec_context_->codec_id); |
156 codec_context_->opaque = this; | |
157 codec_context_->flags |= CODEC_FLAG_EMU_EDGE; | |
158 codec_context_->get_buffer = GetVideoBufferImpl; | |
159 codec_context_->release_buffer = ReleaseVideoBuffer; | |
107 | 160 |
108 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); | 161 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); |
109 if (!codec) { | 162 if (!codec) { |
110 status_cb.Run(PIPELINE_ERROR_DECODE); | 163 status_cb.Run(PIPELINE_ERROR_DECODE); |
111 return; | 164 return; |
112 } | 165 } |
113 | 166 |
114 if (avcodec_open2(codec_context_, codec, NULL) < 0) { | 167 if (avcodec_open2(codec_context_, codec, NULL) < 0) { |
115 status_cb.Run(PIPELINE_ERROR_DECODE); | 168 status_cb.Run(PIPELINE_ERROR_DECODE); |
116 return; | 169 return; |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
355 // The decoder is in a bad state and not decoding correctly. | 408 // The decoder is in a bad state and not decoding correctly. |
356 // Checking for NULL avoids a crash in CopyPlane(). | 409 // Checking for NULL avoids a crash in CopyPlane(). |
357 if (!av_frame_->data[VideoFrame::kYPlane] || | 410 if (!av_frame_->data[VideoFrame::kYPlane] || |
358 !av_frame_->data[VideoFrame::kUPlane] || | 411 !av_frame_->data[VideoFrame::kUPlane] || |
359 !av_frame_->data[VideoFrame::kVPlane]) { | 412 !av_frame_->data[VideoFrame::kVPlane]) { |
360 LOG(ERROR) << "Video frame was produced yet has invalid frame data."; | 413 LOG(ERROR) << "Video frame was produced yet has invalid frame data."; |
361 *video_frame = NULL; | 414 *video_frame = NULL; |
362 return false; | 415 return false; |
363 } | 416 } |
364 | 417 |
365 // We've got a frame! Make sure we have a place to store it. | 418 if (!av_frame_->opaque) { |
366 *video_frame = AllocateVideoFrame(); | 419 LOG(ERROR) << "VideoFrame object associated with frame data not set."; |
367 if (!(*video_frame)) { | |
368 LOG(ERROR) << "Failed to allocate video frame"; | |
369 return false; | 420 return false; |
370 } | 421 } |
422 *video_frame = static_cast<VideoFrame *>(av_frame_->opaque); | |
371 | 423 |
372 // Determine timestamp and calculate the duration based on the repeat picture | 424 // Determine timestamp and calculate the duration based on the repeat picture |
373 // count. According to FFmpeg docs, the total duration can be calculated as | 425 // count. According to FFmpeg docs, the total duration can be calculated as |
374 // follows: | 426 // follows: |
375 // fps = 1 / time_base | 427 // fps = 1 / time_base |
376 // | 428 // |
377 // duration = (1 / fps) + (repeat_pict) / (2 * fps) | 429 // duration = (1 / fps) + (repeat_pict) / (2 * fps) |
378 // = (2 + repeat_pict) / (2 * fps) | 430 // = (2 + repeat_pict) / (2 * fps) |
379 // = (2 + repeat_pict) / (2 * (1 / time_base)) | 431 // = (2 + repeat_pict) / (2 * (1 / time_base)) |
380 DCHECK_LE(av_frame_->repeat_pict, 2); // Sanity check. | 432 DCHECK_LE(av_frame_->repeat_pict, 2); // Sanity check. |
381 AVRational doubled_time_base; | 433 AVRational doubled_time_base; |
382 doubled_time_base.num = frame_rate_denominator_; | 434 doubled_time_base.num = frame_rate_denominator_; |
383 doubled_time_base.den = frame_rate_numerator_ * 2; | 435 doubled_time_base.den = frame_rate_numerator_ * 2; |
384 | 436 |
385 (*video_frame)->SetTimestamp( | 437 (*video_frame)->SetTimestamp( |
386 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); | 438 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); |
387 (*video_frame)->SetDuration( | 439 (*video_frame)->SetDuration( |
388 ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict)); | 440 ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict)); |
389 | 441 |
390 // Copy the frame data since FFmpeg reuses internal buffers for AVFrame | |
391 // output, meaning the data is only valid until the next | |
392 // avcodec_decode_video() call. | |
393 int y_rows = codec_context_->height; | |
394 int uv_rows = codec_context_->height; | |
395 if (codec_context_->pix_fmt == PIX_FMT_YUV420P) { | |
396 uv_rows /= 2; | |
397 } | |
398 | |
399 CopyYPlane(av_frame_->data[0], av_frame_->linesize[0], y_rows, *video_frame); | |
400 CopyUPlane(av_frame_->data[1], av_frame_->linesize[1], uv_rows, *video_frame); | |
401 CopyVPlane(av_frame_->data[2], av_frame_->linesize[2], uv_rows, *video_frame); | |
402 | |
403 return true; | 442 return true; |
404 } | 443 } |
405 | 444 |
406 void FFmpegVideoDecoder::DeliverFrame( | 445 void FFmpegVideoDecoder::DeliverFrame( |
407 const scoped_refptr<VideoFrame>& video_frame) { | 446 const scoped_refptr<VideoFrame>& video_frame) { |
408 // Reset the callback before running to protect against reentrancy. | 447 // Reset the callback before running to protect against reentrancy. |
409 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); | 448 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); |
410 } | 449 } |
411 | 450 |
412 void FFmpegVideoDecoder::ReleaseFFmpegResources() { | 451 void FFmpegVideoDecoder::ReleaseFFmpegResources() { |
413 if (codec_context_) { | 452 if (codec_context_) { |
414 av_free(codec_context_->extradata); | 453 av_free(codec_context_->extradata); |
415 avcodec_close(codec_context_); | 454 avcodec_close(codec_context_); |
416 av_free(codec_context_); | 455 av_free(codec_context_); |
417 codec_context_ = NULL; | 456 codec_context_ = NULL; |
418 } | 457 } |
419 if (av_frame_) { | 458 if (av_frame_) { |
420 av_free(av_frame_); | 459 av_free(av_frame_); |
421 av_frame_ = NULL; | 460 av_frame_ = NULL; |
422 } | 461 } |
423 } | 462 } |
424 | 463 |
425 scoped_refptr<VideoFrame> FFmpegVideoDecoder::AllocateVideoFrame() { | |
426 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); | |
427 size_t width = codec_context_->width; | |
428 size_t height = codec_context_->height; | |
429 | |
430 return VideoFrame::CreateFrame(format, width, height, | |
431 kNoTimestamp(), kNoTimestamp()); | |
432 } | |
433 | |
434 } // namespace media | 464 } // namespace media |
OLD | NEW |