Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1069)

Unified Diff: media/filters/ffmpeg_video_decoder.cc

Issue 60069: FFmpeg video decoder glue code... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/ffmpeg_video_decoder.cc
===================================================================
--- media/filters/ffmpeg_video_decoder.cc (revision 12922)
+++ media/filters/ffmpeg_video_decoder.cc (working copy)
@@ -2,32 +2,152 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
+#include "media/base/video_frame_impl.h"
+#include "media/filters/ffmpeg_common.h"
+#include "media/filters/ffmpeg_demuxer.h"
#include "media/filters/ffmpeg_video_decoder.h"
namespace media {
+
FFmpegVideoDecoder::FFmpegVideoDecoder()
- : DecoderBase<VideoDecoder, VideoFrame>(NULL) {
- NOTIMPLEMENTED();
+ : DecoderBase<VideoDecoder, VideoFrame>(NULL),
+ width_(0),
+ height_(0) {
}
FFmpegVideoDecoder::~FFmpegVideoDecoder() {
- NOTIMPLEMENTED();
}
// static
bool FFmpegVideoDecoder::IsMediaFormatSupported(const MediaFormat& format) {
- NOTIMPLEMENTED();
- return false;
+ std::string mime_type;
+ return format.GetAsString(MediaFormat::kMimeType, &mime_type) &&
+ mime_type::kFFmpegVideo == mime_type;
}
bool FFmpegVideoDecoder::OnInitialize(DemuxerStream* demuxer_stream) {
- NOTIMPLEMENTED();
- return false;
+ scoped_refptr<FFmpegDemuxerStream> ffmpeg_demuxer_stream;
+ if (!demuxer_stream->QueryInterface(&ffmpeg_demuxer_stream)) {
+ return false;
+ }
+
+ AVStream* av_stream = ffmpeg_demuxer_stream->av_stream();
+
+ width_ = av_stream->codec->width;
+ height_ = av_stream->codec->height;
+
+ media_format_.SetAsString(MediaFormat::kMimeType,
+ mime_type::kUncompressedVideo);
+ media_format_.SetAsInteger(MediaFormat::kWidth, width_);
+ media_format_.SetAsInteger(MediaFormat::kHeight, height_);
+
+ codec_context_ = ffmpeg_demuxer_stream->av_stream()->codec;
+
+ return true;
}
-void FFmpegVideoDecoder::OnDecode(Buffer* input) {
- NOTIMPLEMENTED();
+void FFmpegVideoDecoder::OnDecode(Buffer* buffer) {
+ // Check for end of stream.
+ // TODO(scherkus): check for end of stream.
+
+ // Queue the incoming timestamp.
+ TimeTuple times;
+ times.timestamp = buffer->GetTimestamp();
+ times.duration = buffer->GetDuration();
+ time_queue_.push(times);
+
+ // Cast everything to FFmpeg types.
+ const uint8_t* data_in = buffer->GetData();
+ const size_t size_in = buffer->GetDataSize();
+
+ int decoded = 0;
+ AVFrame yuv_frame;
+ avcodec_get_frame_defaults(&yuv_frame);
+ int result = avcodec_decode_video(codec_context_, &yuv_frame, &decoded,
+ data_in, size_in);
+
+ if (result < 0) {
+ host_->Error(PIPELINE_ERROR_DECODE);
+ return;
+ }
+
+ if (result == 0 || decoded == 0) {
+ return;
+ }
+
+ VideoSurface::Format surface_format;
+ switch (codec_context_->pix_fmt) {
+ case PIX_FMT_YUV420P:
+ surface_format = VideoSurface::YV12;
+ break;
+ case PIX_FMT_YUV422P:
+ surface_format = VideoSurface::YV16;
+ break;
+ default:
+ // TODO(scherkus): More formats here?
+ NOTREACHED();
+ host_->Error(PIPELINE_ERROR_DECODE);
+ return;
+ }
+ if (!EnqueueVideoFrame(surface_format, yuv_frame)) {
+ host_->Error(PIPELINE_ERROR_DECODE);
+ }
}
+bool FFmpegVideoDecoder::EnqueueVideoFrame(VideoSurface::Format surface_format,
+ const AVFrame& frame) {
+ // Dequeue the next time tuple and create a VideoFrame object with
+ // that timestamp and duration.
+ TimeTuple time = time_queue_.top();
+ time_queue_.pop();
+
+ scoped_refptr<VideoFrame> video_frame;
+ VideoFrameImpl::CreateFrame(surface_format, width_, height_,
+ time.timestamp, time.duration, &video_frame);
+ if (!video_frame) {
+ return false;
+ }
+ // 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.
+ // TODO(scherkus): figure out pre-allocation/buffer cycling scheme.
+ // TODO(scherkus): is there a cleaner way to figure out the # of planes?
+ VideoSurface surface;
+ if (!video_frame->Lock(&surface)) {
+ return false;
+ }
+ CopyPlane(VideoSurface::kYPlane, surface, frame);
+ CopyPlane(VideoSurface::kUPlane, surface, frame);
+ CopyPlane(VideoSurface::kVPlane, surface, frame);
+ video_frame->Unlock();
+ EnqueueResult(video_frame);
+ return true;
+}
+
+void FFmpegVideoDecoder::CopyPlane(size_t plane,
+ const VideoSurface& surface,
+ const AVFrame& frame) {
+ DCHECK(surface.width % 4 == 0);
+ DCHECK(surface.height % 2 == 0);
+ const uint8* source = frame.data[plane];
+ const size_t source_stride = frame.linesize[plane];
+ uint8* dest = surface.data[plane];
+ const size_t dest_stride = surface.strides[plane];
+ size_t bytes_per_line = surface.width;
+ size_t copy_lines = surface.height;
+ if (plane != VideoSurface::kYPlane) {
+ bytes_per_line /= 2;
+ if (surface.format == VideoSurface::YV12) {
+ copy_lines /= 2;
+ }
+ }
+ DCHECK(bytes_per_line <= source_stride && bytes_per_line <= dest_stride);
+ for (size_t i = 0; i < copy_lines; ++i) {
+ memcpy(dest, source, bytes_per_line);
+ source += source_stride;
+ dest += dest_stride;
+ }
+}
+
} // namespace
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698