| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "media/base/audio_decoder_config.h" | 8 #include "media/base/audio_decoder_config.h" |
| 9 #include "media/base/data_buffer.h" | 9 #include "media/base/data_buffer.h" |
| 10 #include "media/base/demuxer.h" | 10 #include "media/base/demuxer.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 static bool ProducedAudioSamples(int decoded_size) { | 24 static bool ProducedAudioSamples(int decoded_size) { |
| 25 return decoded_size > 0; | 25 return decoded_size > 0; |
| 26 } | 26 } |
| 27 | 27 |
| 28 // Returns true if the decode result was a timestamp packet and not actual audio | 28 // Returns true if the decode result was a timestamp packet and not actual audio |
| 29 // data. | 29 // data. |
| 30 static bool IsTimestampMarkerPacket(int result, Buffer* input) { | 30 static bool IsTimestampMarkerPacket(int result, Buffer* input) { |
| 31 // We can get a positive result but no decoded data. This is ok because this | 31 // We can get a positive result but no decoded data. This is ok because this |
| 32 // this can be a marker packet that only contains timestamp. | 32 // this can be a marker packet that only contains timestamp. |
| 33 return result > 0 && !input->IsEndOfStream() && | 33 return result > 0 && !input->IsEndOfStream() && |
| 34 input->GetTimestamp() != kNoTimestamp && | 34 input->GetTimestamp() != kNoTimestamp() && |
| 35 input->GetDuration() != kNoTimestamp; | 35 input->GetDuration() != kNoTimestamp(); |
| 36 } | 36 } |
| 37 | 37 |
| 38 // Returns true if the decode result was end of stream. | 38 // Returns true if the decode result was end of stream. |
| 39 static bool IsEndOfStream(int result, int decoded_size, Buffer* input) { | 39 static bool IsEndOfStream(int result, int decoded_size, Buffer* input) { |
| 40 // Three conditions to meet to declare end of stream for this decoder: | 40 // Three conditions to meet to declare end of stream for this decoder: |
| 41 // 1. FFmpeg didn't read anything. | 41 // 1. FFmpeg didn't read anything. |
| 42 // 2. FFmpeg didn't output anything. | 42 // 2. FFmpeg didn't output anything. |
| 43 // 3. An end of stream buffer is received. | 43 // 3. An end of stream buffer is received. |
| 44 return result == 0 && decoded_size == 0 && input->IsEndOfStream(); | 44 return result == 0 && decoded_size == 0 && input->IsEndOfStream(); |
| 45 } | 45 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 // Success! | 144 // Success! |
| 145 bits_per_channel_ = config.bits_per_channel(); | 145 bits_per_channel_ = config.bits_per_channel(); |
| 146 channel_layout_ = config.channel_layout(); | 146 channel_layout_ = config.channel_layout(); |
| 147 samples_per_second_ = config.samples_per_second(); | 147 samples_per_second_ = config.samples_per_second(); |
| 148 | 148 |
| 149 callback.Run(); | 149 callback.Run(); |
| 150 } | 150 } |
| 151 | 151 |
| 152 void FFmpegAudioDecoder::DoFlush(const base::Closure& callback) { | 152 void FFmpegAudioDecoder::DoFlush(const base::Closure& callback) { |
| 153 avcodec_flush_buffers(codec_context_); | 153 avcodec_flush_buffers(codec_context_); |
| 154 estimated_next_timestamp_ = kNoTimestamp; | 154 estimated_next_timestamp_ = kNoTimestamp(); |
| 155 callback.Run(); | 155 callback.Run(); |
| 156 } | 156 } |
| 157 | 157 |
| 158 void FFmpegAudioDecoder::DoRead(const ReadCB& callback) { | 158 void FFmpegAudioDecoder::DoRead(const ReadCB& callback) { |
| 159 DCHECK_EQ(MessageLoop::current(), message_loop_); | 159 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 160 DCHECK(!callback.is_null()); | 160 DCHECK(!callback.is_null()); |
| 161 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 161 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; |
| 162 | 162 |
| 163 read_cb_ = callback; | 163 read_cb_ = callback; |
| 164 ReadFromDemuxerStream(); | 164 ReadFromDemuxerStream(); |
| 165 } | 165 } |
| 166 | 166 |
| 167 void FFmpegAudioDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& input) { | 167 void FFmpegAudioDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& input) { |
| 168 DCHECK_EQ(MessageLoop::current(), message_loop_); | 168 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 169 DCHECK(!read_cb_.is_null()); | 169 DCHECK(!read_cb_.is_null()); |
| 170 | 170 |
| 171 // FFmpeg tends to seek Ogg audio streams in the middle of nowhere, giving us | 171 // FFmpeg tends to seek Ogg audio streams in the middle of nowhere, giving us |
| 172 // a whole bunch of AV_NOPTS_VALUE packets. Discard them until we find | 172 // a whole bunch of AV_NOPTS_VALUE packets. Discard them until we find |
| 173 // something valid. Refer to http://crbug.com/49709 | 173 // something valid. Refer to http://crbug.com/49709 |
| 174 if (input->GetTimestamp() == kNoTimestamp && | 174 if (input->GetTimestamp() == kNoTimestamp() && |
| 175 estimated_next_timestamp_ == kNoTimestamp && | 175 estimated_next_timestamp_ == kNoTimestamp() && |
| 176 !input->IsEndOfStream()) { | 176 !input->IsEndOfStream()) { |
| 177 ReadFromDemuxerStream(); | 177 ReadFromDemuxerStream(); |
| 178 return; | 178 return; |
| 179 } | 179 } |
| 180 | 180 |
| 181 AVPacket packet; | 181 AVPacket packet; |
| 182 av_init_packet(&packet); | 182 av_init_packet(&packet); |
| 183 if (input->IsEndOfStream()) { | 183 if (input->IsEndOfStream()) { |
| 184 packet.data = NULL; | 184 packet.data = NULL; |
| 185 packet.size = 0; | 185 packet.size = 0; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 } | 254 } |
| 255 | 255 |
| 256 void FFmpegAudioDecoder::UpdateDurationAndTimestamp( | 256 void FFmpegAudioDecoder::UpdateDurationAndTimestamp( |
| 257 const Buffer* input, | 257 const Buffer* input, |
| 258 DataBuffer* output) { | 258 DataBuffer* output) { |
| 259 // Always calculate duration based on the actual number of samples decoded. | 259 // Always calculate duration based on the actual number of samples decoded. |
| 260 base::TimeDelta duration = CalculateDuration(output->GetDataSize()); | 260 base::TimeDelta duration = CalculateDuration(output->GetDataSize()); |
| 261 output->SetDuration(duration); | 261 output->SetDuration(duration); |
| 262 | 262 |
| 263 // Use the incoming timestamp if it's valid. | 263 // Use the incoming timestamp if it's valid. |
| 264 if (input->GetTimestamp() != kNoTimestamp) { | 264 if (input->GetTimestamp() != kNoTimestamp()) { |
| 265 output->SetTimestamp(input->GetTimestamp()); | 265 output->SetTimestamp(input->GetTimestamp()); |
| 266 estimated_next_timestamp_ = input->GetTimestamp() + duration; | 266 estimated_next_timestamp_ = input->GetTimestamp() + duration; |
| 267 return; | 267 return; |
| 268 } | 268 } |
| 269 | 269 |
| 270 // Otherwise use an estimated timestamp and attempt to update the estimation | 270 // Otherwise use an estimated timestamp and attempt to update the estimation |
| 271 // as long as it's valid. | 271 // as long as it's valid. |
| 272 output->SetTimestamp(estimated_next_timestamp_); | 272 output->SetTimestamp(estimated_next_timestamp_); |
| 273 if (estimated_next_timestamp_ != kNoTimestamp) { | 273 if (estimated_next_timestamp_ != kNoTimestamp()) { |
| 274 estimated_next_timestamp_ += duration; | 274 estimated_next_timestamp_ += duration; |
| 275 } | 275 } |
| 276 } | 276 } |
| 277 | 277 |
| 278 base::TimeDelta FFmpegAudioDecoder::CalculateDuration(int size) { | 278 base::TimeDelta FFmpegAudioDecoder::CalculateDuration(int size) { |
| 279 int64 denominator = ChannelLayoutToChannelCount(channel_layout_) * | 279 int64 denominator = ChannelLayoutToChannelCount(channel_layout_) * |
| 280 bits_per_channel_ / 8 * samples_per_second_; | 280 bits_per_channel_ / 8 * samples_per_second_; |
| 281 double microseconds = size / | 281 double microseconds = size / |
| 282 (denominator / static_cast<double>(base::Time::kMicrosecondsPerSecond)); | 282 (denominator / static_cast<double>(base::Time::kMicrosecondsPerSecond)); |
| 283 return base::TimeDelta::FromMicroseconds(static_cast<int64>(microseconds)); | 283 return base::TimeDelta::FromMicroseconds(static_cast<int64>(microseconds)); |
| 284 } | 284 } |
| 285 | 285 |
| 286 void FFmpegAudioDecoder::DeliverSamples(const scoped_refptr<Buffer>& samples) { | 286 void FFmpegAudioDecoder::DeliverSamples(const scoped_refptr<Buffer>& samples) { |
| 287 // Reset the callback before running to protect against reentrancy. | 287 // Reset the callback before running to protect against reentrancy. |
| 288 ReadCB read_cb = read_cb_; | 288 ReadCB read_cb = read_cb_; |
| 289 read_cb_.Reset(); | 289 read_cb_.Reset(); |
| 290 read_cb.Run(samples); | 290 read_cb.Run(samples); |
| 291 } | 291 } |
| 292 | 292 |
| 293 } // namespace media | 293 } // namespace media |
| OLD | NEW |