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

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

Issue 10855051: Use enum instead of string in MessageLoopFactory::GetMessageLoop* (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years, 4 months 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/filters/ffmpeg_video_decoder.h ('k') | media/filters/ffmpeg_video_decoder_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/message_loop.h" 13 #include "base/location.h"
14 #include "base/message_loop_proxy.h"
14 #include "base/string_number_conversions.h" 15 #include "base/string_number_conversions.h"
15 #include "media/base/decoder_buffer.h" 16 #include "media/base/decoder_buffer.h"
16 #include "media/base/demuxer_stream.h" 17 #include "media/base/demuxer_stream.h"
17 #include "media/base/limits.h" 18 #include "media/base/limits.h"
18 #include "media/base/media_switches.h" 19 #include "media/base/media_switches.h"
19 #include "media/base/pipeline.h" 20 #include "media/base/pipeline.h"
20 #include "media/base/video_decoder_config.h" 21 #include "media/base/video_decoder_config.h"
21 #include "media/base/video_frame.h" 22 #include "media/base/video_frame.h"
22 #include "media/base/video_util.h" 23 #include "media/base/video_util.h"
23 #include "media/ffmpeg/ffmpeg_common.h" 24 #include "media/ffmpeg/ffmpeg_common.h"
(...skipping 23 matching lines...) Expand all
47 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads)); 48 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads));
48 if (threads.empty() || !base::StringToInt(threads, &decode_threads)) 49 if (threads.empty() || !base::StringToInt(threads, &decode_threads))
49 return decode_threads; 50 return decode_threads;
50 51
51 decode_threads = std::max(decode_threads, 0); 52 decode_threads = std::max(decode_threads, 0);
52 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 53 decode_threads = std::min(decode_threads, kMaxDecodeThreads);
53 return decode_threads; 54 return decode_threads;
54 } 55 }
55 56
56 FFmpegVideoDecoder::FFmpegVideoDecoder( 57 FFmpegVideoDecoder::FFmpegVideoDecoder(
57 const base::Callback<MessageLoop*()>& message_loop_cb, 58 const MessageLoopFactoryCB& message_loop_factory_cb,
58 Decryptor* decryptor) 59 Decryptor* decryptor)
59 : message_loop_factory_cb_(message_loop_cb), 60 : message_loop_factory_cb_(message_loop_factory_cb),
60 message_loop_(NULL), 61 message_loop_(NULL),
61 state_(kUninitialized), 62 state_(kUninitialized),
62 codec_context_(NULL), 63 codec_context_(NULL),
63 av_frame_(NULL), 64 av_frame_(NULL),
64 decryptor_(decryptor) { 65 decryptor_(decryptor) {
65 } 66 }
66 67
67 int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context, 68 int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context,
68 AVFrame* frame) { 69 AVFrame* frame) {
69 // Don't use |codec_context_| here! With threaded decoding, 70 // Don't use |codec_context_| here! With threaded decoding,
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 frame->opaque = NULL; 133 frame->opaque = NULL;
133 } 134 }
134 135
135 void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, 136 void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
136 const PipelineStatusCB& status_cb, 137 const PipelineStatusCB& status_cb,
137 const StatisticsCB& statistics_cb) { 138 const StatisticsCB& statistics_cb) {
138 // Ensure FFmpeg has been initialized 139 // Ensure FFmpeg has been initialized
139 FFmpegGlue::GetInstance(); 140 FFmpegGlue::GetInstance();
140 141
141 if (!message_loop_) { 142 if (!message_loop_) {
142 message_loop_ = message_loop_factory_cb_.Run(); 143 message_loop_ = base::ResetAndReturn(&message_loop_factory_cb_).Run();
143 message_loop_factory_cb_.Reset();
144
145 message_loop_->PostTask(FROM_HERE, base::Bind( 144 message_loop_->PostTask(FROM_HERE, base::Bind(
146 &FFmpegVideoDecoder::Initialize, this, 145 &FFmpegVideoDecoder::Initialize, this,
147 stream, status_cb, statistics_cb)); 146 stream, status_cb, statistics_cb));
148 return; 147 return;
149 } 148 }
150 149
151 DCHECK_EQ(MessageLoop::current(), message_loop_); 150 DCHECK(message_loop_->BelongsToCurrentThread());
152 DCHECK(!demuxer_stream_); 151 DCHECK(!demuxer_stream_);
153 152
154 if (!stream) { 153 if (!stream) {
155 status_cb.Run(PIPELINE_ERROR_DECODE); 154 status_cb.Run(PIPELINE_ERROR_DECODE);
156 return; 155 return;
157 } 156 }
158 157
159 demuxer_stream_ = stream; 158 demuxer_stream_ = stream;
160 statistics_cb_ = statistics_cb; 159 statistics_cb_ = statistics_cb;
161 160
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 } 200 }
202 201
203 void FFmpegVideoDecoder::Read(const ReadCB& read_cb) { 202 void FFmpegVideoDecoder::Read(const ReadCB& read_cb) {
204 // Complete operation asynchronously on different stack of execution as per 203 // Complete operation asynchronously on different stack of execution as per
205 // the API contract of VideoDecoder::Read() 204 // the API contract of VideoDecoder::Read()
206 message_loop_->PostTask(FROM_HERE, base::Bind( 205 message_loop_->PostTask(FROM_HERE, base::Bind(
207 &FFmpegVideoDecoder::DoRead, this, read_cb)); 206 &FFmpegVideoDecoder::DoRead, this, read_cb));
208 } 207 }
209 208
210 void FFmpegVideoDecoder::Reset(const base::Closure& closure) { 209 void FFmpegVideoDecoder::Reset(const base::Closure& closure) {
211 if (MessageLoop::current() != message_loop_) { 210 if (!message_loop_->BelongsToCurrentThread()) {
212 message_loop_->PostTask(FROM_HERE, base::Bind( 211 message_loop_->PostTask(FROM_HERE, base::Bind(
213 &FFmpegVideoDecoder::Reset, this, closure)); 212 &FFmpegVideoDecoder::Reset, this, closure));
214 return; 213 return;
215 } 214 }
216 215
217 reset_cb_ = closure; 216 reset_cb_ = closure;
218 217
219 // Defer the reset if a read is pending. 218 // Defer the reset if a read is pending.
220 if (!read_cb_.is_null()) 219 if (!read_cb_.is_null())
221 return; 220 return;
222 221
223 DoReset(); 222 DoReset();
224 } 223 }
225 224
226 void FFmpegVideoDecoder::DoReset() { 225 void FFmpegVideoDecoder::DoReset() {
227 DCHECK(read_cb_.is_null()); 226 DCHECK(read_cb_.is_null());
228 227
229 avcodec_flush_buffers(codec_context_); 228 avcodec_flush_buffers(codec_context_);
230 state_ = kNormal; 229 state_ = kNormal;
231 reset_cb_.Run(); 230 reset_cb_.Run();
232 reset_cb_.Reset(); 231 reset_cb_.Reset();
233 } 232 }
234 233
235 void FFmpegVideoDecoder::Stop(const base::Closure& closure) { 234 void FFmpegVideoDecoder::Stop(const base::Closure& closure) {
236 if (MessageLoop::current() != message_loop_) { 235 if (!message_loop_->BelongsToCurrentThread()) {
237 message_loop_->PostTask(FROM_HERE, base::Bind( 236 message_loop_->PostTask(FROM_HERE, base::Bind(
238 &FFmpegVideoDecoder::Stop, this, closure)); 237 &FFmpegVideoDecoder::Stop, this, closure));
239 return; 238 return;
240 } 239 }
241 240
242 if (decryptor_) 241 if (decryptor_)
243 decryptor_->Stop(); 242 decryptor_->Stop();
244 243
245 stop_cb_ = closure; 244 stop_cb_ = closure;
246 245
247 // Defer stopping if a read is pending. 246 // Defer stopping if a read is pending.
248 if (!read_cb_.is_null()) 247 if (!read_cb_.is_null())
249 return; 248 return;
250 249
251 DoStop(); 250 DoStop();
252 } 251 }
253 252
254 void FFmpegVideoDecoder::DoStop() { 253 void FFmpegVideoDecoder::DoStop() {
255 ReleaseFFmpegResources(); 254 ReleaseFFmpegResources();
256 state_ = kUninitialized; 255 state_ = kUninitialized;
257 base::ResetAndReturn(&stop_cb_).Run(); 256 base::ResetAndReturn(&stop_cb_).Run();
258 } 257 }
259 258
260 FFmpegVideoDecoder::~FFmpegVideoDecoder() { 259 FFmpegVideoDecoder::~FFmpegVideoDecoder() {
261 ReleaseFFmpegResources(); 260 ReleaseFFmpegResources();
262 } 261 }
263 262
264 void FFmpegVideoDecoder::DoRead(const ReadCB& read_cb) { 263 void FFmpegVideoDecoder::DoRead(const ReadCB& read_cb) {
265 DCHECK_EQ(MessageLoop::current(), message_loop_); 264 DCHECK(message_loop_->BelongsToCurrentThread());
266 DCHECK(!read_cb.is_null()); 265 DCHECK(!read_cb.is_null());
267 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; 266 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
268 267
269 // This can happen during shutdown after Stop() has been called. 268 // This can happen during shutdown after Stop() has been called.
270 if (state_ == kUninitialized) { 269 if (state_ == kUninitialized) {
271 return; 270 return;
272 } 271 }
273 272
274 // Return empty frames if decoding has finished. 273 // Return empty frames if decoding has finished.
275 if (state_ == kDecodeFinished) { 274 if (state_ == kDecodeFinished) {
(...skipping 21 matching lines...) Expand all
297 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; 296 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status;
298 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read 297 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read
299 // callback on the same execution stack so we can get rid of forced task post. 298 // callback on the same execution stack so we can get rid of forced task post.
300 message_loop_->PostTask(FROM_HERE, base::Bind( 299 message_loop_->PostTask(FROM_HERE, base::Bind(
301 &FFmpegVideoDecoder::DoDecryptOrDecodeBuffer, this, status, buffer)); 300 &FFmpegVideoDecoder::DoDecryptOrDecodeBuffer, this, status, buffer));
302 } 301 }
303 302
304 void FFmpegVideoDecoder::DoDecryptOrDecodeBuffer( 303 void FFmpegVideoDecoder::DoDecryptOrDecodeBuffer(
305 DemuxerStream::Status status, 304 DemuxerStream::Status status,
306 const scoped_refptr<DecoderBuffer>& buffer) { 305 const scoped_refptr<DecoderBuffer>& buffer) {
307 DCHECK_EQ(MessageLoop::current(), message_loop_); 306 DCHECK(message_loop_->BelongsToCurrentThread());
308 DCHECK_NE(state_, kUninitialized); 307 DCHECK_NE(state_, kUninitialized);
309 DCHECK_NE(state_, kDecodeFinished); 308 DCHECK_NE(state_, kDecodeFinished);
310 DCHECK(!read_cb_.is_null()); 309 DCHECK(!read_cb_.is_null());
311 310
312 if (!stop_cb_.is_null()) { 311 if (!stop_cb_.is_null()) {
313 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 312 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
314 DoStop(); 313 DoStop();
315 return; 314 return;
316 } 315 }
317 316
(...skipping 24 matching lines...) Expand all
342 void FFmpegVideoDecoder::BufferDecrypted( 341 void FFmpegVideoDecoder::BufferDecrypted(
343 Decryptor::Status decrypt_status, 342 Decryptor::Status decrypt_status,
344 const scoped_refptr<DecoderBuffer>& buffer) { 343 const scoped_refptr<DecoderBuffer>& buffer) {
345 message_loop_->PostTask(FROM_HERE, base::Bind( 344 message_loop_->PostTask(FROM_HERE, base::Bind(
346 &FFmpegVideoDecoder::DoBufferDecrypted, this, decrypt_status, buffer)); 345 &FFmpegVideoDecoder::DoBufferDecrypted, this, decrypt_status, buffer));
347 } 346 }
348 347
349 void FFmpegVideoDecoder::DoBufferDecrypted( 348 void FFmpegVideoDecoder::DoBufferDecrypted(
350 Decryptor::Status decrypt_status, 349 Decryptor::Status decrypt_status,
351 const scoped_refptr<DecoderBuffer>& buffer) { 350 const scoped_refptr<DecoderBuffer>& buffer) {
352 DCHECK_EQ(MessageLoop::current(), message_loop_); 351 DCHECK(message_loop_->BelongsToCurrentThread());
353 DCHECK_NE(state_, kUninitialized); 352 DCHECK_NE(state_, kUninitialized);
354 DCHECK_NE(state_, kDecodeFinished); 353 DCHECK_NE(state_, kDecodeFinished);
355 DCHECK(!read_cb_.is_null()); 354 DCHECK(!read_cb_.is_null());
356 355
357 if (!reset_cb_.is_null()) { 356 if (!reset_cb_.is_null()) {
358 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 357 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
359 DoReset(); 358 DoReset();
360 return; 359 return;
361 } 360 }
362 361
363 if (decrypt_status == Decryptor::kNoKey || 362 if (decrypt_status == Decryptor::kNoKey ||
364 decrypt_status == Decryptor::kError) { 363 decrypt_status == Decryptor::kError) {
365 state_ = kDecodeFinished; 364 state_ = kDecodeFinished;
366 base::ResetAndReturn(&read_cb_).Run(kDecryptError, NULL); 365 base::ResetAndReturn(&read_cb_).Run(kDecryptError, NULL);
367 return; 366 return;
368 } 367 }
369 368
370 DCHECK_EQ(Decryptor::kSuccess, decrypt_status); 369 DCHECK_EQ(Decryptor::kSuccess, decrypt_status);
371 DCHECK(buffer); 370 DCHECK(buffer);
372 DCHECK(buffer->GetDataSize()); 371 DCHECK(buffer->GetDataSize());
373 DCHECK(!buffer->GetDecryptConfig()); 372 DCHECK(!buffer->GetDecryptConfig());
374 DecodeBuffer(buffer); 373 DecodeBuffer(buffer);
375 } 374 }
376 375
377 void FFmpegVideoDecoder::DecodeBuffer( 376 void FFmpegVideoDecoder::DecodeBuffer(
378 const scoped_refptr<DecoderBuffer>& buffer) { 377 const scoped_refptr<DecoderBuffer>& buffer) {
379 DCHECK_EQ(MessageLoop::current(), message_loop_); 378 DCHECK(message_loop_->BelongsToCurrentThread());
380 DCHECK_NE(state_, kUninitialized); 379 DCHECK_NE(state_, kUninitialized);
381 DCHECK_NE(state_, kDecodeFinished); 380 DCHECK_NE(state_, kDecodeFinished);
382 DCHECK(reset_cb_.is_null()); 381 DCHECK(reset_cb_.is_null());
383 DCHECK(!read_cb_.is_null()); 382 DCHECK(!read_cb_.is_null());
384 DCHECK(buffer); 383 DCHECK(buffer);
385 384
386 // During decode, because reads are issued asynchronously, it is possible to 385 // During decode, because reads are issued asynchronously, it is possible to
387 // receive multiple end of stream buffers since each read is acked. When the 386 // receive multiple end of stream buffers since each read is acked. When the
388 // first end of stream buffer is read, FFmpeg may still have frames queued 387 // first end of stream buffer is read, FFmpeg may still have frames queued
389 // up in the decoder so we need to go through the decode loop until it stops 388 // up in the decoder so we need to go through the decode loop until it stops
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 av_free(codec_context_); 518 av_free(codec_context_);
520 codec_context_ = NULL; 519 codec_context_ = NULL;
521 } 520 }
522 if (av_frame_) { 521 if (av_frame_) {
523 av_free(av_frame_); 522 av_free(av_frame_);
524 av_frame_ = NULL; 523 av_frame_ = NULL;
525 } 524 }
526 } 525 }
527 526
528 } // namespace media 527 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | media/filters/ffmpeg_video_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698