2 * Copyright (c) 2011 Sveriges Television AB <info@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 "parallel_yadif.h"
28 #include "../../ffmpeg_error.h"
30 #include <common/except.h>
32 #include <boost/assign.hpp>
33 #include <boost/range/iterator_range.hpp>
34 #include <boost/range/adaptors.hpp>
35 #include <boost/assign.hpp>
36 #include <boost/algorithm/string.hpp>
37 #include <boost/foreach.hpp>
43 #pragma warning (push)
44 #pragma warning (disable : 4244)
48 #include <libavutil/avutil.h>
49 #include <libavutil/imgutils.h>
50 #include <libavfilter/avfilter.h>
51 #include <libavfilter/avcodec.h>
52 #include <libavfilter/avfiltergraph.h>
53 #include <libavfilter/buffersink.h>
54 #include <libavfilter/vsrc_buffer.h>
61 namespace caspar { namespace ffmpeg {
63 static int query_formats_444(AVFilterContext *ctx)
65 static const int pix_fmts[] = {PIX_FMT_YUV444P, PIX_FMT_NONE};
66 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
70 static int query_formats_422(AVFilterContext *ctx)
72 static const int pix_fmts[] = {PIX_FMT_YUV422P, PIX_FMT_NONE};
73 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
77 static int query_formats_420(AVFilterContext *ctx)
79 static const int pix_fmts[] = {PIX_FMT_YUV420P, PIX_FMT_NONE};
80 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
84 static int query_formats_420a(AVFilterContext *ctx)
86 static const int pix_fmts[] = {PIX_FMT_YUVA420P, PIX_FMT_NONE};
87 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
91 static int query_formats_411(AVFilterContext *ctx)
93 static const int pix_fmts[] = {PIX_FMT_YUV411P, PIX_FMT_NONE};
94 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
98 static int query_formats_410(AVFilterContext *ctx)
100 static const int pix_fmts[] = {PIX_FMT_YUV410P, PIX_FMT_NONE};
101 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
107 std::wstring filters_;
108 std::shared_ptr<AVFilterGraph> graph_;
109 AVFilterContext* buffersink_ctx_;
110 AVFilterContext* buffersrc_ctx_;
111 std::shared_ptr<void> parallel_yadif_ctx_;
112 std::vector<PixelFormat> pix_fmts_;
113 std::queue<spl::shared_ptr<AVFrame>> bypass_;
115 impl(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts)
117 , parallel_yadif_ctx_(nullptr)
118 , pix_fmts_(pix_fmts)
120 if(pix_fmts_.empty())
122 pix_fmts_ = boost::assign::list_of
135 pix_fmts_.push_back(PIX_FMT_NONE);
138 void push(const std::shared_ptr<AVFrame>& frame)
143 if(frame->data[0] == nullptr || frame->width < 1)
144 CASPAR_THROW_EXCEPTION(invalid_argument());
148 bypass_.push(spl::make_shared_ptr(frame));
158 graph_.reset(avfilter_graph_alloc(), [](AVFilterGraph* p){avfilter_graph_free(&p);});
161 std::stringstream args;
162 args << frame->width << ":" << frame->height << ":" << frame->format << ":" << 0 << ":" << 0 << ":" << 0 << ":" << 0; // don't care about pts and aspect_ratio
163 THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get()), "[filter]");
165 #if FF_API_OLD_VSINK_API
166 THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts_.data(), graph_.get()), "[filter]");
168 spl::shared_ptr<AVBufferSinkParams> buffersink_params(av_buffersink_params_alloc(), av_free);
169 buffersink_params->pixel_fmts = pix_fmts_.data();
170 THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, buffersink_params.get(), graph_.get()), "[filter]");
172 AVFilterInOut* inputs = avfilter_inout_alloc();
173 AVFilterInOut* outputs = avfilter_inout_alloc();
175 outputs->name = av_strdup("in");
176 outputs->filter_ctx = buffersrc_ctx_;
177 outputs->pad_idx = 0;
178 outputs->next = nullptr;
180 inputs->name = av_strdup("out");
181 inputs->filter_ctx = buffersink_ctx_;
183 inputs->next = nullptr;
185 std::string filters = boost::to_lower_copy(u8(filters_));
186 THROW_ON_ERROR2(avfilter_graph_parse(graph_.get(), filters.c_str(), &inputs, &outputs, NULL), "[filter]");
188 auto yadif_filter = boost::adaptors::filtered([&](AVFilterContext* p){return strstr(p->name, "yadif") != 0;});
190 BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter)
192 // Don't trust that libavfilter chooses optimal format.
193 filter_ctx->filter->query_formats = [&]() -> int (*)(AVFilterContext*)
195 switch(frame->format)
197 case PIX_FMT_YUV444P16:
198 case PIX_FMT_YUV444P10:
199 case PIX_FMT_YUV444P9:
200 case PIX_FMT_YUV444P:
203 return query_formats_444;
204 case PIX_FMT_YUV422P16:
205 case PIX_FMT_YUV422P10:
206 case PIX_FMT_YUV422P9:
207 case PIX_FMT_YUV422P:
208 case PIX_FMT_UYVY422:
209 case PIX_FMT_YUYV422:
210 return query_formats_422;
211 case PIX_FMT_YUV420P16:
212 case PIX_FMT_YUV420P10:
213 case PIX_FMT_YUV420P9:
214 case PIX_FMT_YUV420P:
215 return query_formats_420;
216 case PIX_FMT_YUVA420P:
221 return query_formats_420a;
222 case PIX_FMT_UYYVYY411:
223 case PIX_FMT_YUV411P:
224 return query_formats_411;
225 case PIX_FMT_YUV410P:
226 return query_formats_410;
228 return filter_ctx->filter->query_formats;
233 THROW_ON_ERROR2(avfilter_graph_config(graph_.get(), NULL), "[filter]");
235 BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter)
236 parallel_yadif_ctx_ = make_parallel_yadif(filter_ctx);
245 THROW_ON_ERROR2(av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0), "[filter]");
253 CASPAR_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));
257 std::shared_ptr<AVFrame> poll()
263 auto frame = bypass_.front();
273 if(avfilter_poll_frame(buffersink_ctx_->inputs[0]))
275 AVFilterBufferRef *picref;
276 THROW_ON_ERROR2(av_buffersink_get_buffer_ref(buffersink_ctx_, &picref, 0), "[filter]");
281 spl::shared_ptr<AVFrame> frame(avcodec_alloc_frame(), [=](AVFrame* p)
284 avfilter_unref_buffer(picref);
287 avcodec_get_frame_defaults(frame.get());
289 memcpy(frame->data, picref->data, sizeof(frame->data));
290 memcpy(frame->linesize, picref->linesize, sizeof(frame->linesize));
291 frame->format = picref->format;
292 frame->width = picref->video->w;
293 frame->height = picref->video->h;
294 frame->pkt_pos = picref->pos;
295 frame->interlaced_frame = picref->video->interlaced;
296 frame->top_field_first = picref->video->top_field_first;
297 frame->key_frame = picref->video->key_frame;
298 frame->pict_type = picref->video->pict_type;
299 frame->sample_aspect_ratio = picref->video->sample_aspect_ratio;
312 CASPAR_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));
317 filter::filter(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) : impl_(new impl(filters, pix_fmts)){}
318 filter::filter(filter&& other) : impl_(std::move(other.impl_)){}
319 filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;}
320 void filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}
321 std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}
322 std::wstring filter::filter_str() const{return impl_->filters_;}
323 std::vector<spl::shared_ptr<AVFrame>> filter::poll_all()
325 std::vector<spl::shared_ptr<AVFrame>> frames;
326 for(auto frame = poll(); frame; frame = poll())
327 frames.push_back(spl::make_shared_ptr(frame));