GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 24.0% 73 / 0 / 304
Functions: 33.3% 3 / 0 / 9
Branches: 10.1% 129 / 0 / 1272

convert/convert.cpp
Line Branch Exec Source
1 // Avisynth v2.5. Copyright 2002-2009 Ben Rudiak-Gould et al.
2 // http://avisynth.nl
3
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html .
18 //
19 // Linking Avisynth statically or dynamically with other modules is making a
20 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
21 // General Public License cover the whole combination.
22 //
23 // As a special exception, the copyright holders of Avisynth give you
24 // permission to link Avisynth with independent modules that communicate with
25 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
26 // terms of these independent modules, and to copy and distribute the
27 // resulting combined work under terms of your choice, provided that
28 // every copy of the combined work is accompanied by a complete copy of
29 // the source code of Avisynth (the version of Avisynth used to produce the
30 // combined work), being distributed under the terms of the GNU General
31 // Public License plus this exception. An independent module is a module
32 // which is not derived from or based on Avisynth, such as 3rd-party filters,
33 // import and export plugins, or graphical user interfaces.
34
35
36 #include "convert.h"
37 #include "convert_matrix.h"
38 #include "convert_helper.h"
39 #include "convert_bits.h"
40 #include "convert_planar.h"
41 #include "convert_rgb.h"
42
43 #include <avs/alignment.h>
44 #include <avs/minmax.h>
45 #include <avs/config.h>
46 #include <tuple>
47 #include <map>
48 #include <algorithm>
49 #include <cassert>
50
51 #ifdef AVS_WINDOWS
52 #include <avs/win.h>
53 #else
54 #include <avs/posix.h>
55 #endif
56
57 /********************************************************************
58 ***** Declare index of new filters for Avisynth's filter engine *****
59 ********************************************************************/
60
61 extern const AVSFunction Convert_filters[] = {
62 { "ConvertToRGB", BUILTIN_FUNC_PREFIX, "c[matrix]s[interlaced]b[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", CreateConvertToAdaptivePackedRGB, (void *)0 },
63 { "ConvertToRGB24", BUILTIN_FUNC_PREFIX, "c[matrix]s[interlaced]b[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", CreateConvertToPackedRGB, (void *)24 },
64 { "ConvertToRGB32", BUILTIN_FUNC_PREFIX, "c[matrix]s[interlaced]b[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", CreateConvertToPackedRGB, (void *)32 },
65 { "ConvertToRGB48", BUILTIN_FUNC_PREFIX, "c[matrix]s[interlaced]b[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", CreateConvertToPackedRGB, (void *)48 },
66 { "ConvertToRGB64", BUILTIN_FUNC_PREFIX, "c[matrix]s[interlaced]b[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", CreateConvertToPackedRGB, (void *)64 },
67 { "ConvertToPlanarRGB", BUILTIN_FUNC_PREFIX, "c[matrix]s[interlaced]b[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", CreateConvertToRGB, (void *)-1 },
68 { "ConvertToPlanarRGBA", BUILTIN_FUNC_PREFIX, "c[matrix]s[interlaced]b[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", CreateConvertToRGB, (void *)-2 },
69 { "ConvertToY8", BUILTIN_FUNC_PREFIX, "c[matrix]s[bits]i[quality]b", ConvertToPlanarGeneric::CreateY, (void*)0 }, // user_data == 0 -> only 8 bit sources
70 { "ConvertToYV12", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[ChromaOutPlacement]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV420, (void*)0 },
71 { "ConvertToYV24", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV444, (void*)0},
72 { "ConvertToYV16", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[ChromaOutPlacement]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV422, (void*)0},
73 { "ConvertToYV411", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYV411, (void*)0},
74 { "ConvertToYUY2", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[ChromaOutPlacement]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateConvertToYUY2 },
75 { "ConvertBackToYUY2", BUILTIN_FUNC_PREFIX, "c[matrix]s", ConvertToPlanarGeneric::CreateConvertBackToYUY2 },
76 { "ConvertToY", BUILTIN_FUNC_PREFIX, "c[matrix]s[bits]i[quality]b", ConvertToPlanarGeneric::CreateY, (void*)1 }, // user_data == 1 -> any bit depth sources
77 { "ConvertToYUV411", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYV411, (void*)1}, // alias for ConvertToYV411, 8 bit check later
78 { "ConvertToYUV420", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[ChromaOutPlacement]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV420, (void*)1},
79 { "ConvertToYUV422", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[ChromaOutPlacement]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV422, (void*)1},
80 { "ConvertToYUV444", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV444, (void*)1},
81 { "ConvertToYUVA420", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[ChromaOutPlacement]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV420, (void*)2},
82 { "ConvertToYUVA422", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[ChromaOutPlacement]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV422, (void*)2},
83 { "ConvertToYUVA444", BUILTIN_FUNC_PREFIX, "c[interlaced]b[matrix]s[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b", ConvertToPlanarGeneric::CreateYUV444, (void*)2},
84 { "ConvertTo8bit", BUILTIN_FUNC_PREFIX, "c[bits]i[truerange]b[dither]i[dither_bits]i[fulls]b[fulld]b", ConvertBits::Create, (void *)8 },
85 { "ConvertTo16bit", BUILTIN_FUNC_PREFIX, "c[bits]i[truerange]b[dither]i[dither_bits]i[fulls]b[fulld]b", ConvertBits::Create, (void *)16 },
86 { "ConvertToFloat", BUILTIN_FUNC_PREFIX, "c[bits]i[truerange]b[dither]i[dither_bits]i[fulls]b[fulld]b", ConvertBits::Create, (void *)32 },
87 { "ConvertBits", BUILTIN_FUNC_PREFIX, "c[bits]i[truerange]b[dither]i[dither_bits]i[fulls]b[fulld]b", ConvertBits::Create, (void *)0 },
88 { "AddAlphaPlane", BUILTIN_FUNC_PREFIX, "c[mask].[opacity]f", AddAlphaPlane::Create},
89 { "RemoveAlphaPlane", BUILTIN_FUNC_PREFIX, "c", RemoveAlphaPlane::Create},
90 { 0 }
91 };
92
93
94 /****************************************
95 ******* Convert to RGB / RGBA ******
96 ***************************************/
97
98 // 0 1 2 3 4 5 6 7 8 9
99 // c[matrix]s[interlaced]b[ChromaInPlacement]s[chromaresample]s[param1]f[param2]f[param3]f[bits]i[quality]b
100
101 // Special syntax: adaptive packed target format: ConvertToRGB
102 AVSValue __cdecl CreateConvertToAdaptivePackedRGB(AVSValue args, void* user_data, IScriptEnvironment* env)
103 {
104 const PClip clip = args[0].AsClip();
105 const VideoInfo& vi = clip->GetVideoInfo();
106
107 // bits= if given must be 8 or 16 (only valid packed RGB channel depths)
108 int target_bits_per_channel;
109 if (args[8].Defined()) {
110 target_bits_per_channel = args[8].AsInt();
111 if (target_bits_per_channel != 8 && target_bits_per_channel != 16)
112 env->ThrowError("ConvertToRGB: bits must be 8 or 16 if specified. "
113 "Use ConvertToPlanarRGB for other bit depths.");
114 }
115 else {
116 const int src_bits = vi.BitsPerComponent();
117 if (src_bits != 8 && src_bits != 16)
118 env->ThrowError("ConvertToRGB: source bit depth must be 8 or 16. "
119 "Use ConvertToPlanarRGB or ConvertBits(8)/ConvertBits(16) first.");
120 target_bits_per_channel = src_bits;
121 }
122
123 // Decide target format based on source type and alpha capability (and the optional bits= override):
124 // - YUV/YUY2 source: always alpha-capable (RGB32 or RGB64)
125 // - RGB-like source: preserve alpha capability of source format
126 // RGB32/RGB64/PlanarRGBA -> RGB32/RGB64 (with alpha)
127 // RGB24/RGB48/PlanarRGB -> RGB24/RGB48 (without alpha)
128 const bool hasAlpha = vi.IsYUV() || vi.IsYUVA() // YUV always gets alpha target
129 || vi.IsRGB32() || vi.IsRGB64()
130 || vi.IsPlanarRGBA();
131
132 // 8-bit: RGB24 or RGB32, 16-bit: RGB48 or RGB64
133 const intptr_t target_rgbtype = (target_bits_per_channel == 8)
134 ? (hasAlpha ? 32 : 24)
135 : (hasAlpha ? 64 : 48);
136
137 return CreateConvertToPackedRGB(args, reinterpret_cast<void*>(target_rgbtype), env);
138 }
139
140 // Registration names with implied fixed bit depth:
141 // ConvertToRGB24 -> 24-bit only (bits must be 24 if specified)
142 // ConvertToRGB32 -> 32-bit only (bits must be 32 if specified)
143 // ConvertToRGB48 -> 48-bit only (bits must be 48 if specified)
144 // ConvertToRGB64 -> 64-bit only (bits must be 64 if specified)
145 AVSValue __cdecl CreateConvertToPackedRGB(AVSValue args, void* user_data, IScriptEnvironment* env)
146 {
147 const int target_bits = (int)reinterpret_cast<intptr_t>(user_data); // 24, 32, 48, 64
148 const int target_bytes = target_bits / 8; // 3, 4, 6, 8
149 const int bits_per_channel = (target_bytes <= 4) ? 8 : 16; // RGB24/32=8bit, RGB48/64=16bit
150
151 // bits= must match the implied depth if specified
152 if (args[8].Defined() && args[8].AsInt() != bits_per_channel)
153 env->ThrowError("ConvertToRGB%d: bits must be %d if specified.",
154 target_bits, bits_per_channel);
155
156 // Rebuild args with bits forced to the correct value
157 AVSValue new_args[10] = {
158 args[0], args[1], args[2], args[3], args[4],
159 args[5], args[6], args[7],
160 AVSValue(bits_per_channel), // bits forced
161 args[9] // quality
162 };
163 AVSValue new_args_val(new_args, 10);
164 return CreateConvertToRGB(new_args_val, user_data, env);
165 }
166
167 // Dispatch hub for all ConvertToRGB variants.
168 // Since 3.7.6 YUY2 is pre-converted to YV16 before dispatch, so no class is needed.
169 // Called from ConvertToRGB24/32/48/64 and ConvertToPlanarRGB(A) registrations,
170 // and from any internal env->Invoke("ConvertToRGB",...) calls.
171 // All ToRGB variants has bits and quality parameters, bit the quality=true and on-the-fly bit depth
172 // conversion logic is only implemented for YUV->PlanarRGB path.
173
174 // Note: when you add new parameters, find all places env->Invoke("ConvertToRGB",...)
175 // and check parameter count!
176 AVSValue __cdecl CreateConvertToRGB(AVSValue args, void* user_data, IScriptEnvironment* env)
177 {
178 PClip clip = args[0].AsClip();
179 VideoInfo vi = clip->GetVideoInfo();
180
181 // Before any conversions, convert YUY2 to YV16
182 if (vi.IsYUY2()) {
183 clip = new ConvertYUY2ToYV16_or_Y(clip, false /*to_y*/, env);
184 vi = clip->GetVideoInfo();
185 }
186
187 const char* const matrix_name = args[1].AsString(0);
188 const bool haveOpts = args[3].Defined() || args[4].Defined();
189
190 // common Create for all CreateRGB24/32/48/64/Planar(RGBP:-1, RGPAP:-2) using user_data
191 int target_rgbtype = (int)reinterpret_cast<intptr_t>(user_data);
192 // can be overridden later
193 // -1,-2: Planar RGB(A)
194 // 24,32,48,64: RGB24/32/48/64
195 const bool original_target_is_packed = target_rgbtype > 0; // 24,32,48,64
196
197 const int target_bits_per_pixel = args[8].AsInt(vi.BitsPerComponent());
198 // for legacy packed formats it's 8 for target_rgbtype==24,32, and 16 for target_rgbtype==48,64
199 // for planar RGB(A) target, it can be any bit depth supported by the source and the conversion logic (8,10,12,14,16,32)
200
201 const bool quality = args[9].AsBool(false); // yuv-planarrgb float workflow
202
203 // planar YUV-like source
204 if (vi.IsPlanar() && (vi.IsYUV() || vi.IsYUVA())) {
205 // here we keep the bit depth, later, the RGB conversion will take target_bits_per_pixel into account
206 AVSValue new_args[10] = { clip, args[2], args[1], args[3], args[4], args[5], args[6], args[7], vi.BitsPerComponent(), quality };
207 // conversion to planar or packed RGB is always from 444
208 // clip, interlaced, matrix, chromainplacement, chromaresample, param1, param2, param3, bits, quality Check for ConvertToYUV444 param list!!!! Count must match!
209 clip = ConvertToPlanarGeneric::CreateYUV444(AVSValue(new_args, 10), (void*)1, env).AsClip(); // (void *)1: not restricted to 8 bits
210
211 // planar RGB(A) target or packed needing intermediate: set finalBitdepth if conversion needed
212 // also: when quality==true, we need to use the float workflow which requires a planar RGB(A) intermediate
213 if (target_rgbtype > 0) {
214 // packed RGB target: redirect to planar rgb(a) intermediate if bit-depth mismatch or quality mode
215 const bool hasAlpha = (target_rgbtype == 32 || target_rgbtype == 64);
216 if (vi.BitsPerComponent() != target_bits_per_pixel || quality)
217 target_rgbtype = hasAlpha ? -2 : -1;
218 }
219
220 if (target_rgbtype == 48 || target_rgbtype == 64) {
221 // Unlike parameter-less RGB24/32, 16 bit packed format have no direct conversions at all.
222 // 1.) YUV->PlanarRGB first (recursive call),
223 // 2.) then fall through to the planar RGB->packed RGB path below for the final repack
224 // So instead of unoptimized code of YUV(A)444P16->RGB48/64 we convert to PlanarRGB(A) then to RGB48/64
225 // Also: when quality=true or bit-depth conversion is needed, the planar RGB intermediate is required anyway
226 AVSValue new_args2[10] = { clip, args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]/*bits*/, args[9]/*quality*/ };
227
228 const intptr_t target_planar_rgb_type =
229 (target_rgbtype == 24 || target_rgbtype == 48) ? -1 : // no-alpha target: skip alpha even if source has it
230 vi.IsYUVA() ? -2 : // alpha target + alpha source: preserve it
231 -1; // alpha target + no alpha source: no alpha to copy
232 // Note: target_rgbtype == 24 is currently never reached here (24/32 use direct conversion path),
233 // but kept for when 24/32-bit packed is also redirected to the planar intermediate path in the future.
234
235 clip = CreateConvertToRGB(AVSValue(new_args2, 10), (void*)target_planar_rgb_type, env).AsClip();
236 vi = clip->GetVideoInfo(); // must update vi for fall-through
237 // Fall through to planar RGB source path below to do the final pack
238 // reuses the same PlanarRGBtoPackedRGB logic.
239 }
240 else {
241 // Direct YUV444->RGB conversion path
242 bool bitdepthConverted = false;
243 const int finalBitdepth = (vi.BitsPerComponent() != target_bits_per_pixel) ?
244 target_bits_per_pixel : -1; // -1 means: no need to convert
245
246 // Optional bit-depth conversion in PackedRGBtoPlanarRGB.
247 // Note: all formats are bit-depth-converted if finalBitdepth != -1
248 // (historically there were cases and bit-depths which were not implemented to have in-line bit-depth conversion)
249 // pass -1 as finalBitdepth, signing that no bit-depth conversion required
250
251 const int rgbtype_param = (target_rgbtype == -1 || target_rgbtype == -2) ? target_rgbtype : // planar RGB(A)
252 target_rgbtype == 24 ? 3 : 4; // RGB24 or RGB32 "pixel_step" parameter for legacy direct YUV444->RGB24/32 conversion
253
254 clip = new ConvertYUV444ToRGB(clip, matrix_name, rgbtype_param,
255 finalBitdepth, // -1 if no conversion needed
256 quality, /*ref*/bitdepthConverted, env);
257 vi = clip->GetVideoInfo();
258 // When direct YUV-RGB24/32 conversion happens, the result is not planar!
259
260 const bool needConvertFinalBitdepth = finalBitdepth != -1;
261
262 if (needConvertFinalBitdepth && !bitdepthConverted) {
263 AVSValue new_args[] = { clip, finalBitdepth };
264 clip = env->Invoke("ConvertBits", AVSValue(new_args, 2)).AsClip();
265 vi = clip->GetVideoInfo();
266 }
267
268 // We can still have RGB24/32 here, YV24->24/32 is still valid
269 if (original_target_is_packed && vi.IsPlanar()) {
270 // from any planar rgb(a) -> rgb24/32/48/64
271 // source here is always a 8/16bit planar RGB(A), but we used
272 // planar intermediate.
273 // finally it has to be converted to RGB24/32/48/64
274 clip = new PlanarRGBtoPackedRGB(clip, target_rgbtype == -2);
275 vi = clip->GetVideoInfo();
276 }
277 return clip;
278 }
279 } // end of YUV->RGB path
280 else {
281 if (haveOpts)
282 env->ThrowError("ConvertToRGB: ChromaPlacement and ChromaResample options are not supported.");
283 }
284
285 // This part can fallthrough from the YUV path when target is packed RGB
286
287 // RGB->RGB paths (planar or packed) do not support ChromaPlacement and ChromaResample options, as they are meaningless for RGB formats.
288
289 // Planar RGB(A) source
290 if (vi.IsPlanarRGB() || vi.IsPlanarRGBA())
291 {
292 // Handle alpha channel add/remove for planar-to-planar
293 if (target_rgbtype < 0) {
294 if (vi.IsPlanarRGB() && target_rgbtype == -2)
295 clip = new AddAlphaPlane(clip, nullptr, 0.0f, false, env);
296 else if (vi.IsPlanarRGBA() && target_rgbtype == -1)
297 clip = new RemoveAlphaPlane(clip, env);
298 }
299
300 // Convert bit depth if needed
301 if (vi.BitsPerComponent() != target_bits_per_pixel) {
302 AVSValue args[] = { clip, target_bits_per_pixel };
303 // plain Invoke instead of "new ConvertBits", this detects and keeps source and target ranges
304 clip = env->Invoke("ConvertBits", AVSValue(args, 2)).AsClip();
305 }
306
307 // Convert planar to packed
308 if (target_rgbtype >= 0) {
309 bool hasAlpha = (target_rgbtype == 32 || target_rgbtype == 64);
310 clip = new PlanarRGBtoPackedRGB(clip, hasAlpha);
311 }
312
313 return clip;
314 } // Planar RGB(A) source
315
316 // YUV source is done
317 // Planar RGB(A) source is done
318 // Now remains packed RGB source
319 // Conversions from packed RGB
320
321 // Packed to Packed
322 if (target_rgbtype >= 0) {
323 // target bit depth (8-bit for 24/32, 16-bit for 48/64)
324 // target_bits_per_pixel is same as target_rgbtype
325
326 if (vi.BitsPerComponent() != target_bits_per_pixel) {
327 AVSValue args[] = { clip, target_bits_per_pixel };
328 // using Invoke instead of new ConvertBits, this detects and keeps source and target ranges
329 clip = env->Invoke("ConvertBits", AVSValue(args, 2)).AsClip();
330 vi = clip->GetVideoInfo();
331 }
332
333 bool target_has_alpha = (target_rgbtype == 32 || target_rgbtype == 64);
334 bool source_has_alpha = (vi.IsRGB32() || vi.IsRGB64());
335
336 // between packed RGB types, alpha add/remove
337 if (target_has_alpha && !source_has_alpha)
338 return new RGBtoRGBA(clip);
339 if (!target_has_alpha && source_has_alpha)
340 return new RGBAtoRGB(clip);
341
342 return clip;
343 }
344
345 // Packed to Planar
346 // RGB24/32/48/64 ->
347 const bool isSrcRGBA = vi.IsRGB32() || vi.IsRGB64();
348 const bool isTargetRGBA = target_rgbtype == -2; // -2 planar RGBA, -1 planar RGB
349 clip = new PackedRGBtoPlanarRGB(clip, isSrcRGBA, isTargetRGBA);
350 vi = clip->GetVideoInfo(); // new format
351 // no embedded bitdepth conversion in PackedRGBtoPlanarRGB
352 if (target_bits_per_pixel != vi.BitsPerComponent()) {
353 AVSValue new_args[2] = { clip, target_bits_per_pixel };
354 clip = env->Invoke("ConvertBits", AVSValue(new_args, 2)).AsClip();
355 vi = clip->GetVideoInfo(); // new format
356 }
357
358 return clip;
359 }
360
361
362 2 AVSValue AddAlphaPlane::Create(AVSValue args, void*, IScriptEnvironment* env)
363 {
364
2/4
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 312 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 312 not taken.
2 bool isMaskDefined = args[1].Defined();
365
2/4
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 312 not taken.
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 312 not taken.
2 bool isOpacityDefined = args[2].Defined();
366 2 bool maskIsClip = false;
367
368 // if mask is not defined and videoformat has Alpha then we return
369
9/16
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 14 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 312 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 312 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 14 not taken.
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 312 not taken.
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 312 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 1 time.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 2 times.
2 if (isMaskDefined && !args[1].IsClip() && !args[1].IsFloat())
370 env->ThrowError("AddAlphaPlane: mask parameter should be clip or number");
371
372
6/10
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 22 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 312 not taken.
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 312 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 1 time.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 2 times.
2 if (isOpacityDefined && !args[2].IsFloat())
373 env->ThrowError("AddAlphaPlane: opacity parameter should be a number");
374
375
3/4
✓ Branch 25 → 26 taken 1 time.
✓ Branch 25 → 28 taken 1 time.
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 1 time.
2 if (isMaskDefined && isOpacityDefined)
376 env->ThrowError("AddAlphaPlane: cannot specify both mask and opacity parameters");
377
378
3/6
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 200 not taken.
✓ Branch 29 → 30 taken 2 times.
✗ Branch 29 → 200 not taken.
✓ Branch 31 → 32 taken 2 times.
✗ Branch 31 → 198 not taken.
2 const VideoInfo& vi = args[0].AsClip()->GetVideoInfo();
379
4/22
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 44 taken 1 time.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 44 taken 1 time.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 312 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 43 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 312 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 43 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 312 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 43 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 312 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 52 taken 2 times.
2 if (!isMaskDefined && !isOpacityDefined && (vi.IsPlanarRGBA() || vi.IsYUVA() || vi.IsRGB32() || vi.IsRGB64()))
380 return args[0].AsClip();
381
382
1/2
✓ Branch 52 → 53 taken 2 times.
✗ Branch 52 → 312 not taken.
2 PClip alphaClip = nullptr;
383
6/10
✓ Branch 53 → 54 taken 1 time.
✓ Branch 53 → 58 taken 1 time.
✓ Branch 54 → 55 taken 1 time.
✗ Branch 54 → 310 not taken.
✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 310 not taken.
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 1 time.
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 100 taken 2 times.
2 if (isMaskDefined && args[1].IsClip()) {
384 const VideoInfo& viAlphaClip = args[1].AsClip()->GetVideoInfo();
385 maskIsClip = true;
386 if (viAlphaClip.BitsPerComponent() != vi.BitsPerComponent())
387 env->ThrowError("AddAlphaPlane: alpha clip is of different bit depth");
388 if (viAlphaClip.width != vi.width || viAlphaClip.height != vi.height)
389 env->ThrowError("AddAlphaPlane: alpha clip is of different size");
390 if (viAlphaClip.IsY())
391 alphaClip = args[1].AsClip();
392 else if (viAlphaClip.NumComponents() == 4) {
393 AVSValue new_args[1] = { args[1].AsClip() };
394 alphaClip = env->Invoke("ExtractA", AVSValue(new_args, 1)).AsClip();
395 }
396 else {
397 env->ThrowError("AddAlphaPlane: alpha clip should be greyscale or should have alpha plane");
398 }
399 // alphaClip is always greyscale here
400 }
401
402 2 float maskAsFloat = -1.0f;
403
1/2
✓ Branch 100 → 101 taken 2 times.
✗ Branch 100 → 115 not taken.
2 if (!maskIsClip) {
404
2/2
✓ Branch 101 → 102 taken 1 time.
✓ Branch 101 → 112 taken 1 time.
2 if (isOpacityDefined) {
405 // Handle opacity parameter (0.0 to 1.0)
406
2/4
✓ Branch 102 → 103 taken 1 time.
✗ Branch 102 → 310 not taken.
✓ Branch 103 → 104 taken 1 time.
✗ Branch 103 → 310 not taken.
1 float opacity = args[2].AsFloatf(1.0f);
407
2/4
✓ Branch 104 → 105 taken 1 time.
✗ Branch 104 → 106 not taken.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 107 taken 1 time.
1 if (opacity < 0.0f || opacity > 1.0f)
408 env->ThrowError("AddAlphaPlane: opacity must be between 0.0 and 1.0");
409
2/4
✓ Branch 107 → 108 taken 1 time.
✗ Branch 107 → 310 not taken.
✓ Branch 108 → 109 taken 1 time.
✗ Branch 108 → 111 not taken.
1 if (vi.BitsPerComponent() <= 16) {
410
1/2
✓ Branch 109 → 110 taken 1 time.
✗ Branch 109 → 310 not taken.
1 int max_pixel_value = (1 << vi.BitsPerComponent()) - 1;
411 1 maskAsFloat = opacity * max_pixel_value;
412 }
413 else {
414 maskAsFloat = opacity;
415 }
416 }
417 else {
418 // Handle mask parameter (direct value)
419
2/4
✓ Branch 112 → 113 taken 1 time.
✗ Branch 112 → 310 not taken.
✓ Branch 113 → 114 taken 1 time.
✗ Branch 113 → 310 not taken.
1 maskAsFloat = (float)args[1].AsFloat(-1.0f);
420 }
421 }
422
423
2/4
✓ Branch 115 → 116 taken 2 times.
✗ Branch 115 → 310 not taken.
✗ Branch 116 → 117 not taken.
✓ Branch 116 → 147 taken 2 times.
2 if (vi.IsRGB24()) {
424 AVSValue new_args[1] = { args[0].AsClip() };
425 PClip child = env->Invoke("ConvertToRGB32", AVSValue(new_args, 1)).AsClip();
426 return new AddAlphaPlane(child, alphaClip, maskAsFloat, isMaskDefined || isOpacityDefined, env);
427 }
428
2/4
✓ Branch 147 → 148 taken 2 times.
✗ Branch 147 → 310 not taken.
✗ Branch 148 → 149 not taken.
✓ Branch 148 → 179 taken 2 times.
2 else if (vi.IsRGB48()) {
429 AVSValue new_args[1] = { args[0].AsClip() };
430 PClip child = env->Invoke("ConvertToRGB64", AVSValue(new_args, 1)).AsClip();
431 return new AddAlphaPlane(child, alphaClip, maskAsFloat, isMaskDefined || isOpacityDefined, env);
432 }
433
10/20
✓ Branch 179 → 180 taken 2 times.
✗ Branch 179 → 310 not taken.
✓ Branch 180 → 181 taken 1 time.
✓ Branch 180 → 182 taken 1 time.
✓ Branch 181 → 182 taken 1 time.
✗ Branch 181 → 183 not taken.
✓ Branch 184 → 185 taken 2 times.
✗ Branch 184 → 306 not taken.
✓ Branch 185 → 186 taken 2 times.
✗ Branch 185 → 303 not taken.
✓ Branch 186 → 187 taken 2 times.
✗ Branch 186 → 303 not taken.
✓ Branch 187 → 188 taken 2 times.
✗ Branch 187 → 301 not taken.
✓ Branch 188 → 189 taken 2 times.
✗ Branch 188 → 301 not taken.
✗ Branch 192 → 193 not taken.
✓ Branch 192 → 194 taken 2 times.
✗ Branch 307 → 308 not taken.
✗ Branch 307 → 309 not taken.
4 return new AddAlphaPlane(args[0].AsClip(), alphaClip, maskAsFloat, isMaskDefined || isOpacityDefined, env);
434 2 }
435
436 3 AddAlphaPlane::AddAlphaPlane(PClip _child, PClip _alphaClip, float _mask_f, bool isMaskDefined, IScriptEnvironment* env)
437 3 : GenericVideoFilter(_child), alphaClip(_alphaClip)
438
3/6
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 59 not taken.
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 57 not taken.
✓ Branch 5 → 6 taken 3 times.
✗ Branch 5 → 62 not taken.
3 , mask(0), mask_f(0.0f), pixelsize(0), bits_per_pixel(0)
439 {
440
2/4
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 60 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 3 times.
3 if(vi.IsYUY2())
441 env->ThrowError("AddAlphaPlane: YUY2 is not allowed");
442
2/4
✓ Branch 9 → 10 taken 3 times.
✗ Branch 9 → 60 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 3 times.
3 if(vi.IsY())
443 env->ThrowError("AddAlphaPlane: greyscale source is not allowed");
444
10/18
✓ Branch 12 → 13 taken 3 times.
✗ Branch 12 → 60 not taken.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 21 taken 1 time.
✓ Branch 14 → 15 taken 2 times.
✗ Branch 14 → 60 not taken.
✓ Branch 15 → 16 taken 2 times.
✗ Branch 15 → 21 not taken.
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 60 not taken.
✓ Branch 17 → 18 taken 2 times.
✗ Branch 17 → 21 not taken.
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 60 not taken.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 2 times.
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 3 times.
3 if(vi.IsYUV() && !vi.Is420() && !vi.Is422() && !vi.Is444()) // e.g. 410
445 env->ThrowError("AddAlphaPlane: YUV format not supported, must be 420, 422 or 444");
446
8/14
✓ Branch 24 → 25 taken 3 times.
✗ Branch 24 → 60 not taken.
✓ Branch 25 → 26 taken 1 time.
✓ Branch 25 → 31 taken 2 times.
✓ Branch 26 → 27 taken 1 time.
✗ Branch 26 → 60 not taken.
✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 31 not taken.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 60 not taken.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 1 time.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 3 times.
3 if(!vi.IsYUV() && !vi.IsYUVA() && !vi.IsRGB())
447 env->ThrowError("AddAlphaPlane: format not supported");
448
449
1/2
✓ Branch 34 → 35 taken 3 times.
✗ Branch 34 → 60 not taken.
3 pixelsize = vi.ComponentSize();
450
1/2
✓ Branch 35 → 36 taken 3 times.
✗ Branch 35 → 60 not taken.
3 bits_per_pixel = vi.BitsPerComponent();
451
452
3/4
✓ Branch 36 → 37 taken 3 times.
✗ Branch 36 → 60 not taken.
✓ Branch 37 → 38 taken 2 times.
✓ Branch 37 → 42 taken 1 time.
3 if (vi.IsYUV()) {
453 2 int pixel_type = vi.pixel_type;
454
2/4
✓ Branch 38 → 39 taken 2 times.
✗ Branch 38 → 60 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 2 times.
2 if (vi.IsYV12())
455 pixel_type = VideoInfo::CS_YV12;
456 2 int new_pixel_type = (pixel_type & ~VideoInfo::CS_YUV) | VideoInfo::CS_YUVA;
457 2 vi.pixel_type = new_pixel_type;
458
2/4
✓ Branch 42 → 43 taken 1 time.
✗ Branch 42 → 60 not taken.
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 45 not taken.
1 } else if(vi.IsPlanarRGB()) {
459 1 int pixel_type = vi.pixel_type;
460 1 int new_pixel_type = (pixel_type & ~VideoInfo::CS_RGB_TYPE) | VideoInfo::CS_RGBA_TYPE;
461 1 vi.pixel_type = new_pixel_type;
462 }
463 // RGB24 and RGB48 already converted to 32/64
464 // RGB32, RGB64, YUVA and RGBA: no change
465
466 // mask parameter. If none->max opacity
467
468
1/2
✓ Branch 46 → 47 taken 3 times.
✗ Branch 46 → 56 not taken.
3 if (!alphaClip) {
469 3 int max_pixel_value = (1 << bits_per_pixel) - 1; // n/a for float
470
2/2
✓ Branch 47 → 48 taken 1 time.
✓ Branch 47 → 49 taken 2 times.
3 if (!isMaskDefined) {
471 1 mask_f = 1.0f;
472 1 mask = max_pixel_value;
473 }
474 else {
475 2 mask_f = _mask_f;
476
2/4
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 2 times.
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 2 times.
2 mask = (mask_f < 0) ? 0 : (mask_f > max_pixel_value) ? max_pixel_value : (int)(mask_f + 0.5f);
477 2 mask = clamp(mask, 0, max_pixel_value);
478 // no clamp for float
479 }
480 }
481 3 }
482
483 1 PVideoFrame AddAlphaPlane::GetFrame(int n, IScriptEnvironment* env)
484 {
485
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 151 not taken.
1 PVideoFrame src = child->GetFrame(n, env);
486
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 149 not taken.
1 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
487
2/4
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 147 not taken.
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 30 not taken.
1 if(vi.IsPlanar())
488 {
489 1 int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A };
490 1 int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A };
491
4/8
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 140 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 11 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 140 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1 time.
1 int *planes = (vi.IsYUV() || vi.IsYUVA()) ? planes_y : planes_r;
492 // copy existing 3 planes
493
2/2
✓ Branch 28 → 14 taken 3 times.
✓ Branch 28 → 29 taken 1 time.
4 for (int p = 0; p < 3; ++p) {
494 3 const int plane = planes[p];
495
7/14
✓ Branch 15 → 16 taken 3 times.
✗ Branch 15 → 140 not taken.
✓ Branch 17 → 18 taken 3 times.
✗ Branch 17 → 140 not taken.
✓ Branch 19 → 20 taken 3 times.
✗ Branch 19 → 140 not taken.
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 140 not taken.
✓ Branch 23 → 24 taken 3 times.
✗ Branch 23 → 140 not taken.
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 140 not taken.
✓ Branch 26 → 27 taken 3 times.
✗ Branch 26 → 140 not taken.
3 env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane), src->GetReadPtr(plane),
496 src->GetPitch(plane), src->GetRowSize(plane), src->GetHeight(plane));
497 }
498 } else {
499 // Packed RGB, already converted to RGB32 or RGB64
500 env->BitBlt(dst->GetWritePtr(), dst->GetPitch(), src->GetReadPtr(),
501 src->GetPitch(), src->GetRowSize(), src->GetHeight());
502 }
503
504
3/10
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 147 not taken.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 47 taken 1 time.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 147 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
✓ Branch 49 → 50 taken 1 time.
✗ Branch 49 → 86 not taken.
1 if (vi.IsPlanarRGBA() || vi.IsYUVA()) {
505
1/2
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 69 taken 1 time.
1 if (alphaClip) {
506 PVideoFrame srcAlpha = alphaClip->GetFrame(n, env);
507 env->BitBlt(dst->GetWritePtr(PLANAR_A), dst->GetPitch(PLANAR_A), srcAlpha->GetReadPtr(PLANAR_Y),
508 srcAlpha->GetPitch(PLANAR_Y), srcAlpha->GetRowSize(PLANAR_Y), srcAlpha->GetHeight(PLANAR_Y));
509 }
510 else {
511 // default constant
512
1/2
✓ Branch 70 → 71 taken 1 time.
✗ Branch 70 → 147 not taken.
1 const int rowsizeA = dst->GetRowSize(PLANAR_A);
513
1/2
✓ Branch 72 → 73 taken 1 time.
✗ Branch 72 → 147 not taken.
1 const int dst_pitchA = dst->GetPitch(PLANAR_A);
514
1/2
✓ Branch 74 → 75 taken 1 time.
✗ Branch 74 → 147 not taken.
1 BYTE* dstp_a = dst->GetWritePtr(PLANAR_A);
515
1/2
✓ Branch 76 → 77 taken 1 time.
✗ Branch 76 → 147 not taken.
1 const int heightA = dst->GetHeight(PLANAR_A);
516
517
2/6
✓ Branch 77 → 78 taken 1 time.
✗ Branch 77 → 147 not taken.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 81 not taken.
✓ Branch 78 → 83 taken 1 time.
✗ Branch 78 → 85 not taken.
1 switch (vi.ComponentSize())
518 {
519 case 1:
520 fill_plane<BYTE>(dstp_a, heightA, rowsizeA, dst_pitchA, mask);
521 break;
522 case 2:
523 fill_plane<uint16_t>(dstp_a, heightA, rowsizeA, dst_pitchA, mask);
524 break;
525 1 case 4:
526
1/2
✓ Branch 83 → 84 taken 1 time.
✗ Branch 83 → 147 not taken.
1 fill_plane<float>(dstp_a, heightA, rowsizeA, dst_pitchA, mask_f);
527 1 break;
528 }
529 }
530 1 return dst;
531 }
532 // RGB32 and RGB64
533
534 BYTE* pf = dst->GetWritePtr();
535 int pitch = dst->GetPitch();
536 int rowsize = dst->GetRowSize();
537 int height = dst->GetHeight();
538 int width = vi.width;
539
540 if (alphaClip) {
541 // fill by alpha clip already converted to grey-only
542 PVideoFrame srcAlpha = alphaClip->GetFrame(n, env);
543 const BYTE* srcp_a = srcAlpha->GetReadPtr(PLANAR_Y);
544 size_t pitch_a = srcAlpha->GetPitch(PLANAR_Y);
545
546 pf += pitch * (vi.height - 1); // start from bottom: packed RGB is upside down
547
548 if (vi.IsRGB32()) {
549 for (int y = 0; y < height; y++) {
550 for (int x = 0; x < width; x ++) {
551 pf[x*4+3] = srcp_a[x];
552 }
553 pf -= pitch; // packed RGB is upside down
554 srcp_a += pitch_a;
555 }
556 }
557 else if (vi.IsRGB64()) {
558 rowsize /= sizeof(uint16_t);
559 for (int y = 0; y < height; y++) {
560 for (int x = 0; x < width; x ++) {
561 reinterpret_cast<uint16_t *>(pf)[x*4+3] = reinterpret_cast<const uint16_t *>(srcp_a)[x];
562 }
563 pf -= pitch; // packed RGB is upside down
564 srcp_a += pitch_a;
565 }
566 }
567 }
568 else {
569 // fill with constant
570 if (vi.IsRGB32()) {
571 for (int y = 0; y < height; y++) {
572 for (int x = 3; x < rowsize; x += 4) {
573 pf[x] = mask;
574 }
575 pf += pitch;
576 }
577 }
578 else if (vi.IsRGB64()) {
579 rowsize /= sizeof(uint16_t);
580 for (int y = 0; y < height; y++) {
581 for (int x = 3; x < rowsize; x += 4) {
582 reinterpret_cast<uint16_t *>(pf)[x] = mask;
583 }
584 pf += pitch;
585 }
586 }
587 }
588
589 return dst;
590 1 }
591
592 AVSValue RemoveAlphaPlane::Create(AVSValue args, void*, IScriptEnvironment* env)
593 {
594 // if videoformat has no Alpha then we return
595 const VideoInfo& vi = args[0].AsClip()->GetVideoInfo();
596 if(vi.IsPlanar() && (vi.IsYUV() || vi.IsPlanarRGB())) // planar and no alpha
597 return args[0].AsClip();
598 if (vi.IsYUY2()) // YUY2: no alpha
599 return args[0].AsClip();
600 if(vi.IsRGB24() || vi.IsRGB48()) // packed RGB and no alpha
601 return args[0].AsClip();
602 if (vi.IsRGB32()) {
603 AVSValue new_args[1] = { args[0].AsClip() };
604 return env->Invoke("ConvertToRGB24", AVSValue(new_args, 1)).AsClip();
605 }
606 if (vi.IsRGB64()) {
607 AVSValue new_args[1] = { args[0].AsClip() };
608 return env->Invoke("ConvertToRGB48", AVSValue(new_args, 1)).AsClip();
609 }
610 return new RemoveAlphaPlane(args[0].AsClip(), env);
611 }
612
613 RemoveAlphaPlane::RemoveAlphaPlane(PClip _child, IScriptEnvironment* env)
614 : GenericVideoFilter(_child)
615 {
616 if(vi.IsYUY2())
617 env->ThrowError("RemoveAlphaPlane: YUY2 is not allowed");
618 if(vi.IsY())
619 env->ThrowError("RemoveAlphaPlane: greyscale source is not allowed");
620
621 if (vi.IsYUVA()) {
622 int pixel_type = vi.pixel_type;
623 int new_pixel_type = (pixel_type & ~VideoInfo::CS_YUVA) | VideoInfo::CS_YUV;
624 vi.pixel_type = new_pixel_type;
625 } else if(vi.IsPlanarRGBA()) {
626 int pixel_type = vi.pixel_type;
627 int new_pixel_type = (pixel_type & ~VideoInfo::CS_RGBA_TYPE) | VideoInfo::CS_RGB_TYPE;
628 vi.pixel_type = new_pixel_type;
629 }
630 }
631
632 PVideoFrame RemoveAlphaPlane::GetFrame(int n, IScriptEnvironment* env)
633 {
634 PVideoFrame src = child->GetFrame(n, env);
635 // Packed RGB: already handled in ::Create through Invoke 32->24 or 64->48 conversion
636 // only planar here
637 int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A };
638 int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A };
639 int *planes = (vi.IsYUV() || vi.IsYUVA()) ? planes_y : planes_r;
640 // Abuse Subframe to snatch the YUV/GBR planes
641 return env->SubframePlanar(src, 0, src->GetPitch(planes[0]), src->GetRowSize(planes[0]), src->GetHeight(planes[0]), 0, 0, src->GetPitch(planes[1]));
642
643 #if 0
644 // BitBlt version. Kept for reference
645 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
646 // copy 3 planes w/o alpha
647 for (int p = 0; p < 3; ++p) {
648 const int plane = planes[p];
649 env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane), src->GetReadPtr(plane),
650 src->GetPitch(plane), src->GetRowSize(plane), src->GetHeight(plane));
651 }
652 return dst;
653 #endif
654 }
655
656