Cleanup: handle Filter objects by value rather than by reference.
[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 i Our id.
48  *  @param n User-visible name.
49  *  @param c User-visible category.
50  *  @param f String for a FFmpeg filter descriptor.
51  */
52 Filter::Filter (string i, string n, string c, string f)
53         : _id (i)
54         , _name (n)
55         , _category (c)
56         , _ffmpeg (f)
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         maybe_add (N_("vflip"),       _("Vertical flip"),                    _("Orientation"),     N_("vflip"));
79         maybe_add (N_("hflip"),       _("Horizontal flip"),                  _("Orientation"),     N_("hflip"));
80         maybe_add (N_("90clock"),     _("Rotate 90 degrees clockwise"),      _("Orientation"),     N_("transpose=dir=clock"));
81         maybe_add (N_("90anticlock"), _("Rotate 90 degrees anti-clockwise"), _("Orientation"),     N_("transpose=dir=cclock"));
82         maybe_add (N_("mcdeint"),     _("Motion compensating deinterlacer"), _("De-interlacing"),  N_("mcdeint"));
83         maybe_add (N_("kerndeint"),   _("Kernel deinterlacer"),              _("De-interlacing"),  N_("kerndeint"));
84         maybe_add (N_("yadif"),       _("Yet Another Deinterlacing Filter"), _("De-interlacing"),  N_("yadif"));
85         maybe_add (N_("bwdif"),       _("Bob Weaver Deinterlacing Filter"),  _("De-interlacing"),  N_("bwdif"));
86         maybe_add (N_("weave"),       _("Weave filter"),                     _("De-interlacing"),  N_("weave"));
87         maybe_add (N_("gradfun"),     _("Gradient debander"),                _("Misc"),            N_("gradfun"));
88         maybe_add (N_("unsharp"),     _("Unsharp mask and Gaussian blur"),   _("Misc"),            N_("unsharp"));
89         maybe_add (N_("denoise3d"),   _("3D denoiser"),                      _("Noise reduction"), N_("denoise3d"));
90         maybe_add (N_("hqdn3d"),      _("High quality 3D denoiser"),         _("Noise reduction"), N_("hqdn3d"));
91         maybe_add (N_("telecine"),    _("Telecine filter"),                  _("Misc"),            N_("telecine"));
92         maybe_add (N_("ow"),          _("Overcomplete wavelet denoiser"),    _("Noise reduction"), N_("mp=ow"));
93 }
94
95
96 void
97 Filter::maybe_add (string i, string n, string c, string f)
98 {
99         string check_name = f;
100         size_t end = check_name.find("=");
101         if (end != string::npos) {
102                 check_name = check_name.substr (0, end);
103         }
104
105         if (avfilter_get_by_name(check_name.c_str())) {
106                 _filters.push_back (Filter(i, n, c, f));
107         }
108 }
109
110
111 /** @param filters Set of filters.
112  *  @return String to pass to FFmpeg for the video filters.
113  */
114 string
115 Filter::ffmpeg_string(vector<Filter> const& filters)
116 {
117         string ff;
118
119         for (auto const& i: filters) {
120                 if (!ff.empty ()) {
121                         ff += N_(",");
122                 }
123                 ff += i.ffmpeg();
124         }
125
126         return ff;
127 }
128
129
130 /** @param d Our id.
131  *  @return Corresponding Filter, if found.
132  */
133 optional<Filter>
134 Filter::from_id(string id)
135 {
136         auto iter = std::find_if(_filters.begin(), _filters.end(), [id](Filter const& filter) { return filter.id() == id; });
137         if (iter == _filters.end()) {
138                 return {};
139         }
140         return *iter;
141 }
142
143
144 bool
145 operator==(Filter const& a, Filter const& b)
146 {
147         return a.id() == b.id() && a.name() == b.name() && a.category() == b.category() && a.ffmpeg() == b.ffmpeg();
148 }
149
150
151 bool
152 operator!=(Filter const& a, Filter const& b)
153 {
154         return a.id() != b.id() || a.name() != b.name() || a.category() != b.category() || a.ffmpeg() != b.ffmpeg();
155 }
156
157
158 bool
159 operator<(Filter const& a, Filter const& b)
160 {
161         if (a.id() != b.id()) {
162                 return a.id() < b.id();
163         }
164
165         if (a.name() != b.name()) {
166                 return a.name() < b.name();
167         }
168
169         if (a.category() != b.category()) {
170                 return a.category() < b.category();
171         }
172
173         return a.ffmpeg() < b.ffmpeg();
174 }