|
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 |