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/callback_helpers.h" | 7 #include "base/callback_helpers.h" |
8 #include "base/single_thread_task_runner.h" | 8 #include "base/single_thread_task_runner.h" |
9 #include "media/base/audio_buffer.h" | 9 #include "media/base/audio_buffer.h" |
10 #include "media/base/audio_bus.h" | 10 #include "media/base/audio_bus.h" |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 // Make sure we are notified if http://crbug.com/49709 returns. Issue also | 255 // Make sure we are notified if http://crbug.com/49709 returns. Issue also |
256 // occurs with some damaged files. | 256 // occurs with some damaged files. |
257 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp() && | 257 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp() && |
258 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { | 258 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { |
259 DVLOG(1) << "Received a buffer without timestamps!"; | 259 DVLOG(1) << "Received a buffer without timestamps!"; |
260 decode_cb.Run(kDecodeError, NULL); | 260 decode_cb.Run(kDecodeError, NULL); |
261 return; | 261 return; |
262 } | 262 } |
263 | 263 |
264 if (!buffer->end_of_stream()) { | 264 if (!buffer->end_of_stream()) { |
265 if (last_input_timestamp_ == kNoTimestamp() && | 265 DCHECK(buffer->timestamp() != kNoTimestamp()); |
266 codec_context_->codec_id == AV_CODEC_ID_VORBIS && | 266 const bool first_buffer = |
| 267 last_input_timestamp_ == kNoTimestamp() && |
| 268 output_timestamp_helper_->base_timestamp() == kNoTimestamp(); |
| 269 if (first_buffer && codec_context_->codec_id == AV_CODEC_ID_VORBIS && |
267 buffer->timestamp() < base::TimeDelta()) { | 270 buffer->timestamp() < base::TimeDelta()) { |
268 // Dropping frames for negative timestamps as outlined in section A.2 | 271 // Dropping frames for negative timestamps as outlined in section A.2 |
269 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html | 272 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
270 output_frames_to_drop_ = floor(0.5 + -buffer->timestamp().InSecondsF() * | 273 DCHECK_EQ(output_frames_to_drop_, 0); |
271 config_.samples_per_second()); | 274 output_frames_to_drop_ = |
| 275 0.5 + |
| 276 -buffer->timestamp().InSecondsF() * config_.samples_per_second(); |
| 277 |
| 278 // If we are dropping samples for Vorbis, the timeline always starts at 0. |
| 279 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); |
272 } else { | 280 } else { |
273 if (last_input_timestamp_ != kNoTimestamp() && | 281 if (first_buffer) { |
274 buffer->timestamp() < last_input_timestamp_) { | 282 output_timestamp_helper_->SetBaseTimestamp(buffer->timestamp()); |
| 283 } else if (buffer->timestamp() < last_input_timestamp_) { |
275 const base::TimeDelta diff = | 284 const base::TimeDelta diff = |
276 buffer->timestamp() - last_input_timestamp_; | 285 buffer->timestamp() - last_input_timestamp_; |
277 DLOG(WARNING) | 286 DLOG(WARNING) << "Input timestamps are not monotonically increasing! " |
278 << "Input timestamps are not monotonically increasing! " | 287 << " ts " << buffer->timestamp().InMicroseconds() << " us" |
279 << " ts " << buffer->timestamp().InMicroseconds() << " us" | 288 << " diff " << diff.InMicroseconds() << " us"; |
280 << " diff " << diff.InMicroseconds() << " us"; | |
281 } | 289 } |
282 | 290 |
283 last_input_timestamp_ = buffer->timestamp(); | 291 last_input_timestamp_ = buffer->timestamp(); |
284 } | 292 } |
285 } | 293 } |
286 | 294 |
287 // Transition to kFlushCodec on the first end of stream buffer. | 295 // Transition to kFlushCodec on the first end of stream buffer. |
288 if (state_ == kNormal && buffer->end_of_stream()) { | 296 if (state_ == kNormal && buffer->end_of_stream()) { |
289 state_ = kFlushCodec; | 297 state_ = kFlushCodec; |
290 } | 298 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 << buffer->data_size() << " bytes"; | 356 << buffer->data_size() << " bytes"; |
349 | 357 |
350 break; | 358 break; |
351 } | 359 } |
352 | 360 |
353 // Update packet size and data pointer in case we need to call the decoder | 361 // Update packet size and data pointer in case we need to call the decoder |
354 // with the remaining bytes from this packet. | 362 // with the remaining bytes from this packet. |
355 packet.size -= result; | 363 packet.size -= result; |
356 packet.data += result; | 364 packet.data += result; |
357 | 365 |
358 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && | |
359 !buffer->end_of_stream()) { | |
360 DCHECK(buffer->timestamp() != kNoTimestamp()); | |
361 if (output_frames_to_drop_ > 0) { | |
362 // Currently Vorbis is the only codec that causes us to drop samples. | |
363 // If we have to drop samples it always means the timeline starts at 0. | |
364 DCHECK_EQ(codec_context_->codec_id, AV_CODEC_ID_VORBIS); | |
365 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); | |
366 } else { | |
367 output_timestamp_helper_->SetBaseTimestamp(buffer->timestamp()); | |
368 } | |
369 } | |
370 | |
371 scoped_refptr<AudioBuffer> output; | 366 scoped_refptr<AudioBuffer> output; |
372 int decoded_frames = 0; | 367 int decoded_frames = 0; |
373 int original_frames = 0; | 368 int original_frames = 0; |
374 int channels = DetermineChannels(av_frame_.get()); | 369 int channels = DetermineChannels(av_frame_.get()); |
375 if (frame_decoded) { | 370 if (frame_decoded) { |
376 if (av_frame_->sample_rate != config_.samples_per_second() || | 371 if (av_frame_->sample_rate != config_.samples_per_second() || |
377 channels != ChannelLayoutToChannelCount(config_.channel_layout()) || | 372 channels != ChannelLayoutToChannelCount(config_.channel_layout()) || |
378 av_frame_->format != av_sample_format_) { | 373 av_frame_->format != av_sample_format_) { |
379 DLOG(ERROR) << "Unsupported midstream configuration change!" | 374 DLOG(ERROR) << "Unsupported midstream configuration change!" |
380 << " Sample Rate: " << av_frame_->sample_rate << " vs " | 375 << " Sample Rate: " << av_frame_->sample_rate << " vs " |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 << codec_context_->codec_id; | 471 << codec_context_->codec_id; |
477 ReleaseFFmpegResources(); | 472 ReleaseFFmpegResources(); |
478 state_ = kUninitialized; | 473 state_ = kUninitialized; |
479 return false; | 474 return false; |
480 } | 475 } |
481 | 476 |
482 // Success! | 477 // Success! |
483 av_frame_.reset(av_frame_alloc()); | 478 av_frame_.reset(av_frame_alloc()); |
484 output_timestamp_helper_.reset( | 479 output_timestamp_helper_.reset( |
485 new AudioTimestampHelper(config_.samples_per_second())); | 480 new AudioTimestampHelper(config_.samples_per_second())); |
| 481 ResetTimestampState(); |
486 | 482 |
487 av_sample_format_ = codec_context_->sample_fmt; | 483 av_sample_format_ = codec_context_->sample_fmt; |
488 | 484 |
489 if (codec_context_->channels != | 485 if (codec_context_->channels != |
490 ChannelLayoutToChannelCount(config_.channel_layout())) { | 486 ChannelLayoutToChannelCount(config_.channel_layout())) { |
491 DLOG(ERROR) << "Audio configuration specified " | 487 DLOG(ERROR) << "Audio configuration specified " |
492 << ChannelLayoutToChannelCount(config_.channel_layout()) | 488 << ChannelLayoutToChannelCount(config_.channel_layout()) |
493 << " channels, but FFmpeg thinks the file contains " | 489 << " channels, but FFmpeg thinks the file contains " |
494 << codec_context_->channels << " channels"; | 490 << codec_context_->channels << " channels"; |
495 ReleaseFFmpegResources(); | 491 ReleaseFFmpegResources(); |
496 state_ = kUninitialized; | 492 state_ = kUninitialized; |
497 return false; | 493 return false; |
498 } | 494 } |
| 495 |
| 496 output_frames_to_drop_ = config_.codec_delay(); |
499 return true; | 497 return true; |
500 } | 498 } |
501 | 499 |
502 void FFmpegAudioDecoder::ResetTimestampState() { | 500 void FFmpegAudioDecoder::ResetTimestampState() { |
503 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); | 501 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
504 last_input_timestamp_ = kNoTimestamp(); | 502 last_input_timestamp_ = kNoTimestamp(); |
505 output_frames_to_drop_ = 0; | 503 output_frames_to_drop_ = 0; |
506 } | 504 } |
507 | 505 |
508 } // namespace media | 506 } // namespace media |
OLD | NEW |