X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Faudio%2Faudio_decoder.cpp;h=b032c0ff1a53071c818349d246359f91a7fea864;hb=fa621844f986bb0fcfd49547188b4f7745289676;hp=bc8e2b76bdf0114df340788742f08103c187b8f3;hpb=7f97f2ce5fd102061355b24a99f720173f57042a;p=casparcg diff --git a/modules/ffmpeg/producer/audio/audio_decoder.cpp b/modules/ffmpeg/producer/audio/audio_decoder.cpp index bc8e2b76b..b032c0ff1 100644 --- a/modules/ffmpeg/producer/audio/audio_decoder.cpp +++ b/modules/ffmpeg/producer/audio/audio_decoder.cpp @@ -1,34 +1,45 @@ /* -* copyright (c) 2010 Sveriges Television AB +* Copyright (c) 2011 Sveriges Television AB * -* This file is part of CasparCG. +* This file is part of CasparCG (www.casparcg.com). * -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. +* CasparCG is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. * -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . +* CasparCG is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with CasparCG. If not, see . * +* Author: Robert Nagy, ronag89@gmail.com */ + #include "../../stdafx.h" #include "audio_decoder.h" +#include "audio_resampler.h" + +#include "../util/util.h" +#include "../../ffmpeg_error.h" + +#include + +#include + +#include + #if defined(_MSC_VER) #pragma warning (push) #pragma warning (disable : 4244) #endif extern "C" { - #define __STDC_CONSTANT_MACROS - #define __STDC_LIMIT_MACROS #include #include } @@ -36,86 +47,112 @@ extern "C" #pragma warning (pop) #endif -namespace caspar { - +namespace caspar { namespace ffmpeg { + struct audio_decoder::implementation : boost::noncopyable { - AVCodecContext& codec_context_; - const core::video_format_desc format_desc_; - std::vector current_chunk_; - std::vector> chunks_; - size_t frame_number_; + int index_; + const safe_ptr codec_context_; + const core::video_format_desc format_desc_; + + audio_resampler resampler_; + + std::vector> buffer1_; + + std::queue> packets_; + + const int64_t nb_frames_; + tbb::atomic file_frame_number_; public: - explicit implementation(AVCodecContext& codec_context, const core::video_format_desc& format_desc) - : codec_context_(codec_context) - , format_desc_(format_desc) - , frame_number_(0) - { - if(codec_context_.sample_rate != static_cast(format_desc_.audio_sample_rate) || - codec_context_.channels != static_cast(format_desc_.audio_channels)) - { - BOOST_THROW_EXCEPTION( - file_read_error() << - msg_info("Invalid sample-rate or number of channels.") << - arg_value_info(boost::lexical_cast(codec_context_.sample_rate)) << - arg_name_info("codec_context")); - } + explicit implementation(const safe_ptr& context, const core::video_format_desc& format_desc) + : format_desc_(format_desc) + , codec_context_(open_codec(*context, AVMEDIA_TYPE_AUDIO, index_)) + , resampler_(format_desc.audio_channels, codec_context_->channels, + format_desc.audio_sample_rate, codec_context_->sample_rate, + AV_SAMPLE_FMT_S32, codec_context_->sample_fmt) + , buffer1_(AVCODEC_MAX_AUDIO_FRAME_SIZE*2) + , nb_frames_(0)//context->streams[index_]->nb_frames) + { + file_frame_number_ = 0; } - - void push(const std::shared_ptr& audio_packet) + + void push(const std::shared_ptr& packet) { - if(!audio_packet) - { - avcodec_flush_buffers(&codec_context_); - current_chunk_.clear(); - frame_number_ = 0; + if(!packet) return; - } + + if(packet->stream_index == index_ || packet->data == nullptr) + packets_.push(make_safe_ptr(packet)); + } + + std::shared_ptr poll() + { + if(packets_.empty()) + return nullptr; - auto s = current_chunk_.size(); - current_chunk_.resize(s + 4*format_desc_.audio_sample_rate*2+FF_INPUT_BUFFER_PADDING_SIZE/2, 0); - - int written_bytes = (current_chunk_.size() - s)*2 - FF_INPUT_BUFFER_PADDING_SIZE; - const int errn = avcodec_decode_audio3(&codec_context_, ¤t_chunk_[s], &written_bytes, audio_packet.get()); - if(errn < 0) - { - BOOST_THROW_EXCEPTION( - invalid_operation() << - boost::errinfo_api_function("avcodec_decode_audio2") << - boost::errinfo_errno(AVUNERROR(errn))); + auto packet = packets_.front(); + + if(packet->data == nullptr) + { + packets_.pop(); + file_frame_number_ = static_cast(packet->pos); + avcodec_flush_buffers(codec_context_.get()); + return flush_audio(); } - current_chunk_.resize(s + written_bytes/2); + auto audio = decode(*packet); + + if(packet->size == 0) + packets_.pop(); + + return audio; + } + + std::shared_ptr decode(AVPacket& pkt) + { + buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2); + int written_bytes = buffer1_.size() - FF_INPUT_BUFFER_PADDING_SIZE; + + int ret = THROW_ON_ERROR2(avcodec_decode_audio3(codec_context_.get(), reinterpret_cast(buffer1_.data()), &written_bytes, &pkt), "[audio_decoder]"); + + // There might be several frames in one packet. + pkt.size -= ret; + pkt.data += ret; + + buffer1_.resize(written_bytes); - const auto last = current_chunk_.end() - current_chunk_.size() % format_desc_.audio_samples_per_frame; + buffer1_ = resampler_.resample(std::move(buffer1_)); - for(auto it = current_chunk_.begin(); it != last; it += format_desc_.audio_samples_per_frame) - chunks_.push_back(std::vector(it, it + format_desc_.audio_samples_per_frame)); + const auto n_samples = buffer1_.size() / av_get_bytes_per_sample(AV_SAMPLE_FMT_S32); + const auto samples = reinterpret_cast(buffer1_.data()); + + ++file_frame_number_; - current_chunk_.erase(current_chunk_.begin(), last); + return std::make_shared(samples, samples + n_samples); } - bool empty() const + bool ready() const { - return chunks_.empty(); + return packets_.size() > 10; } - std::vector front() + uint32_t nb_frames() const { - return chunks_.front(); + return 0;//std::max(nb_frames_, file_frame_number_); } - void pop() - { - ++frame_number_; - chunks_.pop_back(); + std::wstring print() const + { + return L"[audio-decoder] " + widen(codec_context_->codec->long_name); } }; -audio_decoder::audio_decoder(AVCodecContext& codec_context, const core::video_format_desc& format_desc) : impl_(new implementation(codec_context, format_desc)){} -void audio_decoder::push(const std::shared_ptr& audio_packet){impl_->push(std::move(audio_packet));} -bool audio_decoder::empty() const {return impl_->empty();} -std::vector audio_decoder::front() {return impl_->front();} -void audio_decoder::pop(){impl_->pop();} -size_t audio_decoder::frame_number() const{return impl_->frame_number_;} -} \ No newline at end of file +audio_decoder::audio_decoder(const safe_ptr& context, const core::video_format_desc& format_desc) : impl_(new implementation(context, format_desc)){} +void audio_decoder::push(const std::shared_ptr& packet){impl_->push(packet);} +bool audio_decoder::ready() const{return impl_->ready();} +std::shared_ptr audio_decoder::poll(){return impl_->poll();} +uint32_t audio_decoder::nb_frames() const{return impl_->nb_frames();} +uint32_t audio_decoder::file_frame_number() const{return impl_->file_frame_number_;} +std::wstring audio_decoder::print() const{return impl_->print();} + +}} \ No newline at end of file