Updating trunk VERSION from 935.0 to 936.0
[chromium-blink-merge.git] / media / filters / ffmpeg_video_decoder.cc
blob0254f6352149110c9c49ad388df92ce9587a69e4
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/ffmpeg_video_decoder.h"
7 #include "base/bind.h"
8 #include "base/message_loop.h"
9 #include "media/base/demuxer_stream.h"
10 #include "media/base/filter_host.h"
11 #include "media/base/limits.h"
12 #include "media/base/video_decoder_config.h"
13 #include "media/base/video_frame.h"
14 #include "media/ffmpeg/ffmpeg_common.h"
15 #include "media/video/ffmpeg_video_decode_engine.h"
17 namespace media {
19 FFmpegVideoDecoder::FFmpegVideoDecoder(MessageLoop* message_loop)
20 : message_loop_(message_loop),
21 state_(kUninitialized),
22 decode_engine_(new FFmpegVideoDecodeEngine()) {
25 FFmpegVideoDecoder::~FFmpegVideoDecoder() {}
27 void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
28 const base::Closure& callback,
29 const StatisticsCallback& stats_callback) {
30 if (MessageLoop::current() != message_loop_) {
31 message_loop_->PostTask(FROM_HERE, base::Bind(
32 &FFmpegVideoDecoder::Initialize, this,
33 make_scoped_refptr(demuxer_stream), callback, stats_callback));
34 return;
37 DCHECK(!demuxer_stream_);
39 if (!demuxer_stream) {
40 host()->SetError(PIPELINE_ERROR_DECODE);
41 callback.Run();
42 return;
45 demuxer_stream_ = demuxer_stream;
46 statistics_callback_ = stats_callback;
48 const VideoDecoderConfig& config = demuxer_stream->video_decoder_config();
50 // TODO(scherkus): this check should go in PipelineImpl prior to creating
51 // decoder objects.
52 if (!config.IsValidConfig()) {
53 DLOG(ERROR) << "Invalid video stream -"
54 << " codec: " << config.codec()
55 << " format: " << config.format()
56 << " coded size: [" << config.coded_size().width()
57 << "," << config.coded_size().height() << "]"
58 << " visible rect: [" << config.visible_rect().x()
59 << "," << config.visible_rect().y()
60 << "," << config.visible_rect().width()
61 << "," << config.visible_rect().height() << "]"
62 << " natural size: [" << config.natural_size().width()
63 << "," << config.natural_size().height() << "]"
64 << " frame rate: " << config.frame_rate_numerator()
65 << "/" << config.frame_rate_denominator()
66 << " aspect ratio: " << config.aspect_ratio_numerator()
67 << "/" << config.aspect_ratio_denominator();
69 host()->SetError(PIPELINE_ERROR_DECODE);
70 callback.Run();
71 return;
74 pts_stream_.Initialize(GetFrameDuration(config));
75 natural_size_ = config.natural_size();
77 if (!decode_engine_->Initialize(config)) {
78 host()->SetError(PIPELINE_ERROR_DECODE);
79 callback.Run();
80 return;
83 state_ = kNormal;
84 callback.Run();
87 void FFmpegVideoDecoder::Stop(const base::Closure& callback) {
88 if (MessageLoop::current() != message_loop_) {
89 message_loop_->PostTask(FROM_HERE, base::Bind(
90 &FFmpegVideoDecoder::Stop, this, callback));
91 return;
94 decode_engine_->Uninitialize();
95 state_ = kUninitialized;
96 callback.Run();
99 void FFmpegVideoDecoder::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
100 if (MessageLoop::current() != message_loop_) {
101 message_loop_->PostTask(FROM_HERE, base::Bind(
102 &FFmpegVideoDecoder::Seek, this, time, cb));
103 return;
106 pts_stream_.Seek(time);
107 cb.Run(PIPELINE_OK);
110 void FFmpegVideoDecoder::Pause(const base::Closure& callback) {
111 if (MessageLoop::current() != message_loop_) {
112 message_loop_->PostTask(FROM_HERE, base::Bind(
113 &FFmpegVideoDecoder::Pause, this, callback));
114 return;
117 callback.Run();
120 void FFmpegVideoDecoder::Flush(const base::Closure& callback) {
121 if (MessageLoop::current() != message_loop_) {
122 message_loop_->PostTask(FROM_HERE, base::Bind(
123 &FFmpegVideoDecoder::Flush, this, callback));
124 return;
127 decode_engine_->Flush();
128 pts_stream_.Flush();
129 state_ = kNormal;
130 callback.Run();
133 void FFmpegVideoDecoder::Read(const ReadCB& callback) {
134 // TODO(scherkus): forced task post since VideoRendererBase::FrameReady() will
135 // call Read() on FFmpegVideoDecoder's thread as we executed |read_cb_|.
136 message_loop_->PostTask(FROM_HERE, base::Bind(
137 &FFmpegVideoDecoder::DoRead, this, callback));
140 const gfx::Size& FFmpegVideoDecoder::natural_size() {
141 return natural_size_;
144 void FFmpegVideoDecoder::DoRead(const ReadCB& callback) {
145 DCHECK_EQ(MessageLoop::current(), message_loop_);
146 CHECK(!callback.is_null());
147 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
149 // This can happen during shutdown after Stop() has been called.
150 if (state_ == kUninitialized) {
151 return;
154 // Return empty frames if decoding has finished.
155 if (state_ == kDecodeFinished) {
156 callback.Run(VideoFrame::CreateEmptyFrame());
157 return;
160 read_cb_ = callback;
161 ReadFromDemuxerStream();
165 void FFmpegVideoDecoder::ReadFromDemuxerStream() {
166 DCHECK_NE(state_, kUninitialized);
167 DCHECK_NE(state_, kDecodeFinished);
168 DCHECK(!read_cb_.is_null());
170 demuxer_stream_->Read(base::Bind(&FFmpegVideoDecoder::DecodeBuffer, this));
173 void FFmpegVideoDecoder::DecodeBuffer(const scoped_refptr<Buffer>& buffer) {
174 // TODO(scherkus): forced task post since FFmpegDemuxerStream::Read() can
175 // immediately execute our callback on FFmpegVideoDecoder's thread.
176 message_loop_->PostTask(FROM_HERE, base::Bind(
177 &FFmpegVideoDecoder::DoDecodeBuffer, this, buffer));
180 void FFmpegVideoDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& buffer) {
181 DCHECK_EQ(MessageLoop::current(), message_loop_);
182 DCHECK_NE(state_, kUninitialized);
183 DCHECK_NE(state_, kDecodeFinished);
184 DCHECK(!read_cb_.is_null());
186 // During decode, because reads are issued asynchronously, it is possible to
187 // receive multiple end of stream buffers since each read is acked. When the
188 // first end of stream buffer is read, FFmpeg may still have frames queued
189 // up in the decoder so we need to go through the decode loop until it stops
190 // giving sensible data. After that, the decoder should output empty
191 // frames. There are three states the decoder can be in:
193 // kNormal: This is the starting state. Buffers are decoded. Decode errors
194 // are discarded.
195 // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2
196 // until no more data is returned to flush out remaining
197 // frames. The input buffer is ignored at this point.
198 // kDecodeFinished: All calls return empty frames.
200 // These are the possible state transitions.
202 // kNormal -> kFlushCodec:
203 // When buffer->IsEndOfStream() is first true.
204 // kNormal -> kDecodeFinished:
205 // A decoding error occurs and decoding needs to stop.
206 // kFlushCodec -> kDecodeFinished:
207 // When avcodec_decode_video2() returns 0 data or errors out.
208 // (any state) -> kNormal:
209 // Any time Flush() is called.
211 // Transition to kFlushCodec on the first end of stream buffer.
212 if (state_ == kNormal && buffer->IsEndOfStream()) {
213 state_ = kFlushCodec;
216 // Push all incoming timestamps into the priority queue as long as we have
217 // not yet received an end of stream buffer. It is important that this line
218 // stay below the state transition into kFlushCodec done above.
219 if (state_ == kNormal) {
220 pts_stream_.EnqueuePts(buffer.get());
223 scoped_refptr<VideoFrame> video_frame;
224 if (!decode_engine_->Decode(buffer, &video_frame)) {
225 state_ = kDecodeFinished;
226 DeliverFrame(VideoFrame::CreateEmptyFrame());
227 host()->SetError(PIPELINE_ERROR_DECODE);
228 return;
231 // Any successful decode counts!
232 if (buffer->GetDataSize()) {
233 PipelineStatistics statistics;
234 statistics.video_bytes_decoded = buffer->GetDataSize();
235 statistics_callback_.Run(statistics);
238 // If we didn't get a frame then we've either completely finished decoding or
239 // we need more data.
240 if (!video_frame) {
241 if (state_ == kFlushCodec) {
242 state_ = kDecodeFinished;
243 DeliverFrame(VideoFrame::CreateEmptyFrame());
244 return;
247 ReadFromDemuxerStream();
248 return;
251 // If we got a frame make sure its timestamp is correct before sending it off.
252 pts_stream_.UpdatePtsAndDuration(video_frame.get());
253 video_frame->SetTimestamp(pts_stream_.current_pts());
254 video_frame->SetDuration(pts_stream_.current_duration());
256 DeliverFrame(video_frame);
259 void FFmpegVideoDecoder::DeliverFrame(
260 const scoped_refptr<VideoFrame>& video_frame) {
261 // Reset the callback before running to protect against reentrancy.
262 ReadCB read_cb = read_cb_;
263 read_cb_.Reset();
264 read_cb.Run(video_frame);
267 } // namespace media