Chromium Code Reviews| 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,54 @@ |
| 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 w = codec_context_->width, h = codec_context_->height; |
| + avcodec_align_dimensions(codec_context_, &w, &h); |
| + int ret; |
| + if ((ret = av_image_check_size(w, h, 0, NULL)) < 0) |
| + return ret; |
| + int strides[4]; |
| + if ((ret = av_image_fill_linesizes(strides, codec_context_->pix_fmt, w)) < 0) |
| + return ret; |
| + scoped_refptr<VideoFrame> buf = VideoFrame::CreateFrame(format, |
| + codec_context_->width, codec_context_->height, strides[0], |
| + strides[1], h, kNoTimestamp(), kNoTimestamp()); |
| + |
| + for (int i = 0; i < 3; i++) { |
| + frame->base[i] = buf->data(i); |
| + frame->data[i] = buf->data(i); |
| + frame->linesize[i] = buf->stride(i); |
| + } |
| + |
| + frame->opaque = buf.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 callbackGetVideoBuffer(AVCodecContext *s, AVFrame *frame) { |
| + FFmpegVideoDecoder *vd = static_cast<FFmpegVideoDecoder *>(s->opaque); |
| + return vd->GetVideoBuffer(frame); |
| +} |
| + |
| +static void callbackReleaseVideoBuffer(AVCodecContext *s, AVFrame *frame) { |
| + // We're releasing the refenence to the buffer allocated in |
| + // GetVideoBuffer() here, so the explicit Release() here is |
| + // intentional. Would be nice if scoped_refptr::adopt existed. |
| + scoped_refptr<VideoFrame> buf = static_cast<VideoFrame *>(frame->opaque); |
| + buf->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 +152,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 = callbackGetVideoBuffer; |
|
Ami GONE FROM CHROMIUM
2012/06/09 02:51:23
I still think it should be possible to use base::B
|
| + codec_context_->release_buffer = callbackReleaseVideoBuffer; |
| AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); |
| if (!codec) { |
| @@ -362,12 +414,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 +438,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 +460,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 |