Index: media/filters/audio_file_reader.cc |
diff --git a/media/filters/audio_file_reader.cc b/media/filters/audio_file_reader.cc |
index 582ca9cdc7fbbde62cbefc4bea56a84563da4ebc..3357668ab892b6be712fef7c0cc50fdd2c9212e8 100644 |
--- a/media/filters/audio_file_reader.cc |
+++ b/media/filters/audio_file_reader.cc |
@@ -7,11 +7,13 @@ |
#include <stddef.h> |
#include <cmath> |
+#include <vector> |
#include "base/logging.h" |
#include "base/numerics/safe_math.h" |
#include "base/time/time.h" |
#include "media/base/audio_bus.h" |
+#include "media/base/audio_sample_types.h" |
#include "media/ffmpeg/ffmpeg_common.h" |
namespace media { |
@@ -33,14 +35,7 @@ AudioFileReader::~AudioFileReader() { |
} |
bool AudioFileReader::Open() { |
- if (!OpenDemuxer()) |
- return false; |
- if (!OpenDecoder()) |
- return false; |
- |
- // If the duration is unknown, fail out; this API can not work with streams of |
- // unknown duration currently. |
- return glue_->format_context()->duration != AV_NOPTS_VALUE; |
+ return OpenDemuxer() && OpenDecoder(); |
} |
bool AudioFileReader::OpenDemuxer() { |
@@ -127,11 +122,16 @@ bool AudioFileReader::OpenDecoder() { |
return true; |
} |
+bool AudioFileReader::HasKnownDuration() const { |
+ return glue_->format_context()->duration != AV_NOPTS_VALUE; |
+} |
+ |
void AudioFileReader::Close() { |
codec_context_.reset(); |
glue_.reset(); |
} |
+#if 0 |
int AudioFileReader::Read(AudioBus* audio_bus) { |
DCHECK(glue_.get() && codec_context_) << |
"AudioFileReader::Read() : reader is not opened!"; |
@@ -249,6 +249,102 @@ int AudioFileReader::Read(AudioBus* audio_bus) { |
// Ideally this represents the "true" exact length of the file. |
return current_frame; |
} |
+#endif |
+ |
+int AudioFileReader::Read( |
+ std::vector<std::unique_ptr<AudioBus>>& decodedAudioPackets) { |
+ DCHECK(glue_.get() && codec_context_) |
+ << "AudioFileReader::Read() : reader is not opened!"; |
+ size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt); |
+ |
+ // Holds decoded audio. |
+ std::unique_ptr<AVFrame, ScopedPtrAVFreeFrame> av_frame(av_frame_alloc()); |
+ |
+ AVPacket packet; |
+ size_t total_frames = 0; |
+ bool continue_decoding = true; |
+ |
+ while (continue_decoding && ReadPacket(&packet)) { |
+ // Make a shallow copy of packet so we can slide packet.data as frames are |
+ // decoded from the packet; otherwise av_packet_unref() will corrupt memory. |
+ AVPacket packet_temp = packet; |
+ do { |
+ // Reset frame to default values. |
+ av_frame_unref(av_frame.get()); |
+ |
+ int frame_decoded = 0; |
+ int result = avcodec_decode_audio4(codec_context_.get(), av_frame.get(), |
+ &frame_decoded, &packet_temp); |
+ |
+ if (result < 0) { |
+ DLOG(WARNING) |
+ << "AudioFileReader::Read() : error in avcodec_decode_audio4() -" |
+ << result; |
+ 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
|
+ } |
+ |
+ // Update packet size and data pointer in case we need to call the decoder |
+ // with the remaining bytes from this packet. |
+ packet_temp.size -= result; |
+ packet_temp.data += result; |
+ |
+ if (!frame_decoded) |
+ continue; |
+ |
+ // Determine the number of sample-frames we just decoded. Check overflow. |
+ int frames_read = av_frame->nb_samples; |
+ total_frames += frames_read; |
+ |
+ if (frames_read < 0) { |
+ continue_decoding = false; |
+ break; |
+ } |
+ |
+#ifdef CHROMIUM_NO_AVFRAME_CHANNELS |
+ int channels = |
+ av_get_channel_layout_nb_channels(av_frame->channel_layout); |
+#else |
+ int channels = av_frame->channels; |
+#endif |
+ if (av_frame->sample_rate != sample_rate_ || channels != channels_ || |
+ av_frame->format != av_sample_format_) { |
+ DLOG(ERROR) << "Unsupported midstream configuration change!" |
+ << " Sample Rate: " << av_frame->sample_rate << " vs " |
+ << sample_rate_ << ", Channels: " << channels << " vs " |
+ << channels_ << ", Sample Format: " << av_frame->format |
+ << " vs " << av_sample_format_; |
+ |
+ // This is an unrecoverable error, so bail out. |
+ continue_decoding = false; |
+ 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.
|
+ } |
+ |
+ // Deinterleave each channel and convert to 32bit floating-point with |
+ // nominal range -1.0 -> +1.0. If the output is already in float planar |
+ // format, just copy it into the AudioBus. |
+ std::unique_ptr<AudioBus> audio_bus = |
+ AudioBus::Create(channels, frames_read); |
+ |
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { |
+ audio_bus->FromInterleaved<Float32SampleTypeTraits>( |
+ reinterpret_cast<float*>(av_frame->data[0]), frames_read); |
+ } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) { |
+ for (int ch = 0; ch < audio_bus->channels(); ++ch) { |
+ memcpy(audio_bus->channel(ch), av_frame->extended_data[ch], |
+ sizeof(float) * frames_read); |
+ } |
+ } else { |
+ audio_bus->FromInterleaved(av_frame->data[0], frames_read, |
+ bytes_per_sample); |
+ } |
+ |
+ decodedAudioPackets.push_back(std::move(audio_bus)); |
+ } while (packet_temp.size > 0); |
+ av_packet_unref(&packet); |
+ } |
+ |
+ return total_frames; |
+} |
base::TimeDelta AudioFileReader::GetDuration() const { |
const AVRational av_time_base = {1, AV_TIME_BASE}; |