X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Faudio%2Faudio_decoder.cpp;h=dd0a9e58675e55e488a5775fa716183d137fbed0;hb=6016fd682b267d2886babd51b1faa9cdd1812d54;hp=3cd99a38f685aac411bf01c348a98c484f15b1f1;hpb=56c7f363b3a444da24bd1c6a1b877891e4f774a4;p=casparcg diff --git a/modules/ffmpeg/producer/audio/audio_decoder.cpp b/modules/ffmpeg/producer/audio/audio_decoder.cpp index 3cd99a38f..dd0a9e586 100644 --- a/modules/ffmpeg/producer/audio/audio_decoder.cpp +++ b/modules/ffmpeg/producer/audio/audio_decoder.cpp @@ -21,7 +21,15 @@ #include "audio_decoder.h" -#include +#include "audio_resampler.h" + +#include "../../ffmpeg_error.h" + +#include + +#include + +#include #if defined(_MSC_VER) #pragma warning (push) @@ -29,8 +37,6 @@ #endif extern "C" { - #define __STDC_CONSTANT_MACROS - #define __STDC_LIMIT_MACROS #include #include } @@ -45,109 +51,95 @@ struct audio_decoder::implementation : boost::noncopyable std::shared_ptr codec_context_; const core::video_format_desc format_desc_; int index_; - std::shared_ptr resampler_; + std::unique_ptr resampler_; std::vector> buffer1_; - std::vector> buffer2_; - std::vector> audio_samples_; + std::queue> packets_; int64_t nb_frames_; public: - explicit implementation(const std::shared_ptr& context, const core::video_format_desc& format_desc) + explicit implementation(const safe_ptr& context, const core::video_format_desc& format_desc) : format_desc_(format_desc) , nb_frames_(0) - { - AVCodec* dec; - index_ = av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0); - - if(index_ < 0) - return; - - int errn = avcodec_open(context->streams[index_]->codec, dec); - if(errn < 0) - return; - - codec_context_.reset(context->streams[index_]->codec, avcodec_close); + { + try + { + AVCodec* dec; + index_ = THROW_ON_ERROR2(av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0), "[audio_decoder]"); - //nb_frames_ = context->streams[index_]->nb_frames; - //if(nb_frames_ == 0) - // nb_frames_ = context->streams[index_]->duration * context->streams[index_]->time_base.den; + THROW_ON_ERROR2(avcodec_open(context->streams[index_]->codec, dec), "[audio_decoder]"); + + codec_context_.reset(context->streams[index_]->codec, avcodec_close); - if(codec_context_ && - (codec_context_->sample_rate != static_cast(format_desc_.audio_sample_rate) || - codec_context_->channels != static_cast(format_desc_.audio_channels)) || - codec_context_->sample_fmt != AV_SAMPLE_FMT_S16) - { - auto resampler = av_audio_resample_init(format_desc_.audio_channels, codec_context_->channels, - format_desc_.audio_sample_rate, codec_context_->sample_rate, - AV_SAMPLE_FMT_S16, codec_context_->sample_fmt, - 16, 10, 0, 0.8); + buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2); - CASPAR_LOG(warning) << L" Invalid audio format. Resampling."; + resampler_.reset(new audio_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)); + } + catch(...) + { + index_ = THROW_ON_ERROR2(av_find_best_stream(context.get(), AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0), "[audio_decoder]"); - if(resampler) - resampler_.reset(resampler, audio_resample_close); - else - codec_context_ = nullptr; - } + CASPAR_LOG_CURRENT_EXCEPTION(); + CASPAR_LOG(warning) << "[audio_decoder] Failed to open audio-stream. Running without audio."; + } } void push(const std::shared_ptr& packet) { - if(!codec_context_) - return; - if(packet && packet->stream_index != index_) return; packets_.push(packet); } - std::vector>> poll() + std::vector>> poll() { - std::vector>> result; + std::vector>> result; + + if(packets_.empty()) + return result; if(!codec_context_) - result.push_back(std::make_shared>(format_desc_.audio_samples_per_frame, 0)); - else if(!packets_.empty()) - { - auto packet = std::move(packets_.front()); - packets_.pop(); + return empty_poll(); + + auto packet = packets_.front(); - if(packet) - { - AVPacket pkt; - av_init_packet(&pkt); - pkt.data = packet->data; - pkt.size = packet->size; - - for(int n = 0; n < 64 && pkt.size > 0; ++n) - result.push_back(decode(pkt)); - } - else - { - avcodec_flush_buffers(codec_context_.get()); - result.push_back(nullptr); - } + if(packet) + { + result.push_back(decode(*packet)); + if(packet->size == 0) + packets_.pop(); } + else + { + avcodec_flush_buffers(codec_context_.get()); + result.push_back(nullptr); + packets_.pop(); + } return result; } - std::shared_ptr> decode(AVPacket& pkt) + std::vector>> empty_poll() + { + auto packet = packets_.front(); + packets_.pop(); + + if(!packet) + return boost::assign::list_of(nullptr); + + return boost::assign::list_of(std::make_shared>(format_desc_.audio_samples_per_frame, 0)); + } + + std::shared_ptr> decode(AVPacket& pkt) { - buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2, 0); + buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2); int written_bytes = buffer1_.size() - FF_INPUT_BUFFER_PADDING_SIZE; - - const int ret = avcodec_decode_audio3(codec_context_.get(), reinterpret_cast(buffer1_.data()), &written_bytes, &pkt); - if(ret < 0) - { - BOOST_THROW_EXCEPTION( - invalid_operation() << - boost::errinfo_api_function("avcodec_decode_audio2") << - boost::errinfo_errno(AVUNERROR(ret))); - } + + 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; @@ -155,32 +147,23 @@ public: buffer1_.resize(written_bytes); - if(resampler_) - { - buffer2_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2, 0); - auto ret = audio_resample(resampler_.get(), - reinterpret_cast(buffer2_.data()), - reinterpret_cast(buffer1_.data()), - buffer1_.size() / (av_get_bytes_per_sample(codec_context_->sample_fmt) * codec_context_->channels)); - buffer2_.resize(ret * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * format_desc_.audio_channels); - std::swap(buffer1_, buffer2_); - } - - const auto n_samples = buffer1_.size() / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); - const auto samples = reinterpret_cast(buffer1_.data()); + buffer1_ = resampler_->resample(std::move(buffer1_)); + + const auto n_samples = buffer1_.size() / av_get_bytes_per_sample(AV_SAMPLE_FMT_S32); + const auto samples = reinterpret_cast(buffer1_.data()); - return std::make_shared>(samples, samples + n_samples); + return std::make_shared>(samples, samples + n_samples); } bool ready() const { - return !codec_context_ || !packets_.empty(); + return !packets_.empty(); } }; -audio_decoder::audio_decoder(const std::shared_ptr& context, const core::video_format_desc& format_desc) : impl_(new implementation(context, format_desc)){} +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::vector>> audio_decoder::poll(){return impl_->poll();} +std::vector>> audio_decoder::poll(){return impl_->poll();} int64_t audio_decoder::nb_frames() const{return impl_->nb_frames_;} } \ No newline at end of file