2 * Copyright 2013 Sveriges Television AB http://casparcg.com/
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Robert Nagy, ronag89@gmail.com
22 #include "../../StdAfx.h"
24 #include "audio_filter.h"
26 #include "../../ffmpeg_error.h"
27 #include "../../ffmpeg.h"
28 #include "../util/util.h"
30 #include <common/assert.h>
31 #include <common/except.h>
33 #include <boost/algorithm/string.hpp>
34 #include <boost/thread.hpp>
35 #include <boost/format.hpp>
36 #include <boost/rational.hpp>
44 #pragma warning (push)
45 #pragma warning (disable : 4244)
49 #include <libavutil/avutil.h>
50 #include <libavutil/imgutils.h>
51 #include <libavutil/opt.h>
52 #include <libavfilter/avfilter.h>
53 #include <libavfilter/avcodec.h>
54 #include <libavfilter/buffersink.h>
55 #include <libavfilter/buffersrc.h>
61 namespace caspar { namespace ffmpeg {
63 std::string create_sourcefilter_str(const audio_input_pad& input_pad, std::string name)
65 const auto asrc_options = (boost::format("abuffer=time_base=%1%/%2%:sample_rate=%3%:sample_fmt=%4%:channel_layout=0x%|5$x| [%6%]")
66 % input_pad.time_base.numerator() % input_pad.time_base.denominator()
67 % input_pad.sample_rate
68 % av_get_sample_fmt_name(input_pad.sample_fmt)
69 % input_pad.audio_channel_layout
75 std::string create_sinkfilter_str(const audio_output_pad& output_pad, std::string name)
77 const auto asink_options = (boost::format("[%1%] abuffersink") % name).str();
82 struct audio_filter::implementation
84 std::string filtergraph_;
86 std::shared_ptr<AVFilterGraph> audio_graph_;
87 std::vector<AVFilterContext*> audio_graph_inputs_;
88 std::vector<AVFilterContext*> audio_graph_outputs_;
90 std::vector<audio_input_pad> input_pads_;
93 std::vector<audio_input_pad> input_pads,
94 std::vector<audio_output_pad> output_pads,
95 const std::string& filtergraph)
96 : filtergraph_(boost::to_lower_copy(filtergraph))
97 , input_pads_(std::move(input_pads))
99 if (input_pads_.empty())
100 CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("input_pads cannot be empty"));
102 if (output_pads.empty())
103 CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("output_pads cannot be empty"));
106 avfilter_graph_alloc(),
109 avfilter_graph_free(&p);
112 std::vector<std::string> complete_filter_graph;
116 for (auto& input_pad : input_pads_)
117 complete_filter_graph.push_back(create_sourcefilter_str(input_pad, "a:" + boost::lexical_cast<std::string>(i++)));
120 if (filtergraph_.empty())
121 complete_filter_graph.push_back("[a:0] anull [aout:0]");
123 complete_filter_graph.push_back(filtergraph_);
127 for (auto& output_pad : output_pads)
129 complete_filter_graph.push_back(create_sinkfilter_str(output_pad, "aout:" + boost::lexical_cast<std::string>(i++)));
131 output_pad.sample_fmts.push_back(AVSampleFormat::AV_SAMPLE_FMT_NONE);
132 output_pad.audio_channel_layouts.push_back(0);
133 output_pad.sample_rates.push_back(-1);
137 configure_filtergraph(
139 boost::join(complete_filter_graph, ";"),
141 audio_graph_outputs_,
144 if (is_logging_quiet_for_thread())
146 << u16(std::string("\n")
147 + avfilter_graph_dump(
152 << u16(std::string("\n")
153 + avfilter_graph_dump(
158 void configure_filtergraph(
159 AVFilterGraph& graph,
160 const std::string& filtergraph,
161 std::vector<AVFilterContext*>& source_contexts,
162 std::vector<AVFilterContext*>& sink_contexts,
163 const std::vector<audio_output_pad>& output_pads)
165 AVFilterInOut* outputs = nullptr;
166 AVFilterInOut* inputs = nullptr;
168 FF(avfilter_graph_parse2(
174 // Workaround because outputs and inputs are not filled in for some reason
175 for (unsigned i = 0; i < graph.nb_filters; ++i)
177 auto filter = graph.filters[i];
179 if (std::string(filter->filter->name) == "abuffer")
180 source_contexts.push_back(filter);
182 if (std::string(filter->filter->name) == "abuffersink")
183 sink_contexts.push_back(filter);
186 for (AVFilterInOut* iter = inputs; iter; iter = iter->next)
187 source_contexts.push_back(iter->filter_ctx);
189 for (AVFilterInOut* iter = outputs; iter; iter = iter->next)
190 sink_contexts.push_back(iter->filter_ctx);
192 for (int i = 0; i < sink_contexts.size(); ++i)
194 auto sink_context = sink_contexts.at(i);
195 auto& output_pad = output_pads.at(i);
197 #pragma warning (push)
198 #pragma warning (disable : 4245)
199 FF(av_opt_set_int_list(
202 output_pad.sample_fmts.data(),
204 AV_OPT_SEARCH_CHILDREN));
206 FF(av_opt_set_int_list(
209 output_pad.audio_channel_layouts.data(),
211 AV_OPT_SEARCH_CHILDREN));
213 FF(av_opt_set_int_list(
216 output_pad.sample_rates.data(),
218 AV_OPT_SEARCH_CHILDREN));
219 #pragma warning (pop)
222 FF(avfilter_graph_config(
227 void set_guaranteed_output_num_samples_per_frame(int output_pad_id, int num_samples)
229 av_buffersink_set_frame_size(audio_graph_outputs_.at(output_pad_id), num_samples);
232 void push(int input_pad_id, const std::shared_ptr<AVFrame>& src_av_frame)
234 FF(av_buffersrc_add_frame(
235 audio_graph_inputs_.at(input_pad_id),
236 src_av_frame.get()));
239 void push(int input_pad_id, const boost::iterator_range<const int32_t*>& frame_samples)
241 auto& input_pad = input_pads_.at(input_pad_id);
242 auto num_samples = frame_samples.size() / av_get_channel_layout_nb_channels(input_pad.audio_channel_layout);
243 auto input_frame = ffmpeg::create_frame();
245 input_frame->channels = av_get_channel_layout_nb_channels(input_pad.audio_channel_layout);
246 input_frame->channel_layout = input_pad.audio_channel_layout;
247 input_frame->sample_rate = input_pad.sample_rate;
248 input_frame->nb_samples = static_cast<int>(num_samples);
249 input_frame->format = input_pad.sample_fmt;
250 input_frame->pts = 0;
252 av_samples_fill_arrays(
253 input_frame->extended_data,
254 input_frame->linesize,
255 reinterpret_cast<const std::uint8_t*>(frame_samples.begin()),
256 input_frame->channels,
257 input_frame->nb_samples,
258 static_cast<AVSampleFormat>(input_frame->format),
261 push(input_pad_id, input_frame);
264 std::shared_ptr<AVFrame> poll(int output_pad_id)
266 auto filt_frame = create_frame();
268 const auto ret = av_buffersink_get_frame(
269 audio_graph_outputs_.at(output_pad_id),
272 if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
280 const AVFilterLink& get_output_pad_info(int output_pad_id) const
282 return *audio_graph_outputs_.at(output_pad_id)->inputs[0];
286 audio_filter::audio_filter(
287 std::vector<audio_input_pad> input_pads,
288 std::vector<audio_output_pad> output_pads,
289 const std::string& filtergraph)
290 : impl_(new implementation(std::move(input_pads), std::move(output_pads), filtergraph))
293 audio_filter::audio_filter(audio_filter&& other) : impl_(std::move(other.impl_)){}
294 audio_filter& audio_filter::operator=(audio_filter&& other){impl_ = std::move(other.impl_); return *this;}
295 void audio_filter::set_guaranteed_output_num_samples_per_frame(int output_pad_id, int num_samples) { impl_->set_guaranteed_output_num_samples_per_frame(output_pad_id, num_samples); }
296 void audio_filter::push(int input_pad_id, const std::shared_ptr<AVFrame>& frame){impl_->push(input_pad_id, frame);}
297 void audio_filter::push(int input_pad_id, const boost::iterator_range<const int32_t*>& frame_samples) { impl_->push(input_pad_id, frame_samples); }
298 std::shared_ptr<AVFrame> audio_filter::poll(int output_pad_id){return impl_->poll(output_pad_id);}
299 std::wstring audio_filter::filter_str() const{return u16(impl_->filtergraph_);}
300 int audio_filter::get_num_output_pads() const { return static_cast<int>(impl_->audio_graph_outputs_.size()); }
301 const AVFilterLink& audio_filter::get_output_pad_info(int output_pad_id) const { return impl_->get_output_pad_info(output_pad_id); }
302 std::vector<spl::shared_ptr<AVFrame>> audio_filter::poll_all(int output_pad_id)
304 std::vector<spl::shared_ptr<AVFrame>> frames;
305 for(auto frame = poll(output_pad_id); frame; frame = poll(output_pad_id))
306 frames.push_back(spl::make_shared_ptr(frame));