Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(710)

Unified Diff: media/filters/audio_file_reader.cc

Issue 2655783004: Decode entire in-memory file for WebAudio (Closed)
Patch Set: WIP: cleanup, add tests Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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};

Powered by Google App Engine
This is Rietveld 408576698