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

Side by Side Diff: media/video/ffmpeg_video_decode_engine.cc

Issue 8772069: Collapse FFmpegVideoDecodeEngine into FFmpegVideoDecoder and remove VideoDecodeEngine. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixes Created 9 years 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/video/ffmpeg_video_decode_engine.h ('k') | media/video/video_decode_engine.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "media/video/ffmpeg_video_decode_engine.h"
6
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/string_number_conversions.h"
10 #include "media/base/buffers.h"
11 #include "media/base/media_switches.h"
12 #include "media/base/video_decoder_config.h"
13 #include "media/base/video_util.h"
14 #include "media/ffmpeg/ffmpeg_common.h"
15
16 namespace media {
17
18 FFmpegVideoDecodeEngine::FFmpegVideoDecodeEngine()
19 : codec_context_(NULL),
20 av_frame_(NULL),
21 frame_rate_numerator_(0),
22 frame_rate_denominator_(0) {
23 }
24
25 FFmpegVideoDecodeEngine::~FFmpegVideoDecodeEngine() {
26 Uninitialize();
27 }
28
29 bool FFmpegVideoDecodeEngine::Initialize(const VideoDecoderConfig& config) {
30 frame_rate_numerator_ = config.frame_rate_numerator();
31 frame_rate_denominator_ = config.frame_rate_denominator();
32
33 // Always try to use three threads for video decoding. There is little reason
34 // not to since current day CPUs tend to be multi-core and we measured
35 // performance benefits on older machines such as P4s with hyperthreading.
36 //
37 // Handling decoding on separate threads also frees up the pipeline thread to
38 // continue processing. Although it'd be nice to have the option of a single
39 // decoding thread, FFmpeg treats having one thread the same as having zero
40 // threads (i.e., avcodec_decode_video() will execute on the calling thread).
41 // Yet another reason for having two threads :)
42 static const int kDecodeThreads = 2;
43 static const int kMaxDecodeThreads = 16;
44
45 // Initialize AVCodecContext structure.
46 codec_context_ = avcodec_alloc_context();
47 VideoDecoderConfigToAVCodecContext(config, codec_context_);
48
49 // Enable motion vector search (potentially slow), strong deblocking filter
50 // for damaged macroblocks, and set our error detection sensitivity.
51 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
52 codec_context_->error_recognition = FF_ER_CAREFUL;
53
54 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
55
56 // TODO(fbarchard): Improve thread logic based on size / codec.
57 // TODO(fbarchard): Fix bug affecting video-cookie.html
58 // 07/21/11(ihf): Still about 20 failures when enabling.
59 int decode_threads = (codec_context_->codec_id == CODEC_ID_THEORA) ?
60 1 : kDecodeThreads;
61
62 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
63 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads));
64 if ((!threads.empty() &&
65 !base::StringToInt(threads, &decode_threads)) ||
66 decode_threads < 0 || decode_threads > kMaxDecodeThreads) {
67 decode_threads = kDecodeThreads;
68 }
69
70 codec_context_->thread_count = decode_threads;
71
72 av_frame_ = avcodec_alloc_frame();
73
74 // Open the codec!
75 return codec && avcodec_open(codec_context_, codec) >= 0;
76 }
77
78 void FFmpegVideoDecodeEngine::Uninitialize() {
79 if (codec_context_) {
80 av_free(codec_context_->extradata);
81 avcodec_close(codec_context_);
82 av_free(codec_context_);
83 codec_context_ = NULL;
84 }
85 if (av_frame_) {
86 av_free(av_frame_);
87 av_frame_ = NULL;
88 }
89 frame_rate_numerator_ = 0;
90 frame_rate_denominator_ = 0;
91 }
92
93 bool FFmpegVideoDecodeEngine::Decode(const scoped_refptr<Buffer>& buffer,
94 scoped_refptr<VideoFrame>* video_frame) {
95 DCHECK(video_frame);
96
97 // Create a packet for input data.
98 // Due to FFmpeg API changes we no longer have const read-only pointers.
99 AVPacket packet;
100 av_init_packet(&packet);
101 packet.data = const_cast<uint8*>(buffer->GetData());
102 packet.size = buffer->GetDataSize();
103
104 // Let FFmpeg handle presentation timestamp reordering.
105 codec_context_->reordered_opaque = buffer->GetTimestamp().InMicroseconds();
106
107 // This is for codecs not using get_buffer to initialize
108 // |av_frame_->reordered_opaque|
109 av_frame_->reordered_opaque = codec_context_->reordered_opaque;
110
111 int frame_decoded = 0;
112 int result = avcodec_decode_video2(codec_context_,
113 av_frame_,
114 &frame_decoded,
115 &packet);
116 // Log the problem if we can't decode a video frame and exit early.
117 if (result < 0) {
118 LOG(ERROR) << "Error decoding a video frame with timestamp: "
119 << buffer->GetTimestamp().InMicroseconds() << " us, duration: "
120 << buffer->GetDuration().InMicroseconds() << " us, packet size: "
121 << buffer->GetDataSize() << " bytes";
122 *video_frame = NULL;
123 return false;
124 }
125
126 // If no frame was produced then signal that more data is required to
127 // produce more frames. This can happen under two circumstances:
128 // 1) Decoder was recently initialized/flushed
129 // 2) End of stream was reached and all internal frames have been output
130 if (frame_decoded == 0) {
131 *video_frame = NULL;
132 return true;
133 }
134
135 // TODO(fbarchard): Work around for FFmpeg http://crbug.com/27675
136 // The decoder is in a bad state and not decoding correctly.
137 // Checking for NULL avoids a crash in CopyPlane().
138 if (!av_frame_->data[VideoFrame::kYPlane] ||
139 !av_frame_->data[VideoFrame::kUPlane] ||
140 !av_frame_->data[VideoFrame::kVPlane]) {
141 LOG(ERROR) << "Video frame was produced yet has invalid frame data.";
142 *video_frame = NULL;
143 return false;
144 }
145
146 // We've got a frame! Make sure we have a place to store it.
147 *video_frame = AllocateVideoFrame();
148 if (!(*video_frame)) {
149 LOG(ERROR) << "Failed to allocate video frame";
150 return false;
151 }
152
153 // Determine timestamp and calculate the duration based on the repeat picture
154 // count. According to FFmpeg docs, the total duration can be calculated as
155 // follows:
156 // fps = 1 / time_base
157 //
158 // duration = (1 / fps) + (repeat_pict) / (2 * fps)
159 // = (2 + repeat_pict) / (2 * fps)
160 // = (2 + repeat_pict) / (2 * (1 / time_base))
161 DCHECK_LE(av_frame_->repeat_pict, 2); // Sanity check.
162 AVRational doubled_time_base;
163 doubled_time_base.num = frame_rate_denominator_;
164 doubled_time_base.den = frame_rate_numerator_ * 2;
165
166 (*video_frame)->SetTimestamp(
167 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque));
168 (*video_frame)->SetDuration(
169 ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict));
170
171 // Copy the frame data since FFmpeg reuses internal buffers for AVFrame
172 // output, meaning the data is only valid until the next
173 // avcodec_decode_video() call.
174 int y_rows = codec_context_->height;
175 int uv_rows = codec_context_->height;
176 if (codec_context_->pix_fmt == PIX_FMT_YUV420P) {
177 uv_rows /= 2;
178 }
179
180 CopyYPlane(av_frame_->data[0], av_frame_->linesize[0], y_rows, *video_frame);
181 CopyUPlane(av_frame_->data[1], av_frame_->linesize[1], uv_rows, *video_frame);
182 CopyVPlane(av_frame_->data[2], av_frame_->linesize[2], uv_rows, *video_frame);
183
184 return true;
185 }
186
187 void FFmpegVideoDecodeEngine::Flush() {
188 avcodec_flush_buffers(codec_context_);
189 }
190
191 scoped_refptr<VideoFrame> FFmpegVideoDecodeEngine::AllocateVideoFrame() {
192 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt);
193 size_t width = codec_context_->width;
194 size_t height = codec_context_->height;
195
196 return VideoFrame::CreateFrame(format, width, height,
197 kNoTimestamp, kNoTimestamp);
198 }
199
200 } // namespace media
OLDNEW
« no previous file with comments | « media/video/ffmpeg_video_decode_engine.h ('k') | media/video/video_decode_engine.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698