1 #include "../../stdafx.h"
\r
5 #include "../../ffmpeg_error.h"
\r
7 #include <common/exception/exceptions.h>
\r
8 #include <core/producer/frame/basic_frame.h>
\r
9 #include <core/producer/frame/frame_factory.h>
\r
10 #include <core/mixer/write_frame.h>
\r
12 #include <boost/circular_buffer.hpp>
\r
19 #define __STDC_CONSTANT_MACROS
\r
20 #define __STDC_LIMIT_MACROS
\r
21 #include <libavutil/avutil.h>
\r
22 #include <libavutil/imgutils.h>
\r
23 #include <libavfilter/avfilter.h>
\r
24 #include <libavfilter/avcodec.h>
\r
25 #include <libavfilter/avfiltergraph.h>
\r
26 #include <libavfilter/vsink_buffer.h>
\r
27 #include <libavfilter/vsrc_buffer.h>
\r
32 struct filter::implementation
\r
34 std::string filters_;
\r
35 std::shared_ptr<AVFilterGraph> graph_;
\r
36 AVFilterContext* buffersink_ctx_;
\r
37 AVFilterContext* buffersrc_ctx_;
\r
39 implementation(const std::wstring& filters)
\r
40 : filters_(narrow(filters))
\r
42 std::transform(filters_.begin(), filters_.end(), filters_.begin(), ::tolower);
\r
45 void push(const safe_ptr<AVFrame>& frame)
\r
51 graph_.reset(avfilter_graph_alloc(), [](AVFilterGraph* p){avfilter_graph_free(&p);});
\r
54 std::stringstream args;
\r
55 args << frame->width << ":" << frame->height << ":" << frame->format << ":" << 0 << ":" << 0 << ":" << 0 << ":" << 0; // don't care about pts and aspect_ratio
\r
56 errn = avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get());
\r
59 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
60 boost::errinfo_api_function("avfilter_graph_create_filter") << boost::errinfo_errno(AVUNERROR(errn)));
\r
63 PixelFormat pix_fmts[] = { PIX_FMT_BGRA, PIX_FMT_NONE };
\r
66 errn = avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts, graph_.get());
\r
69 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
70 boost::errinfo_api_function("avfilter_graph_create_filter") << boost::errinfo_errno(AVUNERROR(errn)));
\r
73 AVFilterInOut* outputs = avfilter_inout_alloc();
\r
74 AVFilterInOut* inputs = avfilter_inout_alloc();
\r
76 outputs->name = av_strdup("in");
\r
77 outputs->filter_ctx = buffersrc_ctx_;
\r
78 outputs->pad_idx = 0;
\r
79 outputs->next = NULL;
\r
81 inputs->name = av_strdup("out");
\r
82 inputs->filter_ctx = buffersink_ctx_;
\r
83 inputs->pad_idx = 0;
\r
84 inputs->next = NULL;
\r
86 errn = avfilter_graph_parse(graph_.get(), filters_.c_str(), &inputs, &outputs, NULL);
\r
89 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
90 boost::errinfo_api_function("avfilter_graph_parse") << boost::errinfo_errno(AVUNERROR(errn)));
\r
93 errn = avfilter_graph_config(graph_.get(), NULL);
\r
96 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn))
\r
97 << boost::errinfo_api_function("avfilter_graph_config") << boost::errinfo_errno(AVUNERROR(errn)));
\r
101 errn = av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0);
\r
104 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
105 boost::errinfo_api_function("av_vsrc_buffer_add_frame") << boost::errinfo_errno(AVUNERROR(errn)));
\r
109 std::vector<safe_ptr<AVFrame>> poll()
\r
111 std::vector<safe_ptr<AVFrame>> result;
\r
116 while (avfilter_poll_frame(buffersink_ctx_->inputs[0]))
\r
118 AVFilterBufferRef *picref;
\r
119 av_vsink_buffer_get_video_buffer_ref(buffersink_ctx_, &picref, 0);
\r
122 safe_ptr<AVFrame> frame(avcodec_alloc_frame(), [=](AVFrame* p)
\r
125 avfilter_unref_buffer(picref);
\r
128 avcodec_get_frame_defaults(frame.get());
\r
130 for(size_t n = 0; n < 4; ++n)
\r
132 frame->data[n] = picref->data[n];
\r
133 frame->linesize[n] = picref->linesize[n];
\r
136 frame->format = picref->format;
\r
137 frame->width = picref->video->w;
\r
138 frame->height = picref->video->h;
\r
139 frame->interlaced_frame = picref->video->interlaced;
\r
140 frame->top_field_first = picref->video->top_field_first;
\r
141 frame->key_frame = picref->video->key_frame;
\r
143 result.push_back(frame);
\r
151 filter::filter(const std::wstring& filters) : impl_(new implementation(filters)){}
\r
152 void filter::push(const safe_ptr<AVFrame>& frame) {impl_->push(frame);}
\r
153 std::vector<safe_ptr<AVFrame>> filter::poll() {return impl_->poll();}
\r