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_audio_decoder.h" | 5 #include "media/filters/ffmpeg_audio_decoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "media/base/audio_decoder_config.h" | 8 #include "media/base/audio_decoder_config.h" |
| 9 #include "media/base/data_buffer.h" | 9 #include "media/base/data_buffer.h" |
| 10 #include "media/base/demuxer.h" | 10 #include "media/base/demuxer.h" |
| 11 #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.
| |
| 11 #include "media/base/pipeline.h" | 12 #include "media/base/pipeline.h" |
| 12 #include "media/ffmpeg/ffmpeg_common.h" | 13 #include "media/ffmpeg/ffmpeg_common.h" |
| 13 | 14 |
| 14 namespace media { | 15 namespace media { |
| 15 | 16 |
| 16 // Returns true if the decode result was an error. | 17 // Returns true if the decode result was an error. |
| 17 static bool IsErrorResult(int result, int decoded_size) { | 18 static bool IsErrorResult(int result, int decoded_size) { |
| 18 return result < 0 || | 19 return result < 0 || |
| 19 decoded_size < 0 || | 20 decoded_size < 0 || |
| 20 decoded_size > AVCODEC_MAX_AUDIO_FRAME_SIZE; | 21 decoded_size > AVCODEC_MAX_AUDIO_FRAME_SIZE; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 38 // Returns true if the decode result was end of stream. | 39 // Returns true if the decode result was end of stream. |
| 39 static bool IsEndOfStream(int result, int decoded_size, Buffer* input) { | 40 static bool IsEndOfStream(int result, int decoded_size, Buffer* input) { |
| 40 // Three conditions to meet to declare end of stream for this decoder: | 41 // Three conditions to meet to declare end of stream for this decoder: |
| 41 // 1. FFmpeg didn't read anything. | 42 // 1. FFmpeg didn't read anything. |
| 42 // 2. FFmpeg didn't output anything. | 43 // 2. FFmpeg didn't output anything. |
| 43 // 3. An end of stream buffer is received. | 44 // 3. An end of stream buffer is received. |
| 44 return result == 0 && decoded_size == 0 && input->IsEndOfStream(); | 45 return result == 0 && decoded_size == 0 && input->IsEndOfStream(); |
| 45 } | 46 } |
| 46 | 47 |
| 47 | 48 |
| 48 FFmpegAudioDecoder::FFmpegAudioDecoder(MessageLoop* message_loop) | 49 FFmpegAudioDecoder::FFmpegAudioDecoder( |
| 49 : message_loop_(message_loop), | 50 const base::Callback<MessageLoop*()>& message_loop_cb) |
| 51 : message_loop_cb_(message_loop_cb), | |
| 52 message_loop_(NULL), | |
| 50 codec_context_(NULL), | 53 codec_context_(NULL), |
| 51 bits_per_channel_(0), | 54 bits_per_channel_(0), |
| 52 channel_layout_(CHANNEL_LAYOUT_NONE), | 55 channel_layout_(CHANNEL_LAYOUT_NONE), |
| 53 samples_per_second_(0), | 56 samples_per_second_(0), |
| 54 decoded_audio_size_(AVCODEC_MAX_AUDIO_FRAME_SIZE), | 57 decoded_audio_size_(AVCODEC_MAX_AUDIO_FRAME_SIZE), |
| 55 decoded_audio_(static_cast<uint8*>(av_malloc(decoded_audio_size_))) { | 58 decoded_audio_(static_cast<uint8*>(av_malloc(decoded_audio_size_))) { |
| 56 } | 59 } |
| 57 | 60 |
| 58 FFmpegAudioDecoder::~FFmpegAudioDecoder() { | 61 FFmpegAudioDecoder::~FFmpegAudioDecoder() { |
| 59 av_free(decoded_audio_); | 62 av_free(decoded_audio_); |
| 60 | 63 |
| 61 // TODO(scherkus): should we require Stop() to be called? this might end up | 64 // TODO(scherkus): should we require Stop() to be called? this might end up |
| 62 // getting called on a random thread due to refcounting. | 65 // getting called on a random thread due to refcounting. |
| 63 if (codec_context_) { | 66 if (codec_context_) { |
| 64 av_free(codec_context_->extradata); | 67 av_free(codec_context_->extradata); |
| 65 avcodec_close(codec_context_); | 68 avcodec_close(codec_context_); |
| 66 av_free(codec_context_); | 69 av_free(codec_context_); |
| 67 } | 70 } |
| 68 } | 71 } |
| 69 | 72 |
| 70 void FFmpegAudioDecoder::Initialize( | 73 void FFmpegAudioDecoder::Initialize( |
| 71 const scoped_refptr<DemuxerStream>& stream, | 74 const scoped_refptr<DemuxerStream>& stream, |
| 72 const PipelineStatusCB& callback, | 75 const PipelineStatusCB& callback, |
| 73 const StatisticsCallback& stats_callback) { | 76 const StatisticsCallback& stats_callback) { |
| 74 message_loop_->PostTask( | 77 message_loop_ = message_loop_cb_.Run(); |
| 75 FROM_HERE, | 78 message_loop_->PostTask(FROM_HERE, |
|
scherkus (not reviewing)
2012/03/09 20:01:16
style -- I'd do the following:
message_loop_->Pos
tommi (sloooow) - chröme
2012/03/11 18:49:36
Done.
| |
| 76 base::Bind(&FFmpegAudioDecoder::DoInitialize, this, | 79 base::Bind(&FFmpegAudioDecoder::DoInitialize, this, |
| 77 stream, callback, stats_callback)); | 80 stream, callback, stats_callback)); |
| 78 } | 81 } |
| 79 | 82 |
| 80 void FFmpegAudioDecoder::Read(const ReadCB& callback) { | 83 void FFmpegAudioDecoder::Read(const ReadCB& callback) { |
| 81 // Complete operation asynchronously on different stack of execution as per | 84 // Complete operation asynchronously on different stack of execution as per |
| 82 // the API contract of AudioDecoder::Read() | 85 // the API contract of AudioDecoder::Read() |
| 83 message_loop_->PostTask(FROM_HERE, base::Bind( | 86 message_loop_->PostTask(FROM_HERE, |
|
scherkus (not reviewing)
2012/03/09 20:01:16
ditto here + below (i.e., revert these edits)
tommi (sloooow) - chröme
2012/03/11 18:49:36
Done.
| |
| 84 &FFmpegAudioDecoder::DoRead, this, callback)); | 87 base::Bind(&FFmpegAudioDecoder::DoRead, this, callback)); |
| 85 } | 88 } |
| 86 | 89 |
| 87 int FFmpegAudioDecoder::bits_per_channel() { | 90 int FFmpegAudioDecoder::bits_per_channel() { |
| 88 return bits_per_channel_; | 91 return bits_per_channel_; |
| 89 } | 92 } |
| 90 | 93 |
| 91 ChannelLayout FFmpegAudioDecoder::channel_layout() { | 94 ChannelLayout FFmpegAudioDecoder::channel_layout() { |
| 92 return channel_layout_; | 95 return channel_layout_; |
| 93 } | 96 } |
| 94 | 97 |
| 95 int FFmpegAudioDecoder::samples_per_second() { | 98 int FFmpegAudioDecoder::samples_per_second() { |
| 96 return samples_per_second_; | 99 return samples_per_second_; |
| 97 } | 100 } |
| 98 | 101 |
| 99 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { | 102 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { |
| 100 message_loop_->PostTask(FROM_HERE, base::Bind( | 103 message_loop_->PostTask(FROM_HERE, |
| 101 &FFmpegAudioDecoder::DoReset, this, closure)); | 104 base::Bind(&FFmpegAudioDecoder::DoReset, this, closure)); |
| 102 } | 105 } |
| 103 | 106 |
| 104 void FFmpegAudioDecoder::DoInitialize( | 107 void FFmpegAudioDecoder::DoInitialize( |
| 105 const scoped_refptr<DemuxerStream>& stream, | 108 const scoped_refptr<DemuxerStream>& stream, |
| 106 const PipelineStatusCB& callback, | 109 const PipelineStatusCB& callback, |
| 107 const StatisticsCallback& stats_callback) { | 110 const StatisticsCallback& stats_callback) { |
| 108 demuxer_stream_ = stream; | 111 demuxer_stream_ = stream; |
| 109 const AudioDecoderConfig& config = stream->audio_decoder_config(); | 112 const AudioDecoderConfig& config = stream->audio_decoder_config(); |
| 110 stats_callback_ = stats_callback; | 113 stats_callback_ = stats_callback; |
| 111 | 114 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 | 245 |
| 243 void FFmpegAudioDecoder::ReadFromDemuxerStream() { | 246 void FFmpegAudioDecoder::ReadFromDemuxerStream() { |
| 244 DCHECK(!read_cb_.is_null()); | 247 DCHECK(!read_cb_.is_null()); |
| 245 | 248 |
| 246 demuxer_stream_->Read(base::Bind(&FFmpegAudioDecoder::DecodeBuffer, this)); | 249 demuxer_stream_->Read(base::Bind(&FFmpegAudioDecoder::DecodeBuffer, this)); |
| 247 } | 250 } |
| 248 | 251 |
| 249 void FFmpegAudioDecoder::DecodeBuffer(const scoped_refptr<Buffer>& buffer) { | 252 void FFmpegAudioDecoder::DecodeBuffer(const scoped_refptr<Buffer>& buffer) { |
| 250 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read | 253 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read |
| 251 // callback on the same execution stack so we can get rid of forced task post. | 254 // callback on the same execution stack so we can get rid of forced task post. |
| 252 message_loop_->PostTask(FROM_HERE, base::Bind( | 255 message_loop_->PostTask(FROM_HERE, |
| 253 &FFmpegAudioDecoder::DoDecodeBuffer, this, buffer)); | 256 base::Bind(&FFmpegAudioDecoder::DoDecodeBuffer, this, buffer)); |
| 254 } | 257 } |
| 255 | 258 |
| 256 void FFmpegAudioDecoder::UpdateDurationAndTimestamp( | 259 void FFmpegAudioDecoder::UpdateDurationAndTimestamp( |
| 257 const Buffer* input, | 260 const Buffer* input, |
| 258 DataBuffer* output) { | 261 DataBuffer* output) { |
| 259 // Always calculate duration based on the actual number of samples decoded. | 262 // Always calculate duration based on the actual number of samples decoded. |
| 260 base::TimeDelta duration = CalculateDuration(output->GetDataSize()); | 263 base::TimeDelta duration = CalculateDuration(output->GetDataSize()); |
| 261 output->SetDuration(duration); | 264 output->SetDuration(duration); |
| 262 | 265 |
| 263 // Use the incoming timestamp if it's valid. | 266 // Use the incoming timestamp if it's valid. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 284 } | 287 } |
| 285 | 288 |
| 286 void FFmpegAudioDecoder::DeliverSamples(const scoped_refptr<Buffer>& samples) { | 289 void FFmpegAudioDecoder::DeliverSamples(const scoped_refptr<Buffer>& samples) { |
| 287 // Reset the callback before running to protect against reentrancy. | 290 // Reset the callback before running to protect against reentrancy. |
| 288 ReadCB read_cb = read_cb_; | 291 ReadCB read_cb = read_cb_; |
| 289 read_cb_.Reset(); | 292 read_cb_.Reset(); |
| 290 read_cb.Run(samples); | 293 read_cb.Run(samples); |
| 291 } | 294 } |
| 292 | 295 |
| 293 } // namespace media | 296 } // namespace media |
| OLD | NEW |