| 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 |