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