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"
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>
43 #pragma warning (push)
44 #pragma warning (disable : 4244)
48 #include <libavutil/avutil.h>
49 #include <libavutil/imgutils.h>
50 #include <libavutil/opt.h>
51 #include <libavfilter/avfilter.h>
52 #include <libavfilter/avcodec.h>
53 #include <libavfilter/buffersink.h>
54 #include <libavfilter/buffersrc.h>
60 namespace caspar { namespace ffmpeg {
62 struct filter::implementation
64 std::string filtergraph_;
66 std::shared_ptr<AVFilterGraph> video_graph_;
67 AVFilterContext* video_graph_in_;
68 AVFilterContext* video_graph_out_;
70 std::queue<std::shared_ptr<AVFrame>> fast_path_;
75 boost::rational<int> in_time_base,
76 boost::rational<int> in_frame_rate,
77 boost::rational<int> in_sample_aspect_ratio,
78 AVPixelFormat in_pix_fmt,
79 std::vector<AVPixelFormat> out_pix_fmts,
80 const std::string& filtergraph)
81 : filtergraph_(boost::to_lower_copy(filtergraph))
83 if(out_pix_fmts.empty())
99 out_pix_fmts.push_back(AV_PIX_FMT_NONE);
102 avfilter_graph_alloc(),
105 avfilter_graph_free(&p);
108 video_graph_->nb_threads = 0;
109 video_graph_->thread_type = AVFILTER_THREAD_SLICE;
111 const auto vsrc_options = (boost::format("video_size=%1%x%2%:pix_fmt=%3%:time_base=%4%/%5%:pixel_aspect=%6%/%7%:frame_rate=%8%/%9%")
112 % in_width % in_height
114 % in_time_base.numerator() % in_time_base.denominator()
115 % in_sample_aspect_ratio.numerator() % in_sample_aspect_ratio.denominator()
116 % in_frame_rate.numerator() % in_frame_rate.denominator()).str();
118 AVFilterContext* filt_vsrc = nullptr;
119 FF(avfilter_graph_create_filter(
121 avfilter_get_by_name("buffer"),
123 vsrc_options.c_str(),
125 video_graph_.get()));
127 AVFilterContext* filt_vsink = nullptr;
128 FF(avfilter_graph_create_filter(
130 avfilter_get_by_name("buffersink"),
134 video_graph_.get()));
136 #pragma warning (push)
137 #pragma warning (disable : 4245)
139 FF(av_opt_set_int_list(
144 AV_OPT_SEARCH_CHILDREN));
146 #pragma warning (pop)
148 configure_filtergraph(
154 video_graph_in_ = filt_vsrc;
155 video_graph_out_ = filt_vsink;
157 if (is_logging_quiet_for_thread())
159 << u16(std::string("\n")
160 + avfilter_graph_dump(
165 << u16(std::string("\n")
166 + avfilter_graph_dump(
171 void configure_filtergraph(
172 AVFilterGraph& graph,
173 const std::string& filtergraph,
174 AVFilterContext& source_ctx,
175 AVFilterContext& sink_ctx)
177 AVFilterInOut* outputs = nullptr;
178 AVFilterInOut* inputs = nullptr;
182 if(!filtergraph.empty())
184 outputs = avfilter_inout_alloc();
185 inputs = avfilter_inout_alloc();
187 CASPAR_VERIFY(outputs && inputs);
189 outputs->name = av_strdup("in");
190 outputs->filter_ctx = &source_ctx;
191 outputs->pad_idx = 0;
192 outputs->next = nullptr;
194 inputs->name = av_strdup("out");
195 inputs->filter_ctx = &sink_ctx;
197 inputs->next = nullptr;
199 FF(avfilter_graph_parse(
215 FF(avfilter_graph_config(
221 //avfilter_inout_free(&outputs);
222 //avfilter_inout_free(&inputs);
227 bool fast_path() const
229 return filtergraph_.empty();
232 void push(const std::shared_ptr<AVFrame>& src_av_frame)
235 fast_path_.push(src_av_frame);
237 FF(av_buffersrc_add_frame(
239 src_av_frame.get()));
242 std::shared_ptr<AVFrame> poll()
246 if (fast_path_.empty())
249 auto result = fast_path_.front();
254 std::shared_ptr<AVFrame> filt_frame(
261 const auto ret = av_buffersink_get_frame(
265 if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
277 boost::rational<int> in_time_base,
278 boost::rational<int> in_frame_rate,
279 boost::rational<int> in_sample_aspect_ratio,
280 AVPixelFormat in_pix_fmt,
281 std::vector<AVPixelFormat> out_pix_fmts,
282 const std::string& filtergraph)
283 : impl_(new implementation(
288 in_sample_aspect_ratio,
292 filter::filter(filter&& other) : impl_(std::move(other.impl_)){}
293 filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;}
294 void filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}
295 std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}
296 std::wstring filter::filter_str() const{return u16(impl_->filtergraph_);}
297 std::vector<spl::shared_ptr<AVFrame>> filter::poll_all()
299 std::vector<spl::shared_ptr<AVFrame>> frames;
300 for(auto frame = poll(); frame; frame = poll())
301 frames.push_back(spl::make_shared_ptr(frame));