Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / media / filters / ffmpeg_video_decoder.cc
blob93dcee2157a4bfc12f25759eb55dc6abc4431607
1 // Copyright (c) 2012 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 <algorithm>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/command_line.h"
13 #include "base/location.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "media/base/bind_to_current_loop.h"
17 #include "media/base/decoder_buffer.h"
18 #include "media/base/limits.h"
19 #include "media/base/media_switches.h"
20 #include "media/base/pipeline.h"
21 #include "media/base/video_decoder_config.h"
22 #include "media/base/video_frame.h"
23 #include "media/base/video_util.h"
24 #include "media/ffmpeg/ffmpeg_common.h"
25 #include "media/filters/ffmpeg_glue.h"
27 namespace media {
29 // Always try to use three threads for video decoding. There is little reason
30 // not to since current day CPUs tend to be multi-core and we measured
31 // performance benefits on older machines such as P4s with hyperthreading.
33 // Handling decoding on separate threads also frees up the pipeline thread to
34 // continue processing. Although it'd be nice to have the option of a single
35 // decoding thread, FFmpeg treats having one thread the same as having zero
36 // threads (i.e., avcodec_decode_video() will execute on the calling thread).
37 // Yet another reason for having two threads :)
38 static const int kDecodeThreads = 2;
39 static const int kMaxDecodeThreads = 16;
41 // Returns the number of threads given the FFmpeg CodecID. Also inspects the
42 // command line for a valid --video-threads flag.
43 static int GetThreadCount(AVCodecID codec_id) {
44 // Refer to http://crbug.com/93932 for tsan suppressions on decoding.
45 int decode_threads = kDecodeThreads;
47 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
48 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads));
49 if (threads.empty() || !base::StringToInt(threads, &decode_threads))
50 return decode_threads;
52 decode_threads = std::max(decode_threads, 0);
53 decode_threads = std::min(decode_threads, kMaxDecodeThreads);
54 return decode_threads;
57 static int GetVideoBufferImpl(struct AVCodecContext* s,
58 AVFrame* frame,
59 int flags) {
60 FFmpegVideoDecoder* decoder = static_cast<FFmpegVideoDecoder*>(s->opaque);
61 return decoder->GetVideoBuffer(s, frame, flags);
64 static void ReleaseVideoBufferImpl(void* opaque, uint8* data) {
65 scoped_refptr<VideoFrame> video_frame;
66 video_frame.swap(reinterpret_cast<VideoFrame**>(&opaque));
69 static size_t RoundUp(size_t value, size_t alignment) {
70 // Check that |alignment| is a power of 2.
71 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
72 return ((value + (alignment - 1)) & ~(alignment - 1));
75 FFmpegVideoDecoder::FFmpegVideoDecoder(
76 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
77 : task_runner_(task_runner), state_(kUninitialized),
78 decode_nalus_(false) {}
80 int FFmpegVideoDecoder::GetVideoBuffer(struct AVCodecContext* codec_context,
81 AVFrame* frame,
82 int flags) {
83 // Don't use |codec_context_| here! With threaded decoding,
84 // it will contain unsynchronized width/height/pix_fmt values,
85 // whereas |codec_context| contains the current threads's
86 // updated width/height/pix_fmt, which can change for adaptive
87 // content.
88 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context->pix_fmt);
89 if (format == VideoFrame::UNKNOWN)
90 return AVERROR(EINVAL);
91 DCHECK(format == VideoFrame::YV12 || format == VideoFrame::YV16 ||
92 format == VideoFrame::YV12J || format == VideoFrame::YV24);
94 gfx::Size size(codec_context->width, codec_context->height);
95 const int ret = av_image_check_size(size.width(), size.height(), 0, NULL);
96 if (ret < 0)
97 return ret;
99 gfx::Size natural_size;
100 if (codec_context->sample_aspect_ratio.num > 0) {
101 natural_size = GetNaturalSize(size,
102 codec_context->sample_aspect_ratio.num,
103 codec_context->sample_aspect_ratio.den);
104 } else {
105 natural_size = config_.natural_size();
108 // FFmpeg has specific requirements on the allocation size of the frame. The
109 // following logic replicates FFmpeg's allocation strategy to ensure buffers
110 // are not overread / overwritten. See ff_init_buffer_info() for details.
112 // When lowres is non-zero, dimensions should be divided by 2^(lowres), but
113 // since we don't use this, just DCHECK that it's zero.
115 // Always round up to a multiple of two to match VideoFrame restrictions on
116 // frame alignment.
117 DCHECK_EQ(codec_context->lowres, 0);
118 gfx::Size coded_size(
119 RoundUp(std::max(size.width(), codec_context->coded_width), 2),
120 RoundUp(std::max(size.height(), codec_context->coded_height), 2));
122 if (!VideoFrame::IsValidConfig(
123 format, coded_size, gfx::Rect(size), natural_size))
124 return AVERROR(EINVAL);
126 scoped_refptr<VideoFrame> video_frame = frame_pool_.CreateFrame(
127 format, coded_size, gfx::Rect(size), natural_size, kNoTimestamp());
129 for (int i = 0; i < 3; i++) {
130 frame->data[i] = video_frame->data(i);
131 frame->linesize[i] = video_frame->stride(i);
134 frame->width = coded_size.width();
135 frame->height = coded_size.height();
136 frame->format = codec_context->pix_fmt;
137 frame->reordered_opaque = codec_context->reordered_opaque;
139 // Now create an AVBufferRef for the data just allocated. It will own the
140 // reference to the VideoFrame object.
141 void* opaque = NULL;
142 video_frame.swap(reinterpret_cast<VideoFrame**>(&opaque));
143 frame->buf[0] =
144 av_buffer_create(frame->data[0],
145 VideoFrame::AllocationSize(format, coded_size),
146 ReleaseVideoBufferImpl,
147 opaque,
149 return 0;
152 std::string FFmpegVideoDecoder::GetDisplayName() const {
153 return "FFmpegVideoDecoder";
156 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config,
157 bool low_delay,
158 const PipelineStatusCB& status_cb,
159 const OutputCB& output_cb) {
160 DCHECK(task_runner_->BelongsToCurrentThread());
161 DCHECK(!config.is_encrypted());
162 DCHECK(!output_cb.is_null());
164 FFmpegGlue::InitializeFFmpeg();
166 config_ = config;
167 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
169 if (!config.IsValidConfig() || !ConfigureDecoder(low_delay)) {
170 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
171 return;
174 output_cb_ = BindToCurrentLoop(output_cb);
176 // Success!
177 state_ = kNormal;
178 initialize_cb.Run(PIPELINE_OK);
181 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
182 const DecodeCB& decode_cb) {
183 DCHECK(task_runner_->BelongsToCurrentThread());
184 DCHECK(buffer.get());
185 DCHECK(!decode_cb.is_null());
186 CHECK_NE(state_, kUninitialized);
188 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb);
190 if (state_ == kError) {
191 decode_cb_bound.Run(kDecodeError);
192 return;
195 if (state_ == kDecodeFinished) {
196 decode_cb_bound.Run(kOk);
197 return;
200 DCHECK_EQ(state_, kNormal);
202 // During decode, because reads are issued asynchronously, it is possible to
203 // receive multiple end of stream buffers since each decode is acked. When the
204 // first end of stream buffer is read, FFmpeg may still have frames queued
205 // up in the decoder so we need to go through the decode loop until it stops
206 // giving sensible data. After that, the decoder should output empty
207 // frames. There are three states the decoder can be in:
209 // kNormal: This is the starting state. Buffers are decoded. Decode errors
210 // are discarded.
211 // kDecodeFinished: All calls return empty frames.
212 // kError: Unexpected error happened.
214 // These are the possible state transitions.
216 // kNormal -> kDecodeFinished:
217 // When EOS buffer is received and the codec has been flushed.
218 // kNormal -> kError:
219 // A decoding error occurs and decoding needs to stop.
220 // (any state) -> kNormal:
221 // Any time Reset() is called.
223 bool has_produced_frame;
224 do {
225 has_produced_frame = false;
226 if (!FFmpegDecode(buffer, &has_produced_frame)) {
227 state_ = kError;
228 decode_cb_bound.Run(kDecodeError);
229 return;
231 // Repeat to flush the decoder after receiving EOS buffer.
232 } while (buffer->end_of_stream() && has_produced_frame);
234 if (buffer->end_of_stream())
235 state_ = kDecodeFinished;
237 decode_cb_bound.Run(kOk);
240 void FFmpegVideoDecoder::Reset(const base::Closure& closure) {
241 DCHECK(task_runner_->BelongsToCurrentThread());
243 avcodec_flush_buffers(codec_context_.get());
244 state_ = kNormal;
245 task_runner_->PostTask(FROM_HERE, closure);
248 FFmpegVideoDecoder::~FFmpegVideoDecoder() {
249 DCHECK(task_runner_->BelongsToCurrentThread());
251 if (state_ != kUninitialized)
252 ReleaseFFmpegResources();
255 bool FFmpegVideoDecoder::FFmpegDecode(
256 const scoped_refptr<DecoderBuffer>& buffer,
257 bool* has_produced_frame) {
258 DCHECK(!*has_produced_frame);
260 // Create a packet for input data.
261 // Due to FFmpeg API changes we no longer have const read-only pointers.
262 AVPacket packet;
263 av_init_packet(&packet);
264 if (buffer->end_of_stream()) {
265 packet.data = NULL;
266 packet.size = 0;
267 } else {
268 packet.data = const_cast<uint8*>(buffer->data());
269 packet.size = buffer->data_size();
271 // Let FFmpeg handle presentation timestamp reordering.
272 codec_context_->reordered_opaque = buffer->timestamp().InMicroseconds();
275 int frame_decoded = 0;
276 int result = avcodec_decode_video2(codec_context_.get(),
277 av_frame_.get(),
278 &frame_decoded,
279 &packet);
280 // Log the problem if we can't decode a video frame and exit early.
281 if (result < 0) {
282 LOG(ERROR) << "Error decoding video: " << buffer->AsHumanReadableString();
283 return false;
286 // FFmpeg says some codecs might have multiple frames per packet. Previous
287 // discussions with rbultje@ indicate this shouldn't be true for the codecs
288 // we use.
289 DCHECK_EQ(result, packet.size);
291 // If no frame was produced then signal that more data is required to
292 // produce more frames. This can happen under two circumstances:
293 // 1) Decoder was recently initialized/flushed
294 // 2) End of stream was reached and all internal frames have been output
295 if (frame_decoded == 0) {
296 return true;
299 // TODO(fbarchard): Work around for FFmpeg http://crbug.com/27675
300 // The decoder is in a bad state and not decoding correctly.
301 // Checking for NULL avoids a crash in CopyPlane().
302 if (!av_frame_->data[VideoFrame::kYPlane] ||
303 !av_frame_->data[VideoFrame::kUPlane] ||
304 !av_frame_->data[VideoFrame::kVPlane]) {
305 LOG(ERROR) << "Video frame was produced yet has invalid frame data.";
306 av_frame_unref(av_frame_.get());
307 return false;
310 scoped_refptr<VideoFrame> frame =
311 reinterpret_cast<VideoFrame*>(av_buffer_get_opaque(av_frame_->buf[0]));
312 frame->set_timestamp(
313 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque));
314 *has_produced_frame = true;
315 output_cb_.Run(frame);
317 av_frame_unref(av_frame_.get());
318 return true;
321 void FFmpegVideoDecoder::ReleaseFFmpegResources() {
322 codec_context_.reset();
323 av_frame_.reset();
326 bool FFmpegVideoDecoder::ConfigureDecoder(bool low_delay) {
327 // Release existing decoder resources if necessary.
328 ReleaseFFmpegResources();
330 // Initialize AVCodecContext structure.
331 codec_context_.reset(avcodec_alloc_context3(NULL));
332 VideoDecoderConfigToAVCodecContext(config_, codec_context_.get());
334 codec_context_->thread_count = GetThreadCount(codec_context_->codec_id);
335 codec_context_->thread_type = low_delay ? FF_THREAD_SLICE : FF_THREAD_FRAME;
336 codec_context_->opaque = this;
337 codec_context_->flags |= CODEC_FLAG_EMU_EDGE;
338 codec_context_->get_buffer2 = GetVideoBufferImpl;
339 codec_context_->refcounted_frames = 1;
341 if (decode_nalus_)
342 codec_context_->flags2 |= CODEC_FLAG2_CHUNKS;
344 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
345 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) {
346 ReleaseFFmpegResources();
347 return false;
350 av_frame_.reset(av_frame_alloc());
351 return true;
354 } // namespace media