| 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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 | 118 |
| 119 // Now create an AVBufferRef for the data just allocated. It will own the | 119 // Now create an AVBufferRef for the data just allocated. It will own the |
| 120 // reference to the AudioBuffer object. | 120 // reference to the AudioBuffer object. |
| 121 void* opaque = NULL; | 121 void* opaque = NULL; |
| 122 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); | 122 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); |
| 123 frame->buf[0] = av_buffer_create( | 123 frame->buf[0] = av_buffer_create( |
| 124 frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0); | 124 frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0); |
| 125 return 0; | 125 return 0; |
| 126 } | 126 } |
| 127 | 127 |
| 128 static int TimeDeltaToFrames(base::TimeDelta duration, int sample_rate) { |
| 129 return 0.5 + duration.InSecondsF() * sample_rate; |
| 130 } |
| 131 |
| 128 FFmpegAudioDecoder::FFmpegAudioDecoder( | 132 FFmpegAudioDecoder::FFmpegAudioDecoder( |
| 129 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 133 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
| 130 : task_runner_(task_runner), | 134 : task_runner_(task_runner), |
| 131 state_(kUninitialized), | 135 state_(kUninitialized), |
| 132 av_sample_format_(0), | 136 av_sample_format_(0), |
| 133 last_input_timestamp_(kNoTimestamp()), | 137 last_input_timestamp_(kNoTimestamp()), |
| 134 output_frames_to_drop_(0) {} | 138 output_frames_to_drop_(0) {} |
| 135 | 139 |
| 136 FFmpegAudioDecoder::~FFmpegAudioDecoder() { | 140 FFmpegAudioDecoder::~FFmpegAudioDecoder() { |
| 137 DCHECK_EQ(state_, kUninitialized); | 141 DCHECK_EQ(state_, kUninitialized); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 decode_cb.Run(kDecodeError, NULL); | 264 decode_cb.Run(kDecodeError, NULL); |
| 261 return; | 265 return; |
| 262 } | 266 } |
| 263 | 267 |
| 264 if (!buffer->end_of_stream()) { | 268 if (!buffer->end_of_stream()) { |
| 265 if (last_input_timestamp_ == kNoTimestamp() && | 269 if (last_input_timestamp_ == kNoTimestamp() && |
| 266 codec_context_->codec_id == AV_CODEC_ID_VORBIS && | 270 codec_context_->codec_id == AV_CODEC_ID_VORBIS && |
| 267 buffer->timestamp() < base::TimeDelta()) { | 271 buffer->timestamp() < base::TimeDelta()) { |
| 268 // Dropping frames for negative timestamps as outlined in section A.2 | 272 // 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 | 273 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
| 270 output_frames_to_drop_ = floor(0.5 + -buffer->timestamp().InSecondsF() * | 274 output_frames_to_drop_ = |
| 271 config_.samples_per_second()); | 275 TimeDeltaToFrames(-buffer->timestamp(), config_.samples_per_second()); |
| 272 } else { | 276 } else { |
| 273 if (last_input_timestamp_ != kNoTimestamp() && | 277 if (last_input_timestamp_ != kNoTimestamp() && |
| 274 buffer->timestamp() < last_input_timestamp_) { | 278 buffer->timestamp() < last_input_timestamp_) { |
| 275 const base::TimeDelta diff = | 279 const base::TimeDelta diff = |
| 276 buffer->timestamp() - last_input_timestamp_; | 280 buffer->timestamp() - last_input_timestamp_; |
| 277 DLOG(WARNING) | 281 DLOG(WARNING) |
| 278 << "Input timestamps are not monotonically increasing! " | 282 << "Input timestamps are not monotonically increasing! " |
| 279 << " ts " << buffer->timestamp().InMicroseconds() << " us" | 283 << " ts " << buffer->timestamp().InMicroseconds() << " us" |
| 280 << " diff " << diff.InMicroseconds() << " us"; | 284 << " diff " << diff.InMicroseconds() << " us"; |
| 281 } | 285 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 } | 355 } |
| 352 | 356 |
| 353 // Update packet size and data pointer in case we need to call the decoder | 357 // Update packet size and data pointer in case we need to call the decoder |
| 354 // with the remaining bytes from this packet. | 358 // with the remaining bytes from this packet. |
| 355 packet.size -= result; | 359 packet.size -= result; |
| 356 packet.data += result; | 360 packet.data += result; |
| 357 | 361 |
| 358 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && | 362 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && |
| 359 !buffer->end_of_stream()) { | 363 !buffer->end_of_stream()) { |
| 360 DCHECK(buffer->timestamp() != kNoTimestamp()); | 364 DCHECK(buffer->timestamp() != kNoTimestamp()); |
| 361 if (output_frames_to_drop_ > 0) { | 365 if (output_frames_to_drop_ > 0 && |
| 362 // Currently Vorbis is the only codec that causes us to drop samples. | 366 codec_context_->codec_id == AV_CODEC_ID_VORBIS) { |
| 363 // If we have to drop samples it always means the timeline starts at 0. | 367 // If we are dropping samples for Vorbis, it always means the timeline |
| 364 DCHECK_EQ(codec_context_->codec_id, AV_CODEC_ID_VORBIS); | 368 // starts at 0. |
| 365 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); | 369 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); |
| 366 } else { | 370 } else { |
| 367 output_timestamp_helper_->SetBaseTimestamp(buffer->timestamp()); | 371 output_timestamp_helper_->SetBaseTimestamp(buffer->timestamp()); |
| 368 } | 372 } |
| 369 } | 373 } |
| 370 | 374 |
| 371 scoped_refptr<AudioBuffer> output; | 375 scoped_refptr<AudioBuffer> output; |
| 372 int decoded_frames = 0; | 376 int decoded_frames = 0; |
| 373 int original_frames = 0; | 377 int original_frames = 0; |
| 374 int channels = DetermineChannels(av_frame_.get()); | 378 int channels = DetermineChannels(av_frame_.get()); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 if (codec_context_->channels != | 493 if (codec_context_->channels != |
| 490 ChannelLayoutToChannelCount(config_.channel_layout())) { | 494 ChannelLayoutToChannelCount(config_.channel_layout())) { |
| 491 DLOG(ERROR) << "Audio configuration specified " | 495 DLOG(ERROR) << "Audio configuration specified " |
| 492 << ChannelLayoutToChannelCount(config_.channel_layout()) | 496 << ChannelLayoutToChannelCount(config_.channel_layout()) |
| 493 << " channels, but FFmpeg thinks the file contains " | 497 << " channels, but FFmpeg thinks the file contains " |
| 494 << codec_context_->channels << " channels"; | 498 << codec_context_->channels << " channels"; |
| 495 ReleaseFFmpegResources(); | 499 ReleaseFFmpegResources(); |
| 496 state_ = kUninitialized; | 500 state_ = kUninitialized; |
| 497 return false; | 501 return false; |
| 498 } | 502 } |
| 503 |
| 504 if (config_.codec_delay() > base::TimeDelta()) { |
| 505 output_frames_to_drop_ = |
| 506 TimeDeltaToFrames(config_.codec_delay(), config_.samples_per_second()); |
| 507 } |
| 508 |
| 499 return true; | 509 return true; |
| 500 } | 510 } |
| 501 | 511 |
| 502 void FFmpegAudioDecoder::ResetTimestampState() { | 512 void FFmpegAudioDecoder::ResetTimestampState() { |
| 503 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); | 513 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
| 504 last_input_timestamp_ = kNoTimestamp(); | 514 last_input_timestamp_ = kNoTimestamp(); |
| 505 output_frames_to_drop_ = 0; | 515 output_frames_to_drop_ = 0; |
| 506 } | 516 } |
| 507 | 517 |
| 508 } // namespace media | 518 } // namespace media |
| OLD | NEW |