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

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

Issue 2655783004: Decode entire in-memory file for WebAudio (Closed)
Patch Set: Address review comments 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 unified diff | Download patch
« no previous file with comments | « media/filters/audio_file_reader.h ('k') | media/filters/audio_file_reader_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/audio_file_reader.h" 5 #include "media/filters/audio_file_reader.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <cmath> 9 #include <cmath>
10 #include <vector>
10 11
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/numerics/safe_math.h" 13 #include "base/numerics/safe_math.h"
13 #include "base/time/time.h" 14 #include "base/time/time.h"
14 #include "media/base/audio_bus.h" 15 #include "media/base/audio_bus.h"
16 #include "media/base/audio_sample_types.h"
15 #include "media/ffmpeg/ffmpeg_common.h" 17 #include "media/ffmpeg/ffmpeg_common.h"
16 18
17 namespace media { 19 namespace media {
18 20
19 // AAC(M4A) decoding specific constants. 21 // AAC(M4A) decoding specific constants.
20 static const int kAACPrimingFrameCount = 2112; 22 static const int kAACPrimingFrameCount = 2112;
21 static const int kAACRemainderFrameCount = 519; 23 static const int kAACRemainderFrameCount = 519;
22 24
23 AudioFileReader::AudioFileReader(FFmpegURLProtocol* protocol) 25 AudioFileReader::AudioFileReader(FFmpegURLProtocol* protocol)
24 : stream_index_(0), 26 : stream_index_(0),
25 protocol_(protocol), 27 protocol_(protocol),
26 audio_codec_(kUnknownAudioCodec), 28 audio_codec_(kUnknownAudioCodec),
27 channels_(0), 29 channels_(0),
28 sample_rate_(0), 30 sample_rate_(0),
29 av_sample_format_(0) {} 31 av_sample_format_(0) {}
30 32
31 AudioFileReader::~AudioFileReader() { 33 AudioFileReader::~AudioFileReader() {
32 Close(); 34 Close();
33 } 35 }
34 36
35 bool AudioFileReader::Open() { 37 bool AudioFileReader::Open() {
36 if (!OpenDemuxer()) 38 return OpenDemuxer() && OpenDecoder();
37 return false;
38 if (!OpenDecoder())
39 return false;
40
41 // If the duration is unknown, fail out; this API can not work with streams of
42 // unknown duration currently.
43 return glue_->format_context()->duration != AV_NOPTS_VALUE;
44 } 39 }
45 40
46 bool AudioFileReader::OpenDemuxer() { 41 bool AudioFileReader::OpenDemuxer() {
47 glue_.reset(new FFmpegGlue(protocol_)); 42 glue_.reset(new FFmpegGlue(protocol_));
48 AVFormatContext* format_context = glue_->format_context(); 43 AVFormatContext* format_context = glue_->format_context();
49 44
50 // Open FFmpeg AVFormatContext. 45 // Open FFmpeg AVFormatContext.
51 if (!glue_->OpenContext()) { 46 if (!glue_->OpenContext()) {
52 DLOG(WARNING) << "AudioFileReader::Open() : error in avformat_open_input()"; 47 DLOG(WARNING) << "AudioFileReader::Open() : error in avformat_open_input()";
53 return false; 48 return false;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 } 115 }
121 116
122 // Store initial values to guard against midstream configuration changes. 117 // Store initial values to guard against midstream configuration changes.
123 channels_ = codec_context_->channels; 118 channels_ = codec_context_->channels;
124 audio_codec_ = CodecIDToAudioCodec(codec_context_->codec_id); 119 audio_codec_ = CodecIDToAudioCodec(codec_context_->codec_id);
125 sample_rate_ = codec_context_->sample_rate; 120 sample_rate_ = codec_context_->sample_rate;
126 av_sample_format_ = codec_context_->sample_fmt; 121 av_sample_format_ = codec_context_->sample_fmt;
127 return true; 122 return true;
128 } 123 }
129 124
125 bool AudioFileReader::HasKnownDuration() const {
126 return glue_->format_context()->duration != AV_NOPTS_VALUE;
127 }
128
130 void AudioFileReader::Close() { 129 void AudioFileReader::Close() {
131 codec_context_.reset(); 130 codec_context_.reset();
132 glue_.reset(); 131 glue_.reset();
133 } 132 }
134 133
135 int AudioFileReader::Read(AudioBus* audio_bus) { 134 int AudioFileReader::Read(
136 DCHECK(glue_.get() && codec_context_) << 135 std::vector<std::unique_ptr<AudioBus>>* decoded_audio_packets) {
137 "AudioFileReader::Read() : reader is not opened!"; 136 DCHECK(glue_.get() && codec_context_)
138 137 << "AudioFileReader::Read() : reader is not opened!";
139 DCHECK_EQ(audio_bus->channels(), channels());
140 if (audio_bus->channels() != channels())
141 return 0;
142
143 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt); 138 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt);
144 139
145 // Holds decoded audio. 140 // Holds decoded audio.
146 std::unique_ptr<AVFrame, ScopedPtrAVFreeFrame> av_frame(av_frame_alloc()); 141 std::unique_ptr<AVFrame, ScopedPtrAVFreeFrame> av_frame(av_frame_alloc());
147 142
148 // Read until we hit EOF or we've read the requested number of frames.
149 AVPacket packet; 143 AVPacket packet;
150 int current_frame = 0; 144 size_t total_frames = 0;
DaleCurtis 2017/02/09 23:24:43 Int?
Raymond Toy 2017/02/10 16:36:02 Done.
151 bool continue_decoding = true; 145 bool continue_decoding = true;
152 146
153 while (current_frame < audio_bus->frames() && continue_decoding && 147 while (continue_decoding && ReadPacket(&packet)) {
154 ReadPacket(&packet)) {
155 // Make a shallow copy of packet so we can slide packet.data as frames are 148 // Make a shallow copy of packet so we can slide packet.data as frames are
156 // decoded from the packet; otherwise av_packet_unref() will corrupt memory. 149 // decoded from the packet; otherwise av_packet_unref() will corrupt memory.
157 AVPacket packet_temp = packet; 150 AVPacket packet_temp = packet;
158 do { 151 do {
159 // Reset frame to default values. 152 // Reset frame to default values.
160 av_frame_unref(av_frame.get()); 153 av_frame_unref(av_frame.get());
161 154
162 int frame_decoded = 0; 155 int frame_decoded = 0;
163 int result = avcodec_decode_audio4(codec_context_.get(), av_frame.get(), 156 int result = avcodec_decode_audio4(codec_context_.get(), av_frame.get(),
164 &frame_decoded, &packet_temp); 157 &frame_decoded, &packet_temp);
165 158
166 if (result < 0) { 159 if (result < 0) {
160 // Unable to decode this current packet. We'll skip it and
161 // continue decoding the next packet.
167 DLOG(WARNING) 162 DLOG(WARNING)
168 << "AudioFileReader::Read() : error in avcodec_decode_audio4() -" 163 << "AudioFileReader::Read() : error in avcodec_decode_audio4() -"
169 << result; 164 << result;
170 break; 165 break;
171 } 166 }
172 167
173 // Update packet size and data pointer in case we need to call the decoder 168 // Update packet size and data pointer in case we need to call the decoder
174 // with the remaining bytes from this packet. 169 // with the remaining bytes from this packet.
175 packet_temp.size -= result; 170 packet_temp.size -= result;
176 packet_temp.data += result; 171 packet_temp.data += result;
177 172
178 if (!frame_decoded) 173 if (!frame_decoded)
179 continue; 174 continue;
180 175
181 // Determine the number of sample-frames we just decoded. Check overflow. 176 // Determine the number of sample-frames we just decoded. Check overflow.
182 int frames_read = av_frame->nb_samples; 177 int frames_read = av_frame->nb_samples;
183 if (frames_read < 0) { 178 if (frames_read < 0) {
184 continue_decoding = false; 179 continue_decoding = false;
185 break; 180 break;
186 } 181 }
187 182
188 #ifdef CHROMIUM_NO_AVFRAME_CHANNELS 183 #ifdef CHROMIUM_NO_AVFRAME_CHANNELS
189 int channels = av_get_channel_layout_nb_channels( 184 int channels =
190 av_frame->channel_layout); 185 av_get_channel_layout_nb_channels(av_frame->channel_layout);
191 #else 186 #else
192 int channels = av_frame->channels; 187 int channels = av_frame->channels;
193 #endif 188 #endif
194 if (av_frame->sample_rate != sample_rate_ || 189 if (av_frame->sample_rate != sample_rate_ || channels != channels_ ||
195 channels != channels_ ||
196 av_frame->format != av_sample_format_) { 190 av_frame->format != av_sample_format_) {
197 DLOG(ERROR) << "Unsupported midstream configuration change!" 191 DLOG(ERROR) << "Unsupported midstream configuration change!"
198 << " Sample Rate: " << av_frame->sample_rate << " vs " 192 << " Sample Rate: " << av_frame->sample_rate << " vs "
199 << sample_rate_ 193 << sample_rate_ << ", Channels: " << channels << " vs "
200 << ", Channels: " << channels << " vs " 194 << channels_ << ", Sample Format: " << av_frame->format
201 << channels_ 195 << " vs " << av_sample_format_;
202 << ", Sample Format: " << av_frame->format << " vs "
203 << av_sample_format_;
204 196
205 // This is an unrecoverable error, so bail out. 197 // This is an unrecoverable error, so bail out. We'll return
198 // whatever we've decoded up to this point.
206 continue_decoding = false; 199 continue_decoding = false;
207 break; 200 break;
208 } 201 }
209 202
210 // Truncate, if necessary, if the destination isn't big enough.
211 if (current_frame + frames_read > audio_bus->frames()) {
212 DLOG(ERROR) << "Truncating decoded data due to output size.";
213 frames_read = audio_bus->frames() - current_frame;
214 }
215
216 // Deinterleave each channel and convert to 32bit floating-point with 203 // Deinterleave each channel and convert to 32bit floating-point with
217 // nominal range -1.0 -> +1.0. If the output is already in float planar 204 // nominal range -1.0 -> +1.0. If the output is already in float planar
218 // format, just copy it into the AudioBus. 205 // format, just copy it into the AudioBus.
206 decoded_audio_packets->emplace_back(
207 AudioBus::Create(channels, frames_read));
208 AudioBus* audio_bus = decoded_audio_packets->back().get();
209
219 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { 210 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
DaleCurtis 2017/02/09 23:24:43 Note, if memory balloons too much here we can stor
220 float* decoded_audio_data = reinterpret_cast<float*>(av_frame->data[0]); 211 audio_bus->FromInterleaved<Float32SampleTypeTraits>(
221 int channels = audio_bus->channels(); 212 reinterpret_cast<float*>(av_frame->data[0]), frames_read);
222 for (int ch = 0; ch < channels; ++ch) {
223 float* bus_data = audio_bus->channel(ch) + current_frame;
224 for (int i = 0, offset = ch; i < frames_read;
225 ++i, offset += channels) {
226 bus_data[i] = decoded_audio_data[offset];
227 }
228 }
229 } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) { 213 } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) {
230 for (int ch = 0; ch < audio_bus->channels(); ++ch) { 214 for (int ch = 0; ch < audio_bus->channels(); ++ch) {
231 memcpy(audio_bus->channel(ch) + current_frame, 215 memcpy(audio_bus->channel(ch), av_frame->extended_data[ch],
232 av_frame->extended_data[ch], sizeof(float) * frames_read); 216 sizeof(float) * frames_read);
233 } 217 }
234 } else { 218 } else {
235 audio_bus->FromInterleavedPartial( 219 audio_bus->FromInterleaved(av_frame->data[0], frames_read,
236 av_frame->data[0], current_frame, frames_read, bytes_per_sample); 220 bytes_per_sample);
237 } 221 }
238 222
239 current_frame += frames_read; 223 total_frames += frames_read;
240 } while (packet_temp.size > 0); 224 } while (packet_temp.size > 0);
241 av_packet_unref(&packet); 225 av_packet_unref(&packet);
242 } 226 }
243 227
244 // Zero any remaining frames. 228 return total_frames;
245 audio_bus->ZeroFramesPartial(
246 current_frame, audio_bus->frames() - current_frame);
247
248 // Returns the actual number of sample-frames decoded.
249 // Ideally this represents the "true" exact length of the file.
250 return current_frame;
251 } 229 }
252 230
253 base::TimeDelta AudioFileReader::GetDuration() const { 231 base::TimeDelta AudioFileReader::GetDuration() const {
254 const AVRational av_time_base = {1, AV_TIME_BASE}; 232 const AVRational av_time_base = {1, AV_TIME_BASE};
255 233
256 DCHECK_NE(glue_->format_context()->duration, AV_NOPTS_VALUE); 234 DCHECK_NE(glue_->format_context()->duration, AV_NOPTS_VALUE);
257 base::CheckedNumeric<int64_t> estimated_duration_us = 235 base::CheckedNumeric<int64_t> estimated_duration_us =
258 glue_->format_context()->duration; 236 glue_->format_context()->duration;
259 237
260 if (audio_codec_ == kCodecAAC) { 238 if (audio_codec_ == kCodecAAC) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 glue_->format_context(), stream_index_, 288 glue_->format_context(), stream_index_,
311 ConvertToTimeBase(GetAVStreamForTesting()->time_base, seek_time), 289 ConvertToTimeBase(GetAVStreamForTesting()->time_base, seek_time),
312 AVSEEK_FLAG_BACKWARD) >= 0; 290 AVSEEK_FLAG_BACKWARD) >= 0;
313 } 291 }
314 292
315 const AVStream* AudioFileReader::GetAVStreamForTesting() const { 293 const AVStream* AudioFileReader::GetAVStreamForTesting() const {
316 return glue_->format_context()->streams[stream_index_]; 294 return glue_->format_context()->streams[stream_index_];
317 } 295 }
318 296
319 } // namespace media 297 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/audio_file_reader.h ('k') | media/filters/audio_file_reader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698