Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/filters/audio_file_reader.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include "base/basictypes.h" | |
| 9 #include "base/string_util.h" | |
| 10 #include "media/base/filters.h" | |
| 11 #include "media/ffmpeg/ffmpeg_common.h" | |
| 12 #include "media/ffmpeg/ffmpeg_util.h" | |
| 13 #include "media/filters/ffmpeg_glue.h" | |
| 14 | |
| 15 namespace media { | |
| 16 | |
| 17 AudioFileReader::AudioFileReader(FFmpegURLProtocol* protocol) | |
| 18 : protocol_(protocol), | |
| 19 format_context_(NULL), | |
| 20 codec_context_(NULL), | |
| 21 codec_(NULL) { | |
| 22 } | |
| 23 | |
| 24 AudioFileReader::~AudioFileReader() { | |
| 25 Close(); | |
| 26 } | |
| 27 | |
| 28 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.
| |
| 29 return codec_context_->channels; | |
| 30 } | |
| 31 | |
| 32 double AudioFileReader::GetSampleRate() const { | |
| 33 return codec_context_->sample_rate; | |
| 34 } | |
| 35 | |
| 36 double AudioFileReader::GetDuration() const { | |
| 37 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
| |
| 38 } | |
| 39 | |
| 40 size_t AudioFileReader::Length() const { | |
| 41 return GetDuration() * GetSampleRate(); | |
| 42 } | |
| 43 | |
| 44 int AudioFileReader::Open() { | |
| 45 // Add our data reader to the protocol list and get our unique key. | |
| 46 std::string key = FFmpegGlue::get()->AddProtocol(protocol_); | |
| 47 | |
| 48 // Open FFmpeg AVFormatContext. | |
| 49 DCHECK(!format_context_); | |
| 50 AVFormatContext* context = NULL; | |
| 51 | |
| 52 int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL); | |
| 53 | |
| 54 // Remove our data reader from protocol list since av_open_input_file() setup | |
| 55 // the AVFormatContext with the data reader. | |
| 56 FFmpegGlue::get()->RemoveProtocol(protocol_); | |
| 57 | |
| 58 if (result) { | |
| 59 DLOG(WARNING) | |
| 60 << "AudioFileReader::Open() : error in av_open_input_file() -" | |
| 61 << " result: " << result; | |
| 62 return result; | |
| 63 } | |
| 64 | |
| 65 DCHECK(context); | |
| 66 format_context_ = context; | |
| 67 | |
| 68 // Get the codec context. | |
| 69 codec_context_ = NULL; | |
| 70 for (unsigned i = 0; i < format_context_->nb_streams; ++i) { | |
| 71 AVCodecContext* c = format_context_->streams[i]->codec; | |
| 72 if (c->codec_type == CODEC_TYPE_AUDIO) { | |
| 73 codec_context_ = c; | |
| 74 break; | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 // Get the codec. | |
| 79 if (codec_context_) { | |
| 80 av_find_stream_info(format_context_); | |
| 81 codec_ = avcodec_find_decoder(codec_context_->codec_id); | |
| 82 if (codec_) { | |
| 83 if ((result = avcodec_open(codec_context_, codec_)) < 0) { | |
| 84 DLOG(WARNING) << "AudioFileReader::Open() : could not open codec -" | |
| 85 << " result: " << result; | |
| 86 return result; | |
| 87 } | |
| 88 | |
| 89 result = av_seek_frame(format_context_, 0, 0, 0); | |
| 90 } | |
| 91 } else { | |
| 92 result = -1; | |
| 93 } | |
| 94 | |
| 95 return result; | |
| 96 } | |
| 97 | |
| 98 void AudioFileReader::Close() { | |
| 99 if (codec_context_ && codec_) { | |
| 100 avcodec_close(codec_context_); | |
| 101 } | |
| 102 codec_context_ = NULL; | |
| 103 codec_ = NULL; | |
| 104 | |
| 105 if (format_context_) { | |
| 106 av_close_input_file(format_context_); | |
| 107 format_context_ = NULL; | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 int AudioFileReader::Read(const std::vector<float*>& audio_data, | |
| 112 size_t number_of_frames) { | |
| 113 DCHECK_EQ(audio_data.size(), NumberOfChannels()); | |
| 114 if (audio_data.size() != NumberOfChannels()) | |
| 115 return -1; | |
| 116 | |
| 117 DCHECK(format_context_ && codec_context_); | |
| 118 if (!format_context_ || !codec_context_) { | |
| 119 DLOG(WARNING) << "AudioFileReader::Read() : reader is not opened!"; | |
| 120 return -1; | |
| 121 } | |
| 122 | |
| 123 int16* output_buffer = | |
| 124 static_cast<int16*>(malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE)); | |
| 125 | |
| 126 unsigned number_of_channels = NumberOfChannels(); | |
| 127 | |
| 128 // Read until we hit EOF or we've read the requested number of frames. | |
| 129 AVPacket avpkt; | |
| 130 av_init_packet(&avpkt); | |
| 131 | |
| 132 int result = 0; | |
| 133 unsigned current_frame = 0; | |
| 134 | |
| 135 while (current_frame < number_of_frames | |
| 136 && (result = av_read_frame(format_context_, &avpkt)) >= 0) { | |
| 137 int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; | |
| 138 result = avcodec_decode_audio3(codec_context_, | |
| 139 output_buffer, | |
| 140 &out_size, | |
| 141 &avpkt); | |
| 142 | |
| 143 if (result < 0) { | |
| 144 DLOG(WARNING) | |
| 145 << "AudioFileReader::Read() : error in avcodec_decode_audio3() -" | |
| 146 << result; | |
| 147 free(output_buffer); | |
| 148 return result; | |
| 149 } | |
| 150 | |
| 151 // Determine the number of sample-frames we just decoded. | |
| 152 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.
| |
| 153 ? sizeof(int32) : sizeof(int16); | |
| 154 | |
| 155 unsigned frames_read = out_size / (number_of_channels * sample_byte_size); | |
| 156 | |
| 157 // Truncate, if necessary, if the destination isn't big enough. | |
| 158 if (current_frame + frames_read > number_of_frames) { | |
| 159 frames_read = static_cast<int>(number_of_frames) - current_frame; | |
| 160 } | |
| 161 | |
| 162 // Convert to Float32 with nominal range -1.0 -> +1.0 | |
| 163 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
| |
| 164 ++channelIndex) { | |
| 165 float* destination = audio_data[channelIndex]; | |
| 166 destination += current_frame; | |
| 167 | |
| 168 switch (codec_context_->sample_fmt) { | |
| 169 case AV_SAMPLE_FMT_S16: | |
| 170 { | |
| 171 const float kScale = 1.0f / 32768.0f; | |
| 172 for (unsigned i = 0; i < frames_read; ++i) { | |
| 173 destination[i] = | |
| 174 kScale * output_buffer[i * number_of_channels + channelIndex]; | |
| 175 } | |
| 176 break; | |
| 177 } | |
| 178 | |
| 179 case AV_SAMPLE_FMT_S32: | |
| 180 { | |
| 181 const float kScale = 1.0f / (1L << 31); | |
| 182 int32* output_buffer32 = reinterpret_cast<int32*>(output_buffer); | |
| 183 for (unsigned i = 0; i < frames_read; ++i) { | |
| 184 destination[i] = | |
| 185 kScale * output_buffer32[i * number_of_channels + channelIndex]; | |
| 186 } | |
| 187 break; | |
| 188 } | |
| 189 | |
| 190 default: | |
| 191 DLOG(WARNING) | |
| 192 << "AudioFileReader::Read() : Unsupported sample format : " | |
| 193 << codec_context_->sample_fmt | |
| 194 << " codec_->id : " << codec_->id; | |
| 195 return -1; | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 current_frame += frames_read; | |
| 200 } | |
| 201 | |
| 202 free(output_buffer); | |
| 203 return 0; // success | |
| 204 } | |
| 205 | |
| 206 InMemoryDataReader::InMemoryDataReader(const char* data, int64 size) | |
| 207 : data_(data), | |
| 208 size_(size), | |
| 209 position_(0) { | |
| 210 } | |
| 211 | |
| 212 int InMemoryDataReader::Read(int size, uint8* data) { | |
| 213 if (size < 0) | |
| 214 return -1; | |
| 215 | |
| 216 int64 available_bytes = size_ - position_; | |
| 217 if (size > available_bytes) | |
| 218 size = available_bytes; | |
| 219 | |
| 220 memcpy(data, data_ + position_, size); | |
| 221 position_ += size; | |
| 222 return size; | |
| 223 } | |
| 224 | |
| 225 bool InMemoryDataReader::GetPosition(int64* position_out) { | |
| 226 if (position_out) | |
| 227 *position_out = position_; | |
| 228 return true; | |
| 229 } | |
| 230 | |
| 231 bool InMemoryDataReader::SetPosition(int64 position) { | |
| 232 if (position >= size_) | |
| 233 return false; | |
| 234 position_ = position; | |
| 235 return true; | |
| 236 } | |
| 237 | |
| 238 bool InMemoryDataReader::GetSize(int64* size_out) { | |
| 239 if (size_out) | |
| 240 *size_out = size_; | |
| 241 return true; | |
| 242 } | |
| 243 | |
| 244 bool InMemoryDataReader::IsStreaming() { | |
| 245 return false; | |
| 246 } | |
| 247 | |
| 248 } // namespace media | |
| OLD | NEW |