Index: media/filters/audio_file_reader.cc |
=================================================================== |
--- media/filters/audio_file_reader.cc (revision 0) |
+++ media/filters/audio_file_reader.cc (revision 0) |
@@ -0,0 +1,248 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/filters/audio_file_reader.h" |
+ |
+#include <string> |
+#include "base/basictypes.h" |
+#include "base/string_util.h" |
+#include "media/base/filters.h" |
+#include "media/ffmpeg/ffmpeg_common.h" |
+#include "media/ffmpeg/ffmpeg_util.h" |
+#include "media/filters/ffmpeg_glue.h" |
+ |
+namespace media { |
+ |
+AudioFileReader::AudioFileReader(FFmpegURLProtocol* protocol) |
+ : protocol_(protocol), |
+ format_context_(NULL), |
+ codec_context_(NULL), |
+ codec_(NULL) { |
+} |
+ |
+AudioFileReader::~AudioFileReader() { |
+ Close(); |
+} |
+ |
+size_t AudioFileReader::NumberOfChannels() const { |
scherkus (not reviewing)
2010/12/09 17:35:40
I think it'd be best to not do type conversion her
Chris Rogers
2010/12/10 23:34:00
Done.
|
+ return codec_context_->channels; |
+} |
+ |
+double AudioFileReader::GetSampleRate() const { |
+ return codec_context_->sample_rate; |
+} |
+ |
+double AudioFileReader::GetDuration() const { |
+ return 1e-6 * format_context_->duration; |
scherkus (not reviewing)
2010/12/09 17:35:40
what are we converting here to/from? what are the
fbarchard
2010/12/09 21:11:02
1e-6 is obscure.
Chris Rogers
2010/12/10 23:34:00
Thanks for the tip - I've switched the code over t
Chris Rogers
2010/12/10 23:34:00
This is addressed by switching the code over to us
|
+} |
+ |
+size_t AudioFileReader::Length() const { |
+ return GetDuration() * GetSampleRate(); |
+} |
+ |
+int AudioFileReader::Open() { |
+ // Add our data reader to the protocol list and get our unique key. |
+ std::string key = FFmpegGlue::get()->AddProtocol(protocol_); |
+ |
+ // Open FFmpeg AVFormatContext. |
+ DCHECK(!format_context_); |
+ AVFormatContext* context = NULL; |
+ |
+ int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL); |
+ |
+ // Remove our data reader from protocol list since av_open_input_file() setup |
+ // the AVFormatContext with the data reader. |
+ FFmpegGlue::get()->RemoveProtocol(protocol_); |
+ |
+ if (result) { |
+ DLOG(WARNING) |
+ << "AudioFileReader::Open() : error in av_open_input_file() -" |
+ << " result: " << result; |
+ return result; |
+ } |
+ |
+ DCHECK(context); |
+ format_context_ = context; |
+ |
+ // Get the codec context. |
+ codec_context_ = NULL; |
+ for (unsigned i = 0; i < format_context_->nb_streams; ++i) { |
+ AVCodecContext* c = format_context_->streams[i]->codec; |
+ if (c->codec_type == CODEC_TYPE_AUDIO) { |
+ codec_context_ = c; |
+ break; |
+ } |
+ } |
+ |
+ // Get the codec. |
+ if (codec_context_) { |
+ av_find_stream_info(format_context_); |
+ codec_ = avcodec_find_decoder(codec_context_->codec_id); |
+ if (codec_) { |
+ if ((result = avcodec_open(codec_context_, codec_)) < 0) { |
+ DLOG(WARNING) << "AudioFileReader::Open() : could not open codec -" |
+ << " result: " << result; |
+ return result; |
+ } |
+ |
+ result = av_seek_frame(format_context_, 0, 0, 0); |
+ } |
+ } else { |
+ result = -1; |
+ } |
+ |
+ return result; |
+} |
+ |
+void AudioFileReader::Close() { |
+ if (codec_context_ && codec_) { |
+ avcodec_close(codec_context_); |
+ } |
+ codec_context_ = NULL; |
+ codec_ = NULL; |
+ |
+ if (format_context_) { |
+ av_close_input_file(format_context_); |
+ format_context_ = NULL; |
+ } |
+} |
+ |
+int AudioFileReader::Read(const std::vector<float*>& audio_data, |
+ size_t number_of_frames) { |
+ DCHECK_EQ(audio_data.size(), NumberOfChannels()); |
+ if (audio_data.size() != NumberOfChannels()) |
+ return -1; |
+ |
+ DCHECK(format_context_ && codec_context_); |
+ if (!format_context_ || !codec_context_) { |
+ DLOG(WARNING) << "AudioFileReader::Read() : reader is not opened!"; |
+ return -1; |
+ } |
+ |
+ int16* output_buffer = |
+ static_cast<int16*>(malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE)); |
+ |
+ unsigned number_of_channels = NumberOfChannels(); |
+ |
+ // Read until we hit EOF or we've read the requested number of frames. |
+ AVPacket avpkt; |
+ av_init_packet(&avpkt); |
+ |
+ int result = 0; |
+ unsigned current_frame = 0; |
+ |
+ while (current_frame < number_of_frames |
+ && (result = av_read_frame(format_context_, &avpkt)) >= 0) { |
+ int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; |
+ result = avcodec_decode_audio3(codec_context_, |
+ output_buffer, |
+ &out_size, |
+ &avpkt); |
+ |
+ if (result < 0) { |
+ DLOG(WARNING) |
+ << "AudioFileReader::Read() : error in avcodec_decode_audio3() -" |
+ << result; |
+ free(output_buffer); |
+ return result; |
+ } |
+ |
+ // Determine the number of sample-frames we just decoded. |
+ size_t sample_byte_size = codec_context_->sample_fmt == AV_SAMPLE_FMT_S32 |
scherkus (not reviewing)
2010/12/09 17:35:40
use av_get_bits_per_sample_fmt() and divide by 8 -
fbarchard
2010/12/09 21:11:02
You missed 8 bit.
Chris Rogers
2010/12/10 23:34:00
Done.
Chris Rogers
2010/12/10 23:34:00
Done.
|
+ ? sizeof(int32) : sizeof(int16); |
+ |
+ unsigned frames_read = out_size / (number_of_channels * sample_byte_size); |
+ |
+ // Truncate, if necessary, if the destination isn't big enough. |
+ if (current_frame + frames_read > number_of_frames) { |
+ frames_read = static_cast<int>(number_of_frames) - current_frame; |
+ } |
+ |
+ // Convert to Float32 with nominal range -1.0 -> +1.0 |
+ for (unsigned channelIndex = 0; channelIndex < number_of_channels; |
scherkus (not reviewing)
2010/12/09 17:35:40
I can't remember if FFmpeg offers any sort of util
Chris Rogers
2010/12/10 23:34:00
I've created a utility function called Deinterleav
|
+ ++channelIndex) { |
+ float* destination = audio_data[channelIndex]; |
+ destination += current_frame; |
+ |
+ switch (codec_context_->sample_fmt) { |
+ case AV_SAMPLE_FMT_S16: |
+ { |
+ const float kScale = 1.0f / 32768.0f; |
+ for (unsigned i = 0; i < frames_read; ++i) { |
+ destination[i] = |
+ kScale * output_buffer[i * number_of_channels + channelIndex]; |
+ } |
+ break; |
+ } |
+ |
+ case AV_SAMPLE_FMT_S32: |
+ { |
+ const float kScale = 1.0f / (1L << 31); |
+ int32* output_buffer32 = reinterpret_cast<int32*>(output_buffer); |
+ for (unsigned i = 0; i < frames_read; ++i) { |
+ destination[i] = |
+ kScale * output_buffer32[i * number_of_channels + channelIndex]; |
+ } |
+ break; |
+ } |
+ |
+ default: |
+ DLOG(WARNING) |
+ << "AudioFileReader::Read() : Unsupported sample format : " |
+ << codec_context_->sample_fmt |
+ << " codec_->id : " << codec_->id; |
+ return -1; |
+ } |
+ } |
+ |
+ current_frame += frames_read; |
+ } |
+ |
+ free(output_buffer); |
+ return 0; // success |
+} |
+ |
+InMemoryDataReader::InMemoryDataReader(const char* data, int64 size) |
+ : data_(data), |
+ size_(size), |
+ position_(0) { |
+} |
+ |
+int InMemoryDataReader::Read(int size, uint8* data) { |
+ if (size < 0) |
+ return -1; |
+ |
+ int64 available_bytes = size_ - position_; |
+ if (size > available_bytes) |
+ size = available_bytes; |
+ |
+ memcpy(data, data_ + position_, size); |
+ position_ += size; |
+ return size; |
+} |
+ |
+bool InMemoryDataReader::GetPosition(int64* position_out) { |
+ if (position_out) |
+ *position_out = position_; |
+ return true; |
+} |
+ |
+bool InMemoryDataReader::SetPosition(int64 position) { |
+ if (position >= size_) |
+ return false; |
+ position_ = position; |
+ return true; |
+} |
+ |
+bool InMemoryDataReader::GetSize(int64* size_out) { |
+ if (size_out) |
+ *size_out = size_; |
+ return true; |
+} |
+ |
+bool InMemoryDataReader::IsStreaming() { |
+ return false; |
+} |
+ |
+} // namespace media |
Property changes on: media/filters/audio_file_reader.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |