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_disabled_for_thread())
161 << u16(std::string("\n")
162 + avfilter_graph_dump(
167 void configure_filtergraph(
168 AVFilterGraph& graph,
169 const std::string& filtergraph,
170 AVFilterContext& source_ctx,
171 AVFilterContext& sink_ctx)
173 AVFilterInOut* outputs = nullptr;
174 AVFilterInOut* inputs = nullptr;
178 if(!filtergraph.empty())
180 outputs = avfilter_inout_alloc();
181 inputs = avfilter_inout_alloc();
183 CASPAR_VERIFY(outputs && inputs);
185 outputs->name = av_strdup("in");
186 outputs->filter_ctx = &source_ctx;
187 outputs->pad_idx = 0;
188 outputs->next = nullptr;
190 inputs->name = av_strdup("out");
191 inputs->filter_ctx = &sink_ctx;
193 inputs->next = nullptr;
195 FF(avfilter_graph_parse(
211 FF(avfilter_graph_config(
217 //avfilter_inout_free(&outputs);
218 //avfilter_inout_free(&inputs);
223 void push(const std::shared_ptr<AVFrame>& src_av_frame)
225 FF(av_buffersrc_add_frame(
227 src_av_frame.get()));
230 std::shared_ptr<AVFrame> poll()
232 std::shared_ptr<AVFrame> filt_frame(
239 const auto ret = av_buffersink_get_frame(
243 if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
252 audio_filter::audio_filter(
253 boost::rational<int> in_time_base,
255 AVSampleFormat in_sample_fmt,
256 std::int64_t in_audio_channel_layout,
257 std::vector<int> out_sample_rates,
258 std::vector<AVSampleFormat> out_sample_fmts,
259 std::vector<std::int64_t> out_audio_channel_layouts,
260 const std::string& filtergraph)
261 : impl_(new implementation(
265 in_audio_channel_layout,
266 std::move(out_sample_rates),
267 std::move(out_sample_fmts),
268 std::move(out_audio_channel_layouts),
270 audio_filter::audio_filter(audio_filter&& other) : impl_(std::move(other.impl_)){}
271 audio_filter& audio_filter::operator=(audio_filter&& other){impl_ = std::move(other.impl_); return *this;}
272 void audio_filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}
273 std::shared_ptr<AVFrame> audio_filter::poll(){return impl_->poll();}
274 std::wstring audio_filter::filter_str() const{return u16(impl_->filtergraph_);}
275 std::vector<spl::shared_ptr<AVFrame>> audio_filter::poll_all()
277 std::vector<spl::shared_ptr<AVFrame>> frames;
278 for(auto frame = poll(); frame; frame = poll())
279 frames.push_back(spl::make_shared_ptr(frame));