1 #include "../stdafx.h"
\r
5 #include "../ffmpeg_error.h"
\r
8 #include <common/exception/exceptions.h>
\r
9 #include <core/producer/frame/basic_frame.h>
\r
10 #include <core/producer/frame/frame_factory.h>
\r
11 #include <core/mixer/write_frame.h>
\r
18 #define __STDC_CONSTANT_MACROS
\r
19 #define __STDC_LIMIT_MACROS
\r
20 #include <libavutil/avutil.h>
\r
21 #include <libavutil/imgutils.h>
\r
22 #include <libavfilter/avfilter.h>
\r
23 #include <libavfilter/avcodec.h>
\r
24 #include <libavfilter/vsrc_buffer.h>
\r
25 #include <libavfilter/avfiltergraph.h>
\r
30 struct filter::implementation
\r
32 std::string filters_;
\r
33 std::shared_ptr<AVFilterGraph> graph_;
\r
34 AVFilterContext* video_in_filter_;
\r
35 AVFilterContext* video_out_filter_;
\r
37 implementation(const std::string& filters)
\r
40 std::transform(filters_.begin(), filters_.end(), filters_.begin(), ::tolower);
\r
43 std::vector<safe_ptr<AVFrame>> execute(const safe_ptr<AVFrame>& frame)
\r
49 graph_.reset(avfilter_graph_alloc(), [](AVFilterGraph* p){avfilter_graph_free(&p);});
\r
52 std::stringstream buffer_ss;
\r
53 buffer_ss << frame->width << ":" << frame->height << ":" << frame->format << ":" << 0 << ":" << 0 << ":" << 0 << ":" << 0; // don't care about pts and aspect_ratio
\r
54 errn = avfilter_graph_create_filter(&video_in_filter_, avfilter_get_by_name("buffer"), "src", buffer_ss.str().c_str(), NULL, graph_.get());
\r
57 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
58 boost::errinfo_api_function("avfilter_graph_create_filter") << boost::errinfo_errno(AVUNERROR(errn)));
\r
62 errn = avfilter_graph_create_filter(&video_out_filter_, avfilter_get_by_name("nullsink"), "out", NULL, NULL, graph_.get());
\r
65 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
66 boost::errinfo_api_function("avfilter_graph_create_filter") << boost::errinfo_errno(AVUNERROR(errn)));
\r
69 AVFilterInOut* outputs = reinterpret_cast<AVFilterInOut*>(av_malloc(sizeof(AVFilterInOut)));
\r
70 AVFilterInOut* inputs = reinterpret_cast<AVFilterInOut*>(av_malloc(sizeof(AVFilterInOut)));
\r
72 outputs->name = av_strdup("in");
\r
73 outputs->filter_ctx = video_in_filter_;
\r
74 outputs->pad_idx = 0;
\r
75 outputs->next = NULL;
\r
77 inputs->name = av_strdup("out");
\r
78 inputs->filter_ctx = video_out_filter_;
\r
79 inputs->pad_idx = 0;
\r
80 inputs->next = NULL;
\r
82 errn = avfilter_graph_parse(graph_.get(), filters_.c_str(), inputs, outputs, NULL);
\r
85 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
86 boost::errinfo_api_function("avfilter_graph_parse") << boost::errinfo_errno(AVUNERROR(errn)));
\r
89 // av_free(outputs);
\r
92 errn = avfilter_graph_config(graph_.get(), NULL);
\r
95 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn))
\r
96 << boost::errinfo_api_function("avfilter_graph_config") << boost::errinfo_errno(AVUNERROR(errn)));
\r
100 errn = av_vsrc_buffer_add_frame(video_in_filter_, frame.get(), 0);
\r
103 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
104 boost::errinfo_api_function("av_vsrc_buffer_add_frame") << boost::errinfo_errno(AVUNERROR(errn)));
\r
107 errn = avfilter_poll_frame(video_out_filter_->inputs[0]);
\r
110 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
111 boost::errinfo_api_function("avfilter_poll_frame") << boost::errinfo_errno(AVUNERROR(errn)));
\r
114 std::vector<safe_ptr<AVFrame>> result;
\r
116 std::generate_n(std::back_inserter(result), errn, [&]{return get_frame();});
\r
121 safe_ptr<AVFrame> get_frame()
\r
123 auto link = video_out_filter_->inputs[0];
\r
125 int errn = avfilter_request_frame(link);
\r
128 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<
\r
129 boost::errinfo_api_function("avfilter_request_frame") << boost::errinfo_errno(AVUNERROR(errn)));
\r
132 auto pic = reinterpret_cast<AVPicture*>(link->cur_buf->buf);
\r
134 safe_ptr<AVFrame> frame(avcodec_alloc_frame(), av_free);
\r
135 avcodec_get_frame_defaults(frame.get());
\r
137 for(size_t n = 0; n < 4; ++n)
\r
139 frame->data[n] = pic->data[n];
\r
140 frame->linesize[n] = pic->linesize[n];
\r
144 frame->width = link->cur_buf->video->w;
\r
145 frame->height = link->cur_buf->video->h;
\r
146 frame->format = link->cur_buf->format;
\r
147 frame->interlaced_frame = link->cur_buf->video->interlaced;
\r
148 frame->top_field_first = link->cur_buf->video->top_field_first;
\r
149 frame->key_frame = link->cur_buf->video->key_frame;
\r
155 filter::filter(const std::string& filters) : impl_(new implementation(filters)){}
\r
156 std::vector<safe_ptr<AVFrame>> filter::execute(const safe_ptr<AVFrame>& frame) {return impl_->execute(frame);}
\r