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 |