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

Side by Side Diff: media/filters/ffmpeg_video_decoder.cc

Issue 65803002: Replace MessageLoopProxy with SingleThreadTaskRunner for media/filters/ + associated code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 1 month 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/ffmpeg_video_decoder.h" 5 #include "media/filters/ffmpeg_video_decoder.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
16 #include "media/base/bind_to_loop.h" 16 #include "media/base/bind_to_loop.h"
17 #include "media/base/decoder_buffer.h" 17 #include "media/base/decoder_buffer.h"
18 #include "media/base/limits.h" 18 #include "media/base/limits.h"
19 #include "media/base/media_switches.h" 19 #include "media/base/media_switches.h"
20 #include "media/base/pipeline.h" 20 #include "media/base/pipeline.h"
21 #include "media/base/video_decoder_config.h" 21 #include "media/base/video_decoder_config.h"
22 #include "media/base/video_frame.h" 22 #include "media/base/video_frame.h"
23 #include "media/base/video_util.h" 23 #include "media/base/video_util.h"
24 #include "media/ffmpeg/ffmpeg_common.h" 24 #include "media/ffmpeg/ffmpeg_common.h"
(...skipping 23 matching lines...) Expand all
48 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads)); 48 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads));
49 if (threads.empty() || !base::StringToInt(threads, &decode_threads)) 49 if (threads.empty() || !base::StringToInt(threads, &decode_threads))
50 return decode_threads; 50 return decode_threads;
51 51
52 decode_threads = std::max(decode_threads, 0); 52 decode_threads = std::max(decode_threads, 0);
53 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 53 decode_threads = std::min(decode_threads, kMaxDecodeThreads);
54 return decode_threads; 54 return decode_threads;
55 } 55 }
56 56
57 FFmpegVideoDecoder::FFmpegVideoDecoder( 57 FFmpegVideoDecoder::FFmpegVideoDecoder(
58 const scoped_refptr<base::MessageLoopProxy>& message_loop) 58 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
59 : message_loop_(message_loop), 59 : task_runner_(task_runner),
60 weak_factory_(this), 60 weak_factory_(this),
61 state_(kUninitialized) { 61 state_(kUninitialized) {
62 } 62 }
63 63
64 int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context, 64 int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context,
65 AVFrame* frame) { 65 AVFrame* frame) {
66 // Don't use |codec_context_| here! With threaded decoding, 66 // Don't use |codec_context_| here! With threaded decoding,
67 // it will contain unsynchronized width/height/pix_fmt values, 67 // it will contain unsynchronized width/height/pix_fmt values,
68 // whereas |codec_context| contains the current threads's 68 // whereas |codec_context| contains the current threads's
69 // updated width/height/pix_fmt, which can change for adaptive 69 // updated width/height/pix_fmt, which can change for adaptive
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 video_frame.swap(reinterpret_cast<VideoFrame**>(&frame->opaque)); 122 video_frame.swap(reinterpret_cast<VideoFrame**>(&frame->opaque));
123 123
124 // The FFmpeg API expects us to zero the data pointers in 124 // The FFmpeg API expects us to zero the data pointers in
125 // this callback 125 // this callback
126 memset(frame->data, 0, sizeof(frame->data)); 126 memset(frame->data, 0, sizeof(frame->data));
127 frame->opaque = NULL; 127 frame->opaque = NULL;
128 } 128 }
129 129
130 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, 130 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config,
131 const PipelineStatusCB& status_cb) { 131 const PipelineStatusCB& status_cb) {
132 DCHECK(message_loop_->BelongsToCurrentThread()); 132 DCHECK(task_runner_->BelongsToCurrentThread());
133 DCHECK(decode_cb_.is_null()); 133 DCHECK(decode_cb_.is_null());
134 DCHECK(reset_cb_.is_null()); 134 DCHECK(reset_cb_.is_null());
135 DCHECK(!config.is_encrypted()); 135 DCHECK(!config.is_encrypted());
136 136
137 FFmpegGlue::InitializeFFmpeg(); 137 FFmpegGlue::InitializeFFmpeg();
138 weak_this_ = weak_factory_.GetWeakPtr(); 138 weak_this_ = weak_factory_.GetWeakPtr();
139 139
140 config_ = config; 140 config_ = config;
141 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); 141 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
142 142
143 if (!config.IsValidConfig() || !ConfigureDecoder()) { 143 if (!config.IsValidConfig() || !ConfigureDecoder()) {
144 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 144 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
145 return; 145 return;
146 } 146 }
147 147
148 // Success! 148 // Success!
149 state_ = kNormal; 149 state_ = kNormal;
150 initialize_cb.Run(PIPELINE_OK); 150 initialize_cb.Run(PIPELINE_OK);
151 } 151 }
152 152
153 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 153 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
154 const DecodeCB& decode_cb) { 154 const DecodeCB& decode_cb) {
155 DCHECK(message_loop_->BelongsToCurrentThread()); 155 DCHECK(task_runner_->BelongsToCurrentThread());
156 DCHECK(!decode_cb.is_null()); 156 DCHECK(!decode_cb.is_null());
157 CHECK_NE(state_, kUninitialized); 157 CHECK_NE(state_, kUninitialized);
158 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported."; 158 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported.";
159 decode_cb_ = BindToCurrentLoop(decode_cb); 159 decode_cb_ = BindToCurrentLoop(decode_cb);
160 160
161 if (state_ == kError) { 161 if (state_ == kError) {
162 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); 162 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL);
163 return; 163 return;
164 } 164 }
165 165
166 // Return empty frames if decoding has finished. 166 // Return empty frames if decoding has finished.
167 if (state_ == kDecodeFinished) { 167 if (state_ == kDecodeFinished) {
168 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); 168 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEmptyFrame());
169 return; 169 return;
170 } 170 }
171 171
172 DecodeBuffer(buffer); 172 DecodeBuffer(buffer);
173 } 173 }
174 174
175 void FFmpegVideoDecoder::Reset(const base::Closure& closure) { 175 void FFmpegVideoDecoder::Reset(const base::Closure& closure) {
176 DCHECK(message_loop_->BelongsToCurrentThread()); 176 DCHECK(task_runner_->BelongsToCurrentThread());
177 DCHECK(reset_cb_.is_null()); 177 DCHECK(reset_cb_.is_null());
178 reset_cb_ = BindToCurrentLoop(closure); 178 reset_cb_ = BindToCurrentLoop(closure);
179 179
180 // Defer the reset if a decode is pending. 180 // Defer the reset if a decode is pending.
181 if (!decode_cb_.is_null()) 181 if (!decode_cb_.is_null())
182 return; 182 return;
183 183
184 DoReset(); 184 DoReset();
185 } 185 }
186 186
187 void FFmpegVideoDecoder::DoReset() { 187 void FFmpegVideoDecoder::DoReset() {
188 DCHECK(decode_cb_.is_null()); 188 DCHECK(decode_cb_.is_null());
189 189
190 avcodec_flush_buffers(codec_context_.get()); 190 avcodec_flush_buffers(codec_context_.get());
191 state_ = kNormal; 191 state_ = kNormal;
192 base::ResetAndReturn(&reset_cb_).Run(); 192 base::ResetAndReturn(&reset_cb_).Run();
193 } 193 }
194 194
195 void FFmpegVideoDecoder::Stop(const base::Closure& closure) { 195 void FFmpegVideoDecoder::Stop(const base::Closure& closure) {
196 DCHECK(message_loop_->BelongsToCurrentThread()); 196 DCHECK(task_runner_->BelongsToCurrentThread());
197 base::ScopedClosureRunner runner(BindToCurrentLoop(closure)); 197 base::ScopedClosureRunner runner(BindToCurrentLoop(closure));
198 198
199 if (state_ == kUninitialized) 199 if (state_ == kUninitialized)
200 return; 200 return;
201 201
202 if (!decode_cb_.is_null()) { 202 if (!decode_cb_.is_null()) {
203 base::ResetAndReturn(&decode_cb_).Run(kOk, NULL); 203 base::ResetAndReturn(&decode_cb_).Run(kOk, NULL);
204 // Reset is pending only when decode is pending. 204 // Reset is pending only when decode is pending.
205 if (!reset_cb_.is_null()) 205 if (!reset_cb_.is_null())
206 base::ResetAndReturn(&reset_cb_).Run(); 206 base::ResetAndReturn(&reset_cb_).Run();
207 } 207 }
208 208
209 ReleaseFFmpegResources(); 209 ReleaseFFmpegResources();
210 state_ = kUninitialized; 210 state_ = kUninitialized;
211 } 211 }
212 212
213 FFmpegVideoDecoder::~FFmpegVideoDecoder() { 213 FFmpegVideoDecoder::~FFmpegVideoDecoder() {
214 DCHECK_EQ(kUninitialized, state_); 214 DCHECK_EQ(kUninitialized, state_);
215 DCHECK(!codec_context_); 215 DCHECK(!codec_context_);
216 DCHECK(!av_frame_); 216 DCHECK(!av_frame_);
217 } 217 }
218 218
219 void FFmpegVideoDecoder::DecodeBuffer( 219 void FFmpegVideoDecoder::DecodeBuffer(
220 const scoped_refptr<DecoderBuffer>& buffer) { 220 const scoped_refptr<DecoderBuffer>& buffer) {
221 DCHECK(message_loop_->BelongsToCurrentThread()); 221 DCHECK(task_runner_->BelongsToCurrentThread());
222 DCHECK_NE(state_, kUninitialized); 222 DCHECK_NE(state_, kUninitialized);
223 DCHECK_NE(state_, kDecodeFinished); 223 DCHECK_NE(state_, kDecodeFinished);
224 DCHECK_NE(state_, kError); 224 DCHECK_NE(state_, kError);
225 DCHECK(reset_cb_.is_null()); 225 DCHECK(reset_cb_.is_null());
226 DCHECK(!decode_cb_.is_null()); 226 DCHECK(!decode_cb_.is_null());
227 DCHECK(buffer); 227 DCHECK(buffer);
228 228
229 // During decode, because reads are issued asynchronously, it is possible to 229 // During decode, because reads are issued asynchronously, it is possible to
230 // receive multiple end of stream buffers since each decode is acked. When the 230 // receive multiple end of stream buffers since each decode is acked. When the
231 // first end of stream buffer is read, FFmpeg may still have frames queued 231 // first end of stream buffer is read, FFmpeg may still have frames queued
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { 379 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) {
380 ReleaseFFmpegResources(); 380 ReleaseFFmpegResources();
381 return false; 381 return false;
382 } 382 }
383 383
384 av_frame_.reset(avcodec_alloc_frame()); 384 av_frame_.reset(avcodec_alloc_frame());
385 return true; 385 return true;
386 } 386 }
387 387
388 } // namespace media 388 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698