Index: media/filters/ffmpeg_video_decoder.cc |
=================================================================== |
--- media/filters/ffmpeg_video_decoder.cc (revision 140753) |
+++ media/filters/ffmpeg_video_decoder.cc (working copy) |
@@ -61,6 +61,55 @@ |
decryptor_(NULL) { |
} |
+int FFmpegVideoDecoder::GetVideoBuffer(AVFrame* frame) { |
+ VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); |
+ if (format == VideoFrame::INVALID) |
+ return AVERROR(EINVAL); |
+ DCHECK(format == VideoFrame::YV12 || format == VideoFrame::YV16); |
+ |
+ int width = codec_context_->width; |
+ int height = codec_context_->height; |
+ int ret; |
+ if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) |
+ return ret; |
+ |
+ scoped_refptr<VideoFrame> video_frame = |
+ 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.
|
+ kNoTimestamp(), kNoTimestamp()); |
+ |
+ for (int i = 0; i < 3; i++) { |
+ frame->base[i] = video_frame->data(i); |
+ frame->data[i] = video_frame->data(i); |
+ frame->linesize[i] = video_frame->stride(i); |
+ } |
+ |
+ frame->opaque = video_frame.release(); |
+ frame->type = FF_BUFFER_TYPE_USER; |
+ frame->pkt_pts = codec_context_->pkt ? codec_context_->pkt->pts : |
+ AV_NOPTS_VALUE; |
+ frame->width = codec_context_->width; |
+ frame->height = codec_context_->height; |
+ frame->format = codec_context_->pix_fmt; |
+ |
+ return 0; |
+} |
+ |
+static int GetVideoBufferImpl(AVCodecContext* s, AVFrame* frame) { |
+ FFmpegVideoDecoder* vd = static_cast<FFmpegVideoDecoder*>(s->opaque); |
+ return vd->GetVideoBuffer(frame); |
+} |
+ |
+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.
|
+ // We're releasing the refenence to the buffer allocated in |
+ // GetVideoBuffer() here, so the explicit Release() here is |
+ // intentional. |
+ scoped_refptr<VideoFrame> video_frame = |
+ 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.
|
+ video_frame->Release(); |
+ memset(frame->data, 0, sizeof(frame->data)); |
+ frame->opaque = NULL; |
+} |
+ |
void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, |
const PipelineStatusCB& status_cb, |
const StatisticsCB& statistics_cb) { |
@@ -104,6 +153,10 @@ |
codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; |
codec_context_->err_recognition = AV_EF_CAREFUL; |
codec_context_->thread_count = GetThreadCount(codec_context_->codec_id); |
+ codec_context_->opaque = this; |
+ codec_context_->flags |= CODEC_FLAG_EMU_EDGE; |
+ codec_context_->get_buffer = GetVideoBufferImpl; |
+ codec_context_->release_buffer = ReleaseVideoBuffer; |
AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); |
if (!codec) { |
@@ -362,12 +415,11 @@ |
return false; |
} |
- // We've got a frame! Make sure we have a place to store it. |
- *video_frame = AllocateVideoFrame(); |
- if (!(*video_frame)) { |
- LOG(ERROR) << "Failed to allocate video frame"; |
+ if (!av_frame_->opaque) { |
+ LOG(ERROR) << "VideoFrame object associated with frame data not set."; |
return false; |
} |
+ *video_frame = static_cast<VideoFrame *>(av_frame_->opaque); |
// Determine timestamp and calculate the duration based on the repeat picture |
// count. According to FFmpeg docs, the total duration can be calculated as |
@@ -387,19 +439,6 @@ |
(*video_frame)->SetDuration( |
ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict)); |
- // Copy the frame data since FFmpeg reuses internal buffers for AVFrame |
- // output, meaning the data is only valid until the next |
- // avcodec_decode_video() call. |
- int y_rows = codec_context_->height; |
- int uv_rows = codec_context_->height; |
- if (codec_context_->pix_fmt == PIX_FMT_YUV420P) { |
- uv_rows /= 2; |
- } |
- |
- CopyYPlane(av_frame_->data[0], av_frame_->linesize[0], y_rows, *video_frame); |
- CopyUPlane(av_frame_->data[1], av_frame_->linesize[1], uv_rows, *video_frame); |
- CopyVPlane(av_frame_->data[2], av_frame_->linesize[2], uv_rows, *video_frame); |
- |
return true; |
} |
@@ -422,13 +461,4 @@ |
} |
} |
-scoped_refptr<VideoFrame> FFmpegVideoDecoder::AllocateVideoFrame() { |
- VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); |
- size_t width = codec_context_->width; |
- size_t height = codec_context_->height; |
- |
- return VideoFrame::CreateFrame(format, width, height, |
- kNoTimestamp(), kNoTimestamp()); |
-} |
- |
} // namespace media |