]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/filter/audio_filter.cpp
[ffmpeg] Remove usage of deprecated API usage to easier support a newer version of...
[casparcg] / modules / ffmpeg / producer / filter / audio_filter.cpp
1 /*
2 * Copyright 2013 Sveriges Television AB http://casparcg.com/
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21
22 #include "../../StdAfx.h"
23
24 #include "audio_filter.h"
25
26 #include "../../ffmpeg_error.h"
27 #include "../../ffmpeg.h"
28 #include "../util/util.h"
29
30 #include <common/assert.h>
31 #include <common/except.h>
32
33 #include <boost/algorithm/string.hpp>
34 #include <boost/thread.hpp>
35 #include <boost/format.hpp>
36 #include <boost/rational.hpp>
37
38 #include <cstdio>
39 #include <sstream>
40 #include <string>
41 #include <algorithm>
42
43 #if defined(_MSC_VER)
44 #pragma warning (push)
45 #pragma warning (disable : 4244)
46 #endif
47 extern "C"
48 {
49         #include <libavutil/avutil.h>
50         #include <libavutil/imgutils.h>
51         #include <libavutil/opt.h>
52         #include <libavfilter/avfilter.h>
53         #include <libavfilter/buffersink.h>
54         #include <libavfilter/buffersrc.h>
55 }
56 #if defined(_MSC_VER)
57 #pragma warning (pop)
58 #endif
59
60 namespace caspar { namespace ffmpeg {
61
62 std::string create_sourcefilter_str(const audio_input_pad& input_pad, std::string name)
63 {
64         const auto asrc_options = (boost::format("abuffer=time_base=%1%/%2%:sample_rate=%3%:sample_fmt=%4%:channel_layout=0x%|5$x| [%6%]")
65                 % input_pad.time_base.numerator() % input_pad.time_base.denominator()
66                 % input_pad.sample_rate
67                 % av_get_sample_fmt_name(input_pad.sample_fmt)
68                 % input_pad.audio_channel_layout
69                 % name).str();
70
71         return asrc_options;
72 }
73
74 std::string create_sinkfilter_str(const audio_output_pad& output_pad, std::string name)
75 {
76         const auto asink_options = (boost::format("[%1%] abuffersink") % name).str();
77
78         return asink_options;
79 }
80
81 struct audio_filter::implementation
82 {
83         std::string                                             filtergraph_;
84
85         std::shared_ptr<AVFilterGraph>  audio_graph_;
86         std::vector<AVFilterContext*>   audio_graph_inputs_;
87         std::vector<AVFilterContext*>   audio_graph_outputs_;
88
89         std::vector<audio_input_pad>    input_pads_;
90
91         implementation(
92                         std::vector<audio_input_pad> input_pads,
93                         std::vector<audio_output_pad> output_pads,
94                         const std::string& filtergraph)
95                 : filtergraph_(boost::to_lower_copy(filtergraph))
96                 , input_pads_(std::move(input_pads))
97         {
98                 if (input_pads_.empty())
99                         CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("input_pads cannot be empty"));
100
101                 if (output_pads.empty())
102                         CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("output_pads cannot be empty"));
103
104                 audio_graph_.reset(
105                         avfilter_graph_alloc(),
106                         [](AVFilterGraph* p)
107                 {
108                         avfilter_graph_free(&p);
109                 });
110
111                 std::vector<std::string> complete_filter_graph;
112
113                 {
114                         int i = 0;
115                         for (auto& input_pad : input_pads_)
116                                 complete_filter_graph.push_back(create_sourcefilter_str(input_pad, "a:" + boost::lexical_cast<std::string>(i++)));
117                 }
118
119                 if (filtergraph_.empty())
120                         complete_filter_graph.push_back("[a:0] anull [aout:0]");
121                 else
122                         complete_filter_graph.push_back(filtergraph_);
123
124                 {
125                         int i = 0;
126                         for (auto& output_pad : output_pads)
127                         {
128                                 complete_filter_graph.push_back(create_sinkfilter_str(output_pad, "aout:" + boost::lexical_cast<std::string>(i++)));
129
130                                 output_pad.sample_fmts.push_back(AVSampleFormat::AV_SAMPLE_FMT_NONE);
131                                 output_pad.audio_channel_layouts.push_back(0);
132                                 output_pad.sample_rates.push_back(-1);
133                         }
134                 }
135
136                 configure_filtergraph(
137                                 *audio_graph_,
138                                 boost::join(complete_filter_graph, ";"),
139                                 audio_graph_inputs_,
140                                 audio_graph_outputs_,
141                                 output_pads);
142
143                 if (is_logging_quiet_for_thread())
144                         CASPAR_LOG(trace)
145                                 <<      u16(std::string("\n")
146                                         + avfilter_graph_dump(
147                                                         audio_graph_.get(),
148                                                         nullptr));
149                 else
150                         CASPAR_LOG(debug)
151                                 << u16(std::string("\n")
152                                         + avfilter_graph_dump(
153                                                 audio_graph_.get(),
154                                                 nullptr));
155         }
156
157         void configure_filtergraph(
158                         AVFilterGraph& graph,
159                         const std::string& filtergraph,
160                         std::vector<AVFilterContext*>& source_contexts,
161                         std::vector<AVFilterContext*>& sink_contexts,
162                         const std::vector<audio_output_pad>& output_pads)
163         {
164                 AVFilterInOut* outputs  = nullptr;
165                 AVFilterInOut* inputs   = nullptr;
166
167                 FF(avfilter_graph_parse2(
168                                 &graph,
169                                 filtergraph.c_str(),
170                                 &inputs,
171                                 &outputs));
172
173                 // Workaround because outputs and inputs are not filled in for some reason
174                 for (unsigned i = 0; i < graph.nb_filters; ++i)
175                 {
176                         auto filter = graph.filters[i];
177
178                         if (std::string(filter->filter->name) == "abuffer")
179                                 source_contexts.push_back(filter);
180
181                         if (std::string(filter->filter->name) == "abuffersink")
182                                 sink_contexts.push_back(filter);
183                 }
184
185                 for (AVFilterInOut* iter = inputs; iter; iter = iter->next)
186                         source_contexts.push_back(iter->filter_ctx);
187
188                 for (AVFilterInOut* iter = outputs; iter; iter = iter->next)
189                         sink_contexts.push_back(iter->filter_ctx);
190
191                 for (int i = 0; i < sink_contexts.size(); ++i)
192                 {
193                         auto sink_context = sink_contexts.at(i);
194                         auto& output_pad = output_pads.at(i);
195
196 #pragma warning (push)
197 #pragma warning (disable : 4245)
198                         FF(av_opt_set_int_list(
199                                 sink_context,
200                                 "sample_fmts",
201                                 output_pad.sample_fmts.data(),
202                                 -1,
203                                 AV_OPT_SEARCH_CHILDREN));
204
205                         FF(av_opt_set_int_list(
206                                 sink_context,
207                                 "channel_layouts",
208                                 output_pad.audio_channel_layouts.data(),
209                                 0,
210                                 AV_OPT_SEARCH_CHILDREN));
211
212                         FF(av_opt_set_int_list(
213                                 sink_context,
214                                 "sample_rates",
215                                 output_pad.sample_rates.data(),
216                                 -1,
217                                 AV_OPT_SEARCH_CHILDREN));
218 #pragma warning (pop)
219                 }
220
221                 FF(avfilter_graph_config(
222                         &graph,
223                         nullptr));
224         }
225
226         void set_guaranteed_output_num_samples_per_frame(int output_pad_id, int num_samples)
227         {
228                 av_buffersink_set_frame_size(audio_graph_outputs_.at(output_pad_id), num_samples);
229         }
230
231         void push(int input_pad_id, const std::shared_ptr<AVFrame>& src_av_frame)
232         {
233                 FF(av_buffersrc_add_frame(
234                         audio_graph_inputs_.at(input_pad_id),
235                         src_av_frame.get()));
236         }
237
238         void push(int input_pad_id, const boost::iterator_range<const int32_t*>& frame_samples)
239         {
240                 auto& input_pad                         = input_pads_.at(input_pad_id);
241                 auto num_samples                        = frame_samples.size() / av_get_channel_layout_nb_channels(input_pad.audio_channel_layout);
242                 auto input_frame                        = ffmpeg::create_frame();
243
244                 input_frame->channels           = av_get_channel_layout_nb_channels(input_pad.audio_channel_layout);
245                 input_frame->channel_layout     = input_pad.audio_channel_layout;
246                 input_frame->sample_rate                = input_pad.sample_rate;
247                 input_frame->nb_samples         = static_cast<int>(num_samples);
248                 input_frame->format                     = input_pad.sample_fmt;
249                 input_frame->pts                                = 0;
250
251                 av_samples_fill_arrays(
252                                 input_frame->extended_data,
253                                 input_frame->linesize,
254                                 reinterpret_cast<const std::uint8_t*>(frame_samples.begin()),
255                                 input_frame->channels,
256                                 input_frame->nb_samples,
257                                 static_cast<AVSampleFormat>(input_frame->format),
258                                 16);
259
260                 push(input_pad_id, input_frame);
261         }
262
263         std::shared_ptr<AVFrame> poll(int output_pad_id)
264         {
265                 auto filt_frame = create_frame();
266
267                 const auto ret = av_buffersink_get_frame(
268                         audio_graph_outputs_.at(output_pad_id),
269                         filt_frame.get());
270
271                 if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
272                         return nullptr;
273
274                 FF_RET(ret, "poll");
275
276                 return filt_frame;
277         }
278
279         const AVFilterLink& get_output_pad_info(int output_pad_id) const
280         {
281                 return *audio_graph_outputs_.at(output_pad_id)->inputs[0];
282         }
283 };
284
285 audio_filter::audio_filter(
286                 std::vector<audio_input_pad> input_pads,
287                 std::vector<audio_output_pad> output_pads,
288                 const std::string& filtergraph)
289         : impl_(new implementation(std::move(input_pads), std::move(output_pads), filtergraph))
290 {
291 }
292 audio_filter::audio_filter(audio_filter&& other) : impl_(std::move(other.impl_)){}
293 audio_filter& audio_filter::operator=(audio_filter&& other){impl_ = std::move(other.impl_); return *this;}
294 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); }
295 void audio_filter::push(int input_pad_id, const std::shared_ptr<AVFrame>& frame){impl_->push(input_pad_id, frame);}
296 void audio_filter::push(int input_pad_id, const boost::iterator_range<const int32_t*>& frame_samples) { impl_->push(input_pad_id, frame_samples); }
297 std::shared_ptr<AVFrame> audio_filter::poll(int output_pad_id){return impl_->poll(output_pad_id);}
298 std::wstring audio_filter::filter_str() const{return u16(impl_->filtergraph_);}
299 int audio_filter::get_num_output_pads() const { return static_cast<int>(impl_->audio_graph_outputs_.size()); }
300 const AVFilterLink& audio_filter::get_output_pad_info(int output_pad_id) const { return impl_->get_output_pad_info(output_pad_id); }
301 std::vector<spl::shared_ptr<AVFrame>> audio_filter::poll_all(int output_pad_id)
302 {
303         std::vector<spl::shared_ptr<AVFrame>> frames;
304         for(auto frame = poll(output_pad_id); frame; frame = poll(output_pad_id))
305                 frames.push_back(spl::make_shared_ptr(frame));
306         return frames;
307 }
308
309 ffmpeg::audio_input_pad create_input_pad(const core::video_format_desc& in_format, int num_channels)
310 {
311         return ffmpeg::audio_input_pad(
312                         boost::rational<int>(1, in_format.audio_sample_rate),
313                         in_format.audio_sample_rate,
314                         AVSampleFormat::AV_SAMPLE_FMT_S32,
315                         av_get_default_channel_layout(num_channels));
316 }
317
318 }}