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"
10 #include "base/task.h"
11 #include "media/base/callback.h"
12 #include "media/base/filters.h"
13 #include "media/base/filter_host.h"
14 #include "media/base/limits.h"
15 #include "media/base/video_frame.h"
16 #include "media/ffmpeg/ffmpeg_common.h"
17 #include "media/video/ffmpeg_video_decode_engine.h"
18 #include "media/video/video_decode_context.h"
22 FFmpegVideoDecoder::FFmpegVideoDecoder(MessageLoop
* message_loop
,
23 VideoDecodeContext
* decode_context
)
24 : message_loop_(message_loop
),
25 state_(kUnInitialized
),
26 decode_engine_(new FFmpegVideoDecodeEngine()),
27 decode_context_(decode_context
) {
28 memset(&info_
, 0, sizeof(info_
));
31 FFmpegVideoDecoder::~FFmpegVideoDecoder() {}
33 void FFmpegVideoDecoder::Initialize(DemuxerStream
* demuxer_stream
,
34 FilterCallback
* callback
,
35 StatisticsCallback
* stats_callback
) {
36 if (MessageLoop::current() != message_loop_
) {
37 message_loop_
->PostTask(
39 NewRunnableMethod(this,
40 &FFmpegVideoDecoder::Initialize
,
41 make_scoped_refptr(demuxer_stream
),
42 callback
, stats_callback
));
46 DCHECK_EQ(MessageLoop::current(), message_loop_
);
47 DCHECK(!demuxer_stream_
);
48 DCHECK(!initialize_callback_
.get());
50 if (!demuxer_stream
) {
51 host()->SetError(PIPELINE_ERROR_DECODE
);
54 delete stats_callback
;
58 demuxer_stream_
= demuxer_stream
;
59 initialize_callback_
.reset(callback
);
60 statistics_callback_
.reset(stats_callback
);
62 AVStream
* av_stream
= demuxer_stream
->GetAVStream();
64 VideoCodecInfo info
= {0};
65 OnInitializeComplete(info
);
69 pts_stream_
.Initialize(GetFrameDuration(av_stream
));
71 int width
= av_stream
->codec
->coded_width
;
72 int height
= av_stream
->codec
->coded_height
;
74 int surface_width
= GetSurfaceWidth(av_stream
);
75 int surface_height
= GetSurfaceHeight(av_stream
);
77 if (surface_width
> Limits::kMaxDimension
||
78 surface_height
> Limits::kMaxDimension
||
79 (surface_width
* surface_height
) > Limits::kMaxCanvas
) {
80 VideoCodecInfo info
= {0};
81 OnInitializeComplete(info
);
85 VideoDecoderConfig
config(CodecIDToVideoCodec(av_stream
->codec
->codec_id
),
87 surface_width
, surface_height
,
88 av_stream
->r_frame_rate
.num
,
89 av_stream
->r_frame_rate
.den
,
90 av_stream
->codec
->extradata
,
91 av_stream
->codec
->extradata_size
);
92 state_
= kInitializing
;
93 decode_engine_
->Initialize(message_loop_
, this, NULL
, config
);
96 void FFmpegVideoDecoder::OnInitializeComplete(const VideoCodecInfo
& info
) {
97 DCHECK_EQ(MessageLoop::current(), message_loop_
);
98 DCHECK(initialize_callback_
.get());
101 AutoCallbackRunner
done_runner(initialize_callback_
.release());
106 host()->SetError(PIPELINE_ERROR_DECODE
);
110 void FFmpegVideoDecoder::Stop(FilterCallback
* callback
) {
111 if (MessageLoop::current() != message_loop_
) {
112 message_loop_
->PostTask(FROM_HERE
,
113 NewRunnableMethod(this,
114 &FFmpegVideoDecoder::Stop
,
119 DCHECK_EQ(MessageLoop::current(), message_loop_
);
120 DCHECK(!uninitialize_callback_
.get());
122 uninitialize_callback_
.reset(callback
);
123 if (state_
!= kUnInitialized
)
124 decode_engine_
->Uninitialize();
126 OnUninitializeComplete();
129 void FFmpegVideoDecoder::OnUninitializeComplete() {
130 DCHECK_EQ(MessageLoop::current(), message_loop_
);
131 DCHECK(uninitialize_callback_
.get());
133 AutoCallbackRunner
done_runner(uninitialize_callback_
.release());
136 // TODO(jiesun): Destroy the decoder context.
139 void FFmpegVideoDecoder::Pause(FilterCallback
* callback
) {
140 if (MessageLoop::current() != message_loop_
) {
141 message_loop_
->PostTask(FROM_HERE
,
142 NewRunnableMethod(this,
143 &FFmpegVideoDecoder::Pause
,
148 AutoCallbackRunner
done_runner(callback
);
152 void FFmpegVideoDecoder::Flush(FilterCallback
* callback
) {
153 if (MessageLoop::current() != message_loop_
) {
154 message_loop_
->PostTask(FROM_HERE
,
155 NewRunnableMethod(this,
156 &FFmpegVideoDecoder::Flush
,
161 DCHECK_EQ(MessageLoop::current(), message_loop_
);
162 DCHECK(!flush_callback_
.get());
168 flush_callback_
.reset(callback
);
170 decode_engine_
->Flush();
173 void FFmpegVideoDecoder::OnFlushComplete() {
174 DCHECK_EQ(MessageLoop::current(), message_loop_
);
175 DCHECK(flush_callback_
.get());
177 AutoCallbackRunner
done_runner(flush_callback_
.release());
179 // Everything in the presentation time queue is invalid, clear the queue.
182 // Mark flush operation had been done.
186 void FFmpegVideoDecoder::Seek(base::TimeDelta time
, const FilterStatusCB
& cb
) {
187 if (MessageLoop::current() != message_loop_
) {
188 message_loop_
->PostTask(FROM_HERE
,
189 NewRunnableMethod(this, &FFmpegVideoDecoder::Seek
,
194 DCHECK_EQ(MessageLoop::current(), message_loop_
);
195 DCHECK(seek_cb_
.is_null());
197 pts_stream_
.Seek(time
);
199 decode_engine_
->Seek();
202 void FFmpegVideoDecoder::OnSeekComplete() {
203 DCHECK_EQ(MessageLoop::current(), message_loop_
);
204 DCHECK(!seek_cb_
.is_null());
206 ResetAndRunCB(&seek_cb_
, PIPELINE_OK
);
209 void FFmpegVideoDecoder::OnError() {
210 VideoFrameReady(NULL
);
213 void FFmpegVideoDecoder::OnReadComplete(Buffer
* buffer_in
) {
214 scoped_refptr
<Buffer
> buffer(buffer_in
);
215 message_loop_
->PostTask(
217 NewRunnableMethod(this,
218 &FFmpegVideoDecoder::OnReadCompleteTask
,
222 void FFmpegVideoDecoder::OnReadCompleteTask(scoped_refptr
<Buffer
> buffer
) {
223 DCHECK_EQ(MessageLoop::current(), message_loop_
);
224 DCHECK_NE(state_
, kStopped
); // because of Flush() before Stop().
226 // During decode, because reads are issued asynchronously, it is possible to
227 // receive multiple end of stream buffers since each read is acked. When the
228 // first end of stream buffer is read, FFmpeg may still have frames queued
229 // up in the decoder so we need to go through the decode loop until it stops
230 // giving sensible data. After that, the decoder should output empty
231 // frames. There are three states the decoder can be in:
233 // kNormal: This is the starting state. Buffers are decoded. Decode errors
235 // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2
236 // until no more data is returned to flush out remaining
237 // frames. The input buffer is ignored at this point.
238 // kDecodeFinished: All calls return empty frames.
240 // These are the possible state transitions.
242 // kNormal -> kFlushCodec:
243 // When buffer->IsEndOfStream() is first true.
244 // kNormal -> kDecodeFinished:
245 // A catastrophic failure occurs, and decoding needs to stop.
246 // kFlushCodec -> kDecodeFinished:
247 // When avcodec_decode_video2() returns 0 data or errors out.
248 // (any state) -> kNormal:
249 // Any time buffer->IsDiscontinuous() is true.
251 // Transition to kFlushCodec on the first end of stream buffer.
252 if (state_
== kNormal
&& buffer
->IsEndOfStream()) {
253 state_
= kFlushCodec
;
256 // Push all incoming timestamps into the priority queue as long as we have
257 // not yet received an end of stream buffer. It is important that this line
258 // stay below the state transition into kFlushCodec done above.
260 // TODO(ajwong): This push logic, along with the pop logic below needs to
261 // be reevaluated to correctly handle decode errors.
262 if (state_
== kNormal
) {
263 pts_stream_
.EnqueuePts(buffer
.get());
266 // Otherwise, attempt to decode a single frame.
267 decode_engine_
->ConsumeVideoSample(buffer
);
270 void FFmpegVideoDecoder::ProduceVideoFrame(
271 scoped_refptr
<VideoFrame
> video_frame
) {
272 if (MessageLoop::current() != message_loop_
) {
273 message_loop_
->PostTask(
275 NewRunnableMethod(this,
276 &FFmpegVideoDecoder::ProduceVideoFrame
, video_frame
));
280 DCHECK_EQ(MessageLoop::current(), message_loop_
);
282 // Synchronized flushing before stop should prevent this.
283 DCHECK_NE(state_
, kStopped
);
285 // If the decoding is finished, we just always return empty frames.
286 if (state_
== kDecodeFinished
) {
287 // Signal VideoRenderer the end of the stream event.
288 VideoFrameReady(VideoFrame::CreateEmptyFrame());
290 // Fall through, because we still need to keep record of this frame.
293 // Notify decode engine the available of new frame.
294 decode_engine_
->ProduceVideoFrame(video_frame
);
297 void FFmpegVideoDecoder::ConsumeVideoFrame(
298 scoped_refptr
<VideoFrame
> video_frame
,
299 const PipelineStatistics
& statistics
) {
300 DCHECK_EQ(MessageLoop::current(), message_loop_
);
301 DCHECK_NE(state_
, kStopped
);
303 statistics_callback_
->Run(statistics
);
305 if (video_frame
.get()) {
306 if (kPausing
== state_
|| kFlushing
== state_
) {
307 frame_queue_flushed_
.push_back(video_frame
);
308 if (kFlushing
== state_
)
313 // If we actually got data back, enqueue a frame.
314 pts_stream_
.UpdatePtsAndDuration(video_frame
.get());
316 video_frame
->SetTimestamp(pts_stream_
.current_pts());
317 video_frame
->SetDuration(pts_stream_
.current_duration());
319 VideoFrameReady(video_frame
);
321 // When in kFlushCodec, any errored decode, or a 0-lengthed frame,
322 // is taken as a signal to stop decoding.
323 if (state_
== kFlushCodec
) {
324 state_
= kDecodeFinished
;
326 // Signal VideoRenderer the end of the stream event.
327 VideoFrameReady(VideoFrame::CreateEmptyFrame());
332 void FFmpegVideoDecoder::ProduceVideoSample(
333 scoped_refptr
<Buffer
> buffer
) {
334 DCHECK_EQ(MessageLoop::current(), message_loop_
);
335 DCHECK_NE(state_
, kStopped
);
337 demuxer_stream_
->Read(base::Bind(&FFmpegVideoDecoder::OnReadComplete
,
341 int FFmpegVideoDecoder::width() {
342 DCHECK(info_
.success
);
343 return info_
.surface_width
;
346 int FFmpegVideoDecoder::height() {
347 DCHECK(info_
.success
);
348 return info_
.surface_height
;
351 void FFmpegVideoDecoder::FlushBuffers() {
352 while (!frame_queue_flushed_
.empty()) {
353 scoped_refptr
<VideoFrame
> video_frame
;
354 video_frame
= frame_queue_flushed_
.front();
355 frame_queue_flushed_
.pop_front();
357 // Return frames back to the decode engine.
358 decode_engine_
->ProduceVideoFrame(video_frame
);
362 void FFmpegVideoDecoder::SetVideoDecodeEngineForTest(
363 VideoDecodeEngine
* engine
) {
364 decode_engine_
.reset(engine
);