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 |