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