X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Faudio%2Faudio_decoder.cpp;h=cd5b377926e30c4ac7ccc71865ce1eb78047a8fc;hb=726897adbf881d3b75f171fff24f2b917ba5f05a;hp=e92a7c18134859e05370fc65b13e6fb18a5d720e;hpb=cd1a44a41dd64c05de067ba728c285f001b66bf3;p=casparcg diff --git a/modules/ffmpeg/producer/audio/audio_decoder.cpp b/modules/ffmpeg/producer/audio/audio_decoder.cpp index e92a7c181..cd5b37792 100644 --- a/modules/ffmpeg/producer/audio/audio_decoder.cpp +++ b/modules/ffmpeg/producer/audio/audio_decoder.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2011 Sveriges Television AB +* Copyright 2013 Sveriges Television AB http://casparcg.com/ * * This file is part of CasparCG (www.casparcg.com). * @@ -19,18 +19,16 @@ * Author: Robert Nagy, ronag89@gmail.com */ -#include "../../StdAfx.h" +#include "../../stdafx.h" #include "audio_decoder.h" #include "../util/util.h" -#include "../input/input.h" #include "../../ffmpeg_error.h" #include -#include +#include -#include #include #include @@ -51,128 +49,119 @@ extern "C" namespace caspar { namespace ffmpeg { -uint64_t get_ffmpeg_channel_layout(AVCodecContext* dec) -{ - auto layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels); - return layout; -} - -struct audio_decoder::impl : boost::noncopyable +struct audio_decoder::implementation : boost::noncopyable { - core::monitor::subject monitor_subject_; - input& input_; - int index_; - int actual_index_; - const core::video_format_desc format_desc_; - const spl::shared_ptr codec_context_ = open_codec(input_.context(), AVMEDIA_TYPE_AUDIO, actual_index_, false); - - std::shared_ptr swr_ { - swr_alloc_set_opts( - nullptr, - create_channel_layout_bitmask(codec_context_->channels),//get_ffmpeg_channel_layout(codec_context_.get()), - AV_SAMPLE_FMT_S32, - format_desc_.audio_sample_rate, - create_channel_layout_bitmask(codec_context_->channels),//get_ffmpeg_channel_layout(codec_context_.get()), - codec_context_->sample_fmt, - codec_context_->sample_rate, - 0, - nullptr), - [](SwrContext* p){swr_free(&p); } - }; - - cache_aligned_vector buffer_; - - std::shared_ptr current_packet_; + int index_ = -1; + const spl::shared_ptr codec_context_; + const int out_samplerate_; + cache_aligned_vector buffer_; + + std::queue> packets_; + + std::shared_ptr swr_ { + swr_alloc_set_opts( + nullptr, + codec_context_->channel_layout + ? codec_context_->channel_layout + : av_get_default_channel_layout(codec_context_->channels), + AV_SAMPLE_FMT_S32, + out_samplerate_, + codec_context_->channel_layout + ? codec_context_->channel_layout + : av_get_default_channel_layout(codec_context_->channels), + codec_context_->sample_fmt, + codec_context_->sample_rate, + 0, + nullptr), + [](SwrContext* p) + { + swr_free(&p); + } + }; + public: - explicit impl( - input& in, - const core::video_format_desc& format_desc, - int audio_stream_index) - : input_(in) - , index_(audio_stream_index) - , actual_index_(input_.get_actual_audio_stream_index(index_)) - , format_desc_(format_desc) - , buffer_(480000 * 4) - { + explicit implementation(const spl::shared_ptr& context, int out_samplerate) + : codec_context_(open_codec(*context, AVMEDIA_TYPE_AUDIO, index_, false)) + , out_samplerate_(out_samplerate) + , buffer_(10 * out_samplerate_ * codec_context_->channels) // 10 seconds of audio + { if(!swr_) - CASPAR_THROW_EXCEPTION(bad_alloc()); - + BOOST_THROW_EXCEPTION(bad_alloc()); + THROW_ON_ERROR2(swr_init(swr_.get()), "[audio_decoder]"); + + codec_context_->refcounted_frames = 1; } - - std::shared_ptr poll() - { - if(!current_packet_ && !input_.try_pop_audio(current_packet_, index_)) + + void push(const std::shared_ptr& packet) + { + if(!packet) + return; + + if(packet->stream_index == index_ || packet->data == nullptr) + packets_.push(spl::make_shared_ptr(packet)); + } + + std::shared_ptr poll() + { + if(packets_.empty()) return nullptr; - - std::shared_ptr audio; + + auto packet = packets_.front(); - if (!current_packet_->data) + if(packet->data == nullptr) { - if(codec_context_->codec->capabilities & CODEC_CAP_DELAY) - audio = decode(*current_packet_); - - if (!audio) - { - avcodec_flush_buffers(codec_context_.get()); - current_packet_.reset(); - audio = flush(); - } + packets_.pop(); + avcodec_flush_buffers(codec_context_.get()); + return flush_audio(); } - else - { - audio = decode(*current_packet_); - - if(current_packet_->size == 0) - current_packet_.reset(); - } - + + auto audio = decode(*packet); + + if(packet->size == 0) + packets_.pop(); + return audio; } - std::shared_ptr decode(AVPacket& pkt) - { - auto frame = create_frame(); - + std::shared_ptr decode(AVPacket& pkt) + { + auto decoded_frame = create_frame(); + int got_frame = 0; - auto len = THROW_ON_ERROR2(avcodec_decode_audio4(codec_context_.get(), frame.get(), &got_frame, &pkt), "[audio_decoder]"); - - if(len == 0) + auto len = THROW_ON_ERROR2(avcodec_decode_audio4(codec_context_.get(), decoded_frame.get(), &got_frame, &pkt), "[audio_decoder]"); + + if (len == 0) { pkt.size = 0; return nullptr; } - pkt.data += len; - pkt.size -= len; + pkt.data += len; + pkt.size -= len; - if(!got_frame) + if (!got_frame) return nullptr; - - const uint8_t **in = const_cast(frame->extended_data); - uint8_t* out[] = {buffer_.data()}; - auto channel_samples = swr_convert(swr_.get(), - out, static_cast(buffer_.size()) / codec_context_->channels / av_get_bytes_per_sample(AV_SAMPLE_FMT_S32), - in, frame->nb_samples); + const uint8_t **in = const_cast(decoded_frame->extended_data); + uint8_t* out[] = { reinterpret_cast(buffer_.data()) }; - frame->data[0] = buffer_.data(); - frame->linesize[0] = channel_samples * codec_context_->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S32); - frame->nb_samples = channel_samples; - frame->format = AV_SAMPLE_FMT_S32; + const auto channel_samples = swr_convert( + swr_.get(), + out, + static_cast(buffer_.size()) / codec_context_->channels, + in, + decoded_frame->nb_samples); - monitor_subject_ << core::monitor::message("/file/audio/sample-rate") % codec_context_->sample_rate - << core::monitor::message("/file/audio/channels") % codec_context_->channels - << core::monitor::message("/file/audio/format") % u8(av_get_sample_fmt_name(codec_context_->sample_fmt)) - << core::monitor::message("/file/audio/codec") % u8(codec_context_->codec->long_name); - - return frame; + return std::make_shared( + buffer_.begin(), + buffer_.begin() + channel_samples * decoded_frame->channels); } - - uint32_t nb_frames() const + + bool ready() const { - return 0; + return packets_.size() > 10; } std::wstring print() const @@ -181,12 +170,12 @@ public: } }; -audio_decoder::audio_decoder(input& input, const core::video_format_desc& format_desc, int audio_stream_index) : impl_(new impl(input, format_desc, audio_stream_index)){} -audio_decoder::audio_decoder(audio_decoder&& other) : impl_(std::move(other.impl_)){} -audio_decoder& audio_decoder::operator=(audio_decoder&& other){impl_ = std::move(other.impl_); return *this;} -std::shared_ptr audio_decoder::operator()(){return impl_->poll();} -uint32_t audio_decoder::nb_frames() const{return impl_->nb_frames();} +audio_decoder::audio_decoder(const spl::shared_ptr& context, int out_samplerate) : impl_(new implementation(context, out_samplerate)){} +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(); } +int audio_decoder::num_channels() const { return impl_->codec_context_->channels; } +uint64_t audio_decoder::ffmpeg_channel_layout() const { return impl_->codec_context_->channel_layout; } std::wstring audio_decoder::print() const{return impl_->print();} -core::monitor::subject& audio_decoder::monitor_output() { return impl_->monitor_subject_;} }}