1 /*****************************************************************************
2 
3         Bitdepth.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/fnc.h"
28 #include "fmtcavs/FmtAvs.h"
29 #include "fmtcavs/Bitdepth.h"
30 #include "fmtcavs/CpuOpt.h"
31 #include "fmtcavs/fnc.h"
32 #include "fmtcavs/function_names.h"
33 
34 #include <cassert>
35 
36 
37 
38 namespace fmtcavs
39 {
40 
41 
42 
43 /*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
44 
45 
46 
Bitdepth(::IScriptEnvironment & env,const::AVSValue & args)47 Bitdepth::Bitdepth (::IScriptEnvironment &env, const ::AVSValue &args)
48 :	Inherited (env, args [Param_CLIP_SRC].AsClip ())
49 ,	_clip_src_sptr (args [Param_CLIP_SRC].AsClip ())
50 ,	_vi_src (vi)
51 {
52 	const CpuOpt   cpu_opt (args [Param_CPUOPT]);
53 	const bool     sse2_flag = cpu_opt.has_sse2 ();
54 	const bool     avx2_flag = cpu_opt.has_avx2 ();
55 
56 	if (! _vi_src.IsPlanar ())
57 	{
58 		env.ThrowError (fmtcavs_BITDEPTH ": input must be planar.");
59 	}
60 
61 	// Guess the output format if incomplete
62 	const FmtAvs   fmt_src (_vi_src);
63 	int            res      = args [Param_BITS].AsInt (-1);
64 	const auto &   arg_flt  = args [Param_FLT];
65 	bool           flt_flag = arg_flt.AsBool ();
66 	if (arg_flt.Defined ())
67 	{
68 		if (res < 0 && flt_flag)
69 		{
70 			res = 32;
71 		}
72 	}
73 	else
74 	{
75 		flt_flag = (res == 32);
76 	}
77 	if (res < 0)
78 	{
79 		res = _vi_src.BitsPerComponent ();
80 	}
81 
82 	// Checks the output format
83 	if (! (   (! flt_flag && (   res ==  8
84 	                          || res == 10
85 	                          || res == 12
86 	                          || res == 16))
87 	       || (  flt_flag &&     res == 32 )))
88 	{
89 		env.ThrowError (
90 			fmtcavs_BITDEPTH ": output pixel bitdepth not supported."
91 		);
92 	}
93 
94 	// Builds and validates the output format
95 	auto           fmt_dst = fmt_src;
96 	fmt_dst.set_bitdepth (res);
97 	if (fmt_dst.conv_to_vi (vi) != 0)
98 	{
99 		env.ThrowError (fmtcavs_BITDEPTH ": illegal output colorspace.");
100 	}
101 
102 	// Conversion-related things
103 	_fulls_flag     =
104 		args [Param_FULLS].AsBool (avsutl::is_full_range_default (_vi_src));
105 	_fulld_flag     = args [Param_FULLD].AsBool (_fulls_flag);
106 	_range_def_flag =
107 		(args [Param_FULLS].Defined () || args [Param_FULLD].Defined ());
108 
109 	// Configures the plane processor
110 	_plane_proc_uptr =
111 		std::make_unique <avsutl::PlaneProcessor> (vi, *this, false);
112 	_plane_proc_uptr->set_clip_info (
113 		avsutl::PlaneProcessor::ClipIdx_SRC1, _clip_src_sptr
114 	);
115 	_plane_proc_uptr->set_proc_mode (args [Param_PLANES].AsString ("all"));
116 
117 	// Dithering parameters
118 	auto           dmode = static_cast <fmtcl::Dither::DMode> (
119 		args [Param_DMODE].AsInt (fmtcl::Dither::DMode_FILTERLITE)
120 	);
121 	if (dmode == fmtcl::Dither::DMode_ROUND_ALIAS)
122 	{
123 		dmode = fmtcl::Dither::DMode_ROUND;
124 	}
125 	if (   dmode <  0
126 	    || (dmode & 0xFFFF) >= fmtcl::Dither::DMode_NBR_ELT)
127 	{
128 		env.ThrowError (fmtcavs_BITDEPTH ": invalid dmode.");
129 	}
130 
131 	const double   ampo = args [Param_AMPO].AsFloat (1.0);
132 	if (ampo < 0)
133 	{
134 		env.ThrowError (fmtcavs_BITDEPTH ": ampo cannot be negative.");
135 	}
136 
137 	const double   ampn = args [Param_AMPN].AsFloat (0.0);
138 	if (ampn < 0)
139 	{
140 		env.ThrowError (fmtcavs_BITDEPTH ": ampn cannot be negative.");
141 	}
142 
143 	const int      pat_size = args [Param_PATSIZE].AsInt (32);
144 	if (   pat_size < 4
145 	    || pat_size > fmtcl::Dither::_pat_max_size
146 	    || ! fstb::is_pow_2 (pat_size))
147 	{
148 		env.ThrowError (fmtcavs_BITDEPTH ": wrong value for patsize.");
149 	}
150 
151 	const bool     dyn_flag          = args [Param_DYN        ].AsBool (false);
152 	const bool     static_noise_flag = args [Param_STATICNOISE].AsBool (false);
153 	const bool     tpdfo_flag        = args [Param_TPDFO      ].AsBool (false);
154 	const bool     tpdfn_flag        = args [Param_TPDFN      ].AsBool (false);
155 	const bool     corplane_flag     = args [Param_CORPLANE   ].AsBool (false);
156 
157 	// Finally...
158 	const int      nbr_planes = vi.NumComponents ();
159 	int            res_src;
160 	fmtcl::SplFmt  splfmt_src;
161 	conv_vi_to_splfmt (splfmt_src, res_src, _vi_src);
162 	fmtcl::SplFmt  splfmt_dst = conv_vi_to_splfmt (vi);
163 	fmtcl::ColorFamily   col_fam = conv_vi_to_colfam (vi);
164 
165 	_engine_uptr = std::make_unique <fmtcl::Dither> (
166 		splfmt_src, res_src, _fulls_flag,
167 		splfmt_dst, res    , _fulld_flag,
168 		col_fam, nbr_planes, vi.width,
169 		dmode, pat_size, ampo, ampn,
170 		dyn_flag, static_noise_flag, corplane_flag,
171 		tpdfo_flag, tpdfn_flag,
172 		sse2_flag, avx2_flag
173 	);
174 }
175 
176 
177 
GetFrame(int n,::IScriptEnvironment * env_ptr)178 ::PVideoFrame __stdcall	Bitdepth::GetFrame (int n, ::IScriptEnvironment *env_ptr)
179 {
180 	::PVideoFrame  src_sptr = _clip_src_sptr->GetFrame (n, env_ptr);
181 	::PVideoFrame	dst_sptr = build_new_frame (*env_ptr, vi, &src_sptr);
182 
183 	_plane_proc_uptr->process_frame (dst_sptr, n, *env_ptr, nullptr);
184 
185 	// Frame properties
186 	if (supports_props ())
187 	{
188 		::AVSMap *     props_ptr = env_ptr->getFramePropsRW (dst_sptr);
189 
190 		if (_range_def_flag)
191 		{
192 			const int      cr_val = (_fulld_flag) ? 0 : 1;
193 			env_ptr->propSetInt (
194 				props_ptr, "_ColorRange", cr_val, ::PROPAPPENDMODE_REPLACE
195 			);
196 		}
197 	}
198 
199 	return dst_sptr;
200 }
201 
202 
203 
204 /*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
205 
206 
207 
do_process_plane(::PVideoFrame & dst_sptr,int n,::IScriptEnvironment & env,int plane_index,int plane_id,void * ctx_ptr)208 void	Bitdepth::do_process_plane (::PVideoFrame &dst_sptr, int n, ::IScriptEnvironment &env, int plane_index, int plane_id, void *ctx_ptr)
209 {
210 	fstb::unused (ctx_ptr);
211 
212 	::PVideoFrame  src_sptr     = _clip_src_sptr->GetFrame (n, &env);
213 
214 	uint8_t *      data_dst_ptr = dst_sptr->GetWritePtr (plane_id);
215 	const int      stride_dst   = dst_sptr->GetPitch (plane_id);
216 	const uint8_t* data_src_ptr = src_sptr->GetReadPtr (plane_id);
217 	const int      stride_src   = src_sptr->GetPitch (plane_id);
218 	const int      w = _plane_proc_uptr->get_width (
219 		dst_sptr, plane_id, avsutl::PlaneProcessor::ClipIdx_DST
220 	);
221 	const int      h = _plane_proc_uptr->get_height (dst_sptr, plane_id);
222 
223 	try
224 	{
225 		_engine_uptr->process_plane (
226 			data_dst_ptr, stride_dst,
227 			data_src_ptr, stride_src,
228 			w, h, n, plane_index
229 		);
230 	}
231 	catch (...)
232 	{
233 		assert (false);
234 	}
235 }
236 
237 
238 
239 /*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
240 
241 
242 
243 }  // namespace fmtcavs
244 
245 
246 
247 /*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
248