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

Side by Side Diff: media/filters/audio_file_reader.cc

Issue 5550006: Implement WebKitClientImpl::loadAudioResource() to decode in-memory audio fil... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 10 years 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 unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698