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"
29 #include <common/assert.h>
30 #include <common/except.h>
32 #include <boost/algorithm/string.hpp>
33 #include <boost/thread.hpp>
34 #include <boost/format.hpp>
35 #include <boost/rational.hpp>
42 #pragma warning (push)
43 #pragma warning (disable : 4244)
47 #include <libavutil/avutil.h>
48 #include <libavutil/imgutils.h>
49 #include <libavutil/opt.h>
50 #include <libavfilter/avfilter.h>
51 #include <libavfilter/avcodec.h>
52 #include <libavfilter/buffersink.h>
53 #include <libavfilter/buffersrc.h>
59 namespace caspar { namespace ffmpeg {
61 struct audio_filter::implementation
63 std::string filtergraph_;
65 std::shared_ptr<AVFilterGraph> audio_graph_;
66 AVFilterContext* audio_graph_in_;
67 AVFilterContext* audio_graph_out_;
70 boost::rational<int> in_time_base,
72 AVSampleFormat in_sample_fmt,
73 std::int64_t in_audio_channel_layout,
74 std::vector<int> out_sample_rates,
75 std::vector<AVSampleFormat> out_sample_fmts,
76 std::vector<std::int64_t> out_audio_channel_layouts,
77 const std::string& filtergraph)
78 : filtergraph_(boost::to_lower_copy(filtergraph))
80 if (out_sample_rates.empty())
81 out_sample_rates.push_back(48000);
83 out_sample_rates.push_back(-1);
85 if (out_sample_fmts.empty())
86 out_sample_fmts.push_back(AV_SAMPLE_FMT_S32);
88 out_sample_fmts.push_back(AV_SAMPLE_FMT_NONE);
90 if (out_audio_channel_layouts.empty())
91 out_audio_channel_layouts.push_back(AV_CH_LAYOUT_NATIVE);
93 out_audio_channel_layouts.push_back(-1);
96 avfilter_graph_alloc(),
99 avfilter_graph_free(&p);
102 const auto asrc_options = (boost::format("time_base=%1%/%2%:sample_rate=%3%:sample_fmt=%4%:channel_layout=0x%|5$x|")
103 % in_time_base.numerator() % in_time_base.denominator()
105 % av_get_sample_fmt_name(in_sample_fmt)
106 % in_audio_channel_layout).str();
108 AVFilterContext* filt_asrc = nullptr;
109 FF(avfilter_graph_create_filter(
111 avfilter_get_by_name("abuffer"),
113 asrc_options.c_str(),
115 audio_graph_.get()));
117 AVFilterContext* filt_asink = nullptr;
118 FF(avfilter_graph_create_filter(
120 avfilter_get_by_name("abuffersink"),
124 audio_graph_.get()));
126 #pragma warning (push)
127 #pragma warning (disable : 4245)
129 FF(av_opt_set_int_list(
132 out_sample_fmts.data(),
134 AV_OPT_SEARCH_CHILDREN));
135 FF(av_opt_set_int_list(
138 out_audio_channel_layouts.data(),
140 AV_OPT_SEARCH_CHILDREN));
141 FF(av_opt_set_int_list(
144 out_sample_rates.data(),
146 AV_OPT_SEARCH_CHILDREN));
148 #pragma warning (pop)
150 configure_filtergraph(
156 audio_graph_in_ = filt_asrc;
157 audio_graph_out_ = filt_asink;
159 if (is_logging_quiet_for_thread())
161 << u16(std::string("\n")
162 + avfilter_graph_dump(
167 << u16(std::string("\n")
168 + avfilter_graph_dump(
173 void configure_filtergraph(
174 AVFilterGraph& graph,
175 const std::string& filtergraph,
176 AVFilterContext& source_ctx,
177 AVFilterContext& sink_ctx)
179 AVFilterInOut* outputs = nullptr;
180 AVFilterInOut* inputs = nullptr;
184 if(!filtergraph.empty())
186 outputs = avfilter_inout_alloc();
187 inputs = avfilter_inout_alloc();
189 CASPAR_VERIFY(outputs && inputs);
191 outputs->name = av_strdup("in");
192 outputs->filter_ctx = &source_ctx;
193 outputs->pad_idx = 0;
194 outputs->next = nullptr;
196 inputs->name = av_strdup("out");
197 inputs->filter_ctx = &sink_ctx;
199 inputs->next = nullptr;
201 FF(avfilter_graph_parse(
217 FF(avfilter_graph_config(
223 //avfilter_inout_free(&outputs);
224 //avfilter_inout_free(&inputs);
229 void push(const std::shared_ptr<AVFrame>& src_av_frame)
231 FF(av_buffersrc_add_frame(
233 src_av_frame.get()));
236 std::shared_ptr<AVFrame> poll()
238 std::shared_ptr<AVFrame> filt_frame(
245 const auto ret = av_buffersink_get_frame(
249 if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
258 audio_filter::audio_filter(
259 boost::rational<int> in_time_base,
261 AVSampleFormat in_sample_fmt,
262 std::int64_t in_audio_channel_layout,
263 std::vector<int> out_sample_rates,
264 std::vector<AVSampleFormat> out_sample_fmts,
265 std::vector<std::int64_t> out_audio_channel_layouts,
266 const std::string& filtergraph)
267 : impl_(new implementation(
271 in_audio_channel_layout,
272 std::move(out_sample_rates),
273 std::move(out_sample_fmts),
274 std::move(out_audio_channel_layouts),
276 audio_filter::audio_filter(audio_filter&& other) : impl_(std::move(other.impl_)){}
277 audio_filter& audio_filter::operator=(audio_filter&& other){impl_ = std::move(other.impl_); return *this;}
278 void audio_filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}
279 std::shared_ptr<AVFrame> audio_filter::poll(){return impl_->poll();}
280 std::wstring audio_filter::filter_str() const{return u16(impl_->filtergraph_);}
281 std::vector<spl::shared_ptr<AVFrame>> audio_filter::poll_all()
283 std::vector<spl::shared_ptr<AVFrame>> frames;
284 for(auto frame = poll(); frame; frame = poll())
285 frames.push_back(spl::make_shared_ptr(frame));