Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
| 11 #include "media/base/demuxer_stream.h" | 11 #include "media/base/demuxer_stream.h" |
| 12 #include "media/base/filter_host.h" | 12 #include "media/base/filter_host.h" |
| 13 #include "media/base/limits.h" | 13 #include "media/base/limits.h" |
| 14 #include "media/base/media_switches.h" | 14 #include "media/base/media_switches.h" |
| 15 #include "media/base/message_loop_factory.h" | |
|
scherkus (not reviewing)
2012/03/09 20:01:16
not needed
tommi (sloooow) - chröme
2012/03/11 18:49:36
Done.
| |
| 15 #include "media/base/pipeline.h" | 16 #include "media/base/pipeline.h" |
| 16 #include "media/base/video_decoder_config.h" | 17 #include "media/base/video_decoder_config.h" |
| 17 #include "media/base/video_frame.h" | 18 #include "media/base/video_frame.h" |
| 18 #include "media/base/video_util.h" | 19 #include "media/base/video_util.h" |
| 19 #include "media/ffmpeg/ffmpeg_common.h" | 20 #include "media/ffmpeg/ffmpeg_common.h" |
| 20 | 21 |
| 21 namespace media { | 22 namespace media { |
| 22 | 23 |
| 23 // Always try to use three threads for video decoding. There is little reason | 24 // Always try to use three threads for video decoding. There is little reason |
| 24 // not to since current day CPUs tend to be multi-core and we measured | 25 // not to since current day CPUs tend to be multi-core and we measured |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 44 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 45 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
| 45 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads)); | 46 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads)); |
| 46 if (threads.empty() || !base::StringToInt(threads, &decode_threads)) | 47 if (threads.empty() || !base::StringToInt(threads, &decode_threads)) |
| 47 return decode_threads; | 48 return decode_threads; |
| 48 | 49 |
| 49 decode_threads = std::max(decode_threads, 0); | 50 decode_threads = std::max(decode_threads, 0); |
| 50 decode_threads = std::min(decode_threads, kMaxDecodeThreads); | 51 decode_threads = std::min(decode_threads, kMaxDecodeThreads); |
| 51 return decode_threads; | 52 return decode_threads; |
| 52 } | 53 } |
| 53 | 54 |
| 54 FFmpegVideoDecoder::FFmpegVideoDecoder(MessageLoop* message_loop) | 55 FFmpegVideoDecoder::FFmpegVideoDecoder( |
| 55 : message_loop_(message_loop), | 56 const base::Callback<MessageLoop*()>& message_loop_cb) |
| 57 : message_loop_cb_(message_loop_cb), | |
| 58 message_loop_(NULL), | |
| 56 state_(kUninitialized), | 59 state_(kUninitialized), |
| 57 codec_context_(NULL), | 60 codec_context_(NULL), |
| 58 av_frame_(NULL), | 61 av_frame_(NULL), |
| 59 frame_rate_numerator_(0), | 62 frame_rate_numerator_(0), |
| 60 frame_rate_denominator_(0) { | 63 frame_rate_denominator_(0) { |
| 61 } | 64 } |
| 62 | 65 |
| 63 FFmpegVideoDecoder::~FFmpegVideoDecoder() { | 66 FFmpegVideoDecoder::~FFmpegVideoDecoder() { |
| 64 ReleaseFFmpegResources(); | 67 ReleaseFFmpegResources(); |
| 65 } | 68 } |
| 66 | 69 |
| 67 void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, | 70 void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, |
| 68 const PipelineStatusCB& callback, | 71 const PipelineStatusCB& callback, |
| 69 const StatisticsCallback& stats_callback) { | 72 const StatisticsCallback& stats_callback) { |
| 73 message_loop_ = message_loop_cb_.Run(); | |
|
Ami GONE FROM CHROMIUM
2012/03/09 16:15:06
add message_loop_cb_.Reset(); for clarity after th
tommi (sloooow) - chröme
2012/03/11 18:49:36
Done.
| |
| 70 if (MessageLoop::current() != message_loop_) { | 74 if (MessageLoop::current() != message_loop_) { |
| 71 message_loop_->PostTask(FROM_HERE, base::Bind( | 75 message_loop_->PostTask(FROM_HERE, |
| 72 &FFmpegVideoDecoder::Initialize, this, | 76 base::Bind(&FFmpegVideoDecoder::Initialize, this, |
|
Ami GONE FROM CHROMIUM
2012/03/09 16:15:06
This indentation violates the google style guide.
tommi (sloooow) - chröme
2012/03/11 18:49:36
Done.
| |
| 73 make_scoped_refptr(demuxer_stream), callback, stats_callback)); | 77 make_scoped_refptr(demuxer_stream), callback, |
| 78 stats_callback)); | |
| 74 return; | 79 return; |
| 75 } | 80 } |
| 76 | 81 |
| 77 DCHECK(!demuxer_stream_); | 82 DCHECK(!demuxer_stream_); |
| 78 | 83 |
| 79 if (!demuxer_stream) { | 84 if (!demuxer_stream) { |
| 80 callback.Run(PIPELINE_ERROR_DECODE); | 85 callback.Run(PIPELINE_ERROR_DECODE); |
| 81 return; | 86 return; |
| 82 } | 87 } |
| 83 | 88 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 state_ = kNormal; | 124 state_ = kNormal; |
| 120 av_frame_ = avcodec_alloc_frame(); | 125 av_frame_ = avcodec_alloc_frame(); |
| 121 natural_size_ = config.natural_size(); | 126 natural_size_ = config.natural_size(); |
| 122 frame_rate_numerator_ = config.frame_rate_numerator(); | 127 frame_rate_numerator_ = config.frame_rate_numerator(); |
| 123 frame_rate_denominator_ = config.frame_rate_denominator(); | 128 frame_rate_denominator_ = config.frame_rate_denominator(); |
| 124 callback.Run(PIPELINE_OK); | 129 callback.Run(PIPELINE_OK); |
| 125 } | 130 } |
| 126 | 131 |
| 127 void FFmpegVideoDecoder::Stop(const base::Closure& callback) { | 132 void FFmpegVideoDecoder::Stop(const base::Closure& callback) { |
| 128 if (MessageLoop::current() != message_loop_) { | 133 if (MessageLoop::current() != message_loop_) { |
| 129 message_loop_->PostTask(FROM_HERE, base::Bind( | 134 message_loop_->PostTask(FROM_HERE, |
| 130 &FFmpegVideoDecoder::Stop, this, callback)); | 135 base::Bind(&FFmpegVideoDecoder::Stop, this, callback)); |
| 131 return; | 136 return; |
| 132 } | 137 } |
| 133 | 138 |
| 134 ReleaseFFmpegResources(); | 139 ReleaseFFmpegResources(); |
| 135 state_ = kUninitialized; | 140 state_ = kUninitialized; |
| 136 callback.Run(); | 141 callback.Run(); |
| 137 } | 142 } |
| 138 | 143 |
| 139 void FFmpegVideoDecoder::Seek(base::TimeDelta time, const FilterStatusCB& cb) { | 144 void FFmpegVideoDecoder::Seek(base::TimeDelta time, const FilterStatusCB& cb) { |
| 140 if (MessageLoop::current() != message_loop_) { | 145 if (MessageLoop::current() != message_loop_) { |
| 141 message_loop_->PostTask(FROM_HERE, base::Bind( | 146 message_loop_->PostTask(FROM_HERE, |
| 142 &FFmpegVideoDecoder::Seek, this, time, cb)); | 147 base::Bind(&FFmpegVideoDecoder::Seek, this, time, cb)); |
| 143 return; | 148 return; |
| 144 } | 149 } |
| 145 | 150 |
| 146 cb.Run(PIPELINE_OK); | 151 cb.Run(PIPELINE_OK); |
| 147 } | 152 } |
| 148 | 153 |
| 149 void FFmpegVideoDecoder::Pause(const base::Closure& callback) { | 154 void FFmpegVideoDecoder::Pause(const base::Closure& callback) { |
| 150 if (MessageLoop::current() != message_loop_) { | 155 if (MessageLoop::current() != message_loop_) { |
| 151 message_loop_->PostTask(FROM_HERE, base::Bind( | 156 message_loop_->PostTask(FROM_HERE, |
| 152 &FFmpegVideoDecoder::Pause, this, callback)); | 157 base::Bind(&FFmpegVideoDecoder::Pause, this, callback)); |
| 153 return; | 158 return; |
| 154 } | 159 } |
| 155 | 160 |
| 156 callback.Run(); | 161 callback.Run(); |
| 157 } | 162 } |
| 158 | 163 |
| 159 void FFmpegVideoDecoder::Flush(const base::Closure& callback) { | 164 void FFmpegVideoDecoder::Flush(const base::Closure& callback) { |
| 160 if (MessageLoop::current() != message_loop_) { | 165 if (MessageLoop::current() != message_loop_) { |
| 161 message_loop_->PostTask(FROM_HERE, base::Bind( | 166 message_loop_->PostTask(FROM_HERE, |
| 162 &FFmpegVideoDecoder::Flush, this, callback)); | 167 base::Bind(&FFmpegVideoDecoder::Flush, this, callback)); |
| 163 return; | 168 return; |
| 164 } | 169 } |
| 165 | 170 |
| 166 avcodec_flush_buffers(codec_context_); | 171 avcodec_flush_buffers(codec_context_); |
| 167 state_ = kNormal; | 172 state_ = kNormal; |
| 168 callback.Run(); | 173 callback.Run(); |
| 169 } | 174 } |
| 170 | 175 |
| 171 void FFmpegVideoDecoder::Read(const ReadCB& callback) { | 176 void FFmpegVideoDecoder::Read(const ReadCB& callback) { |
| 172 // Complete operation asynchronously on different stack of execution as per | 177 // Complete operation asynchronously on different stack of execution as per |
| 173 // the API contract of VideoDecoder::Read() | 178 // the API contract of VideoDecoder::Read() |
| 174 message_loop_->PostTask(FROM_HERE, base::Bind( | 179 message_loop_->PostTask(FROM_HERE, |
| 175 &FFmpegVideoDecoder::DoRead, this, callback)); | 180 base::Bind(&FFmpegVideoDecoder::DoRead, this, callback)); |
| 176 } | 181 } |
| 177 | 182 |
| 178 const gfx::Size& FFmpegVideoDecoder::natural_size() { | 183 const gfx::Size& FFmpegVideoDecoder::natural_size() { |
| 179 return natural_size_; | 184 return natural_size_; |
| 180 } | 185 } |
| 181 | 186 |
| 182 void FFmpegVideoDecoder::DoRead(const ReadCB& callback) { | 187 void FFmpegVideoDecoder::DoRead(const ReadCB& callback) { |
| 183 DCHECK_EQ(MessageLoop::current(), message_loop_); | 188 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 184 DCHECK(!callback.is_null()); | 189 DCHECK(!callback.is_null()); |
| 185 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 190 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 204 DCHECK_NE(state_, kUninitialized); | 209 DCHECK_NE(state_, kUninitialized); |
| 205 DCHECK_NE(state_, kDecodeFinished); | 210 DCHECK_NE(state_, kDecodeFinished); |
| 206 DCHECK(!read_cb_.is_null()); | 211 DCHECK(!read_cb_.is_null()); |
| 207 | 212 |
| 208 demuxer_stream_->Read(base::Bind(&FFmpegVideoDecoder::DecodeBuffer, this)); | 213 demuxer_stream_->Read(base::Bind(&FFmpegVideoDecoder::DecodeBuffer, this)); |
| 209 } | 214 } |
| 210 | 215 |
| 211 void FFmpegVideoDecoder::DecodeBuffer(const scoped_refptr<Buffer>& buffer) { | 216 void FFmpegVideoDecoder::DecodeBuffer(const scoped_refptr<Buffer>& buffer) { |
| 212 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read | 217 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read |
| 213 // callback on the same execution stack so we can get rid of forced task post. | 218 // callback on the same execution stack so we can get rid of forced task post. |
| 214 message_loop_->PostTask(FROM_HERE, base::Bind( | 219 message_loop_->PostTask(FROM_HERE, |
| 215 &FFmpegVideoDecoder::DoDecodeBuffer, this, buffer)); | 220 base::Bind(&FFmpegVideoDecoder::DoDecodeBuffer, this, buffer)); |
| 216 } | 221 } |
| 217 | 222 |
| 218 void FFmpegVideoDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& buffer) { | 223 void FFmpegVideoDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& buffer) { |
| 219 DCHECK_EQ(MessageLoop::current(), message_loop_); | 224 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 220 DCHECK_NE(state_, kUninitialized); | 225 DCHECK_NE(state_, kUninitialized); |
| 221 DCHECK_NE(state_, kDecodeFinished); | 226 DCHECK_NE(state_, kDecodeFinished); |
| 222 DCHECK(!read_cb_.is_null()); | 227 DCHECK(!read_cb_.is_null()); |
| 223 | 228 |
| 224 if (!buffer) { | 229 if (!buffer) { |
| 225 DeliverFrame(NULL); | 230 DeliverFrame(NULL); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 417 scoped_refptr<VideoFrame> FFmpegVideoDecoder::AllocateVideoFrame() { | 422 scoped_refptr<VideoFrame> FFmpegVideoDecoder::AllocateVideoFrame() { |
| 418 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); | 423 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); |
| 419 size_t width = codec_context_->width; | 424 size_t width = codec_context_->width; |
| 420 size_t height = codec_context_->height; | 425 size_t height = codec_context_->height; |
| 421 | 426 |
| 422 return VideoFrame::CreateFrame(format, width, height, | 427 return VideoFrame::CreateFrame(format, width, height, |
| 423 kNoTimestamp(), kNoTimestamp()); | 428 kNoTimestamp(), kNoTimestamp()); |
| 424 } | 429 } |
| 425 | 430 |
| 426 } // namespace media | 431 } // namespace media |
| OLD | NEW |