Index: webkit/media/crypto/decoders/ffmpeg_video_decoder.cc |
diff --git a/webkit/media/crypto/decoders/ffmpeg_video_decoder.cc b/webkit/media/crypto/decoders/ffmpeg_video_decoder.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d16976b61b8ce97807b45bb40ee3bdc8e261455a |
--- /dev/null |
+++ b/webkit/media/crypto/decoders/ffmpeg_video_decoder.cc |
@@ -0,0 +1,127 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/logging.h" |
+#include "base/memory/ref_counted.h" |
+#include "media/base/limits.h" |
+#include "media/ffmpeg/ffmpeg_common.h" |
+#include "webkit/media/crypto/decoders/ffmpeg_util.h" |
+#include "webkit/media/crypto/decoders/ffmpeg_video_decoder.h" |
+#include "webkit/media/crypto/ppapi/content_decryption_module.h" |
+ |
+namespace webkit_media { |
+ |
+using cdm::VideoDecoderConfig; |
+using cdm::VideoFrame; |
+ |
+static int GetVideoBufferImpl(AVCodecContext* s, AVFrame* frame) { |
+ FFmpegVideoDecoder* vd = static_cast<FFmpegVideoDecoder*>(s->opaque); |
+ return vd->GetVideoBuffer(s, frame); |
+} |
+ |
+static void ReleaseVideoBufferImpl(AVCodecContext* s, AVFrame* frame) { |
+ scoped_refptr<VideoFrame> video_frame; |
+ video_frame.swap(reinterpret_cast<VideoFrame**>(&frame->opaque)); |
+ |
+ // The FFmpeg API expects us to zero the data pointers in |
+ // this callback |
+ memset(frame->data, 0, sizeof(frame->data)); |
+ frame->opaque = NULL; |
+} |
+ |
+FFmpegVideoDecoder::FFmpegVideoDecoder() |
+ : codec_context_(NULL), |
+ av_frame_(NULL) { |
+} |
+ |
+FFmpegVideoDecoder::~FFmpegVideoDecoder() { |
+} |
+ |
+bool FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config) { |
+ return false; |
+} |
+ |
+bool FFmpegVideoDecoder::DecodeFrame(const VideoFrame& compressed_frame, |
+ VideoFrame* decompressed_frame) { |
+ return false; |
+} |
+ |
+int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context, |
+ AVFrame* frame) { |
+ // Don't use |codec_context_| here! With threaded decoding, |
+ // it will contain unsynchronized width/height/pix_fmt values, |
+ // whereas |codec_context| contains the current threads's |
+ // updated width/height/pix_fmt, which can change for adaptive |
+ // content. |
+ VideoFrame::Format format = PixelFormatToVideoFormat(codec_context->pix_fmt); |
+ if (format == VideoFrame::INVALID) |
+ return AVERROR(EINVAL); |
+ DCHECK(format == VideoFrame::YV12 || format == VideoFrame::YV16); |
+ |
+ gfx::Size size(codec_context->width, codec_context->height); |
+ int ret; |
+ if ((ret = av_image_check_size(size.width(), size.height(), 0, NULL)) < 0) |
+ return ret; |
+ |
+ gfx::Size natural_size; |
+ if (codec_context->sample_aspect_ratio.num > 0) { |
+ natural_size = GetNaturalSize(size, |
+ codec_context->sample_aspect_ratio.num, |
+ codec_context->sample_aspect_ratio.den); |
+ } else { |
+ natural_size = demuxer_stream_->video_decoder_config().natural_size(); |
+ } |
+ |
+ if (!VideoFrame::IsValidConfig(format, size, natural_size)) |
+ return AVERROR(EINVAL); |
+ |
+ scoped_refptr<VideoFrame> video_frame = |
+ VideoFrame::CreateFrame(format, size, natural_size, 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 = NULL; |
+ video_frame.swap(reinterpret_cast<VideoFrame**>(&frame->opaque)); |
+ 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 |
+bool VideoFrame::IsValidConfig(VideoFrame::Format format, |
+ const Size& data_size) { |
+ return (format != VideoFrame::INVALID && |
+ data_size.width() > 0 && data_size.height() > 0 && |
+ data_size.width() <= limits::kMaxDimension && |
+ data_size.height() <= limits::kMaxDimension && |
+ data_size.width() * data_size.height() <= limits::kMaxCanvas && |
+ natural_size.width() > 0 && natural_size.height() > 0 && |
+ natural_size.width() <= limits::kMaxDimension && |
+ natural_size.height() <= limits::kMaxDimension && |
+ natural_size.width() * natural_size.height() <= limits::kMaxCanvas); |
+} |
+ |
+void FFmpegVideoDecoder::ReleaseFFmpegResources() { |
+ if (codec_context_) { |
+ av_free(codec_context_->extradata); |
+ avcodec_close(codec_context_); |
+ av_free(codec_context_); |
+ codec_context_ = NULL; |
+ } |
+ if (av_frame_) { |
+ av_free(av_frame_); |
+ av_frame_ = NULL; |
+ } |
+} |
+ |
+} // namespace webkit_media |