2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG.
\r
6 * CasparCG is free software: you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation, either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * CasparCG is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
\r
20 #include "../../stdafx.h"
\r
22 #include "audio_decoder.h"
\r
24 #include <tbb/task_group.h>
\r
26 #if defined(_MSC_VER)
\r
27 #pragma warning (push)
\r
28 #pragma warning (disable : 4244)
\r
32 #define __STDC_CONSTANT_MACROS
\r
33 #define __STDC_LIMIT_MACROS
\r
34 #include <libavformat/avformat.h>
\r
35 #include <libavcodec/avcodec.h>
\r
37 #if defined(_MSC_VER)
\r
38 #pragma warning (pop)
\r
43 struct audio_decoder::implementation : boost::noncopyable
\r
45 std::shared_ptr<AVCodecContext> codec_context_;
\r
46 const core::video_format_desc format_desc_;
\r
48 std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> buffer_; // avcodec_decode_audio3 needs 4 byte alignment
\r
49 std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_samples_; // avcodec_decode_audio3 needs 4 byte alignment
\r
50 std::queue<std::shared_ptr<AVPacket>> packets_;
\r
52 explicit implementation(AVStream* stream, const core::video_format_desc& format_desc)
\r
53 : format_desc_(format_desc)
\r
55 if(!stream || !stream->codec)
\r
58 auto codec = avcodec_find_decoder(stream->codec->codec_id);
\r
62 int errn = avcodec_open(stream->codec, codec);
\r
66 index_ = stream->index;
\r
67 codec_context_.reset(stream->codec, avcodec_close);
\r
69 if(codec_context_ &&
\r
70 (codec_context_->sample_rate != static_cast<int>(format_desc_.audio_sample_rate) ||
\r
71 codec_context_->channels != static_cast<int>(format_desc_.audio_channels)))
\r
73 BOOST_THROW_EXCEPTION(
\r
74 file_read_error() <<
\r
75 msg_info("Invalid sample-rate or number of channels.") <<
\r
76 arg_value_info(boost::lexical_cast<std::string>(codec_context_->sample_rate)) <<
\r
77 arg_name_info("codec_context"));
\r
81 void push(const std::shared_ptr<AVPacket>& packet)
\r
86 if(packet && packet->stream_index != index_)
\r
89 packets_.push(packet);
\r
92 std::vector<std::vector<int16_t>> poll()
\r
94 std::vector<std::vector<int16_t>> result;
\r
97 result.push_back(std::vector<int16_t>(format_desc_.audio_samples_per_frame, 0));
\r
98 else if(!packets_.empty())
\r
100 decode(packets_.front());
\r
103 while(audio_samples_.size() > format_desc_.audio_samples_per_frame)
\r
105 const auto begin = audio_samples_.begin();
\r
106 const auto end = audio_samples_.begin() + format_desc_.audio_samples_per_frame;
\r
108 result.push_back(std::vector<int16_t>(begin, end));
\r
109 audio_samples_.erase(begin, end);
\r
116 void decode(const std::shared_ptr<AVPacket>& packet)
\r
120 auto truncate = audio_samples_.size() % format_desc_.audio_samples_per_frame;
\r
123 audio_samples_.resize(audio_samples_.size() - truncate);
\r
124 CASPAR_LOG(info) << L"Truncating " << truncate << L" audio-samples.";
\r
126 avcodec_flush_buffers(codec_context_.get());
\r
130 buffer_.resize(4*format_desc_.audio_sample_rate*2+FF_INPUT_BUFFER_PADDING_SIZE/2, 0);
\r
132 int written_bytes = buffer_.size() - FF_INPUT_BUFFER_PADDING_SIZE/2;
\r
133 const int errn = avcodec_decode_audio3(codec_context_.get(), buffer_.data(), &written_bytes, packet.get());
\r
136 BOOST_THROW_EXCEPTION(
\r
137 invalid_operation() <<
\r
138 boost::errinfo_api_function("avcodec_decode_audio2") <<
\r
139 boost::errinfo_errno(AVUNERROR(errn)));
\r
142 buffer_.resize(written_bytes/2);
\r
143 audio_samples_.insert(audio_samples_.end(), buffer_.begin(), buffer_.end());
\r
150 return !codec_context_ || !packets_.empty();
\r
154 audio_decoder::audio_decoder(AVStream* stream, const core::video_format_desc& format_desc) : impl_(new implementation(stream, format_desc)){}
\r
155 void audio_decoder::push(const std::shared_ptr<AVPacket>& packet){impl_->push(packet);}
\r
156 bool audio_decoder::ready() const{return impl_->ready();}
\r
157 std::vector<std::vector<int16_t>> audio_decoder::poll(){return impl_->poll();}
\r