Supporters update.
[dcpomatic.git] / src / lib / filter.cc
1 /*
2     Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic 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 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 /** @file src/filter.cc
23  *  @brief A class to describe one of FFmpeg's video or audio filters.
24  */
25
26
27 #include "dcpomatic_assert.h"
28 #include "filter.h"
29 #include <dcp/warnings.h>
30 LIBDCP_DISABLE_WARNINGS
31 extern "C" {
32 #include <libavfilter/avfilter.h>
33 }
34 LIBDCP_ENABLE_WARNINGS
35 #include <algorithm>
36
37 #include "i18n.h"
38
39
40 using namespace std;
41 using boost::optional;
42
43
44 vector<Filter> Filter::_filters;
45
46
47 /** @param id Our id.
48  *  @param name User-visible name.
49  *  @param category User-visible category.
50  *  @param ffmpeg_string String for a FFmpeg filter descriptor.
51  */
52 Filter::Filter(string id, string name, string category, string ffmpeg_string)
53         : _id(id)
54         , _name(name)
55         , _category(category)
56         , _ffmpeg(ffmpeg_string)
57 {
58
59 }
60
61
62 /** @return All available filters */
63 vector<Filter>
64 Filter::all ()
65 {
66         return _filters;
67 }
68
69
70 /** Set up the static _filters vector; must be called before from_*
71  *  methods are used.
72  */
73 void
74 Filter::setup_filters ()
75 {
76         /* Note: "none" is a magic id name, so don't use it here */
77
78         auto maybe_add = [](string id, string name, string category, string ffmpeg)
79         {
80                 string check_name = ffmpeg;
81                 size_t end = check_name.find("=");
82                 if (end != string::npos) {
83                         check_name = check_name.substr(0, end);
84                 }
85
86                 if (avfilter_get_by_name(check_name.c_str())) {
87                         _filters.push_back(Filter(id, name, category, ffmpeg));
88                 }
89         };
90
91         maybe_add (N_("vflip"),       _("Vertical flip"),                    _("Orientation"),     N_("vflip"));
92         maybe_add (N_("hflip"),       _("Horizontal flip"),                  _("Orientation"),     N_("hflip"));
93         maybe_add (N_("90clock"),     _("Rotate 90 degrees clockwise"),      _("Orientation"),     N_("transpose=dir=clock"));
94         maybe_add (N_("90anticlock"), _("Rotate 90 degrees anti-clockwise"), _("Orientation"),     N_("transpose=dir=cclock"));
95         maybe_add (N_("mcdeint"),     _("Motion compensating deinterlacer"), _("De-interlacing"),  N_("mcdeint"));
96         maybe_add (N_("kerndeint"),   _("Kernel deinterlacer"),              _("De-interlacing"),  N_("kerndeint"));
97         maybe_add (N_("yadif"),       _("Yet Another Deinterlacing Filter"), _("De-interlacing"),  N_("yadif"));
98         maybe_add (N_("bwdif"),       _("Bob Weaver Deinterlacing Filter"),  _("De-interlacing"),  N_("bwdif"));
99         maybe_add (N_("weave"),       _("Weave filter"),                     _("De-interlacing"),  N_("weave"));
100         maybe_add (N_("gradfun"),     _("Gradient debander"),                _("Misc"),            N_("gradfun"));
101         maybe_add (N_("unsharp"),     _("Unsharp mask and Gaussian blur"),   _("Misc"),            N_("unsharp"));
102         maybe_add (N_("denoise3d"),   _("3D denoiser"),                      _("Noise reduction"), N_("denoise3d"));
103         maybe_add (N_("hqdn3d"),      _("High quality 3D denoiser"),         _("Noise reduction"), N_("hqdn3d"));
104         maybe_add (N_("telecine"),    _("Telecine filter"),                  _("Misc"),            N_("telecine"));
105         maybe_add (N_("ow"),          _("Overcomplete wavelet denoiser"),    _("Noise reduction"), N_("mp=ow"));
106         maybe_add (N_("premultiply"), _("Premultiply alpha channel"),        _("Misc"),            N_("premultiply=inplace=1"));
107 }
108
109
110 /** @param filters Set of filters.
111  *  @return String to pass to FFmpeg for the video filters.
112  */
113 string
114 Filter::ffmpeg_string(vector<Filter> const& filters)
115 {
116         string ff;
117
118         for (auto const& i: filters) {
119                 if (!ff.empty ()) {
120                         ff += N_(",");
121                 }
122                 ff += i.ffmpeg();
123         }
124
125         return ff;
126 }
127
128
129 /** @param d Our id.
130  *  @return Corresponding Filter, if found.
131  */
132 optional<Filter>
133 Filter::from_id(string id)
134 {
135         auto iter = std::find_if(_filters.begin(), _filters.end(), [id](Filter const& filter) { return filter.id() == id; });
136         if (iter == _filters.end()) {
137                 return {};
138         }
139         return *iter;
140 }
141
142
143 bool
144 operator==(Filter const& a, Filter const& b)
145 {
146         return a.id() == b.id() && a.name() == b.name() && a.category() == b.category() && a.ffmpeg() == b.ffmpeg();
147 }
148
149
150 bool
151 operator!=(Filter const& a, Filter const& b)
152 {
153         return a.id() != b.id() || a.name() != b.name() || a.category() != b.category() || a.ffmpeg() != b.ffmpeg();
154 }
155
156
157 bool
158 operator<(Filter const& a, Filter const& b)
159 {
160         if (a.id() != b.id()) {
161                 return a.id() < b.id();
162         }
163
164         if (a.name() != b.name()) {
165                 return a.name() < b.name();
166         }
167
168         if (a.category() != b.category()) {
169                 return a.category() < b.category();
170         }
171
172         return a.ffmpeg() < b.ffmpeg();
173 }