Chromium Code Reviews| Index: media/filters/audio_file_reader.cc |
| diff --git a/media/filters/audio_file_reader.cc b/media/filters/audio_file_reader.cc |
| index 582ca9cdc7fbbde62cbefc4bea56a84563da4ebc..315164e0c4a5bd1c706881a69f637a53c7c2fd8d 100644 |
| --- a/media/filters/audio_file_reader.cc |
| +++ b/media/filters/audio_file_reader.cc |
| @@ -33,14 +33,7 @@ AudioFileReader::~AudioFileReader() { |
| } |
| bool AudioFileReader::Open() { |
| - if (!OpenDemuxer()) |
| - return false; |
| - if (!OpenDecoder()) |
| - return false; |
| - |
| - // If the duration is unknown, fail out; this API can not work with streams of |
| - // unknown duration currently. |
| - return glue_->format_context()->duration != AV_NOPTS_VALUE; |
| + return OpenDemuxer() && OpenDecoder(); |
| } |
| bool AudioFileReader::OpenDemuxer() { |
| @@ -127,6 +120,10 @@ bool AudioFileReader::OpenDecoder() { |
| return true; |
| } |
| +bool AudioFileReader::HasKnownDuration() const { |
| + return glue_->format_context()->duration != AV_NOPTS_VALUE; |
| +} |
| + |
| void AudioFileReader::Close() { |
| codec_context_.reset(); |
| glue_.reset(); |
| @@ -250,6 +247,124 @@ int AudioFileReader::Read(AudioBus* audio_bus) { |
| return current_frame; |
| } |
| +std::unique_ptr<AudioBus> AudioFileReader::StreamingRead() { |
|
DaleCurtis
2017/01/25 22:42:25
Needs refactor, so we don't have two copies of the
|
| + DCHECK(glue_.get() && codec_context_) |
| + << "AudioFileReader::StreamingRead() : reader is not opened!"; |
| + size_t bytes_per_sample = av_get_bytes_per_sample(codec_context_->sample_fmt); |
| + |
| + // Holds decoded audio. |
| + std::unique_ptr<AVFrame, ScopedPtrAVFreeFrame> av_frame(av_frame_alloc()); |
| + |
| + // Holds a vector of AudioBus' containing each decoded packet. |
| + std::vector<std::unique_ptr<AudioBus>> decodedAudioPackets; |
| + |
| + AVPacket packet; |
| + int current_frame = 0; |
| + size_t total_frames = 0; |
| + bool continue_decoding = true; |
| + |
| + while (continue_decoding && ReadPacket(&packet)) { |
| + // Make a shallow copy of packet so we can slide packet.data as frames are |
| + // decoded from the packet; otherwise av_packet_unref() will corrupt memory. |
| + AVPacket packet_temp = packet; |
| + do { |
| + // Reset frame to default values. |
| + av_frame_unref(av_frame.get()); |
| + |
| + int frame_decoded = 0; |
| + int result = avcodec_decode_audio4(codec_context_.get(), av_frame.get(), |
| + &frame_decoded, &packet_temp); |
| + |
| + if (result < 0) { |
| + DLOG(WARNING) |
| + << "AudioFileReader::Read() : error in avcodec_decode_audio4() -" |
| + << result; |
| + break; |
| + } |
| + |
| + // Update packet size and data pointer in case we need to call the decoder |
| + // with the remaining bytes from this packet. |
| + packet_temp.size -= result; |
| + packet_temp.data += result; |
| + |
| + if (!frame_decoded) |
| + continue; |
| + |
| + // Determine the number of sample-frames we just decoded. Check overflow. |
| + int frames_read = av_frame->nb_samples; |
| + total_frames += frames_read; |
| + |
| + if (frames_read < 0) { |
| + continue_decoding = false; |
| + break; |
| + } |
| + |
| +#ifdef CHROMIUM_NO_AVFRAME_CHANNELS |
| + int channels = |
| + av_get_channel_layout_nb_channels(av_frame->channel_layout); |
| +#else |
| + int channels = av_frame->channels; |
| +#endif |
| + if (av_frame->sample_rate != sample_rate_ || channels != channels_ || |
| + av_frame->format != av_sample_format_) { |
| + DLOG(ERROR) << "Unsupported midstream configuration change!" |
| + << " Sample Rate: " << av_frame->sample_rate << " vs " |
| + << sample_rate_ << ", Channels: " << channels << " vs " |
| + << channels_ << ", Sample Format: " << av_frame->format |
| + << " vs " << av_sample_format_; |
| + |
| + // This is an unrecoverable error, so bail out. |
| + continue_decoding = false; |
| + break; |
| + } |
| + |
| + // Deinterleave each channel and convert to 32bit floating-point with |
| + // nominal range -1.0 -> +1.0. If the output is already in float planar |
| + // format, just copy it into the AudioBus. |
| + std::unique_ptr<AudioBus> audio_bus = |
| + AudioBus::Create(channels, frames_read); |
| + |
| + if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) { |
|
DaleCurtis
2017/01/25 22:42:25
I believe there's an AudioBus::FromInterleaved met
|
| + float* decoded_audio_data = reinterpret_cast<float*>(av_frame->data[0]); |
| + int channels = audio_bus->channels(); |
| + for (int ch = 0; ch < channels; ++ch) { |
| + float* bus_data = audio_bus->channel(ch) + current_frame; |
| + for (int i = 0, offset = ch; i < frames_read; |
| + ++i, offset += channels) { |
| + bus_data[i] = decoded_audio_data[offset]; |
| + } |
| + } |
| + } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) { |
| + for (int ch = 0; ch < audio_bus->channels(); ++ch) { |
| + memcpy(audio_bus->channel(ch) + current_frame, |
| + av_frame->extended_data[ch], sizeof(float) * frames_read); |
| + } |
| + } else { |
| + audio_bus->FromInterleavedPartial(av_frame->data[0], current_frame, |
| + frames_read, bytes_per_sample); |
| + } |
| + |
| + decodedAudioPackets.push_back(std::move(audio_bus)); |
| + // current_frame += frames_read; |
| + } while (packet_temp.size > 0); |
| + av_packet_unref(&packet); |
| + } |
| + |
| + // Concatenate all the decoded chunks into one big bus. |
| + std::unique_ptr<AudioBus> outputBus = |
| + AudioBus::Create(channels_, total_frames); |
| + |
| + int dest_start_frame = 0; |
| + for (size_t k = 0; k < decodedAudioPackets.size(); ++k) { |
| + int frame_count = decodedAudioPackets[k]->frames(); |
| + decodedAudioPackets[k]->CopyPartialFramesTo( |
| + 0, frame_count, dest_start_frame, outputBus.get()); |
| + dest_start_frame += frame_count; |
| + } |
| + |
| + return outputBus; |
| +} |
| + |
| base::TimeDelta AudioFileReader::GetDuration() const { |
| const AVRational av_time_base = {1, AV_TIME_BASE}; |