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