2 * Copyright 2013 Sveriges Television AB http://casparcg.com/
\r
4 * This file is part of CasparCG (www.casparcg.com).
\r
6 * CasparCG is free software: you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation, either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * CasparCG is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
\r
19 * Author: Robert Nagy, ronag89@gmail.com
\r
22 #include "../../stdafx.h"
\r
26 #include "../../ffmpeg_error.h"
\r
28 #include <common/exception/exceptions.h>
\r
30 #include <boost/assign.hpp>
\r
31 #include <boost/range/iterator_range.hpp>
\r
32 #include <boost/range/adaptors.hpp>
\r
33 #include <boost/assign.hpp>
\r
34 #include <boost/algorithm/string.hpp>
\r
35 #include <boost/foreach.hpp>
\r
36 #include <boost/thread.hpp>
\r
37 #include <boost/format.hpp>
\r
38 #include <boost/rational.hpp>
\r
44 #if defined(_MSC_VER)
\r
45 #pragma warning (push)
\r
46 #pragma warning (disable : 4244)
\r
50 #include <libavutil/avutil.h>
\r
51 #include <libavutil/imgutils.h>
\r
52 #include <libavutil/opt.h>
\r
53 #include <libavfilter/avfilter.h>
\r
54 #include <libavfilter/avcodec.h>
\r
55 #include <libavfilter/avfilter.h>
\r
56 #include <libavfilter/buffersink.h>
\r
57 #include <libavfilter/buffersrc.h>
\r
59 #if defined(_MSC_VER)
\r
60 #pragma warning (pop)
\r
63 namespace caspar { namespace ffmpeg {
\r
65 struct filter::implementation
\r
67 std::string filtergraph_;
\r
68 std::shared_ptr<AVFilterGraph> video_graph_;
\r
69 AVFilterContext* video_graph_in_;
\r
70 AVFilterContext* video_graph_out_;
\r
75 boost::rational<int> in_time_base,
\r
76 boost::rational<int> in_frame_rate,
\r
77 boost::rational<int> in_sample_aspect_ratio,
\r
78 AVPixelFormat in_pix_fmt,
\r
79 std::vector<AVPixelFormat> out_pix_fmts,
\r
80 const std::string& filtergraph)
\r
81 : filtergraph_(boost::to_lower_copy(filtergraph))
\r
83 if(out_pix_fmts.empty())
\r
85 out_pix_fmts = boost::assign::list_of
\r
86 (AV_PIX_FMT_YUVA420P)
\r
87 (AV_PIX_FMT_YUV444P)
\r
88 (AV_PIX_FMT_YUV422P)
\r
89 (AV_PIX_FMT_YUV420P)
\r
90 (AV_PIX_FMT_YUV411P)
\r
98 out_pix_fmts.push_back(AV_PIX_FMT_NONE);
\r
100 video_graph_.reset(
\r
101 avfilter_graph_alloc(),
\r
102 [](AVFilterGraph* p)
\r
104 avfilter_graph_free(&p);
\r
107 video_graph_->nb_threads = boost::thread::hardware_concurrency();
\r
108 video_graph_->thread_type = AVFILTER_THREAD_SLICE;
\r
110 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%")
\r
111 % in_width % in_height
\r
113 % in_time_base.numerator() % in_time_base.denominator()
\r
114 % in_sample_aspect_ratio.numerator() % in_sample_aspect_ratio.denominator()
\r
115 % in_frame_rate.numerator() % in_frame_rate.denominator()).str();
\r
117 AVFilterContext* filt_vsrc = nullptr;
\r
118 FF(avfilter_graph_create_filter(
\r
120 avfilter_get_by_name("buffer"),
\r
122 vsrc_options.c_str(),
\r
124 video_graph_.get()));
\r
126 AVFilterContext* filt_vsink = nullptr;
\r
127 FF(avfilter_graph_create_filter(
\r
129 avfilter_get_by_name("buffersink"),
\r
130 "filter_buffersink",
\r
133 video_graph_.get()));
\r
135 #pragma warning (push)
\r
136 #pragma warning (disable : 4245)
\r
138 FF(av_opt_set_int_list(
\r
141 out_pix_fmts.data(),
\r
143 AV_OPT_SEARCH_CHILDREN));
\r
145 #pragma warning (pop)
\r
147 configure_filtergraph(
\r
153 video_graph_in_ = filt_vsrc;
\r
154 video_graph_out_ = filt_vsink;
\r
157 << widen(std::string("\n")
\r
158 + avfilter_graph_dump(
\r
159 video_graph_.get(),
\r
163 void configure_filtergraph(
\r
164 AVFilterGraph& graph,
\r
165 const std::string& filtergraph,
\r
166 AVFilterContext& source_ctx,
\r
167 AVFilterContext& sink_ctx)
\r
169 AVFilterInOut* outputs = nullptr;
\r
170 AVFilterInOut* inputs = nullptr;
\r
174 if(!filtergraph.empty())
\r
176 outputs = avfilter_inout_alloc();
\r
177 inputs = avfilter_inout_alloc();
\r
179 CASPAR_VERIFY(outputs && inputs);
\r
181 outputs->name = av_strdup("in");
\r
182 outputs->filter_ctx = &source_ctx;
\r
183 outputs->pad_idx = 0;
\r
184 outputs->next = nullptr;
\r
186 inputs->name = av_strdup("out");
\r
187 inputs->filter_ctx = &sink_ctx;
\r
188 inputs->pad_idx = 0;
\r
189 inputs->next = nullptr;
\r
191 FF(avfilter_graph_parse(
\r
193 filtergraph.c_str(),
\r
207 FF(avfilter_graph_config(
\r
213 avfilter_inout_free(&outputs);
\r
214 avfilter_inout_free(&inputs);
\r
219 void push(const std::shared_ptr<AVFrame>& src_av_frame)
\r
221 FF(av_buffersrc_add_frame(
\r
223 src_av_frame.get()));
\r
226 std::shared_ptr<AVFrame> poll()
\r
228 std::shared_ptr<AVFrame> filt_frame(
\r
235 const auto ret = av_buffersink_get_frame(
\r
239 if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
\r
242 FF_RET(ret, "poll");
\r
251 boost::rational<int> in_time_base,
\r
252 boost::rational<int> in_frame_rate,
\r
253 boost::rational<int> in_sample_aspect_ratio,
\r
254 AVPixelFormat in_pix_fmt,
\r
255 std::vector<AVPixelFormat> out_pix_fmts,
\r
256 const std::string& filtergraph)
\r
257 : impl_(new implementation(
\r
262 in_sample_aspect_ratio,
\r
266 filter::filter(filter&& other) : impl_(std::move(other.impl_)){}
\r
267 filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;}
\r
268 void filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}
\r
269 std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}
\r
270 std::wstring filter::filter_str() const{return widen(impl_->filtergraph_);}
\r
271 std::vector<safe_ptr<AVFrame>> filter::poll_all()
\r
273 std::vector<safe_ptr<AVFrame>> frames;
\r
274 for(auto frame = poll(); frame; frame = poll())
\r
275 frames.push_back(make_safe_ptr(frame));
\r