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 "base/callback_helpers.h" | |
| 8 #include "media/base/audio_decoder_config.h" | 9 #include "media/base/audio_decoder_config.h" |
| 9 #include "media/base/data_buffer.h" | 10 #include "media/base/data_buffer.h" |
| 10 #include "media/base/decoder_buffer.h" | 11 #include "media/base/decoder_buffer.h" |
| 11 #include "media/base/demuxer.h" | 12 #include "media/base/demuxer.h" |
| 12 #include "media/base/pipeline.h" | 13 #include "media/base/pipeline.h" |
| 13 #include "media/ffmpeg/ffmpeg_common.h" | 14 #include "media/ffmpeg/ffmpeg_common.h" |
| 14 #include "media/filters/ffmpeg_glue.h" | 15 #include "media/filters/ffmpeg_glue.h" |
| 15 | 16 |
| 16 namespace media { | 17 namespace media { |
| 17 | 18 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 void FFmpegAudioDecoder::DoRead(const ReadCB& read_cb) { | 159 void FFmpegAudioDecoder::DoRead(const ReadCB& read_cb) { |
| 159 DCHECK_EQ(MessageLoop::current(), message_loop_); | 160 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 160 DCHECK(!read_cb.is_null()); | 161 DCHECK(!read_cb.is_null()); |
| 161 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 162 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; |
| 162 | 163 |
| 163 read_cb_ = read_cb; | 164 read_cb_ = read_cb; |
| 164 ReadFromDemuxerStream(); | 165 ReadFromDemuxerStream(); |
| 165 } | 166 } |
| 166 | 167 |
| 167 void FFmpegAudioDecoder::DoDecodeBuffer( | 168 void FFmpegAudioDecoder::DoDecodeBuffer( |
| 169 DemuxerStream::Status status, | |
| 168 const scoped_refptr<DecoderBuffer>& input) { | 170 const scoped_refptr<DecoderBuffer>& input) { |
| 169 DCHECK_EQ(MessageLoop::current(), message_loop_); | 171 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 170 DCHECK(!read_cb_.is_null()); | 172 DCHECK(!read_cb_.is_null()); |
| 171 | 173 |
| 172 if (!input) { | 174 if (status != DemuxerStream::kOk) { |
|
Ami GONE FROM CHROMIUM
2012/06/26 00:33:21
DCHECK(!input) ?
acolwell GONE FROM CHROMIUM
2012/07/12 01:19:38
Done.
| |
| 173 // DemuxeStream::Read() was aborted so we abort the decoder's pending read. | 175 // TODO(acolwell): Add support for reinitializing the decoder when |
| 174 DeliverSamples(NULL); | 176 // |status| == kConfigChanged. For now we just trigger a decode error. |
| 177 AudioDecoder::Status decoder_status = | |
| 178 (status == DemuxerStream::kAborted) ? kAborted : kDecodeError; | |
| 179 base::ResetAndReturn(&read_cb_).Run(decoder_status, NULL); | |
| 175 return; | 180 return; |
| 176 } | 181 } |
| 177 | 182 |
| 178 // FFmpeg tends to seek Ogg audio streams in the middle of nowhere, giving us | 183 // FFmpeg tends to seek Ogg audio streams in the middle of nowhere, giving us |
| 179 // a whole bunch of AV_NOPTS_VALUE packets. Discard them until we find | 184 // a whole bunch of AV_NOPTS_VALUE packets. Discard them until we find |
| 180 // something valid. Refer to http://crbug.com/49709 | 185 // something valid. Refer to http://crbug.com/49709 |
| 181 if (input->GetTimestamp() == kNoTimestamp() && | 186 if (input->GetTimestamp() == kNoTimestamp() && |
| 182 estimated_next_timestamp_ == kNoTimestamp() && | 187 estimated_next_timestamp_ == kNoTimestamp() && |
| 183 !input->IsEndOfStream()) { | 188 !input->IsEndOfStream()) { |
| 184 ReadFromDemuxerStream(); | 189 ReadFromDemuxerStream(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 } else if (IsEndOfStream(result, decoded_audio_size, input)) { | 243 } else if (IsEndOfStream(result, decoded_audio_size, input)) { |
| 239 // Create an end of stream output buffer. | 244 // Create an end of stream output buffer. |
| 240 output = new DataBuffer(0); | 245 output = new DataBuffer(0); |
| 241 output->SetTimestamp(input->GetTimestamp()); | 246 output->SetTimestamp(input->GetTimestamp()); |
| 242 output->SetDuration(input->GetDuration()); | 247 output->SetDuration(input->GetDuration()); |
| 243 } | 248 } |
| 244 | 249 |
| 245 // Decoding finished successfully, update stats and execute callback. | 250 // Decoding finished successfully, update stats and execute callback. |
| 246 statistics_cb_.Run(statistics); | 251 statistics_cb_.Run(statistics); |
| 247 if (output) { | 252 if (output) { |
| 248 DeliverSamples(output); | 253 base::ResetAndReturn(&read_cb_).Run(kOk, output); |
| 249 } else { | 254 } else { |
| 250 ReadFromDemuxerStream(); | 255 ReadFromDemuxerStream(); |
| 251 } | 256 } |
| 252 } | 257 } |
| 253 | 258 |
| 254 void FFmpegAudioDecoder::ReadFromDemuxerStream() { | 259 void FFmpegAudioDecoder::ReadFromDemuxerStream() { |
| 255 DCHECK(!read_cb_.is_null()); | 260 DCHECK(!read_cb_.is_null()); |
| 256 | 261 |
| 257 demuxer_stream_->Read(base::Bind(&FFmpegAudioDecoder::DecodeBuffer, this)); | 262 demuxer_stream_->Read(base::Bind(&FFmpegAudioDecoder::DecodeBuffer, this)); |
| 258 } | 263 } |
| 259 | 264 |
| 260 void FFmpegAudioDecoder::DecodeBuffer( | 265 void FFmpegAudioDecoder::DecodeBuffer( |
| 266 DemuxerStream::Status status, | |
| 261 const scoped_refptr<DecoderBuffer>& buffer) { | 267 const scoped_refptr<DecoderBuffer>& buffer) { |
| 268 DCHECK_EQ(status != DemuxerStream::kOk, !buffer); | |
| 269 | |
| 262 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read | 270 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read |
| 263 // callback on the same execution stack so we can get rid of forced task post. | 271 // callback on the same execution stack so we can get rid of forced task post. |
| 264 message_loop_->PostTask(FROM_HERE, base::Bind( | 272 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 265 &FFmpegAudioDecoder::DoDecodeBuffer, this, buffer)); | 273 &FFmpegAudioDecoder::DoDecodeBuffer, this, status, buffer)); |
| 266 } | 274 } |
| 267 | 275 |
| 268 void FFmpegAudioDecoder::UpdateDurationAndTimestamp( | 276 void FFmpegAudioDecoder::UpdateDurationAndTimestamp( |
| 269 const Buffer* input, | 277 const Buffer* input, |
| 270 DataBuffer* output) { | 278 DataBuffer* output) { |
| 271 // Always calculate duration based on the actual number of samples decoded. | 279 // Always calculate duration based on the actual number of samples decoded. |
| 272 base::TimeDelta duration = CalculateDuration(output->GetDataSize()); | 280 base::TimeDelta duration = CalculateDuration(output->GetDataSize()); |
| 273 output->SetDuration(duration); | 281 output->SetDuration(duration); |
| 274 | 282 |
| 275 // Use the incoming timestamp if it's valid. | 283 // Use the incoming timestamp if it's valid. |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 288 } | 296 } |
| 289 | 297 |
| 290 base::TimeDelta FFmpegAudioDecoder::CalculateDuration(int size) { | 298 base::TimeDelta FFmpegAudioDecoder::CalculateDuration(int size) { |
| 291 int64 denominator = ChannelLayoutToChannelCount(channel_layout_) * | 299 int64 denominator = ChannelLayoutToChannelCount(channel_layout_) * |
| 292 bits_per_channel_ / 8 * samples_per_second_; | 300 bits_per_channel_ / 8 * samples_per_second_; |
| 293 double microseconds = size / | 301 double microseconds = size / |
| 294 (denominator / static_cast<double>(base::Time::kMicrosecondsPerSecond)); | 302 (denominator / static_cast<double>(base::Time::kMicrosecondsPerSecond)); |
| 295 return base::TimeDelta::FromMicroseconds(static_cast<int64>(microseconds)); | 303 return base::TimeDelta::FromMicroseconds(static_cast<int64>(microseconds)); |
| 296 } | 304 } |
| 297 | 305 |
| 298 void FFmpegAudioDecoder::DeliverSamples(const scoped_refptr<Buffer>& samples) { | |
| 299 // Reset the callback before running to protect against reentrancy. | |
| 300 ReadCB read_cb = read_cb_; | |
| 301 read_cb_.Reset(); | |
| 302 read_cb.Run(samples); | |
| 303 } | |
| 304 | |
| 305 } // namespace media | 306 } // namespace media |
| OLD | NEW |