Chromium Code Reviews| 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/audio_file_reader.h" | 5 #include "media/filters/audio_file_reader.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <cmath> | 9 #include <cmath> |
| 10 #include <vector> | |
| 10 | 11 |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/numerics/safe_math.h" | 13 #include "base/numerics/safe_math.h" |
| 13 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 14 #include "media/base/audio_bus.h" | 15 #include "media/base/audio_bus.h" |
| 16 #include "media/base/audio_sample_types.h" | |
| 15 #include "media/ffmpeg/ffmpeg_common.h" | 17 #include "media/ffmpeg/ffmpeg_common.h" |
| 16 | 18 |
| 17 namespace media { | 19 namespace media { |
| 18 | 20 |
| 19 // AAC(M4A) decoding specific constants. | 21 // AAC(M4A) decoding specific constants. |
| 20 static const int kAACPrimingFrameCount = 2112; | 22 static const int kAACPrimingFrameCount = 2112; |
| 21 static const int kAACRemainderFrameCount = 519; | 23 static const int kAACRemainderFrameCount = 519; |
| 22 | 24 |
| 23 AudioFileReader::AudioFileReader(FFmpegURLProtocol* protocol) | 25 AudioFileReader::AudioFileReader(FFmpegURLProtocol* protocol) |
| 24 : stream_index_(0), | 26 : stream_index_(0), |
| 25 protocol_(protocol), | 27 protocol_(protocol), |
| 26 audio_codec_(kUnknownAudioCodec), | 28 audio_codec_(kUnknownAudioCodec), |
| 27 channels_(0), | 29 channels_(0), |
| 28 sample_rate_(0), | 30 sample_rate_(0), |
| 29 av_sample_format_(0) {} | 31 av_sample_format_(0) {} |
| 30 | 32 |
| 31 AudioFileReader::~AudioFileReader() { | 33 AudioFileReader::~AudioFileReader() { |
| 32 Close(); | 34 Close(); |
| 33 } | 35 } |
| 34 | 36 |
| 35 bool AudioFileReader::Open() { | 37 bool AudioFileReader::Open() { |
| 36 if (!OpenDemuxer()) | 38 return OpenDemuxer() && OpenDecoder(); |
| 37 return false; | |
| 38 if (!OpenDecoder()) | |
| 39 return false; | |
| 40 | |
| 41 // If the duration is unknown, fail out; this API can not work with streams of | |
| 42 // unknown duration currently. | |
| 43 return glue_->format_context()->duration != AV_NOPTS_VALUE; | |
| 44 } | 39 } |
| 45 | 40 |
| 46 bool AudioFileReader::OpenDemuxer() { | 41 bool AudioFileReader::OpenDemuxer() { |
| 47 glue_.reset(new FFmpegGlue(protocol_)); | 42 glue_.reset(new FFmpegGlue(protocol_)); |
| 48 AVFormatContext* format_context = glue_->format_context(); | 43 AVFormatContext* format_context = glue_->format_context(); |
| 49 | 44 |
| 50 // Open FFmpeg AVFormatContext. | 45 // Open FFmpeg AVFormatContext. |
| 51 if (!glue_->OpenContext()) { | 46 if (!glue_->OpenContext()) { |
| 52 DLOG(WARNING) << "AudioFileReader::Open() : error in avformat_open_input()"; | 47 DLOG(WARNING) << "AudioFileReader::Open() : error in avformat_open_input()"; |
| 53 return false; | 48 return false; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 120 } | 115 } |
| 121 | 116 |
| 122 // Store initial values to guard against midstream configuration changes. | 117 // Store initial values to guard against midstream configuration changes. |
| 123 channels_ = codec_context_->channels; | 118 channels_ = codec_context_->channels; |
| 124 audio_codec_ = CodecIDToAudioCodec(codec_context_->codec_id); | 119 audio_codec_ = CodecIDToAudioCodec(codec_context_->codec_id); |
| 125 sample_rate_ = codec_context_->sample_rate; | 120 sample_rate_ = codec_context_->sample_rate; |
| 126 av_sample_format_ = codec_context_->sample_fmt; | 121 av_sample_format_ = codec_context_->sample_fmt; |
| 127 return true; | 122 return true; |
| 128 } | 123 } |
| 129 | 124 |
| 125 bool AudioFileReader::HasKnownDuration() const { | |
| 126 return glue_->format_context()->duration != AV_NOPTS_VALUE; | |
| 127 } | |
| 128 | |
| 130 void AudioFileReader::Close() { | 129 void AudioFileReader::Close() { |
| 131 codec_context_.reset(); | 130 codec_context_.reset(); |
| 132 glue_.reset(); | 131 glue_.reset(); |
| 133 } | 132 } |
| 134 | 133 |
| 134 #if 0 | |
| 135 int AudioFileReader::Read(AudioBus* audio_bus) { | 135 int AudioFileReader::Read(AudioBus* audio_bus) { |
| 136 DCHECK(glue_.get() && codec_context_) << | 136 DCHECK(glue_.get() && codec_context_) << |
| 137 "AudioFileReader::Read() : reader is not opened!"; | 137 "AudioFileReader::Read() : reader is not opened!"; |
| 138 | 138 |
| 139 DCHECK_EQ(audio_bus->channels(), channels()); | 139 DCHECK_EQ(audio_bus->channels(), channels()); |
| 140 if (audio_bus->channels() != channels()) | 140 if (audio_bus->channels() != channels()) |
| 141 return 0; | 141 return 0; |
| 142 | 142 |
| 143 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt); | 143 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt); |
| 144 | 144 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 } | 242 } |
| 243 | 243 |
| 244 // Zero any remaining frames. | 244 // Zero any remaining frames. |
| 245 audio_bus->ZeroFramesPartial( | 245 audio_bus->ZeroFramesPartial( |
| 246 current_frame, audio_bus->frames() - current_frame); | 246 current_frame, audio_bus->frames() - current_frame); |
| 247 | 247 |
| 248 // Returns the actual number of sample-frames decoded. | 248 // Returns the actual number of sample-frames decoded. |
| 249 // Ideally this represents the "true" exact length of the file. | 249 // Ideally this represents the "true" exact length of the file. |
| 250 return current_frame; | 250 return current_frame; |
| 251 } | 251 } |
| 252 #endif | |
| 253 | |
| 254 int AudioFileReader::Read( | |
| 255 std::vector<std::unique_ptr<AudioBus>>& decodedAudioPackets) { | |
| 256 DCHECK(glue_.get() && codec_context_) | |
| 257 << "AudioFileReader::Read() : reader is not opened!"; | |
| 258 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt); | |
| 259 | |
| 260 // Holds decoded audio. | |
| 261 std::unique_ptr<AVFrame, ScopedPtrAVFreeFrame> av_frame(av_frame_alloc()); | |
| 262 | |
| 263 AVPacket packet; | |
| 264 size_t total_frames = 0; | |
| 265 bool continue_decoding = true; | |
| 266 | |
| 267 while (continue_decoding && ReadPacket(&packet)) { | |
| 268 // Make a shallow copy of packet so we can slide packet.data as frames are | |
| 269 // decoded from the packet; otherwise av_packet_unref() will corrupt memory. | |
| 270 AVPacket packet_temp = packet; | |
| 271 do { | |
| 272 // Reset frame to default values. | |
| 273 av_frame_unref(av_frame.get()); | |
| 274 | |
| 275 int frame_decoded = 0; | |
| 276 int result = avcodec_decode_audio4(codec_context_.get(), av_frame.get(), | |
| 277 &frame_decoded, &packet_temp); | |
| 278 | |
| 279 if (result < 0) { | |
| 280 DLOG(WARNING) | |
| 281 << "AudioFileReader::Read() : error in avcodec_decode_audio4() -" | |
| 282 << result; | |
| 283 break; | |
|
Raymond Toy
2017/02/08 21:30:45
This continues the while loop. Is that what we re
DaleCurtis
2017/02/08 21:47:52
Up to you, but we traditionally ignore one-off aud
Raymond Toy
2017/02/08 22:08:35
Thanks. I'll add some comments to this effect so t
| |
| 284 } | |
| 285 | |
| 286 // Update packet size and data pointer in case we need to call the decoder | |
| 287 // with the remaining bytes from this packet. | |
| 288 packet_temp.size -= result; | |
| 289 packet_temp.data += result; | |
| 290 | |
| 291 if (!frame_decoded) | |
| 292 continue; | |
| 293 | |
| 294 // Determine the number of sample-frames we just decoded. Check overflow. | |
| 295 int frames_read = av_frame->nb_samples; | |
| 296 total_frames += frames_read; | |
| 297 | |
| 298 if (frames_read < 0) { | |
| 299 continue_decoding = false; | |
| 300 break; | |
| 301 } | |
| 302 | |
| 303 #ifdef CHROMIUM_NO_AVFRAME_CHANNELS | |
| 304 int channels = | |
| 305 av_get_channel_layout_nb_channels(av_frame->channel_layout); | |
| 306 #else | |
| 307 int channels = av_frame->channels; | |
| 308 #endif | |
| 309 if (av_frame->sample_rate != sample_rate_ || channels != channels_ || | |
| 310 av_frame->format != av_sample_format_) { | |
| 311 DLOG(ERROR) << "Unsupported midstream configuration change!" | |
| 312 << " Sample Rate: " << av_frame->sample_rate << " vs " | |
| 313 << sample_rate_ << ", Channels: " << channels << " vs " | |
| 314 << channels_ << ", Sample Format: " << av_frame->format | |
| 315 << " vs " << av_sample_format_; | |
| 316 | |
| 317 // This is an unrecoverable error, so bail out. | |
| 318 continue_decoding = false; | |
| 319 break; | |
|
Raymond Toy
2017/02/08 21:30:44
Is the expectation here that we'll just return wha
DaleCurtis
2017/02/08 21:47:52
Yes.
| |
| 320 } | |
| 321 | |
| 322 // Deinterleave each channel and convert to 32bit floating-point with | |
| 323 // nominal range -1.0 -> +1.0. If the output is already in float planar | |
| 324 // format, just copy it into the AudioBus. | |
| 325 std::unique_ptr<AudioBus> audio_bus = | |
| 326 AudioBus::Create(channels, frames_read); | |
| 327 | |
| 328 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { | |
| 329 audio_bus->FromInterleaved<Float32SampleTypeTraits>( | |
| 330 reinterpret_cast<float*>(av_frame->data[0]), frames_read); | |
| 331 } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) { | |
| 332 for (int ch = 0; ch < audio_bus->channels(); ++ch) { | |
| 333 memcpy(audio_bus->channel(ch), av_frame->extended_data[ch], | |
| 334 sizeof(float) * frames_read); | |
| 335 } | |
| 336 } else { | |
| 337 audio_bus->FromInterleaved(av_frame->data[0], frames_read, | |
| 338 bytes_per_sample); | |
| 339 } | |
| 340 | |
| 341 decodedAudioPackets.push_back(std::move(audio_bus)); | |
| 342 } while (packet_temp.size > 0); | |
| 343 av_packet_unref(&packet); | |
| 344 } | |
| 345 | |
| 346 return total_frames; | |
| 347 } | |
| 252 | 348 |
| 253 base::TimeDelta AudioFileReader::GetDuration() const { | 349 base::TimeDelta AudioFileReader::GetDuration() const { |
| 254 const AVRational av_time_base = {1, AV_TIME_BASE}; | 350 const AVRational av_time_base = {1, AV_TIME_BASE}; |
| 255 | 351 |
| 256 DCHECK_NE(glue_->format_context()->duration, AV_NOPTS_VALUE); | 352 DCHECK_NE(glue_->format_context()->duration, AV_NOPTS_VALUE); |
| 257 base::CheckedNumeric<int64_t> estimated_duration_us = | 353 base::CheckedNumeric<int64_t> estimated_duration_us = |
| 258 glue_->format_context()->duration; | 354 glue_->format_context()->duration; |
| 259 | 355 |
| 260 if (audio_codec_ == kCodecAAC) { | 356 if (audio_codec_ == kCodecAAC) { |
| 261 // For certain AAC-encoded files, FFMPEG's estimated frame count might not | 357 // For certain AAC-encoded files, FFMPEG's estimated frame count might not |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 310 glue_->format_context(), stream_index_, | 406 glue_->format_context(), stream_index_, |
| 311 ConvertToTimeBase(GetAVStreamForTesting()->time_base, seek_time), | 407 ConvertToTimeBase(GetAVStreamForTesting()->time_base, seek_time), |
| 312 AVSEEK_FLAG_BACKWARD) >= 0; | 408 AVSEEK_FLAG_BACKWARD) >= 0; |
| 313 } | 409 } |
| 314 | 410 |
| 315 const AVStream* AudioFileReader::GetAVStreamForTesting() const { | 411 const AVStream* AudioFileReader::GetAVStreamForTesting() const { |
| 316 return glue_->format_context()->streams[stream_index_]; | 412 return glue_->format_context()->streams[stream_index_]; |
| 317 } | 413 } |
| 318 | 414 |
| 319 } // namespace media | 415 } // namespace media |
| OLD | NEW |