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

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

Issue 2655783004: Decode entire in-memory file for WebAudio (Closed)
Patch Set: Clean up implementation. 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 10
(...skipping 15 matching lines...) Expand all
26 audio_codec_(kUnknownAudioCodec), 26 audio_codec_(kUnknownAudioCodec),
27 channels_(0), 27 channels_(0),
28 sample_rate_(0), 28 sample_rate_(0),
29 av_sample_format_(0) {} 29 av_sample_format_(0) {}
30 30
31 AudioFileReader::~AudioFileReader() { 31 AudioFileReader::~AudioFileReader() {
32 Close(); 32 Close();
33 } 33 }
34 34
35 bool AudioFileReader::Open() { 35 bool AudioFileReader::Open() {
36 if (!OpenDemuxer()) 36 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 } 37 }
45 38
46 bool AudioFileReader::OpenDemuxer() { 39 bool AudioFileReader::OpenDemuxer() {
47 glue_.reset(new FFmpegGlue(protocol_)); 40 glue_.reset(new FFmpegGlue(protocol_));
48 AVFormatContext* format_context = glue_->format_context(); 41 AVFormatContext* format_context = glue_->format_context();
49 42
50 // Open FFmpeg AVFormatContext. 43 // Open FFmpeg AVFormatContext.
51 if (!glue_->OpenContext()) { 44 if (!glue_->OpenContext()) {
52 DLOG(WARNING) << "AudioFileReader::Open() : error in avformat_open_input()"; 45 DLOG(WARNING) << "AudioFileReader::Open() : error in avformat_open_input()";
53 return false; 46 return false;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 } 113 }
121 114
122 // Store initial values to guard against midstream configuration changes. 115 // Store initial values to guard against midstream configuration changes.
123 channels_ = codec_context_->channels; 116 channels_ = codec_context_->channels;
124 audio_codec_ = CodecIDToAudioCodec(codec_context_->codec_id); 117 audio_codec_ = CodecIDToAudioCodec(codec_context_->codec_id);
125 sample_rate_ = codec_context_->sample_rate; 118 sample_rate_ = codec_context_->sample_rate;
126 av_sample_format_ = codec_context_->sample_fmt; 119 av_sample_format_ = codec_context_->sample_fmt;
127 return true; 120 return true;
128 } 121 }
129 122
123 bool AudioFileReader::HasKnownDuration() const {
124 return glue_->format_context()->duration != AV_NOPTS_VALUE;
125 }
126
130 void AudioFileReader::Close() { 127 void AudioFileReader::Close() {
131 codec_context_.reset(); 128 codec_context_.reset();
132 glue_.reset(); 129 glue_.reset();
133 } 130 }
134 131
135 int AudioFileReader::Read(AudioBus* audio_bus) { 132 int AudioFileReader::Read(AudioBus* audio_bus) {
136 DCHECK(glue_.get() && codec_context_) << 133 DCHECK(glue_.get() && codec_context_) <<
137 "AudioFileReader::Read() : reader is not opened!"; 134 "AudioFileReader::Read() : reader is not opened!";
138 135
139 DCHECK_EQ(audio_bus->channels(), channels()); 136 DCHECK_EQ(audio_bus->channels(), channels());
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 240
244 // Zero any remaining frames. 241 // Zero any remaining frames.
245 audio_bus->ZeroFramesPartial( 242 audio_bus->ZeroFramesPartial(
246 current_frame, audio_bus->frames() - current_frame); 243 current_frame, audio_bus->frames() - current_frame);
247 244
248 // Returns the actual number of sample-frames decoded. 245 // Returns the actual number of sample-frames decoded.
249 // Ideally this represents the "true" exact length of the file. 246 // Ideally this represents the "true" exact length of the file.
250 return current_frame; 247 return current_frame;
251 } 248 }
252 249
250 std::unique_ptr<AudioBus> AudioFileReader::StreamingRead() {
DaleCurtis 2017/01/25 22:42:25 Needs refactor, so we don't have two copies of the
251 DCHECK(glue_.get() && codec_context_)
252 << "AudioFileReader::StreamingRead() : reader is not opened!";
253 size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt);
254
255 // Holds decoded audio.
256 std::unique_ptr<AVFrame, ScopedPtrAVFreeFrame> av_frame(av_frame_alloc());
257
258 // Holds a vector of AudioBus' containing each decoded packet.
259 std::vector<std::unique_ptr<AudioBus>> decodedAudioPackets;
260
261 AVPacket packet;
262 int current_frame = 0;
263 size_t total_frames = 0;
264 bool continue_decoding = true;
265
266 while (continue_decoding && ReadPacket(&packet)) {
267 // Make a shallow copy of packet so we can slide packet.data as frames are
268 // decoded from the packet; otherwise av_packet_unref() will corrupt memory.
269 AVPacket packet_temp = packet;
270 do {
271 // Reset frame to default values.
272 av_frame_unref(av_frame.get());
273
274 int frame_decoded = 0;
275 int result = avcodec_decode_audio4(codec_context_.get(), av_frame.get(),
276 &frame_decoded, &packet_temp);
277
278 if (result < 0) {
279 DLOG(WARNING)
280 << "AudioFileReader::Read() : error in avcodec_decode_audio4() -"
281 << result;
282 break;
283 }
284
285 // Update packet size and data pointer in case we need to call the decoder
286 // with the remaining bytes from this packet.
287 packet_temp.size -= result;
288 packet_temp.data += result;
289
290 if (!frame_decoded)
291 continue;
292
293 // Determine the number of sample-frames we just decoded. Check overflow.
294 int frames_read = av_frame->nb_samples;
295 total_frames += frames_read;
296
297 if (frames_read < 0) {
298 continue_decoding = false;
299 break;
300 }
301
302 #ifdef CHROMIUM_NO_AVFRAME_CHANNELS
303 int channels =
304 av_get_channel_layout_nb_channels(av_frame->channel_layout);
305 #else
306 int channels = av_frame->channels;
307 #endif
308 if (av_frame->sample_rate != sample_rate_ || channels != channels_ ||
309 av_frame->format != av_sample_format_) {
310 DLOG(ERROR) << "Unsupported midstream configuration change!"
311 << " Sample Rate: " << av_frame->sample_rate << " vs "
312 << sample_rate_ << ", Channels: " << channels << " vs "
313 << channels_ << ", Sample Format: " << av_frame->format
314 << " vs " << av_sample_format_;
315
316 // This is an unrecoverable error, so bail out.
317 continue_decoding = false;
318 break;
319 }
320
321 // Deinterleave each channel and convert to 32bit floating-point with
322 // nominal range -1.0 -> +1.0. If the output is already in float planar
323 // format, just copy it into the AudioBus.
324 std::unique_ptr<AudioBus> audio_bus =
325 AudioBus::Create(channels, frames_read);
326
327 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
DaleCurtis 2017/01/25 22:42:25 I believe there's an AudioBus::FromInterleaved met
328 float* decoded_audio_data = reinterpret_cast<float*>(av_frame->data[0]);
329 int channels = audio_bus->channels();
330 for (int ch = 0; ch < channels; ++ch) {
331 float* bus_data = audio_bus->channel(ch) + current_frame;
332 for (int i = 0, offset = ch; i < frames_read;
333 ++i, offset += channels) {
334 bus_data[i] = decoded_audio_data[offset];
335 }
336 }
337 } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) {
338 for (int ch = 0; ch < audio_bus->channels(); ++ch) {
339 memcpy(audio_bus->channel(ch) + current_frame,
340 av_frame->extended_data[ch], sizeof(float) * frames_read);
341 }
342 } else {
343 audio_bus->FromInterleavedPartial(av_frame->data[0], current_frame,
344 frames_read, bytes_per_sample);
345 }
346
347 decodedAudioPackets.push_back(std::move(audio_bus));
348 // current_frame += frames_read;
349 } while (packet_temp.size > 0);
350 av_packet_unref(&packet);
351 }
352
353 // Concatenate all the decoded chunks into one big bus.
354 std::unique_ptr<AudioBus> outputBus =
355 AudioBus::Create(channels_, total_frames);
356
357 int dest_start_frame = 0;
358 for (size_t k = 0; k < decodedAudioPackets.size(); ++k) {
359 int frame_count = decodedAudioPackets[k]->frames();
360 decodedAudioPackets[k]->CopyPartialFramesTo(
361 0, frame_count, dest_start_frame, outputBus.get());
362 dest_start_frame += frame_count;
363 }
364
365 return outputBus;
366 }
367
253 base::TimeDelta AudioFileReader::GetDuration() const { 368 base::TimeDelta AudioFileReader::GetDuration() const {
254 const AVRational av_time_base = {1, AV_TIME_BASE}; 369 const AVRational av_time_base = {1, AV_TIME_BASE};
255 370
256 DCHECK_NE(glue_->format_context()->duration, AV_NOPTS_VALUE); 371 DCHECK_NE(glue_->format_context()->duration, AV_NOPTS_VALUE);
257 base::CheckedNumeric<int64_t> estimated_duration_us = 372 base::CheckedNumeric<int64_t> estimated_duration_us =
258 glue_->format_context()->duration; 373 glue_->format_context()->duration;
259 374
260 if (audio_codec_ == kCodecAAC) { 375 if (audio_codec_ == kCodecAAC) {
261 // For certain AAC-encoded files, FFMPEG's estimated frame count might not 376 // For certain AAC-encoded files, FFMPEG's estimated frame count might not
262 // be sufficient to capture the entire audio content that we want. This is 377 // be sufficient to capture the entire audio content that we want. This is
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 glue_->format_context(), stream_index_, 425 glue_->format_context(), stream_index_,
311 ConvertToTimeBase(GetAVStreamForTesting()->time_base, seek_time), 426 ConvertToTimeBase(GetAVStreamForTesting()->time_base, seek_time),
312 AVSEEK_FLAG_BACKWARD) >= 0; 427 AVSEEK_FLAG_BACKWARD) >= 0;
313 } 428 }
314 429
315 const AVStream* AudioFileReader::GetAVStreamForTesting() const { 430 const AVStream* AudioFileReader::GetAVStreamForTesting() const {
316 return glue_->format_context()->streams[stream_index_]; 431 return glue_->format_context()->streams[stream_index_];
317 } 432 }
318 433
319 } // namespace media 434 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698