1 /*****************************************************************************
2
3 fnc_fmtcavs.cpp
4 Author: Laurent de Soras, 2021
5
6 --- Legal stuff ---
7
8 This program is free software. It comes without any warranty, to
9 the extent permitted by applicable law. You can redistribute it
10 and/or modify it under the terms of the Do What The Fuck You Want
11 To Public License, Version 2, as published by Sam Hocevar. See
12 http://www.wtfpl.net/ for more details.
13
14 *Tab=3***********************************************************************/
15
16
17
18 #if defined (_MSC_VER)
19 #pragma warning (1 : 4130 4223 4705 4706)
20 #pragma warning (4 : 4355 4786 4800)
21 #endif
22
23
24
25 /*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
26
27 #include "avsutl/CsPlane.h"
28 #include "avsutl/fnc.h"
29 #include "avsutl/PlaneProcessor.h"
30 #include "fmtcavs/FmtAvs.h"
31 #include "fmtcavs/fnc.h"
32 #include "fmtcl/fnc.h"
33 #include "fmtcl/MatrixProc.h"
34 #include "fstb/fnc.h"
35 #include "avisynth.h"
36
37 #include <algorithm>
38
39 #include <cassert>
40
41
42
43 namespace fmtcavs
44 {
45
46
47
48 /*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
49
50
51
52 template <typename T, typename FT, typename FR>
extract_array_any(::IScriptEnvironment & env,const::AVSValue & arg,const char * filter_and_arg_0,const char * typename_0,FT fnc_test,FR fnc_read)53 std::vector <T> extract_array_any (::IScriptEnvironment &env, const ::AVSValue &arg, const char *filter_and_arg_0, const char *typename_0, FT fnc_test, FR fnc_read)
54 {
55 std::vector <T> val_arr;
56
57 if (arg.Defined ())
58 {
59 if (arg.IsString ())
60 {
61 val_arr = fmtcl::conv_str_to_arr <T> (arg.AsString (""));
62 }
63
64 else if (arg.IsArray ())
65 {
66 if (arg.ArraySize () == 1 && arg [0].IsString ())
67 {
68 val_arr = fmtcl::conv_str_to_arr <T> (arg [0].AsString (""));
69 }
70
71 else
72 {
73 const int sz = arg.ArraySize ();
74 for (int k = 0; k < sz; ++k)
75 {
76 const ::AVSValue & elt = arg [k];
77 if (! fnc_test (elt))
78 {
79 env.ThrowError (
80 "%s: element %d (base 0) should be a %s.",
81 filter_and_arg_0, k, typename_0
82 );
83 }
84 val_arr.push_back (fnc_read (elt));
85 }
86 }
87 }
88
89 else if (fnc_test (arg))
90 {
91 val_arr.push_back (fnc_read (arg));
92 }
93
94 else
95 {
96 env.ThrowError (
97 "%s: unexpected type. Should be a string or an array of float.",
98 filter_and_arg_0
99 );
100 }
101 }
102
103 return val_arr;
104 }
105
106
107
108 /*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
109
110
111
conv_fmtavs_to_picfmt(const FmtAvs & fmt,bool full_flag)112 fmtcl::PicFmt conv_fmtavs_to_picfmt (const FmtAvs &fmt, bool full_flag)
113 {
114 assert (fmt.is_valid ());
115
116 fmtcl::PicFmt pic_fmt;
117 pic_fmt._sf = conv_bitdepth_to_splfmt (fmt.get_bitdepth ());
118 pic_fmt._res = fmt.get_bitdepth ();
119 pic_fmt._col_fam = fmt.get_col_fam ();
120 pic_fmt._full_flag = full_flag;
121
122 return pic_fmt;
123 }
124
125
126
conv_vi_to_splfmt(const::VideoInfo & vi)127 fmtcl::SplFmt conv_vi_to_splfmt (const ::VideoInfo &vi)
128 {
129 fmtcl::SplFmt type = fmtcl::SplFmt_ILLEGAL;
130 int bitdepth = 0;
131
132 conv_vi_to_splfmt (type, bitdepth, vi);
133 assert (type != fmtcl::SplFmt_ILLEGAL);
134
135 return type;
136 }
137
138
139
conv_vi_to_splfmt(fmtcl::SplFmt & type,int & bitdepth,const::VideoInfo & vi)140 void conv_vi_to_splfmt (fmtcl::SplFmt &type, int &bitdepth, const ::VideoInfo &vi)
141 {
142 bitdepth = vi.BitsPerComponent ();
143 type = conv_bitdepth_to_splfmt (bitdepth);
144 }
145
146
147
conv_bitdepth_to_splfmt(int bitdepth)148 fmtcl::SplFmt conv_bitdepth_to_splfmt (int bitdepth)
149 {
150 fmtcl::SplFmt type = fmtcl::SplFmt_ILLEGAL;
151
152 if (bitdepth == 32)
153 {
154 type = fmtcl::SplFmt_FLOAT;
155 }
156 else
157 {
158 if (bitdepth > 8 && bitdepth <= 16)
159 {
160 type = fmtcl::SplFmt_INT16;
161 }
162 else if (bitdepth <= 8)
163 {
164 type = fmtcl::SplFmt_INT8;
165 }
166 }
167
168 return type;
169 }
170
171
172
conv_vi_to_colfam(const::VideoInfo & vi)173 fmtcl::ColorFamily conv_vi_to_colfam (const ::VideoInfo &vi)
174 {
175 auto col_fam = fmtcl::ColorFamily_INVALID;
176
177 if (vi.IsY ())
178 {
179 col_fam = fmtcl::ColorFamily_GRAY;
180 }
181 else if (avsutl::is_rgb (vi))
182 {
183 col_fam = fmtcl::ColorFamily_RGB;
184 }
185 else if (vi.IsYUV () || vi.IsYUVA ())
186 {
187 col_fam = fmtcl::ColorFamily_YUV;
188 }
189
190 return col_fam;
191 }
192
193
194
conv_str_to_colfam(std::string str)195 fmtcl::ColorFamily conv_str_to_colfam (std::string str)
196 {
197 fstb::conv_to_lower_case (str);
198
199 auto col_fam = fmtcl::ColorFamily_INVALID;
200
201 if (str == "y" || str == "grey" || str == "gray")
202 {
203 col_fam = fmtcl::ColorFamily_GRAY;
204 }
205 else if (str == "rgb")
206 {
207 col_fam = fmtcl::ColorFamily_RGB;
208 }
209 else if (str == "yuv")
210 {
211 col_fam = fmtcl::ColorFamily_YUV;
212 }
213
214 return col_fam;
215 }
216
217
218
219 // plane_out < 0: all planes are selected for output
prepare_matrix_coef(::IScriptEnvironment & env,fmtcl::MatrixProc & mat_proc,const fmtcl::Mat4 & mat_main,const FmtAvs & fmt_dst,bool full_range_dst_flag,const FmtAvs & fmt_src,bool full_range_src_flag,fmtcl::ColorSpaceH265 csp_out,int plane_out)220 void prepare_matrix_coef (::IScriptEnvironment &env, fmtcl::MatrixProc &mat_proc, const fmtcl::Mat4 &mat_main, const FmtAvs &fmt_dst, bool full_range_dst_flag, const FmtAvs &fmt_src, bool full_range_src_flag, fmtcl::ColorSpaceH265 csp_out, int plane_out)
221 {
222 const fmtcl::PicFmt fmt_src_fmtcl =
223 conv_fmtavs_to_picfmt (fmt_src, full_range_src_flag);
224 const fmtcl::PicFmt fmt_dst_fmtcl =
225 conv_fmtavs_to_picfmt (fmt_dst, full_range_dst_flag);
226
227 const int ret_val = fmtcl::prepare_matrix_coef (
228 mat_proc, mat_main, fmt_dst_fmtcl, fmt_src_fmtcl, csp_out, plane_out
229 );
230
231 if (ret_val != fmtcl::MatrixProc::Err_OK)
232 {
233 if (ret_val == fmtcl::MatrixProc::Err_POSSIBLE_OVERFLOW)
234 {
235 env.ThrowError (
236 "One of the matrix coefficients could cause an overflow."
237 );
238 }
239 else if (ret_val == fmtcl::MatrixProc::Err_TOO_BIG_COEF)
240 {
241 env.ThrowError (
242 "Too big matrix coefficient."
243 );
244 }
245 else if (ret_val == fmtcl::MatrixProc::Err_INVALID_FORMAT_COMBINATION)
246 {
247 env.ThrowError (
248 "Invalid frame format combination."
249 );
250 }
251 else
252 {
253 assert (false);
254 env.ThrowError (
255 "Unidentified error while building the matrix."
256 );
257 }
258 }
259 }
260
261
262
build_mat_proc(const::VideoInfo & vi_dst,const::PVideoFrame & dst_sptr,const::VideoInfo & vi_src,const::PVideoFrame & src_sptr,bool single_plane_flag)263 fmtcl::ProcComp3Arg build_mat_proc (const ::VideoInfo &vi_dst, const ::PVideoFrame &dst_sptr, const ::VideoInfo &vi_src, const ::PVideoFrame &src_sptr, bool single_plane_flag)
264 {
265 fmtcl::ProcComp3Arg pa;
266 pa._w = vi_dst.width;
267 pa._h = vi_dst.height;
268
269 const int nbr_active_planes = std::min <int> (
270 fmtcl::ProcComp3Arg::_nbr_planes,
271 avsutl::get_nbr_comp_non_alpha (vi_src)
272 );
273 assert (nbr_active_planes == 1 || nbr_active_planes == 3);
274
275 for (int p_idx = 0; p_idx < nbr_active_planes; ++p_idx)
276 {
277 if (! single_plane_flag || p_idx == 0)
278 {
279 const int pd = avsutl::CsPlane::get_plane_id (p_idx, vi_dst);
280 pa._dst [p_idx]._ptr = dst_sptr->GetWritePtr (pd);
281 pa._dst [p_idx]._stride = dst_sptr->GetPitch (pd);
282 }
283 const int ps = avsutl::CsPlane::get_plane_id (p_idx, vi_src);
284 pa._src [p_idx]._ptr = src_sptr->GetReadPtr (ps);
285 pa._src [p_idx]._stride = src_sptr->GetPitch (ps);
286 }
287
288 return pa;
289 }
290
291
292
293 // For ".+" and ".*" arguments
294 // Assumes the argument is not defined if the array is empty.
is_array_defined(const::AVSValue & arg)295 bool is_array_defined (const ::AVSValue &arg)
296 {
297 return (
298 arg.Defined ()
299 && ( ! arg.IsArray ()
300 || (arg.ArraySize () > 0 && arg [0].Defined ()))
301 );
302 }
303
304
305
extract_array_f(::IScriptEnvironment & env,const::AVSValue & arg,const char * filter_and_arg_0,double def_val)306 std::vector <double> extract_array_f (::IScriptEnvironment &env, const ::AVSValue &arg, const char *filter_and_arg_0, double def_val)
307 {
308 return extract_array_any <double> (env, arg, filter_and_arg_0, "float",
309 [ ] (const ::AVSValue &elt) { return elt.IsFloat (); },
310 [def_val] (const ::AVSValue &elt) { return elt.AsFloat (float (def_val)); }
311 );
312 }
313
314
315
extract_array_i(::IScriptEnvironment & env,const::AVSValue & arg,const char * filter_and_arg_0,int def_val)316 std::vector <int> extract_array_i (::IScriptEnvironment &env, const ::AVSValue &arg, const char *filter_and_arg_0, int def_val)
317 {
318 return extract_array_any <int> (env, arg, filter_and_arg_0, "int",
319 [ ] (const ::AVSValue &elt) { return elt.IsInt (); },
320 [def_val] (const ::AVSValue &elt) { return elt.AsInt (def_val); }
321 );
322 }
323
324
325
extract_array_b(::IScriptEnvironment & env,const::AVSValue & arg,const char * filter_and_arg_0,bool def_val)326 std::vector <bool> extract_array_b (::IScriptEnvironment &env, const ::AVSValue &arg, const char *filter_and_arg_0, bool def_val)
327 {
328 return extract_array_any <bool> (env, arg, filter_and_arg_0, "bool",
329 [ ] (const ::AVSValue &elt) { return elt.IsBool (); },
330 [def_val] (const ::AVSValue &elt) { return elt.AsBool (def_val); }
331 );
332 }
333
334
335
extract_array_s(::IScriptEnvironment & env,const::AVSValue & arg,const char * filter_and_arg_0,std::string def_val)336 std::vector <std::string> extract_array_s (::IScriptEnvironment &env, const ::AVSValue &arg, const char *filter_and_arg_0, std::string def_val)
337 {
338 return extract_array_any <std::string> (env, arg, filter_and_arg_0, "string",
339 [ ] (const ::AVSValue &elt) { return elt.IsString (); },
340 [def_val] (const ::AVSValue &elt) { return elt.AsString (def_val.c_str ()); }
341 );
342 }
343
344
345
set_masktools_planes_param(avsutl::PlaneProcessor & pp,::IScriptEnvironment & env,const::AVSValue & arg,const char * filter_and_arg_0,double def_val)346 void set_masktools_planes_param (avsutl::PlaneProcessor &pp, ::IScriptEnvironment &env, const ::AVSValue &arg, const char *filter_and_arg_0, double def_val)
347 {
348 if (arg.IsString ())
349 {
350 pp.set_proc_mode (arg.AsString ("all"));
351 }
352 else
353 {
354 const auto plist =
355 extract_array_f (env, arg, filter_and_arg_0, def_val);
356 const auto nbr_planes = pp.get_nbr_planes ();
357 for (int p_idx = 0; p_idx < nbr_planes; ++p_idx)
358 {
359 const auto mode = fmtcl::get_arr_elt (plist, p_idx, def_val);
360 pp.set_proc_mode (p_idx, mode);
361 }
362 }
363 }
364
365
366
367 } // namespace fmtcavs
368
369
370
371 /*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
372