1 /*****************************************************************************
2 
3         Primaries.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 "fmtcavs/CpuOpt.h"
29 #include "fmtcavs/fnc.h"
30 #include "fmtcavs/function_names.h"
31 #include "fmtcavs/Primaries.h"
32 #include "fmtcl/fnc.h"
33 #include "fmtcl/PrimUtil.h"
34 #include "fstb/fnc.h"
35 
36 #include <array>
37 
38 #include <cassert>
39 
40 
41 
42 namespace fmtcavs
43 {
44 
45 
46 
47 /*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
48 
49 
50 
Primaries(::IScriptEnvironment & env,const::AVSValue & args)51 Primaries::Primaries (::IScriptEnvironment &env, const ::AVSValue &args)
52 :	Inherited (env, args [Param_CLIP_SRC].AsClip ())
53 ,	_clip_src_sptr (args [Param_CLIP_SRC].AsClip ())
54 ,	_vi_src (vi)
55 {
56 	const CpuOpt   cpu_opt (args [Param_CPUOPT]);
57 	_sse_flag  = cpu_opt.has_sse ();
58 	_sse2_flag = cpu_opt.has_sse2 ();
59 	_avx_flag  = cpu_opt.has_avx ();
60 	_avx2_flag = cpu_opt.has_avx2 ();
61 
62 	_proc_uptr = std::unique_ptr <fmtcl::MatrixProc> (new fmtcl::MatrixProc (
63 		_sse_flag, _sse2_flag, _avx_flag, _avx2_flag
64 	));
65 
66 	// Checks the input clip
67 	const FmtAvs   fmt_src (vi);
68 	if (! fmt_src.is_planar ())
69 	{
70 		env.ThrowError (fmtcavs_PRIMARIES ": input must be planar.");
71 	}
72 	const auto     col_fam = fmt_src.get_col_fam ();
73 	if (col_fam != fmtcl::ColorFamily_RGB)
74 	{
75 		env.ThrowError (
76 			fmtcavs_PRIMARIES ": colorspace must be RGB (assumed linear)."
77 		);
78 	}
79 	const auto     res      = fmt_src.get_bitdepth ();
80 	const bool     flt_flag = fmt_src.is_float ();
81 	if (   (! flt_flag && res != 16)
82 	    || (  flt_flag && res != 32))
83 	{
84 		env.ThrowError (fmtcavs_PRIMARIES
85 			": pixel bitdepth not supported, "
86 			"clip must be 16-bit integer or 32-bit float."
87 		);
88 	}
89 	assert (fmt_src.get_subspl_h () == 0 && fmt_src.get_subspl_v () == 0);
90 	assert (fmt_src.get_nbr_comp_non_alpha () == _nbr_planes_proc);
91 
92 	// Destination format
93 	const auto     fmt_dst = fmt_src;
94 
95 	// Alpha plane processing, if any
96 	_proc_alpha_uptr = std::make_unique <fmtcavs::ProcAlpha> (
97 		fmt_dst, fmt_src, vi.width, vi.height, cpu_opt
98 	);
99 
100 	// Primaries
101 	init (_prim_s, env, args, Param_PRIMS);
102 	init (_prim_s, env, args, Param_RS, Param_GS, Param_BS, Param_WS);
103 	if (! _prim_s.is_ready ())
104 	{
105 		env.ThrowError (fmtcavs_PRIMARIES ": input primaries not set.");
106 	}
107 
108 	_prim_d = _prim_s;
109 	init (_prim_d, env, args, Param_PRIMD);
110 	init (_prim_d, env, args, Param_RD, Param_GD, Param_BD, Param_WD);
111 	assert (_prim_d.is_ready ());
112 
113 	const fmtcl::Mat3 mat_conv =
114 		fmtcl::PrimUtil::compute_conversion_matrix (_prim_s, _prim_d);
115 	_mat_main.insert3 (mat_conv);
116 	_mat_main.clean3 (1);
117 
118 	prepare_matrix_coef (
119 		env, *_proc_uptr, _mat_main,
120 		fmt_dst, true,
121 		fmt_src, true,
122 		fmtcl::ColorSpaceH265_RGB, -1
123 	);
124 }
125 
126 
127 
GetFrame(int n,::IScriptEnvironment * env_ptr)128 ::PVideoFrame __stdcall	Primaries::GetFrame (int n, ::IScriptEnvironment *env_ptr)
129 {
130 	::PVideoFrame  src_sptr = _clip_src_sptr->GetFrame (n, env_ptr);
131 	::PVideoFrame	dst_sptr = build_new_frame (*env_ptr, vi, &src_sptr);
132 
133 	const auto     pa { build_mat_proc (vi, dst_sptr, _vi_src, src_sptr) };
134 	_proc_uptr->process (pa);
135 
136 	// Alpha plane now
137 	_proc_alpha_uptr->process_plane (dst_sptr, src_sptr);
138 
139 	// Frame properties
140 	if (supports_props ())
141 	{
142 		::AVSMap *     props_ptr = env_ptr->getFramePropsRW (dst_sptr);
143 
144 		const fmtcl::PrimariesPreset  preset_d = _prim_d._preset;
145 		if (preset_d >= 0 && preset_d < fmtcl::PrimariesPreset_NBR_ELT)
146 		{
147 			env_ptr->propSetInt (
148 				props_ptr, "_Primaries", int (preset_d), ::PROPAPPENDMODE_REPLACE
149 			);
150 		}
151 		else
152 		{
153 			env_ptr->propDeleteKey (props_ptr, "_Primaries");
154 		}
155 	}
156 
157 	return dst_sptr;
158 }
159 
160 
161 
162 /*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
163 
164 
165 
166 /*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
167 
168 
169 
170 constexpr int	Primaries::_nbr_planes_proc;
171 
172 
173 
init(fmtcl::RgbSystem & prim,::IScriptEnvironment & env,const::AVSValue & args,Param preset)174 void	Primaries::init (fmtcl::RgbSystem &prim, ::IScriptEnvironment &env, const ::AVSValue &args, Param preset)
175 {
176 	assert (preset >= 0);
177 	assert (preset < Param_NBR_ELT);
178 
179 	std::string    preset_str = args [preset].AsString ("");
180 	fstb::conv_to_lower_case (preset_str);
181 	prim._preset = fmtcl::PrimUtil::conv_string_to_primaries (preset_str);
182 	if (prim._preset == fmtcl::PrimariesPreset_INVALID)
183 	{
184 		env.ThrowError (fmtcavs_PRIMARIES ": invalid preset name.");
185 	}
186 	else if (prim._preset >= 0)
187 	{
188 		prim.set (prim._preset);
189 	}
190 }
191 
192 
193 
init(fmtcl::RgbSystem & prim,::IScriptEnvironment & env,const::AVSValue & args,Param pr,Param pg,Param pb,Param pw)194 void	Primaries::init (fmtcl::RgbSystem &prim, ::IScriptEnvironment &env, const ::AVSValue &args, Param pr, Param pg, Param pb, Param pw)
195 {
196 	assert (pr >= 0);
197 	assert (pr < Param_NBR_ELT);
198 	assert (pg >= 0);
199 	assert (pg < Param_NBR_ELT);
200 	assert (pb >= 0);
201 	assert (pb < Param_NBR_ELT);
202 	assert (pw >= 0);
203 	assert (pw < Param_NBR_ELT);
204 
205 	const bool     ready_old_flag = prim.is_ready ();
206 	std::array <fmtcl::RgbSystem::Vec2, _nbr_planes_proc> rgb_old = prim._rgb;
207 	fmtcl::RgbSystem::Vec2  w_old = prim._white;
208 
209 	const std::array <Param, _nbr_planes_proc> param_arr { pr, pg, pb };
210 	for (int k = 0; k < _nbr_planes_proc; ++k)
211 	{
212 		prim._init_flag_arr [k] |=
213 			read_coord_tuple (prim._rgb [k], env, args, param_arr [k]);
214 	}
215 
216 	prim._init_flag_arr [_nbr_planes_proc] |=
217 		read_coord_tuple (prim._white, env, args, pw);
218 
219 	if (   ready_old_flag && prim.is_ready ()
220 	    && (rgb_old != prim._rgb || w_old != prim._white))
221 	{
222 		prim._preset = fmtcl::PrimariesPreset_UNDEF;
223 	}
224 }
225 
226 
227 
read_coord_tuple(fmtcl::RgbSystem::Vec2 & c,::IScriptEnvironment & env,const::AVSValue & args,Param p)228 bool	Primaries::read_coord_tuple (fmtcl::RgbSystem::Vec2 &c, ::IScriptEnvironment &env, const ::AVSValue &args, Param p)
229 {
230 	bool           set_flag = false;
231 
232 	auto           c_v = extract_array_f (env, args [p], fmtcavs_PRIMARIES);
233 	if (! c_v.empty ())
234 	{
235 		if (c_v.size () != c.size ())
236 		{
237 			env.ThrowError (fmtcavs_PRIMARIES
238 				": wrong number of coordinates (expected x and y)."
239 			);
240 		}
241 		for (size_t k = 0; k < c_v.size (); ++k)
242 		{
243 			c [k] = c_v [k];
244 		}
245 		if (c [1] == 0)
246 		{
247 			env.ThrowError (
248 				fmtcavs_PRIMARIES ": y coordinate cannot be 0."
249 			);
250 		}
251 
252 		set_flag = true;
253 	}
254 
255 	return set_flag;
256 }
257 
258 
259 
260 }  // namespace fmtcavs
261 
262 
263 
264 /*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
265