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

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

Issue 2655783004: Decode entire in-memory file for WebAudio (Closed)
Patch Set: WIP: cleanup, add tests 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
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
134 #if 0
135 int AudioFileReader::Read(AudioBus* audio_bus) { 135 int AudioFileReader::Read(AudioBus* audio_bus) {
136 DCHECK(glue_.get() && codec_context_) << 136 DCHECK(glue_.get() && codec_context_) <<
137 "AudioFileReader::Read() : reader is not opened!"; 137 "AudioFileReader::Read() : reader is not opened!";
138 138
139 DCHECK_EQ(audio_bus->channels(), channels()); 139 DCHECK_EQ(audio_bus->channels(), channels());
140 if (audio_bus->channels() != channels()) 140 if (audio_bus->channels() != channels())
141 return 0; 141 return 0;
142 142
143 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt); 143 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt);
144 144
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 } 242 }
243 243
244 // Zero any remaining frames. 244 // Zero any remaining frames.
245 audio_bus->ZeroFramesPartial( 245 audio_bus->ZeroFramesPartial(
246 current_frame, audio_bus->frames() - current_frame); 246 current_frame, audio_bus->frames() - current_frame);
247 247
248 // Returns the actual number of sample-frames decoded. 248 // Returns the actual number of sample-frames decoded.
249 // Ideally this represents the "true" exact length of the file. 249 // Ideally this represents the "true" exact length of the file.
250 return current_frame; 250 return current_frame;
251 } 251 }
252 #endif
253
254 int AudioFileReader::Read(
255 std::vector<std::unique_ptr<AudioBus>>& decodedAudioPackets) {
256 DCHECK(glue_.get() && codec_context_)
257 << "AudioFileReader::Read() : reader is not opened!";
258 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt);
259
260 // Holds decoded audio.
261 std::unique_ptr<AVFrame, ScopedPtrAVFreeFrame> av_frame(av_frame_alloc());
262
263 AVPacket packet;
264 size_t total_frames = 0;
265 bool continue_decoding = true;
266
267 while (continue_decoding && ReadPacket(&packet)) {
268 // Make a shallow copy of packet so we can slide packet.data as frames are
269 // decoded from the packet; otherwise av_packet_unref() will corrupt memory.
270 AVPacket packet_temp = packet;
271 do {
272 // Reset frame to default values.
273 av_frame_unref(av_frame.get());
274
275 int frame_decoded = 0;
276 int result = avcodec_decode_audio4(codec_context_.get(), av_frame.get(),
277 &frame_decoded, &packet_temp);
278
279 if (result < 0) {
280 DLOG(WARNING)
281 << "AudioFileReader::Read() : error in avcodec_decode_audio4() -"
282 << result;
283 break;
Raymond Toy 2017/02/08 21:30:45 This continues the while loop. Is that what we re
DaleCurtis 2017/02/08 21:47:52 Up to you, but we traditionally ignore one-off aud
Raymond Toy 2017/02/08 22:08:35 Thanks. I'll add some comments to this effect so t
284 }
285
286 // Update packet size and data pointer in case we need to call the decoder
287 // with the remaining bytes from this packet.
288 packet_temp.size -= result;
289 packet_temp.data += result;
290
291 if (!frame_decoded)
292 continue;
293
294 // Determine the number of sample-frames we just decoded. Check overflow.
295 int frames_read = av_frame->nb_samples;
296 total_frames += frames_read;
297
298 if (frames_read < 0) {
299 continue_decoding = false;
300 break;
301 }
302
303 #ifdef CHROMIUM_NO_AVFRAME_CHANNELS
304 int channels =
305 av_get_channel_layout_nb_channels(av_frame->channel_layout);
306 #else
307 int channels = av_frame->channels;
308 #endif
309 if (av_frame->sample_rate != sample_rate_ || channels != channels_ ||
310 av_frame->format != av_sample_format_) {
311 DLOG(ERROR) << "Unsupported midstream configuration change!"
312 << " Sample Rate: " << av_frame->sample_rate << " vs "
313 << sample_rate_ << ", Channels: " << channels << " vs "
314 << channels_ << ", Sample Format: " << av_frame->format
315 << " vs " << av_sample_format_;
316
317 // This is an unrecoverable error, so bail out.
318 continue_decoding = false;
319 break;
Raymond Toy 2017/02/08 21:30:44 Is the expectation here that we'll just return wha
DaleCurtis 2017/02/08 21:47:52 Yes.
320 }
321
322 // Deinterleave each channel and convert to 32bit floating-point with
323 // nominal range -1.0 -> +1.0. If the output is already in float planar
324 // format, just copy it into the AudioBus.
325 std::unique_ptr<AudioBus> audio_bus =
326 AudioBus::Create(channels, frames_read);
327
328 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
329 audio_bus->FromInterleaved<Float32SampleTypeTraits>(
330 reinterpret_cast<float*>(av_frame->data[0]), frames_read);
331 } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) {
332 for (int ch = 0; ch < audio_bus->channels(); ++ch) {
333 memcpy(audio_bus->channel(ch), av_frame->extended_data[ch],
334 sizeof(float) * frames_read);
335 }
336 } else {
337 audio_bus->FromInterleaved(av_frame->data[0], frames_read,
338 bytes_per_sample);
339 }
340
341 decodedAudioPackets.push_back(std::move(audio_bus));
342 } while (packet_temp.size > 0);
343 av_packet_unref(&packet);
344 }
345
346 return total_frames;
347 }
252 348
253 base::TimeDelta AudioFileReader::GetDuration() const { 349 base::TimeDelta AudioFileReader::GetDuration() const {
254 const AVRational av_time_base = {1, AV_TIME_BASE}; 350 const AVRational av_time_base = {1, AV_TIME_BASE};
255 351
256 DCHECK_NE(glue_->format_context()->duration, AV_NOPTS_VALUE); 352 DCHECK_NE(glue_->format_context()->duration, AV_NOPTS_VALUE);
257 base::CheckedNumeric<int64_t> estimated_duration_us = 353 base::CheckedNumeric<int64_t> estimated_duration_us =
258 glue_->format_context()->duration; 354 glue_->format_context()->duration;
259 355
260 if (audio_codec_ == kCodecAAC) { 356 if (audio_codec_ == kCodecAAC) {
261 // For certain AAC-encoded files, FFMPEG's estimated frame count might not 357 // For certain AAC-encoded files, FFMPEG's estimated frame count might not
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 glue_->format_context(), stream_index_, 406 glue_->format_context(), stream_index_,
311 ConvertToTimeBase(GetAVStreamForTesting()->time_base, seek_time), 407 ConvertToTimeBase(GetAVStreamForTesting()->time_base, seek_time),
312 AVSEEK_FLAG_BACKWARD) >= 0; 408 AVSEEK_FLAG_BACKWARD) >= 0;
313 } 409 }
314 410
315 const AVStream* AudioFileReader::GetAVStreamForTesting() const { 411 const AVStream* AudioFileReader::GetAVStreamForTesting() const {
316 return glue_->format_context()->streams[stream_index_]; 412 return glue_->format_context()->streams[stream_index_];
317 } 413 }
318 414
319 } // namespace media 415 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698