]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/filter/filter.cpp
set svn:eol-style native on .h and .cpp files
[casparcg] / modules / ffmpeg / producer / filter / filter.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21
22 #include "../../stdafx.h"
23
24 #include "filter.h"
25
26 #include "parallel_yadif.h"
27
28 #include "../../ffmpeg_error.h"
29
30 #include <common/except.h>
31
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>
38
39 #include <cstdio>
40 #include <sstream>
41
42 #if defined(_MSC_VER)
43 #pragma warning (push)
44 #pragma warning (disable : 4244)
45 #endif
46 extern "C" 
47 {
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>
55 }
56 #if defined(_MSC_VER)
57 #pragma warning (pop)
58 #endif
59
60
61 namespace caspar { namespace ffmpeg {
62
63 static int query_formats_444(AVFilterContext *ctx)
64 {
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));
67     return 0;
68 }
69
70 static int query_formats_422(AVFilterContext *ctx)
71 {
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));
74     return 0;
75 }
76
77 static int query_formats_420(AVFilterContext *ctx)
78 {
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));
81     return 0;
82 }
83
84 static int query_formats_420a(AVFilterContext *ctx)
85 {
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));
88     return 0;
89 }
90
91 static int query_formats_411(AVFilterContext *ctx)
92 {
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));
95     return 0;
96 }
97
98 static int query_formats_410(AVFilterContext *ctx)
99 {
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));
102     return 0;
103 }
104
105 struct filter::impl
106 {
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_;
114                 
115         impl(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) 
116                 : filters_(filters)
117                 , parallel_yadif_ctx_(nullptr)
118                 , pix_fmts_(pix_fmts)
119         {
120                 if(pix_fmts_.empty())
121                 {
122                         pix_fmts_ = boost::assign::list_of
123                                 (PIX_FMT_YUVA420P)
124                                 (PIX_FMT_YUV444P)
125                                 (PIX_FMT_YUV422P)
126                                 (PIX_FMT_YUV420P)
127                                 (PIX_FMT_YUV411P)
128                                 (PIX_FMT_BGRA)
129                                 (PIX_FMT_ARGB)
130                                 (PIX_FMT_RGBA)
131                                 (PIX_FMT_ABGR)
132                                 (PIX_FMT_GRAY8);
133                 }
134                 
135                 pix_fmts_.push_back(PIX_FMT_NONE);
136         }
137         
138         void push(const std::shared_ptr<AVFrame>& frame)
139         {               
140                 if(!frame)
141                         return;
142
143                 if(frame->data[0] == nullptr || frame->width < 1)
144                         CASPAR_THROW_EXCEPTION(invalid_argument());
145
146                 if(filters_.empty())
147                 {
148                         bypass_.push(spl::make_shared_ptr(frame));
149                         return;
150                 }
151                 
152                 try
153                 {
154                         if(!graph_)
155                         {
156                                 try
157                                 {
158                                         graph_.reset(avfilter_graph_alloc(), [](AVFilterGraph* p){avfilter_graph_free(&p);});
159                                                                 
160                                         // Input
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]");
164                                         
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]");
167                                 #else
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]");                            
171                                 #endif
172                                         AVFilterInOut* inputs  = avfilter_inout_alloc();
173                                         AVFilterInOut* outputs = avfilter_inout_alloc();
174                                                                 
175                                         outputs->name                   = av_strdup("in");
176                                         outputs->filter_ctx             = buffersrc_ctx_;
177                                         outputs->pad_idx                = 0;
178                                         outputs->next                   = nullptr;
179
180                                         inputs->name                    = av_strdup("out");
181                                         inputs->filter_ctx              = buffersink_ctx_;
182                                         inputs->pad_idx                 = 0;
183                                         inputs->next                    = nullptr;
184                         
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]");
187                         
188                                         auto yadif_filter = boost::adaptors::filtered([&](AVFilterContext* p){return strstr(p->name, "yadif") != 0;});
189
190                                         BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter)
191                                         {
192                                                 // Don't trust that libavfilter chooses optimal format.
193                                                 filter_ctx->filter->query_formats = [&]() -> int (*)(AVFilterContext*)
194                                                 {
195                                                         switch(frame->format)
196                                                         {
197                                                         case PIX_FMT_YUV444P16: 
198                                                         case PIX_FMT_YUV444P10: 
199                                                         case PIX_FMT_YUV444P9:          
200                                                         case PIX_FMT_YUV444P:   
201                                                         case PIX_FMT_BGR24:             
202                                                         case PIX_FMT_RGB24:     
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:  
217                                                         case PIX_FMT_BGRA:              
218                                                         case PIX_FMT_RGBA:              
219                                                         case PIX_FMT_ABGR:              
220                                                         case PIX_FMT_ARGB:              
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;
227                                                         default:                                
228                                                                 return filter_ctx->filter->query_formats;
229                                                         }
230                                                 }();
231                                         }
232                                         
233                                         THROW_ON_ERROR2(avfilter_graph_config(graph_.get(), NULL), "[filter]"); 
234                                         
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);                                          
237                                 }
238                                 catch(...)
239                                 {
240                                         graph_ = nullptr;
241                                         throw;
242                                 }
243                         }
244                 
245                         THROW_ON_ERROR2(av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0), "[filter]");
246                 }
247                 catch(ffmpeg_error&)
248                 {
249                         throw;
250                 }
251                 catch(...)
252                 {
253                         CASPAR_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));
254                 }
255         }
256
257         std::shared_ptr<AVFrame> poll()
258         {
259                 if(filters_.empty())
260                 {
261                         if(bypass_.empty())
262                                 return nullptr;
263                         auto frame = bypass_.front();
264                         bypass_.pop();
265                         return frame;
266                 }
267
268                 if(!graph_)
269                         return nullptr;
270                 
271                 try
272                 {
273                         if(avfilter_poll_frame(buffersink_ctx_->inputs[0])) 
274                         {
275                                 AVFilterBufferRef *picref;
276                                 THROW_ON_ERROR2(av_buffersink_get_buffer_ref(buffersink_ctx_, &picref, 0), "[filter]");
277
278                                 if (!picref) 
279                                         return nullptr;
280                                 
281                                 spl::shared_ptr<AVFrame> frame(avcodec_alloc_frame(), [=](AVFrame* p)
282                                 {
283                                         av_free(p);
284                                         avfilter_unref_buffer(picref);
285                                 });
286
287                                 avcodec_get_frame_defaults(frame.get());        
288
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;
300                                         
301                                 return frame;                           
302                         }
303
304                         return nullptr;
305                 }
306                 catch(ffmpeg_error&)
307                 {
308                         throw;
309                 }
310                 catch(...)
311                 {
312                         CASPAR_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));
313                 }
314         }
315 };
316
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()
324 {       
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));
328         return frames;
329 }
330
331 }}