├── .gitignore ├── ChangeLog.txt ├── FrameRateConverter.avsi ├── FrameRateConverter.py ├── LICENSE ├── README.md └── Src ├── Avisynth ├── ContinuousMaskAvs.cpp ├── ContinuousMaskAvs.h ├── ConvertFpsLimitAvs.cpp ├── ConvertFpsLimitAvs.h ├── InitAvs.cpp ├── StripeMaskAvs.cpp ├── StripeMaskAvs.h ├── avisynth.h ├── avs │ ├── alignment.h │ ├── capi.h │ ├── config.h │ ├── cpuid.h │ ├── minmax.h │ ├── types.h │ └── win.h ├── conditional.cpp ├── conditional.h ├── conditional_functions.cpp └── conditional_functions.h ├── Common ├── ContinuousMaskBase.cpp ├── ContinuousMaskBase.h ├── ConvertFpsLimitBase.cpp ├── ConvertFpsLimitBase.h ├── StripeMaskBase.cpp ├── StripeMaskBase.h ├── merge.cpp ├── merge.h ├── merge_avx2.cpp └── merge_avx2.h ├── Environments ├── Avisynth.hpp ├── Common.h ├── VapourSynth.hpp ├── VpyFilter.hpp ├── VpyPropReader.hpp ├── cpufeatures.cpp ├── cpufeatures.h ├── instrset_detect.cpp └── instrset_detect.h ├── FrameRateConverter.sln ├── FrameRateConverter.vcxproj ├── FrameRateConverter.vcxproj.filters └── VapourSynth ├── ContinuousMaskVpy.cpp ├── ContinuousMaskVpy.h ├── ConvertFpsLimitVpy.cpp ├── ConvertFpsLimitVpy.h ├── FrcVapourSynth.vcxproj ├── FrcVapourSynth.vcxproj.filters ├── InitVpy.cpp ├── StripeMaskVpy.cpp ├── StripeMaskVpy.h ├── VSHelper.h ├── VSScript.h └── VapourSynth.h /.gitignore: -------------------------------------------------------------------------------- 1 | ipch/ 2 | Debug/ 3 | Release/ 4 | .vs/ 5 | 6 | *.db 7 | *.opendb 8 | *.user 9 | 10 | # Compiled Object files 11 | *.slo 12 | *.lo 13 | *.o 14 | *.obj 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Compiled Dynamic libraries 21 | *.so 22 | *.dylib 23 | *.dll 24 | 25 | # Fortran module files 26 | *.mod 27 | *.smod 28 | 29 | # Compiled Static libraries 30 | *.lai 31 | *.la 32 | *.a 33 | *.lib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | -------------------------------------------------------------------------------- /ChangeLog.txt: -------------------------------------------------------------------------------- 1 | Version 2.0 (2021-06-20) 2 | - Ported to VapourSynth 3 | - Fixed a bug in StripeMask 4 | - StripeMask linear gamma correction is now more accurate 5 | - StripeMask now accounts for PC vs TV range 6 | - StripeMask: added fullRange parameter, set to True if input is in full range 7 | 8 | Version 1.3 (2019-06-01) 9 | - Greatly enhanced quality in artifact areas! Ghost effect eliminated. 10 | - Added ConvertFpsLimit to blend with reduced blending ratios. Ratio=0 is frame copy and Ratio=100 is full blending. Ratio=50 reduces blending by half. 11 | - Now perform soft blending with a default ratio of 40, meaning frames blending at 50/50 will blend as 20/80 (50 * .4 = 20) 12 | - You can adjust frame blending ratio with BlendRatio 13 | 14 | 15 | Version 1.2.1 (2018-05-12) 16 | - Slightly improved quality. Added sharp=1 and rfilter=4 to MSuper. 17 | 18 | 19 | Version 1.2 (2017-09-02) 20 | - Mask strength now adjusted to produce similar artifacts masking with different DCT values 21 | - Removed Stripes parameter as Skip isn't practical 22 | - Added Stp parameter, whether to detect and blend stripes 23 | - Changed MaskTrh default from 100 to 120 24 | - Changed BlendOver default from 65 to 70 25 | - If NewNum is twice the clip's frame rate, set FrameDouble to true by default to preserve source frames 26 | 27 | 28 | Version 1.1 (2017-09-01) 29 | - Added InterpolateDoubles function to replace double frames with interpolated frames using FrameRateConverter 30 | - Added DctRe parameter to specify DCT for MRecalculate 31 | - DCT now also applied for MRecalculate by default 32 | - Preset Normal now uses DCT=4 for MRecalculate. Old Normal is now Fast and old Fast is now Faster. 33 | - Presets Slow and Slower also now use DCT=4 for MRecalculate 34 | - SkipOver default treshold increased from 120 to 210 35 | - BlendOver default treshold increased from 60 to 65 36 | - SkipOver now specified for thSCD2 of MMask. Previously, scene changes would cause 2 adjacent frames to be skipped. Specifying thSCD2 causes only 1 frame to be marked for scene change. 37 | - Updated Avisynth headers in DLL 38 | - StripeMask: renamed trh parameter to thr 39 | 40 | 41 | Version 1.0 (2017-08-08): Official Release -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FrameRateConverter 2 | Increases the frame rate with interpolation and fine artifact removal. 3 | 4 | by Etienne Charland 5 | 6 | 7 | ## FrameRateConverter 8 | 9 | Increases the frame rate with interpolation and fine artifact removal. 10 | 11 | FrameRateConverter(C, NewNum, NewDen, Preset, BlkSize, BlkSizeV, FrameDouble, Output, Debug, Prefilter, MaskThr, MaskOcc, SkipThr, BlendOver, SkipOver, Stp, Dct, DctRe) 12 | 13 | YV12/YV24/Y8/YUY2 14 | Requires: FrameRateConverter.dll, MaskTools2, MvTools2 (pinterf), GRunT (for debug only) 15 | 16 | @ NewNum - The new framerate numerator (if FrameDouble = false, default = 60) 17 | 18 | @ NewDen - The new framerate denominator (if FrameDouble = false, default = 1) 19 | 20 | @ Preset - The speed/quality preset [slowest|slower|slow|normal|fast|faster]. (default=normal) 21 | 22 | @ BlkSize - The block size. Latest MvTools2.dll version from Pinterf supports 6, 8, 12, 16, 24, 32, 48 and 64. 23 | Defaults for 4/3 video of height: 24 | 0-359: 8 25 | 360-749: 12 26 | 750-1199: 16 27 | 1200-1699: 24 28 | 1600-2160: 32 29 | 30 | @ BlkSizeV - The vertical block size. (default = BlkSize) 31 | 32 | @ FrameDouble - Whether to double the frame rate and preserve original frames (default = true) 33 | 34 | @ Output - Output mode [auto|flow|over|none|raw|mask|skip|diff|stripe] (default = auto) 35 | auto=normal artifact masking; flow=interpolation only; over=mask as cyan overlay, stripes mask as yellow; none=ConvertFPS only; raw=raw mask; 36 | mask=mask only; skip=mask used to Skip; diff=mask where alternate interpolation is better; stripe=mask used to cover stripes 37 | 38 | @ Debug - Whether to display AverageLuma values of Skip, Mask and Raw. (Default = false) 39 | 40 | @ Prefilter - Specifies a prefilter such as RgTools' RemoveGrain(21). Recommended only when not using a denoiser (Default=none) 41 | 42 | @ MaskThr - The threshold where a block is considered bad, between 0 and 255. Smaller = stronger. 43 | 0 to disable artifact masking. (Default = 120) 44 | 45 | @ MaskOcc - Occlusion mask threshold, between 0 and 255. 0 to disable occlusion masking. (Default = 105) 46 | 47 | @ SkipThr - The threshold where a block is counted for the skip mask, between 0 and 255. Smaller = stronger. 48 | Must be smaller (stronger) than MaskThr. (Default = 55) 49 | 50 | @ BlendOver - Try fallback block size when artifacts cover more than specified threshold, or 0 to disable. 51 | If it fails again, it will revert to frame blending. (default = 70) 52 | 53 | @ SkipOver - Skip interpolation of frames when artifacts cover more than specified threshold, 54 | or 0 to disable. (Default = 210) 55 | 56 | @ Stp - Whether to detect and blend stripes (default=true) 57 | 58 | @ Dct - Overrides DCT parameter for MAnalyse (default: Normal=0, Slow=4, Slowest=1) 59 | 60 | @ DctRe - Overrides DCT parameter for MRecalculate (default: Fast=0, Normal=4, Slowest=1) 61 | 62 | @ BlendRatio - Changes the blend ratio used to fill artifact zones. 0 = frame copy and 100 = full blend. 63 | Other values provide a result in-between to eliminate ghost effects. Default = 40. 64 | 65 | 66 | Presets 67 | Faster: Basic interpolation 68 | Fast: MRecalculate 69 | Normal: MRecalculate with DCT=4 70 | Slow: MAnalyze + MRecalculate with DCT=4 71 | Slower: Calculate diff between DCT=4 and DCT=0 to take the best from both 72 | Slowest: Calculate diff between DCT=1 and DCT=0 to take the best from both 73 | Anime: Slow with BlendOver=40, SkipOver=140 74 | 75 | 76 | 77 | 78 | ## InterpolateDoubles 79 | 80 | Replace double frames with interpolated frames using FrameRateConverter 81 | 82 | InterpolateDoubles(C, Thr, Show, Preset, BlkSize, BlkSizeV, MaskThr, MaskOcc, SkipThr, BlendOver, SkipOver, Stripes, Dct, DctRe) 83 | 84 | @ Thr - Frames will be replaced when Luma difference with previous frame is greater than threshold (default=.1) 85 | 86 | @ Show - If true, "FRAME FIXED" will be written on replaced frames (default=false) 87 | 88 | @ All other parameters are the same as FrameRateConverter 89 | 90 | 91 | 92 | 93 | ## StripeMask 94 | 95 | Builds a mask detecting horizontal and vertical straight lines and patterns, as MvTools tends to fail in such areas. 96 | 97 | StripeMask(C, BlkSize, BlkSizeV, Overlap, OverlapV, Thr, Comp, CompV, Str, StrF, Lines 98 | 99 | @ BlkSize, BlkSizeV - The horizontal and vertical block size. (default: BlkSize=16, BlkSizeV=BlkSize) 100 | 101 | @ Overlap, OverlapV - How many pixels to overlap between blocks, generally between 1/4 and 1/2 of block size. (default = BlkSize/4) 102 | 103 | @ Thr - Dynamic content gives blended (grey) line averages while lines and stripes have contrast between average values. This specifies the contrast threshold where a line average is taken for calculations. A lower value gives a stronger and more sensitive mask. (default = 26) 104 | 105 | @ Comp, CompV - How many lines averages to compare with each other. (default = 2 with BlkSize<16 and 3 with BlkSize>=16) 106 | 107 | @ Str - The value to set on the mask when a pattern is detected, between 0 and 255. (default = 255) 108 | 109 | @ StrF - If > 0, calculates the next frame and set its patterns to this value, between 0 and 255. (default = 0) 110 | 111 | @ Lines - If true, display the raw contrast lines being used for calculations. If false, the pattern areas between those lines will be marked. (default = false) 112 | 113 | 114 | 115 | 116 | ## ConvertFpsLimit 117 | 118 | Same as ConvertFps but with an extra parameter: 119 | 120 | @ Ratio - Changes the blend ratio. 0 = frame copy and 100 = full blend. 121 | Other values provide a result in-between to eliminate ghost effects. Default = 100. 122 | 123 | 124 | 125 | 126 | ## ConditionalFilterMT 127 | 128 | [Avisynth+ MT](https://forum.doom9.org/showthread.php?t=168856) provides great capabilities to process videos. However, conditional functions are 129 | not compatible with MT (multi-threading) due to design limitations. To work around this problem, 130 | this class provides a subset of conditional features that will work with MT mode. 131 | 132 | Currently supported: 133 | - [ConditionalFilter](http://avisynth.nl/index.php/ConditionalFilter) 134 | 135 | Example: this will apply blur to all frames with AverageLuma < 50 136 | ``` 137 | LoadPlugin("ConditionalMT.dll") 138 | vid = AviSource("Source.avi") 139 | vid_blur = vid.Blur(1.5) 140 | ConditionalFilterMT(vid, vid_blur, vid, "AverageLuma", "lessthan", "50") 141 | Prefetch(4) 142 | ``` 143 | 144 | All the standard function expressions are supported. However, only a single plain function name is supported -- no expression. 145 | Do not include parenthesis. 146 | - AverageLuma 147 | - AverageChromaU 148 | - AverageChromaV 149 | - RGBDifference 150 | - LumaDifference 151 | - ChromaUDifference 152 | - ChromaVDifference 153 | - YDifferenceFromPrevious 154 | - UDifferenceFromPrevious 155 | - VDifferenceFromPrevious 156 | - RGBDifferenceFromPrevious 157 | - YDifferenceToNext 158 | - UDifferenceToNext 159 | - VDifferenceToNext 160 | - RGBDifferenceToNext 161 | - YPlaneMax 162 | - YPlaneMin 163 | - YPlaneMedian 164 | - UPlaneMax 165 | - UPlaneMin 166 | - UPlaneMedian 167 | - VPlaneMax 168 | - VPlaneMin 169 | - VPlaneMedian 170 | - YPlaneMinMaxDifference 171 | - UPlaneMinMaxDifference 172 | - VPlaneMinMaxDifference 173 | 174 | Functions comparing two clips will compare testclip with source1. Some functions have threshold and offset parameters. 175 | These parameters are not currently supported and are left at 0. If you need them, feel free to edit the code to parse parameter values. 176 | -------------------------------------------------------------------------------- /Src/Avisynth/ContinuousMaskAvs.cpp: -------------------------------------------------------------------------------- 1 | #include "ContinuousMaskAvs.h" 2 | 3 | AVSValue __cdecl ContinuousMaskAvs::Create(AVSValue args, void* user_data, IScriptEnvironment* env) 4 | { 5 | PClip clip = args[0].AsClip(); 6 | int radius = args[1].AsInt(16); 7 | int thr = args[2].AsInt(0); 8 | return new ContinuousMaskAvs(clip, radius, thr, env); 9 | } 10 | 11 | ContinuousMaskAvs::ContinuousMaskAvs(PClip _child, int _radius, int _thr, IScriptEnvironment* env) : 12 | GenericVideoFilter(_child), 13 | ContinuousMaskBase(new AvsVideo(_child), AvsEnvironment(PluginName, env), _radius, _thr) 14 | { 15 | } 16 | 17 | PVideoFrame __stdcall ContinuousMaskAvs::GetFrame(int n, IScriptEnvironment* env) 18 | { 19 | PVideoFrame src = child->GetFrame(n, env); 20 | PVideoFrame dst = env->NewVideoFrame(vi); 21 | ProcessFrame(AvsFrame(src, vi), AvsFrame(dst, vi)); 22 | return dst; 23 | } 24 | 25 | // Marks filter as multi-threading friendly. 26 | int __stdcall ContinuousMaskAvs::SetCacheHints(int cachehints, int frame_range) 27 | { 28 | return cachehints == CachePolicyHint::CACHE_GET_MTMODE ? MT_NICE_FILTER : 0; 29 | } 30 | -------------------------------------------------------------------------------- /Src/Avisynth/ContinuousMaskAvs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Environments/Avisynth.hpp" 3 | #include "../Common/ContinuousMaskBase.h" 4 | 5 | class ContinuousMaskAvs : public GenericVideoFilter, public ContinuousMaskBase 6 | { 7 | public: 8 | static AVSValue __cdecl Create(AVSValue args, void* user_data, IScriptEnvironment* env); 9 | ContinuousMaskAvs(PClip _child, int _radius, int _thr, IScriptEnvironment* env); 10 | ~ContinuousMaskAvs() {} 11 | PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); 12 | int __stdcall SetCacheHints(int cachehints, int frame_range); 13 | }; 14 | -------------------------------------------------------------------------------- /Src/Avisynth/ConvertFpsLimitAvs.cpp: -------------------------------------------------------------------------------- 1 | #include "ConvertFpsLimitAvs.h" 2 | 3 | ConvertFpsLimitAvs::ConvertFpsLimitAvs(PClip _child, unsigned new_numerator, unsigned new_denominator, int _ratio, IScriptEnvironment* env) : 4 | GenericVideoFilter(_child), 5 | ConvertFPSLimitBase(new AvsVideo(_child), AvsEnvironment(PluginName, env), new_numerator, new_denominator, _ratio) 6 | { 7 | vi.SetFPS(new_numerator, new_denominator); 8 | const int64_t num_frames = (vi.num_frames * fb + (fa >> 1)) / fa; 9 | if (num_frames > 0x7FFFFFFF) // MAXINT 10 | env->ThrowError("ConvertFpsLimit: Maximum number of frames exceeded."); 11 | vi.num_frames = int(num_frames); 12 | } 13 | 14 | PVideoFrame __stdcall ConvertFpsLimitAvs::GetFrame(int n, IScriptEnvironment* env) 15 | { 16 | int nsrc = int(n * fa / fb); 17 | PVideoFrame src = child->GetFrame(nsrc, env); 18 | PVideoFrame src2 = child->GetFrame(nsrc + 1, env); 19 | env->MakeWritable(&src); 20 | ICommonFrame& Result = ProcessFrame(n, AvsFrame(src, vi), AvsFrame(src2, vi), AvsEnvironment(PluginName, env)); 21 | return *(PVideoFrame*)Result.Ref; 22 | } 23 | 24 | bool __stdcall ConvertFpsLimitAvs::GetParity(int n) 25 | { 26 | if (vi.IsFieldBased()) 27 | return child->GetParity(0) ^ (n & 1); 28 | else 29 | return child->GetParity(0); 30 | } 31 | 32 | AVSValue __cdecl ConvertFpsLimitAvs::Create(AVSValue args, void*, IScriptEnvironment* env) 33 | { 34 | return new ConvertFpsLimitAvs(args[0].AsClip(), args[1].AsInt(), args[2].AsInt(1), args[3].AsInt(100), env); 35 | } 36 | 37 | AVSValue __cdecl ConvertFpsLimitAvs::CreateFloat(AVSValue args, void*, IScriptEnvironment* env) 38 | { 39 | uint32_t num, den; 40 | ConvertFpsLimitAvs::FloatToFPS((float)args[1].AsFloat(), num, den, AvsEnvironment(ConvertFpsLimitAvs::PluginName, env)); 41 | return new ConvertFpsLimitAvs(args[0].AsClip(), num, den, args[2].AsInt(100), env); 42 | } 43 | 44 | // Tritical Jan 2006 45 | AVSValue __cdecl ConvertFpsLimitAvs::CreatePreset(AVSValue args, void*, IScriptEnvironment* env) 46 | { 47 | uint32_t num, den; 48 | ConvertFpsLimitAvs::PresetToFPS(args[1].AsString(), num, den, AvsEnvironment(ConvertFpsLimitAvs::PluginName, env)); 49 | return new ConvertFpsLimitAvs(args[0].AsClip(), num, den, args[2].AsInt(100), env); 50 | } 51 | 52 | AVSValue __cdecl ConvertFpsLimitAvs::CreateFromClip(AVSValue args, void*, IScriptEnvironment* env) 53 | { 54 | const VideoInfo& vi = args[1].AsClip()->GetVideoInfo(); 55 | 56 | if (!vi.HasVideo()) 57 | { 58 | env->ThrowError("ConvertFpsLimit: The clip supplied to get the FPS from must contain video."); 59 | } 60 | 61 | return new ConvertFpsLimitAvs(args[0].AsClip(), vi.fps_numerator, vi.fps_denominator, args[2].AsInt(100), env); 62 | } 63 | -------------------------------------------------------------------------------- /Src/Avisynth/ConvertFpsLimitAvs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Common/ConvertFpsLimitBase.h" 3 | #include "../Environments/Avisynth.hpp" 4 | 5 | class ConvertFpsLimitAvs: public GenericVideoFilter, public ConvertFPSLimitBase 6 | /** 7 | * Class to change the framerate, attempting to smooth the transitions 8 | **/ 9 | { 10 | public: 11 | ConvertFpsLimitAvs(PClip _child, unsigned new_numerator, unsigned new_denominator, int _ratio, IScriptEnvironment* env); 12 | PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); 13 | bool __stdcall GetParity(int n); 14 | 15 | int __stdcall SetCacheHints(int cachehints, int frame_range) override { 16 | return cachehints == CACHE_GET_MTMODE ? MT_NICE_FILTER : 0; 17 | } 18 | 19 | static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env); 20 | static AVSValue __cdecl CreateFloat(AVSValue args, void*, IScriptEnvironment* env); 21 | static AVSValue __cdecl CreatePreset(AVSValue args, void*, IScriptEnvironment* env); 22 | static AVSValue __cdecl CreateFromClip(AVSValue args, void*, IScriptEnvironment* env); 23 | }; 24 | -------------------------------------------------------------------------------- /Src/Avisynth/InitAvs.cpp: -------------------------------------------------------------------------------- 1 | #include "avisynth.h" 2 | #include "conditional.h" 3 | #include "StripeMaskAvs.h" 4 | #include "ContinuousMaskAvs.h" 5 | #include "ConvertFpsLimitAvs.h" 6 | 7 | const AVS_Linkage *AVS_linkage = 0; 8 | 9 | extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit3(IScriptEnvironment* env, const AVS_Linkage* const vectors) 10 | { 11 | AVS_linkage = vectors; 12 | env->AddFunction("ConditionalFilterMT", "cccsss[show]b", ConditionalFilter::Create, 0); 13 | env->AddFunction("StripeMaskPass", "c[blkSize]i[blkSizeV]i[overlap]i[overlapV]i[thr]i[range]i[gamma]f[comp]i[compV]i[str]i[fullRange]b[lines]b", StripeMaskAvs::Create, 0); 14 | env->AddFunction("ContinuousMask", "c[radius]i[thr]i", ContinuousMaskAvs::Create, 0); 15 | env->AddFunction("ConvertFpsLimit", "ci[]i[ratio]i", ConvertFpsLimitAvs::Create, 0); 16 | env->AddFunction("ConvertFpsLimit", "cf[ratio]i", ConvertFpsLimitAvs::CreateFloat, 0); 17 | env->AddFunction("ConvertFpsLimit", "cs[ratio]i", ConvertFpsLimitAvs::CreatePreset, 0); 18 | env->AddFunction("ConvertFpsLimit", "cc[ratio]i", ConvertFpsLimitAvs::CreateFromClip, 0); 19 | return "FrameRateConverter"; 20 | } 21 | -------------------------------------------------------------------------------- /Src/Avisynth/StripeMaskAvs.cpp: -------------------------------------------------------------------------------- 1 | #include "StripeMaskAvs.h" 2 | 3 | AVSValue __cdecl StripeMaskAvs::Create(AVSValue args, void* user_data, IScriptEnvironment* env) 4 | { 5 | PClip input = args[0].AsClip(); 6 | int BlkSize = args[1].AsInt(16); 7 | int BlkSizeV = args[2].AsInt(BlkSize > 0 ? BlkSize : 16); 8 | int Overlap = args[3].AsInt(BlkSize / 4); 9 | int OverlapV = args[4].AsInt(BlkSizeV / 4); 10 | int Thr = args[5].AsInt(28); 11 | int Range = args[6].AsInt(255); 12 | double Gamma = args[7].AsFloat(2.2); 13 | int Comp = args[8].AsInt(BlkSize <= 16 ? 2 : 3); 14 | int CompV = args[9].AsInt(Comp); 15 | int Str = args[10].AsInt(255); 16 | int FullRange = args[11].AsBool(false); 17 | bool Lines = args[12].AsBool(false); 18 | 19 | AvsEnvironment Env = AvsEnvironment(PluginName, env); 20 | if (Range < 1 || Range > 255) 21 | { 22 | Env.ThrowError("Range must be between 1 and 255."); 23 | } 24 | else if (Gamma <= 0 || Gamma > 100) 25 | { 26 | Env.ThrowError("Gamma must be greater than 0 and less than 100."); 27 | } 28 | 29 | int BitDepth = input->GetVideoInfo().BitsPerComponent(); 30 | 31 | // Convert input to 8-bit; nothing to gain in processing at higher bit-depth. 32 | if (BitDepth > 8) 33 | { 34 | AVSValue sargs[2] = { input, 8 }; 35 | const char* nargs[2] = { 0, 0 }; 36 | input = env->Invoke("ConvertBits", AVSValue(sargs, 2), nargs).AsClip(); 37 | } 38 | 39 | // Convert to Y 40 | { 41 | AVSValue sargs[1] = { input }; 42 | const char* nargs[1] = { 0 }; 43 | input = env->Invoke("ConvertToY", AVSValue(sargs, 1), nargs).AsClip(); 44 | } 45 | 46 | // Convert to Full levels. 47 | //if (!FullRange) 48 | //{ 49 | // AVSValue sargs[2] = { input, "TV->PC" }; 50 | // const char* nargs[2] = { 0, "levels" }; 51 | // input = env->Invoke("ColorYUV", AVSValue(sargs, 2), nargs).AsClip(); 52 | //} 53 | 54 | // Convert range and apply gamma. 55 | { 56 | int InMin = FullRange ? 0 : 16; 57 | int InMax = FullRange ? 255 : 235; 58 | AVSValue sargs[7] = { input, InMin, 1.0 / Gamma, InMax, 0, Range, false }; 59 | const char* nargs[7] = { 0, 0, 0, 0, 0, 0, "coring"}; 60 | input = env->Invoke("Levels", AVSValue(sargs, 7), nargs).AsClip(); 61 | } 62 | 63 | input = new StripeMaskAvs(input, BlkSize, BlkSizeV, Overlap, OverlapV, Thr, Comp, CompV, Str, Lines, env); 64 | 65 | // Convert back to original bit depth. 66 | if (BitDepth > 8) 67 | { 68 | AVSValue sargs[2] = { input, BitDepth }; 69 | const char* nargs[2] = { 0, 0 }; 70 | input = env->Invoke("ConvertBits", AVSValue(sargs, 2), nargs).AsClip(); 71 | } 72 | return input; 73 | } 74 | 75 | StripeMaskAvs::StripeMaskAvs(PClip _child, int _blksize, int _blksizev, int _overlap, int _overlapv, int _thr, int _comp, int _compv, int _str, bool _lines, IScriptEnvironment* env) : 76 | GenericVideoFilter(_child), StripeMaskBase(new AvsVideo(_child), AvsEnvironment(PluginName, env), _blksize, _blksizev, _overlap, _overlapv, _thr, _comp, _compv, _str, _lines) 77 | { 78 | int b = vi.BitsPerComponent(); 79 | vi.pixel_type = b == 8 ? VideoInfo::CS_Y8 : b == 10 ? VideoInfo::CS_Y10 : b == 12 ? VideoInfo::CS_Y12 : b == 14 ? VideoInfo::CS_Y14 : b == 16 ? VideoInfo::CS_Y16 : b == 32 ? VideoInfo::CS_Y32 : VideoInfo::CS_Y8; 80 | } 81 | 82 | PVideoFrame __stdcall StripeMaskAvs::GetFrame(int n, IScriptEnvironment* env) 83 | { 84 | PVideoFrame src = child->GetFrame(n, env); 85 | PVideoFrame dst = env->NewVideoFrame(vi); 86 | ProcessFrame(AvsFrame(src, vi), AvsFrame(dst, vi), AvsEnvironment(PluginName, env)); 87 | return dst; 88 | } 89 | 90 | // Marks filter as multi-threading friendly. 91 | int __stdcall StripeMaskAvs::SetCacheHints(int cachehints, int frame_range) { 92 | return cachehints == CachePolicyHint::CACHE_GET_MTMODE ? MT_NICE_FILTER : 0; 93 | } 94 | -------------------------------------------------------------------------------- /Src/Avisynth/StripeMaskAvs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Environments/Avisynth.hpp" 3 | #include "../Common/StripeMaskBase.h" 4 | 5 | class StripeMaskAvs : public GenericVideoFilter, public StripeMaskBase { 6 | public: 7 | static AVSValue __cdecl Create(AVSValue args, void* user_data, IScriptEnvironment* env); 8 | StripeMaskAvs(PClip _child, int _blksize, int _blksizev, int _overlap, int _overlapv, int _thr, int comp, int compv, int _str, bool _lines, IScriptEnvironment* env); 9 | ~StripeMaskAvs() {} 10 | PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); 11 | int __stdcall SetCacheHints(int cachehints, int frame_range); 12 | }; 13 | -------------------------------------------------------------------------------- /Src/Avisynth/avs/alignment.h: -------------------------------------------------------------------------------- 1 | // Avisynth C Interface Version 0.20 2 | // Copyright 2003 Kevin Atkinson 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 | // As a special exception, I give you permission to link to the 20 | // Avisynth C interface with independent modules that communicate with 21 | // the Avisynth C interface solely through the interfaces defined in 22 | // avisynth_c.h, regardless of the license terms of these independent 23 | // modules, and to copy and distribute the resulting combined work 24 | // under terms of your choice, provided that every copy of the 25 | // combined work is accompanied by a complete copy of the source code 26 | // of the Avisynth C interface and Avisynth itself (with the version 27 | // used to produce the combined work), being distributed under the 28 | // terms of the GNU General Public License plus this exception. An 29 | // independent module is a module which is not derived from or based 30 | // on Avisynth C Interface, such as 3rd-party filters, import and 31 | // export plugins, or graphical user interfaces. 32 | 33 | #ifndef AVS_ALIGNMENT_H 34 | #define AVS_ALIGNMENT_H 35 | 36 | // Functions and macros to help work with alignment requirements. 37 | 38 | // Tells if a number is a power of two. 39 | #define IS_POWER2(n) ((n) && !((n) & ((n) - 1))) 40 | 41 | // Tells if the pointer "ptr" is aligned to "align" bytes. 42 | #define IS_PTR_ALIGNED(ptr, align) (((uintptr_t)ptr & ((uintptr_t)(align-1))) == 0) 43 | 44 | // Rounds up the number "n" to the next greater multiple of "align" 45 | #define ALIGN_NUMBER(n, align) (((n) + (align)-1) & (~((align)-1))) 46 | 47 | // Rounds up the pointer address "ptr" to the next greater multiple of "align" 48 | #define ALIGN_POINTER(ptr, align) (((uintptr_t)(ptr) + (align)-1) & (~(uintptr_t)((align)-1))) 49 | 50 | #ifdef __cplusplus 51 | 52 | #include 53 | #include 54 | #include 55 | #include "../Avisynth/avs/config.h" 56 | 57 | #if defined(MSVC) 58 | // needed for VS2013, otherwise C++11 'alignas' works 59 | #define avs_alignas(x) __declspec(align(x)) 60 | #else 61 | // assumes C++11 support 62 | #define avs_alignas(x) alignas(x) 63 | #endif 64 | 65 | template 66 | static bool IsPtrAligned(T* ptr, size_t align) 67 | { 68 | assert(IS_POWER2(align)); 69 | return (bool)IS_PTR_ALIGNED(ptr, align); 70 | } 71 | 72 | template 73 | static T AlignNumber(T n, T align) 74 | { 75 | assert(IS_POWER2(align)); 76 | return ALIGN_NUMBER(n, align); 77 | } 78 | 79 | template 80 | static T* AlignPointer(T* ptr, size_t align) 81 | { 82 | assert(IS_POWER2(align)); 83 | return (T*)ALIGN_POINTER(ptr, align); 84 | } 85 | 86 | extern "C" 87 | { 88 | #else 89 | #include 90 | #endif // __cplusplus 91 | 92 | // Returns a new buffer that is at least the size "nbytes". 93 | // The buffer will be aligned to "align" bytes. 94 | // Returns NULL on error. On successful allocation, 95 | // the returned buffer must be freed using "avs_free". 96 | inline void* avs_malloc(size_t nbytes, size_t align) 97 | { 98 | if (!IS_POWER2(align)) 99 | return NULL; 100 | 101 | size_t offset = sizeof(void*) + align - 1; 102 | 103 | void *orig = malloc(nbytes + offset); 104 | if (orig == NULL) 105 | return NULL; 106 | 107 | void **aligned = (void**)(((uintptr_t)orig + (uintptr_t)offset) & (~(uintptr_t)(align-1))); 108 | aligned[-1] = orig; 109 | return aligned; 110 | } 111 | 112 | // Buffers allocated using "avs_malloc" must be freed 113 | // using "avs_free" instead of "free". 114 | inline void avs_free(void *ptr) 115 | { 116 | // Mirroring free()'s semantic requires us to accept NULLs 117 | if (ptr == NULL) 118 | return; 119 | 120 | free(((void**)ptr)[-1]); 121 | } 122 | 123 | #ifdef __cplusplus 124 | } // extern "C" 125 | 126 | // The point of these undef's is to force using the template functions 127 | // if we are in C++ mode. For C, the user can rely only on the macros. 128 | #undef IS_PTR_ALIGNED 129 | #undef ALIGN_NUMBER 130 | #undef ALIGN_POINTER 131 | 132 | #endif // __cplusplus 133 | 134 | #endif //AVS_ALIGNMENT_H 135 | -------------------------------------------------------------------------------- /Src/Avisynth/avs/capi.h: -------------------------------------------------------------------------------- 1 | // Avisynth C Interface Version 0.20 2 | // Copyright 2003 Kevin Atkinson 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 | // As a special exception, I give you permission to link to the 20 | // Avisynth C interface with independent modules that communicate with 21 | // the Avisynth C interface solely through the interfaces defined in 22 | // avisynth_c.h, regardless of the license terms of these independent 23 | // modules, and to copy and distribute the resulting combined work 24 | // under terms of your choice, provided that every copy of the 25 | // combined work is accompanied by a complete copy of the source code 26 | // of the Avisynth C interface and Avisynth itself (with the version 27 | // used to produce the combined work), being distributed under the 28 | // terms of the GNU General Public License plus this exception. An 29 | // independent module is a module which is not derived from or based 30 | // on Avisynth C Interface, such as 3rd-party filters, import and 31 | // export plugins, or graphical user interfaces. 32 | 33 | #ifndef AVS_CAPI_H 34 | #define AVS_CAPI_H 35 | 36 | #ifdef __cplusplus 37 | # define EXTERN_C extern "C" 38 | #else 39 | # define EXTERN_C 40 | #endif 41 | 42 | #ifdef MSVC 43 | #ifndef AVSC_USE_STDCALL 44 | # define AVSC_CC __cdecl 45 | #else 46 | # define AVSC_CC __stdcall 47 | #endif 48 | #else 49 | # define AVSC_CC 50 | #endif 51 | 52 | #define AVSC_INLINE static __inline 53 | 54 | #ifdef BUILDING_AVSCORE 55 | # define AVSC_EXPORT __declspec(dllexport) 56 | # define AVSC_API(ret, name) EXTERN_C AVSC_EXPORT ret AVSC_CC name 57 | #else 58 | # define AVSC_EXPORT EXTERN_C __declspec(dllimport) 59 | # ifndef AVSC_NO_DECLSPEC 60 | # define AVSC_API(ret, name) EXTERN_C AVSC_EXPORT ret AVSC_CC name 61 | # else 62 | # define AVSC_API(ret, name) typedef ret (AVSC_CC *name##_func) 63 | # endif 64 | #endif 65 | 66 | #endif //AVS_CAPI_H 67 | -------------------------------------------------------------------------------- /Src/Avisynth/avs/config.h: -------------------------------------------------------------------------------- 1 | // Avisynth C Interface Version 0.20 2 | // Copyright 2003 Kevin Atkinson 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 | // As a special exception, I give you permission to link to the 20 | // Avisynth C interface with independent modules that communicate with 21 | // the Avisynth C interface solely through the interfaces defined in 22 | // avisynth_c.h, regardless of the license terms of these independent 23 | // modules, and to copy and distribute the resulting combined work 24 | // under terms of your choice, provided that every copy of the 25 | // combined work is accompanied by a complete copy of the source code 26 | // of the Avisynth C interface and Avisynth itself (with the version 27 | // used to produce the combined work), being distributed under the 28 | // terms of the GNU General Public License plus this exception. An 29 | // independent module is a module which is not derived from or based 30 | // on Avisynth C Interface, such as 3rd-party filters, import and 31 | // export plugins, or graphical user interfaces. 32 | 33 | #ifndef AVS_CONFIG_H 34 | #define AVS_CONFIG_H 35 | 36 | // Undefine this to get cdecl calling convention 37 | #define AVSC_USE_STDCALL 1 38 | 39 | // NOTE TO PLUGIN AUTHORS: 40 | // Because FRAME_ALIGN can be substantially higher than the alignment 41 | // a plugin actually needs, plugins should not use FRAME_ALIGN to check for 42 | // alignment. They should always request the exact alignment value they need. 43 | // This is to make sure that plugins work over the widest range of AviSynth 44 | // builds possible. 45 | #define FRAME_ALIGN 32 46 | 47 | #if defined(_M_AMD64) || defined(__x86_64) 48 | # define X86_64 49 | #elif defined(_M_IX86) || defined(__i386__) 50 | # define X86_32 51 | #else 52 | # error Unsupported CPU architecture. 53 | #endif 54 | 55 | #if defined(_MSC_VER) 56 | # define MSVC 57 | #elif defined(__GNUC__) 58 | # define GCC 59 | #elif defined(__clang__) 60 | # define CLANG 61 | #else 62 | # error Unsupported compiler. 63 | #endif 64 | 65 | #if defined(GCC) 66 | # undef __forceinline 67 | # define __forceinline inline 68 | #endif 69 | 70 | #endif //AVS_CONFIG_H 71 | -------------------------------------------------------------------------------- /Src/Avisynth/avs/cpuid.h: -------------------------------------------------------------------------------- 1 | // This program is free software; you can redistribute it and/or modify 2 | // it under the terms of the GNU General Public License as published by 3 | // the Free Software Foundation; either version 2 of the License, or 4 | // (at your option) any later version. 5 | // 6 | // This program is distributed in the hope that it will be useful, 7 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | // GNU General Public License for more details. 10 | // 11 | // You should have received a copy of the GNU General Public License 12 | // along with this program; if not, write to the Free Software 13 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 14 | // http://www.gnu.org/copyleft/gpl.html . 15 | // 16 | // Linking Avisynth statically or dynamically with other modules is making a 17 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU 18 | // General Public License cover the whole combination. 19 | // 20 | // As a special exception, the copyright holders of Avisynth give you 21 | // permission to link Avisynth with independent modules that communicate with 22 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license 23 | // terms of these independent modules, and to copy and distribute the 24 | // resulting combined work under terms of your choice, provided that 25 | // every copy of the combined work is accompanied by a complete copy of 26 | // the source code of Avisynth (the version of Avisynth used to produce the 27 | // combined work), being distributed under the terms of the GNU General 28 | // Public License plus this exception. An independent module is a module 29 | // which is not derived from or based on Avisynth, such as 3rd-party filters, 30 | // import and export plugins, or graphical user interfaces. 31 | 32 | #ifndef AVSCORE_CPUID_H 33 | #define AVSCORE_CPUID_H 34 | 35 | // For GetCPUFlags. These are backwards-compatible with those in VirtualDub. 36 | // ending with SSE4_2 37 | // For emulation see https://software.intel.com/en-us/articles/intel-software-development-emulator 38 | enum { 39 | /* oldest CPU to support extension */ 40 | CPUF_FORCE = 0x01, // N/A 41 | CPUF_FPU = 0x02, // 386/486DX 42 | CPUF_MMX = 0x04, // P55C, K6, PII 43 | CPUF_INTEGER_SSE = 0x08, // PIII, Athlon 44 | CPUF_SSE = 0x10, // PIII, Athlon XP/MP 45 | CPUF_SSE2 = 0x20, // PIV, K8 46 | CPUF_3DNOW = 0x40, // K6-2 47 | CPUF_3DNOW_EXT = 0x80, // Athlon 48 | CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which 49 | // only Hammer will have anyway) 50 | CPUF_SSE3 = 0x100, // PIV+, K8 Venice 51 | CPUF_SSSE3 = 0x200, // Core 2 52 | CPUF_SSE4 = 0x400, 53 | CPUF_SSE4_1 = 0x400, // Penryn, Wolfdale, Yorkfield 54 | CPUF_AVX = 0x800, // Sandy Bridge, Bulldozer 55 | CPUF_SSE4_2 = 0x1000, // Nehalem 56 | // AVS+ 57 | CPUF_AVX2 = 0x2000, // Haswell 58 | CPUF_FMA3 = 0x4000, 59 | CPUF_F16C = 0x8000, 60 | CPUF_MOVBE = 0x10000, // Big Endian move 61 | CPUF_POPCNT = 0x20000, 62 | CPUF_AES = 0x40000, 63 | CPUF_FMA4 = 0x80000, 64 | 65 | CPUF_AVX512F = 0x100000, // AVX-512 Foundation. 66 | CPUF_AVX512DQ = 0x200000, // AVX-512 DQ (Double/Quad granular) Instructions 67 | CPUF_AVX512PF = 0x400000, // AVX-512 Prefetch 68 | CPUF_AVX512ER = 0x800000, // AVX-512 Exponential and Reciprocal 69 | CPUF_AVX512CD = 0x1000000, // AVX-512 Conflict Detection 70 | CPUF_AVX512BW = 0x2000000, // AVX-512 BW (Byte/Word granular) Instructions 71 | CPUF_AVX512VL = 0x4000000, // AVX-512 VL (128/256 Vector Length) Extensions 72 | CPUF_AVX512IFMA = 0x8000000, // AVX-512 IFMA integer 52 bit 73 | CPUF_AVX512VBMI = 0x10000000,// AVX-512 VBMI 74 | }; 75 | 76 | #ifdef BUILDING_AVSCORE 77 | int GetCPUFlags(); 78 | #endif 79 | 80 | #endif // AVSCORE_CPUID_H 81 | -------------------------------------------------------------------------------- /Src/Avisynth/avs/minmax.h: -------------------------------------------------------------------------------- 1 | // This program is free software; you can redistribute it and/or modify 2 | // it under the terms of the GNU General Public License as published by 3 | // the Free Software Foundation; either version 2 of the License, or 4 | // (at your option) any later version. 5 | // 6 | // This program is distributed in the hope that it will be useful, 7 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | // GNU General Public License for more details. 10 | // 11 | // You should have received a copy of the GNU General Public License 12 | // along with this program; if not, write to the Free Software 13 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 14 | // http://www.gnu.org/copyleft/gpl.html . 15 | // 16 | // Linking Avisynth statically or dynamically with other modules is making a 17 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU 18 | // General Public License cover the whole combination. 19 | // 20 | // As a special exception, the copyright holders of Avisynth give you 21 | // permission to link Avisynth with independent modules that communicate with 22 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license 23 | // terms of these independent modules, and to copy and distribute the 24 | // resulting combined work under terms of your choice, provided that 25 | // every copy of the combined work is accompanied by a complete copy of 26 | // the source code of Avisynth (the version of Avisynth used to produce the 27 | // combined work), being distributed under the terms of the GNU General 28 | // Public License plus this exception. An independent module is a module 29 | // which is not derived from or based on Avisynth, such as 3rd-party filters, 30 | // import and export plugins, or graphical user interfaces. 31 | 32 | #ifndef AVSCORE_MINMAX_H 33 | #define AVSCORE_MINMAX_H 34 | 35 | template 36 | T min(T v1, T v2) 37 | { 38 | return v1 < v2 ? v1 : v2; 39 | } 40 | 41 | template 42 | T max(T v1, T v2) 43 | { 44 | return v1 > v2 ? v1 : v2; 45 | } 46 | 47 | template 48 | T clamp(T n, T min, T max) 49 | { 50 | n = n > max ? max : n; 51 | return n < min ? min : n; 52 | } 53 | 54 | #endif // AVSCORE_MINMAX_H 55 | -------------------------------------------------------------------------------- /Src/Avisynth/avs/types.h: -------------------------------------------------------------------------------- 1 | // Avisynth C Interface Version 0.20 2 | // Copyright 2003 Kevin Atkinson 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 | // As a special exception, I give you permission to link to the 20 | // Avisynth C interface with independent modules that communicate with 21 | // the Avisynth C interface solely through the interfaces defined in 22 | // avisynth_c.h, regardless of the license terms of these independent 23 | // modules, and to copy and distribute the resulting combined work 24 | // under terms of your choice, provided that every copy of the 25 | // combined work is accompanied by a complete copy of the source code 26 | // of the Avisynth C interface and Avisynth itself (with the version 27 | // used to produce the combined work), being distributed under the 28 | // terms of the GNU General Public License plus this exception. An 29 | // independent module is a module which is not derived from or based 30 | // on Avisynth C Interface, such as 3rd-party filters, import and 31 | // export plugins, or graphical user interfaces. 32 | 33 | #ifndef AVS_TYPES_H 34 | #define AVS_TYPES_H 35 | 36 | // Define all types necessary for interfacing with avisynth.dll 37 | 38 | #ifdef __cplusplus 39 | #include 40 | #else 41 | #include 42 | #endif 43 | 44 | // Raster types used by VirtualDub & Avisynth 45 | typedef unsigned int Pixel32; 46 | typedef unsigned char BYTE; 47 | 48 | // Audio Sample information 49 | typedef float SFLOAT; 50 | 51 | #ifdef __GNUC__ 52 | typedef long long int INT64; 53 | #else 54 | typedef __int64 INT64; 55 | #endif 56 | 57 | #endif //AVS_TYPES_H 58 | -------------------------------------------------------------------------------- /Src/Avisynth/avs/win.h: -------------------------------------------------------------------------------- 1 | // This program is free software; you can redistribute it and/or modify 2 | // it under the terms of the GNU General Public License as published by 3 | // the Free Software Foundation; either version 2 of the License, or 4 | // (at your option) any later version. 5 | // 6 | // This program is distributed in the hope that it will be useful, 7 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | // GNU General Public License for more details. 10 | // 11 | // You should have received a copy of the GNU General Public License 12 | // along with this program; if not, write to the Free Software 13 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 14 | // http://www.gnu.org/copyleft/gpl.html . 15 | // 16 | // Linking Avisynth statically or dynamically with other modules is making a 17 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU 18 | // General Public License cover the whole combination. 19 | // 20 | // As a special exception, the copyright holders of Avisynth give you 21 | // permission to link Avisynth with independent modules that communicate with 22 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license 23 | // terms of these independent modules, and to copy and distribute the 24 | // resulting combined work under terms of your choice, provided that 25 | // every copy of the combined work is accompanied by a complete copy of 26 | // the source code of Avisynth (the version of Avisynth used to produce the 27 | // combined work), being distributed under the terms of the GNU General 28 | // Public License plus this exception. An independent module is a module 29 | // which is not derived from or based on Avisynth, such as 3rd-party filters, 30 | // import and export plugins, or graphical user interfaces. 31 | 32 | #ifndef AVSCORE_WIN_H 33 | #define AVSCORE_WIN_H 34 | 35 | // Whenever you need windows headers, start by including this file, then the rest. 36 | 37 | // WWUUT? We require XP now? 38 | #if !defined(NTDDI_VERSION) && !defined(_WIN32_WINNT) 39 | #define NTDDI_VERSION 0x05020000 40 | #define _WIN32_WINNT 0x0502 41 | #endif 42 | 43 | #define WIN32_LEAN_AND_MEAN 44 | #define STRICT 45 | #if !defined(NOMINMAX) 46 | #define NOMINMAX 47 | #endif 48 | 49 | #include 50 | 51 | // Provision for UTF-8 max 4 bytes per code point 52 | #define AVS_MAX_PATH MAX_PATH*4 53 | 54 | #endif // AVSCORE_WIN_H 55 | -------------------------------------------------------------------------------- /Src/Avisynth/conditional.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. 3 | // http://www.avisynth.org 4 | 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software 17 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 18 | // http://www.gnu.org/copyleft/gpl.html . 19 | // 20 | // Linking Avisynth statically or dynamically with other modules is making a 21 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU 22 | // General Public License cover the whole combination. 23 | // 24 | // As a special exception, the copyright holders of Avisynth give you 25 | // permission to link Avisynth with independent modules that communicate with 26 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license 27 | // terms of these independent modules, and to copy and distribute the 28 | // resulting combined work under terms of your choice, provided that 29 | // every copy of the combined work is accompanied by a complete copy of 30 | // the source code of Avisynth (the version of Avisynth used to produce the 31 | // combined work), being distributed under the terms of the GNU General 32 | // Public License plus this exception. An independent module is a module 33 | // which is not derived from or based on Avisynth, such as 3rd-party filters, 34 | // import and export plugins, or graphical user interfaces. 35 | 36 | #include "conditional.h" 37 | 38 | #define W_DIVISOR 5 // Width divisor for onscreen messages 39 | 40 | /******************************** 41 | * Conditional filter 42 | * 43 | * Returns each one frame from two sources, 44 | * based on an evaluator. 45 | ********************************/ 46 | 47 | AVSValue __cdecl ConditionalFilter::Create(AVSValue args, void* user_data, IScriptEnvironment* env) 48 | { 49 | return new ConditionalFilter(args[0].AsClip(), args[1].AsClip(), args[2].AsClip(), args[3], args[4], args[5], args[6].AsBool(false), env); 50 | } 51 | 52 | ConditionalFilter::ConditionalFilter(PClip _child, PClip _source1, PClip _source2, 53 | AVSValue _condition1, AVSValue _evaluator, AVSValue _condition2, 54 | bool _show, IScriptEnvironment* env) : 55 | GenericVideoFilter(_child), source1(_source1), source2(_source2), 56 | eval1(_condition1), eval2(_condition2), show(_show) { 57 | 58 | evaluator = NONE; 59 | 60 | if (lstrcmpi(_evaluator.AsString(), "equals") == 0 || 61 | lstrcmpi(_evaluator.AsString(), "=") == 0 || 62 | lstrcmpi(_evaluator.AsString(), "==") == 0) 63 | evaluator = EQUALS; 64 | if (lstrcmpi(_evaluator.AsString(), "greaterthan") == 0 || lstrcmpi(_evaluator.AsString(), ">") == 0) 65 | evaluator = GREATERTHAN; 66 | if (lstrcmpi(_evaluator.AsString(), "lessthan") == 0 || lstrcmpi(_evaluator.AsString(), "<") == 0) 67 | evaluator = LESSTHAN; 68 | 69 | if (evaluator == NONE) 70 | env->ThrowError("ConditionalFilter: Evaluator could not be recognized!"); 71 | 72 | VideoInfo vi1 = source1->GetVideoInfo(); 73 | VideoInfo vi2 = source2->GetVideoInfo(); 74 | 75 | if (vi1.height != vi2.height) 76 | env->ThrowError("ConditionalFilter: The two sources must have the same height!"); 77 | if (vi1.width != vi2.width) 78 | env->ThrowError("ConditionalFilter: The two sources must have the same width!"); 79 | if (!vi1.IsSameColorspace(vi2)) 80 | env->ThrowError("ConditionalFilter: The two sources must be the same colorspace!"); 81 | 82 | vi.height = vi1.height; 83 | vi.width = vi1.width; 84 | vi.pixel_type = vi1.pixel_type; 85 | vi.num_frames = max(vi1.num_frames, vi2.num_frames); 86 | vi.num_audio_samples = vi1.num_audio_samples; 87 | vi.audio_samples_per_second = vi1.audio_samples_per_second; 88 | vi.image_type = vi1.image_type; 89 | vi.fps_denominator = vi1.fps_denominator; 90 | vi.fps_numerator = vi1.fps_numerator; 91 | vi.nchannels = vi1.nchannels; 92 | vi.sample_type = vi1.sample_type; 93 | } 94 | 95 | const char* const t_TRUE = "TRUE"; 96 | const char* const t_FALSE = "FALSE"; 97 | 98 | 99 | PVideoFrame __stdcall ConditionalFilter::GetFrame(int n, IScriptEnvironment* env) { 100 | 101 | VideoInfo vi1 = source1->GetVideoInfo(); 102 | VideoInfo vi2 = source2->GetVideoInfo(); 103 | 104 | AVSValue e1_result; 105 | AVSValue e2_result; 106 | try { 107 | e1_result = ConditionalFunction(eval1.AsString(), child, source1, n, env); 108 | e2_result = ConditionalFunction(eval2.AsString(), child, source1, n, env); 109 | } 110 | catch (const AvisynthError &error) { 111 | const char* error_msg = error.msg; 112 | 113 | PVideoFrame dst = source1->GetFrame(n, env); 114 | env->MakeWritable(&dst); 115 | env->ApplyMessage(&dst, vi1, error_msg, vi.width / W_DIVISOR, 0xa0a0a0, 0, 0); 116 | return dst; 117 | } 118 | 119 | bool test_int = false; 120 | bool test_string = false; 121 | 122 | int e1 = 0; 123 | int e2 = 0; 124 | float f1 = 0.0f; 125 | float f2 = 0.0f; 126 | try { 127 | if (e1_result.IsString()) { 128 | if (!e2_result.IsString()) 129 | env->ThrowError("Conditional filter: Second expression did not return a string, as in first string expression."); 130 | test_string = true; 131 | test_int = true; 132 | e1 = lstrcmp(e1_result.AsString(), e2_result.AsString()); 133 | e2 = 0; 134 | 135 | } 136 | else if (e1_result.IsBool()) { 137 | if (!(e2_result.IsInt() || e2_result.IsBool())) 138 | env->ThrowError("Conditional filter: Second expression did not return an integer or bool, as in first bool expression."); 139 | test_int = true; 140 | e1 = e1_result.AsBool(); 141 | e2 = e2_result.IsInt() ? e2_result.AsInt() : e2_result.AsBool(); 142 | 143 | } 144 | else if (e1_result.IsInt()) { 145 | if (e2_result.IsInt() || e2_result.IsBool()) { 146 | test_int = true; 147 | e1 = e1_result.AsInt(); 148 | e2 = e2_result.IsInt() ? e2_result.AsInt() : e2_result.AsBool(); 149 | } 150 | else if (e2_result.IsFloat()) { 151 | f1 = (float)e1_result.AsFloat(); 152 | f2 = (float)e2_result.AsFloat(); 153 | } 154 | else 155 | env->ThrowError("Conditional filter: Second expression did not return a float, integer or bool, as in first integer expression."); 156 | 157 | } 158 | else if (e1_result.IsFloat()) { 159 | f1 = (float)e1_result.AsFloat(); 160 | if (!e2_result.IsFloat()) 161 | env->ThrowError("Conditional filter: Second expression did not return a float or an integer, as in first float expression."); 162 | f2 = (float)e2_result.AsFloat(); 163 | } 164 | else { 165 | env->ThrowError("ConditionalFilter: First expression did not return an integer, bool or float!"); 166 | } 167 | } 168 | catch (const AvisynthError &error) { 169 | const char* error_msg = error.msg; 170 | 171 | PVideoFrame dst = source1->GetFrame(n, env); 172 | env->MakeWritable(&dst); 173 | env->ApplyMessage(&dst, vi1, error_msg, vi.width / W_DIVISOR, 0xa0a0a0, 0, 0); 174 | return dst; 175 | } 176 | 177 | 178 | bool state = false; 179 | 180 | if (test_int) { // String and Int compare 181 | if (evaluator&EQUALS) 182 | if (e1 == e2) state = true; 183 | 184 | if (evaluator&GREATERTHAN) 185 | if (e1 > e2) state = true; 186 | 187 | if (evaluator&LESSTHAN) 188 | if (e1 < e2) state = true; 189 | 190 | } 191 | else { // Float compare 192 | if (evaluator&EQUALS) 193 | if (fabs(f1 - f2) < 0.000001f) state = true; // Exact equal will sometimes be rounded to wrong values. 194 | 195 | if (evaluator&GREATERTHAN) 196 | if (f1 > f2) state = true; 197 | 198 | if (evaluator&LESSTHAN) 199 | if (f1 < f2) state = true; 200 | } 201 | 202 | if (show) { 203 | char text[400]; 204 | if (test_string) { 205 | _snprintf(text, sizeof(text) - 1, 206 | "Left side Conditional Result:%.40s\n" 207 | "Right side Conditional Result:%.40s\n" 208 | "Evaluate result: %s\n", 209 | e1_result.AsString(), e2_result.AsString(), (state) ? t_TRUE : t_FALSE 210 | ); 211 | } 212 | else if (test_int) { 213 | _snprintf(text, sizeof(text) - 1, 214 | "Left side Conditional Result:%i\n" 215 | "Right side Conditional Result:%i\n" 216 | "Evaluate result: %s\n", 217 | e1, e2, (state) ? t_TRUE : t_FALSE 218 | ); 219 | } 220 | else { 221 | _snprintf(text, sizeof(text) - 1, 222 | "Left side Conditional Result:%7.4f\n" 223 | "Right side Conditional Result:%7.4f\n" 224 | "Evaluate result: %s\n", 225 | f1, f2, (state) ? t_TRUE : t_FALSE 226 | ); 227 | } 228 | 229 | PVideoFrame dst = (state) ? source1->GetFrame(min(vi1.num_frames - 1, n), env) : source2->GetFrame(min(vi2.num_frames - 1, n), env); 230 | env->MakeWritable(&dst); 231 | env->ApplyMessage(&dst, vi, text, vi.width / 4, 0xa0a0a0, 0, 0); 232 | 233 | return dst; 234 | } 235 | 236 | if (state) 237 | return source1->GetFrame(min(vi1.num_frames - 1, n), env); 238 | 239 | return source2->GetFrame(min(vi1.num_frames - 1, n), env); 240 | } 241 | 242 | void __stdcall ConditionalFilter::GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { 243 | source1->GetAudio(buf, start, count, env); 244 | } 245 | 246 | int __stdcall ConditionalFilter::SetCacheHints(int cachehints, int frame_range) { 247 | return cachehints == CachePolicyHint::CACHE_GET_MTMODE ? MT_NICE_FILTER : 0; 248 | } -------------------------------------------------------------------------------- /Src/Avisynth/conditional.h: -------------------------------------------------------------------------------- 1 | 2 | // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. 3 | // http://www.avisynth.org 4 | 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software 17 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 18 | // http://www.gnu.org/copyleft/gpl.html . 19 | // 20 | // Linking Avisynth statically or dynamically with other modules is making a 21 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU 22 | // General Public License cover the whole combination. 23 | // 24 | // As a special exception, the copyright holders of Avisynth give you 25 | // permission to link Avisynth with independent modules that communicate with 26 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license 27 | // terms of these independent modules, and to copy and distribute the 28 | // resulting combined work under terms of your choice, provided that 29 | // every copy of the combined work is accompanied by a complete copy of 30 | // the source code of Avisynth (the version of Avisynth used to produce the 31 | // combined work), being distributed under the terms of the GNU General 32 | // Public License plus this exception. An independent module is a module 33 | // which is not derived from or based on Avisynth, such as 3rd-party filters, 34 | // import and export plugins, or graphical user interfaces. 35 | 36 | 37 | #include "avisynth.h" 38 | #include 39 | #include "avs/win.h" 40 | #include "avs/minmax.h" 41 | #include "conditional_functions.h" 42 | #include 43 | 44 | class ConditionalFilter : public GenericVideoFilter 45 | /** 46 | * Conditional 47 | **/ 48 | { 49 | enum Eval { 50 | NONE = 0, 51 | EQUALS = 1, 52 | GREATERTHAN = 2, 53 | LESSTHAN = 4 54 | }; 55 | 56 | public: 57 | static AVSValue __cdecl Create(AVSValue args, void* user_data, IScriptEnvironment* env); 58 | ConditionalFilter(PClip _child, PClip _source1, PClip _source2, AVSValue _condition1, AVSValue _evaluator, AVSValue _condition2, bool _show, IScriptEnvironment* env); 59 | PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); 60 | void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env); 61 | int __stdcall SetCacheHints(int cachehints, int frame_range); 62 | private: 63 | PClip source1; 64 | PClip source2; 65 | Eval evaluator; 66 | AVSValue eval1; 67 | // const AVSFunction* eval1fct; 68 | AVSValue eval2; 69 | bool show; 70 | }; -------------------------------------------------------------------------------- /Src/Avisynth/conditional_functions.h: -------------------------------------------------------------------------------- 1 | // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. 2 | // http://www.avisynth.org 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 "avisynth.h" 37 | #include "avs\config.h" 38 | #include "avs\minmax.h" 39 | #include "avs\alignment.h" 40 | #include 41 | #include 42 | 43 | enum { MIN = 1, MAX = 2, MEDIAN = 3, MINMAX_DIFFERENCE = 4 }; 44 | 45 | AVSValue ConditionalFunction(const char* expr, AVSValue clip, AVSValue clip2, int n, IScriptEnvironment* env); 46 | 47 | AVSValue AvgPlane(AVSValue clip, void* user_data, int plane, int n, IScriptEnvironment* env); 48 | AVSValue CmpPlane(AVSValue clip, AVSValue clip2, int n, int plane, IScriptEnvironment* env); 49 | AVSValue CmpPlaneSame(AVSValue clip, int n, int offset, int plane, IScriptEnvironment* env); 50 | AVSValue MinMax(AVSValue clip, int n, double threshold, int offset, int plane, int mode, IScriptEnvironment* env); 51 | float Normalize(float value, VideoInfo vi); -------------------------------------------------------------------------------- /Src/Common/ContinuousMaskBase.cpp: -------------------------------------------------------------------------------- 1 | #include "ContinuousMaskBase.h" 2 | 3 | const char* ContinuousMaskBase::PluginName = "ContinuousMask"; 4 | 5 | ContinuousMaskBase::ContinuousMaskBase(ICommonVideo* _child, ICommonEnvironment& env, int _radius, int _thr) : 6 | source(_child), radius(_radius), thr(_thr), bitsPerSample(_child->BitsPerSample()) 7 | { 8 | if (radius <= 1) 9 | { 10 | env.ThrowError("radius must be above 1"); 11 | } 12 | else if (thr < 0 || thr > 255) 13 | { 14 | env.ThrowError("thr must be between 0 and 255."); 15 | } 16 | } 17 | 18 | void ContinuousMaskBase::ProcessFrame(ICommonFrame& src, ICommonFrame& dst) 19 | { 20 | for (int i = 0; i < source->NumPlanes(); i++) 21 | { 22 | auto width = src.GetWidth(i); 23 | auto height = src.GetHeight(i); 24 | auto srcp = src.GetReadPtr(i); 25 | auto srcPitch = src.GetStride(i); 26 | auto dstp = dst.GetWritePtr(i); 27 | auto dstPitch = dst.GetStride(i); 28 | 29 | if (bitsPerSample == 8) 30 | { 31 | Calculate(width, height, srcp, srcPitch, dstp, dstPitch); 32 | } 33 | else if (bitsPerSample < 32) 34 | { 35 | Calculate(width, height, srcp, srcPitch, dstp, dstPitch); 36 | } 37 | else 38 | { 39 | Calculate(width, height, srcp, srcPitch, dstp, dstPitch); 40 | } 41 | } 42 | } 43 | 44 | // T: data type to calculate total (must hold P.MaxValue * radius * 4) 45 | // P: data type of each pixel 46 | template void ContinuousMaskBase::Calculate(int width, int height, const BYTE* srcp, int srcPitch, BYTE* dstp, int dstPitch) 47 | { 48 | memset(dstp, 0, static_cast(dstPitch) * height); 49 | T Sum = 0; 50 | const P* srcIter = (const P*)srcp; 51 | P* dstIter = (P*)dstp; 52 | int radFwd, radBck; 53 | int radFwdV, radBckV; 54 | srcPitch = srcPitch / sizeof(P); 55 | dstPitch = dstPitch / sizeof(P); 56 | 57 | // Calculate the average of [radius] pixels in all 4 directions, for source pixels having a value. 58 | for (int y = 0; y < height; y++) 59 | { 60 | for (int x = 0; x < width; x++) 61 | { 62 | if (srcIter[x] > thr) 63 | { 64 | Sum = 0; 65 | radFwd = min(radius, width - x); 66 | radBck = min(min(radius, x + 1), width) - 1; 67 | radFwdV = min(radius, height - y); 68 | radBckV = min(min(radius, y + 1), height) - 1; 69 | for (int i = -radBck; i < radFwd; i++) 70 | { 71 | Sum += (T)srcIter[x + i]; 72 | } 73 | for (int i = -radBckV; i < radFwdV; i++) 74 | { 75 | Sum += (T)srcIter[x + i * srcPitch]; 76 | } 77 | dstIter[x] = P(Sum / (radFwd + radBck + radFwdV + radBckV)); 78 | } 79 | } 80 | srcIter += srcPitch; 81 | dstIter += dstPitch; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Src/Common/ContinuousMaskBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Environments/Common.h" 3 | #include 4 | #include 5 | #include 6 | 7 | class ContinuousMaskBase 8 | { 9 | public: 10 | static const char* PluginName; 11 | 12 | private: 13 | // ICommonEnvironment& env; 14 | const int radius; 15 | const int thr; 16 | const int bitsPerSample; 17 | 18 | protected: 19 | ContinuousMaskBase(ICommonVideo* _child, ICommonEnvironment& _env, int _radius, int _thr); 20 | ~ContinuousMaskBase() {} 21 | void ProcessFrame(ICommonFrame& src, ICommonFrame& dst); 22 | ICommonVideo* source; 23 | 24 | // T: data type to calculate total (must hold P.MaxValue * radius * 4) 25 | // P: data type of each pixel 26 | template void Calculate(int width, int height, const BYTE* srcp, int srcPitch, BYTE* dstp, int dstPitch); 27 | }; 28 | -------------------------------------------------------------------------------- /Src/Common/ConvertFpsLimitBase.cpp: -------------------------------------------------------------------------------- 1 | #include "ConvertFpsLimitBase.h" 2 | 3 | const char* ConvertFPSLimitBase::PluginName = "ConvertFpsLimit"; 4 | 5 | ConvertFPSLimitBase::ConvertFPSLimitBase(ICommonVideo* _child, ICommonEnvironment& env, int new_numerator, int new_denominator, int _ratio) 6 | : source(_child), ratio(_ratio), fa(0), fb(0) 7 | { 8 | if (_ratio < 0 || _ratio > 100) 9 | { 10 | env.ThrowError("ratio must be between 0 (frame copy) and 100 (full blend)"); 11 | return; 12 | } 13 | 14 | fa = int64_t(source->FpsNum()) * new_denominator; 15 | fb = int64_t(source->FpsDen()) * new_numerator; 16 | //if (3 * fb < (fa << 1)) 17 | //{ 18 | // int dec = MulDiv(source->FpsNum(), 20000, source->FpsDen()); 19 | // env.ThrowError("New frame rate too small. Must be greater than %d.%04d ", dec / 30000, (dec / 3) % 10000); 20 | // return; 21 | //} 22 | } 23 | 24 | ICommonFrame& ConvertFPSLimitBase::ProcessFrame(int n, ICommonFrame& src, ICommonFrame& srcNext, ICommonEnvironment& env) 25 | { 26 | static const int resolution = 10; //bits. Must be >= 4, or modify next line 27 | static const int threshold = (1 << (resolution - 4)) * ratio / 100; 28 | static const int one = 1 << resolution; 29 | static const int half = 1 << (resolution - 1); 30 | 31 | //double nsrc_f, frac_f; 32 | //frac_f = modf((double)n * fa / fb, &nsrc_f); 33 | // integer versions 34 | int nsrc = int(n * fa / fb); 35 | int frac = int((((n * fa) % fb) << resolution) / fb); 36 | 37 | double frac_f_from_int = (double)frac / one; 38 | 39 | // Mode 1: Blend full frames 40 | int mix_ratio = frac; 41 | 42 | if (mix_ratio < half) 43 | mix_ratio = mix_ratio * ratio / 100; 44 | else 45 | mix_ratio = one - ((one - mix_ratio) * ratio / 100); 46 | 47 | // Don't bother if the blend ratio is small 48 | if (mix_ratio < threshold) 49 | return src; 50 | 51 | if (mix_ratio > (one - threshold)) 52 | return srcNext; 53 | 54 | float mix_ratio_f = (float)mix_ratio / one; 55 | 56 | //const int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A }; 57 | //const int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A }; 58 | const int planes[4] = { 0, 1, 2, 3 }; 59 | 60 | //int planeCount; 61 | int planeCount = source->NumPlanes(); 62 | //planes = (!vinfo->IsPlanar() || vinfo->IsYUV()) ? planes_y : planes_r; 63 | 64 | const int bits_per_pixel = source->BitsPerSample(); 65 | for (int plane = 0; plane < planeCount; ++plane) 66 | { 67 | // const int plane = planes[j]; 68 | const BYTE* b_data = srcNext.GetReadPtr(plane); 69 | int b_pitch = srcNext.GetStride(plane); 70 | BYTE* a_data = src.GetWritePtr(plane); 71 | int a_pitch = src.GetStride(plane); 72 | int row_size = src.GetRowSize(plane); 73 | int height = src.GetHeight(plane); 74 | 75 | int weight_i; 76 | int invweight_i; 77 | // float weight = (float)frac_f; 78 | MergeFuncPtr weighted_merge_planar = getMergeFunc(bits_per_pixel, env.GetCpuSupport(), a_data, b_data, mix_ratio_f, /*out*/weight_i, /*out*/invweight_i); 79 | weighted_merge_planar(a_data, b_data, a_pitch, b_pitch, row_size, height, mix_ratio_f, weight_i, invweight_i); 80 | } 81 | 82 | return src; 83 | } 84 | 85 | 86 | 87 | 88 | 89 | /********************************************* 90 | ****** Float and Rational utility ****** 91 | ********************************************* 92 | 93 | ********************************************* 94 | ****** Thanks to RAYMOD2 for his help ***** 95 | ****** in beating continued fractions ***** 96 | ****** into a usable form. IanB ***** 97 | *********************************************/ 98 | 99 | // This function converts a 32-bit IEEE float into a fraction. This 100 | // process is lossless but it may fail for very large or very small 101 | // floats. It also discards the sign bit. Since the denominator will 102 | // always be a power of 2 and the numerator will always be odd (except 103 | // when the denominator is 1) the fraction will already be reduced 104 | // to its lowest terms. output range (2^32-2^(32-24))/1 -- (1/2^31) 105 | // i.e. 4294967040/1 -- 1/2147483648 (4.65661287307e-10) 106 | // returns true if input is out of range 107 | 108 | bool ConvertFPSLimitBase::float_to_frac(float input, unsigned& num, unsigned& den) 109 | { 110 | union { float f; unsigned i; } value{}; 111 | uint32_t mantissa; 112 | int exponent; 113 | 114 | // Bit strip the float 115 | value.f = input; 116 | mantissa = (value.i & 0x7FFFFF) + 0x800000; // add implicit bit on the left 117 | exponent = ((value.i & 0x7F800000) >> 23) - 127 - 23; // remove decimal pt 118 | 119 | // minimize the mantissa by removing any trailing 0's 120 | while (!(mantissa & 1)) { mantissa >>= 1; exponent += 1; } 121 | 122 | // if too small try to pull result from the reciprocal 123 | if (exponent < -31) { 124 | return float_to_frac((float)(1.0 / input), den, num); 125 | } 126 | 127 | // if exponent is too large try removing leading 0's of mantissa 128 | while ((exponent > 0) && !(mantissa & 0x80000000)) { 129 | mantissa <<= 1; exponent -= 1; 130 | } 131 | if (exponent > 0) { // number too large 132 | num = 0xffffffff; 133 | den = 1; 134 | return true; // Out of range! 135 | } 136 | num = mantissa; 137 | den = 1 << (-exponent); 138 | 139 | return false; 140 | } 141 | 142 | 143 | // This function uses continued fractions to find the rational 144 | // approximation such that the result truncated to a float is 145 | // equal to value. The semiconvergents for the smallest such 146 | // rational pair is then returned. The algorithm is modified 147 | // from Wikipedia, Continued Fractions. 148 | 149 | bool ConvertFPSLimitBase::reduce_float(float value, unsigned& num, unsigned& den) 150 | { 151 | if (float_to_frac(value, num, den)) { 152 | return true; 153 | } 154 | 155 | uint32_t n0 = 0, n1 = 1, n2, nx = num; // numerators 156 | uint32_t d0 = 1, d1 = 0, d2, dx = den; // denominators 157 | uint32_t a2, ax, amin; // integer parts of quotients 158 | uint32_t f1 = 0, f2; // fractional parts of quotients 159 | 160 | for (;;) // calculate convergents 161 | { 162 | a2 = nx / dx; 163 | f2 = nx % dx; 164 | n2 = n0 + n1 * a2; 165 | d2 = d0 + d1 * a2; 166 | 167 | if (f2 == 0) break; // no more convergents (n2 / d2 == input) 168 | 169 | // Damn compiler does not correctly cast 170 | // to intermediate results to float 171 | float f = (float)((double)n2 / d2); 172 | if (f == value) break; 173 | 174 | n0 = n1; n1 = n2; 175 | d0 = d1; d1 = d2; 176 | nx = dx; dx = f1 = f2; 177 | } 178 | if (d2 == 1) 179 | { 180 | num = n2; 181 | den = d2; 182 | } 183 | else { // we have been through the loop at least twice 184 | 185 | if ((a2 % 2 == 0) && (d0 * f1 > f2 * d1)) 186 | amin = a2 / 2; // passed 1/2 a_k admissibility test 187 | else 188 | amin = a2 / 2 + 1; 189 | 190 | // find the sign of the error (actual + error = n2/d2) and then 191 | // set (n2/d2) = (num/den + sign * epsilon) = R2 and solve for ax 192 | //-------------------- 193 | // n2 = n0 + n1 * ax 194 | // d2 = d0 + d1 * ax 195 | //----------------------------------------------- 196 | // (n2/d2) = R2 = (n0 + n1 * ax)/(d0 + d1 * ax) 197 | // n0 + n1 * ax = R2 * (d0 + d1 * ax) 198 | // n0 + n1 * ax = R2 * d0 + R2 * d1 * ax 199 | // R2 * d1 * ax - n1 * ax = n0 - R2 * d0 200 | // (R2 * d1 - n1) * ax = n0 - R2 * d0 201 | // ax = (n0 - R2 * d0)/(R2 * d1 - n1) 202 | 203 | // bump float to adjacent float value 204 | union { float f; uint32_t i; } eps{}; eps.f = value; 205 | if (UInt32x32To64(n1, den) > UInt32x32To64(num, d1)) { 206 | eps.i -= 1; 207 | } 208 | else { 209 | eps.i += 1; 210 | } 211 | double r2 = eps.f; 212 | r2 += value; 213 | r2 /= 2; 214 | 215 | double yn = n0 - r2 * d0; 216 | double yd = r2 * d1 - n1; 217 | ax = (uint32_t)((yn + yd) / yd); // ceiling value 218 | 219 | if (ax < amin) ax = amin; 220 | 221 | // calculate nicest semiconvergent 222 | num = n0 + n1 * ax; 223 | den = d0 + d1 * ax; 224 | } 225 | return false; 226 | } 227 | 228 | 229 | // This function uses continued fractions to find the best rational 230 | // approximation that satisfies (denom <= limit). The algorithm 231 | // is from Wikipedia, Continued Fractions. 232 | // 233 | void ConvertFPSLimitBase::reduce_frac(uint32_t& num, uint32_t& den, uint32_t limit) 234 | { 235 | uint32_t n0 = 0, n1 = 1, n2, nx = num; // numerators 236 | uint32_t d0 = 1, d1 = 0, d2, dx = den; // denominators 237 | uint32_t a2, ax, amin; // integer parts of quotients 238 | uint32_t f1 = 0, f2; // fractional parts of quotients 239 | int i = 0; // number of loop iterations 240 | 241 | for (;;) { // calculate convergents 242 | a2 = nx / dx; 243 | f2 = nx % dx; 244 | n2 = n0 + n1 * a2; 245 | d2 = d0 + d1 * a2; 246 | 247 | if (f2 == 0) break; 248 | if ((i++) && (d2 >= limit)) break; 249 | 250 | n0 = n1; n1 = n2; 251 | d0 = d1; d1 = d2; 252 | nx = dx; dx = f1 = f2; 253 | } 254 | if (d2 <= limit) 255 | { 256 | num = n2; den = d2; // use last convergent 257 | } 258 | else { // (d2 > limit) 259 | // d2 = d0 + d1 * ax 260 | // d1 * ax = d2 - d1 261 | ax = (limit - d0) / d1; // set d2 = limit and solve for a2 262 | 263 | if ((a2 % 2 == 0) && (d0 * f1 > f2 * d1)) 264 | amin = a2 / 2; // passed 1/2 a_k admissibility test 265 | else 266 | amin = a2 / 2 + 1; 267 | 268 | if (ax < amin) { 269 | // use previous convergent 270 | num = n1; 271 | den = d1; 272 | } 273 | else { 274 | // calculate best semiconvergent 275 | num = n0 + n1 * ax; 276 | den = d0 + d1 * ax; 277 | } 278 | } 279 | } 280 | 281 | 282 | /*************************************** 283 | ******* Float to FPS utility ****** 284 | ***************************************/ 285 | 286 | void ConvertFPSLimitBase::FloatToFPS(float n, uint32_t& num, uint32_t& den, ICommonEnvironment& env) 287 | { 288 | if (n <= 0) 289 | env.ThrowError("FPS must be greater then 0."); 290 | 291 | float x; 292 | uint32_t u = (uint32_t)(n * 1001 + 0.5); 293 | 294 | // Check for the 30000/1001 multiples 295 | x = (float)((u / 30000.0 * 30000) / 1001.0); 296 | if (x == n) { num = u; den = 1001; return; } 297 | 298 | // Check for the 24000/1001 multiples 299 | x = (float)((u / 24000.0 * 24000) / 1001.0); 300 | if (x == n) { num = u; den = 1001; return; } 301 | 302 | if (n < 14.986) { 303 | // Check for the 30000/1001 factors 304 | u = (uint32_t)(30000.0 / n + 0.5); 305 | x = (float)(30000.0 / (u / 1001.0 * 1001)); 306 | if (x == n) { num = 30000; den = u; return; } 307 | 308 | // Check for the 24000/1001 factors 309 | u = (uint32_t)(24000.0 / n + 0.5); 310 | x = (float)(24000.0 / (u / 1001.0 * 1001)); 311 | if (x == n) { num = 24000; den = u; return; } 312 | } 313 | 314 | // Find the rational pair with the smallest denominator 315 | // that is equal to n within the accuracy of an IEEE float. 316 | if (reduce_float(n, num, den)) 317 | env.ThrowError("FPS value is out of range."); 318 | 319 | } 320 | 321 | 322 | /**************************************** 323 | ******* Preset to FPS utility ****** -- Tritcal, IanB Jan 2006 324 | ****************************************/ 325 | 326 | void ConvertFPSLimitBase::PresetToFPS(const char* p, uint32_t& num, uint32_t& den, ICommonEnvironment& env) 327 | { 328 | if (lstrcmpi(p, "ntsc_film") == 0) { num = 24000; den = 1001; } 329 | else if (lstrcmpi(p, "ntsc_video") == 0) { num = 30000; den = 1001; } 330 | else if (lstrcmpi(p, "ntsc_double") == 0) { num = 60000; den = 1001; } 331 | else if (lstrcmpi(p, "ntsc_quad") == 0) { num = 120000; den = 1001; } 332 | 333 | else if (lstrcmpi(p, "ntsc_round_film") == 0) { num = 2997; den = 125; } 334 | else if (lstrcmpi(p, "ntsc_round_video") == 0) { num = 2997; den = 100; } 335 | else if (lstrcmpi(p, "ntsc_round_double") == 0) { num = 2997; den = 50; } 336 | else if (lstrcmpi(p, "ntsc_round_quad") == 0) { num = 2997; den = 25; } 337 | 338 | else if (lstrcmpi(p, "film") == 0) { num = 24; den = 1; } 339 | 340 | else if (lstrcmpi(p, "pal_film") == 0) { num = 25; den = 1; } 341 | else if (lstrcmpi(p, "pal_video") == 0) { num = 25; den = 1; } 342 | else if (lstrcmpi(p, "pal_double") == 0) { num = 50; den = 1; } 343 | else if (lstrcmpi(p, "pal_quad") == 0) { num = 100; den = 1; } 344 | 345 | else if (lstrcmpi(p, "drop24") == 0) { num = 24000; den = 1001; } 346 | else if (lstrcmpi(p, "drop30") == 0) { num = 30000; den = 1001; } 347 | else if (lstrcmpi(p, "drop60") == 0) { num = 60000; den = 1001; } 348 | else if (lstrcmpi(p, "drop120") == 0) { num = 120000; den = 1001; } 349 | /* 350 | else if (lstrcmpi(p, "drop25" ) == 0) { num = 25000; den = 1001; } 351 | else if (lstrcmpi(p, "drop50" ) == 0) { num = 50000; den = 1001; } 352 | else if (lstrcmpi(p, "drop100" ) == 0) { num =100000; den = 1001; } 353 | 354 | else if (lstrcmpi(p, "nondrop24" ) == 0) { num = 24; den = 1; } 355 | else if (lstrcmpi(p, "nondrop25" ) == 0) { num = 25; den = 1; } 356 | else if (lstrcmpi(p, "nondrop30" ) == 0) { num = 30; den = 1; } 357 | else if (lstrcmpi(p, "nondrop50" ) == 0) { num = 50; den = 1; } 358 | else if (lstrcmpi(p, "nondrop60" ) == 0) { num = 60; den = 1; } 359 | else if (lstrcmpi(p, "nondrop100" ) == 0) { num = 100; den = 1; } 360 | else if (lstrcmpi(p, "nondrop120" ) == 0) { num = 120; den = 1; } 361 | 362 | else if (lstrcmpi(p, "23.976" ) == 0) { num = 24000; den = 1001; } 363 | else if (lstrcmpi(p, "23.976!" ) == 0) { num = 2997; den = 125; } 364 | else if (lstrcmpi(p, "24.0" ) == 0) { num = 24; den = 1; } 365 | else if (lstrcmpi(p, "25.0" ) == 0) { num = 25; den = 1; } 366 | else if (lstrcmpi(p, "29.97" ) == 0) { num = 30000; den = 1001; } 367 | else if (lstrcmpi(p, "29.97!" ) == 0) { num = 2997; den = 100; } 368 | else if (lstrcmpi(p, "30.0" ) == 0) { num = 30; den = 1; } 369 | else if (lstrcmpi(p, "59.94" ) == 0) { num = 60000; den = 1001; } 370 | else if (lstrcmpi(p, "59.94!" ) == 0) { num = 2997; den = 50; } 371 | else if (lstrcmpi(p, "60.0" ) == 0) { num = 60; den = 1; } 372 | else if (lstrcmpi(p, "100.0" ) == 0) { num = 100; den = 1; } 373 | else if (lstrcmpi(p, "119.88" ) == 0) { num =120000; den = 1001; } 374 | else if (lstrcmpi(p, "119.88!" ) == 0) { num = 2997; den = 25; } 375 | else if (lstrcmpi(p, "120.0" ) == 0) { num = 120; den = 1; } 376 | */ 377 | else { 378 | env.ThrowError("Invalid preset value used."); 379 | } 380 | } 381 | -------------------------------------------------------------------------------- /Src/Common/ConvertFpsLimitBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Environments/Common.h" 3 | #include "merge.h" 4 | #include 5 | #include 6 | #include 7 | 8 | // Class to change the framerate, attempting to smooth the transitions 9 | class ConvertFPSLimitBase 10 | { 11 | public: 12 | static const char* PluginName; 13 | ConvertFPSLimitBase(ICommonVideo* _child, ICommonEnvironment& env, int new_numerator, int new_denominator, int _ratio); 14 | ICommonFrame& ProcessFrame(int n, ICommonFrame& src, ICommonFrame& srcNext, ICommonEnvironment& env); 15 | 16 | protected: 17 | ICommonVideo* source; 18 | int64_t fa, fb; 19 | int ratio; 20 | 21 | private: 22 | static bool float_to_frac(float input, unsigned& num, unsigned& den); 23 | static bool reduce_float(float value, unsigned& num, unsigned& den); 24 | static void reduce_frac(uint32_t& num, uint32_t& den, uint32_t limit); 25 | public: 26 | static void FloatToFPS(float n, uint32_t& num, uint32_t& den, ICommonEnvironment& env); 27 | static void PresetToFPS(const char* p, uint32_t& num, uint32_t& den, ICommonEnvironment& env); 28 | }; 29 | -------------------------------------------------------------------------------- /Src/Common/StripeMaskBase.cpp: -------------------------------------------------------------------------------- 1 | #include "StripeMaskBase.h" 2 | 3 | const char* StripeMaskBase::PluginName = "StripeMaskPass"; 4 | 5 | StripeMaskBase::StripeMaskBase(ICommonVideo* _child, ICommonEnvironment& env, int _blksize, int _blksizev, int _overlap, int _overlapv, int _thr, int _comp, int _compv, int _str, bool _lines) : 6 | source(_child), blksize(_blksize), blksizev(_blksizev), overlap(_overlap), overlapv(_overlapv), thr(_thr), comp(_comp), compv(_compv), str(_str), lines(_lines) 7 | { 8 | if (!_child->IsYUV() && !_child->IsY()) 9 | env.ThrowError("clip must be Y or YUV format"); 10 | if (blksize < 0) 11 | env.ThrowError("blksize must be 0 or above"); 12 | if (blksizev < 0) 13 | env.ThrowError("blksizev must be 0 or above"); 14 | if (blksize != 0 && (overlap < 0 || overlap >= blksize)) 15 | env.ThrowError("overlap must be smaller than blksize"); 16 | if (blksizev != 0 && (overlapv < 0 || overlapv >= blksizev)) 17 | env.ThrowError("overlapv must be smaller than blksizev"); 18 | if (thr < 0 || thr > 255) 19 | env.ThrowError("Trh must be between 0 and 255"); 20 | if (comp < 2 || comp > 5) 21 | env.ThrowError("Comp must be between 2 and 5"); 22 | if (compv < 2 || compv > 5) 23 | env.ThrowError("CompV must be between 2 and 5"); 24 | if (str < 0 || str > 255) 25 | env.ThrowError("Str must be between 0 and 255"); 26 | 27 | // int b = _child.BitsPerSample(); 28 | // vi.pixel_type = b == 8 ? VideoInfo::CS_Y8 : b == 10 ? VideoInfo::CS_Y10 : b == 12 ? VideoInfo::CS_Y12 : b == 14 ? VideoInfo::CS_Y14 : b == 16 ? VideoInfo::CS_Y16 : b == 32 ? VideoInfo::CS_Y32 : VideoInfo::CS_Y8; 29 | } 30 | 31 | StripeMaskBase::~StripeMaskBase() 32 | { 33 | if (source) 34 | { 35 | delete source; 36 | } 37 | } 38 | 39 | void StripeMaskBase::ProcessFrame(ICommonFrame& src, ICommonFrame& dst, ICommonEnvironment& env) 40 | { 41 | int width = source->Width(); 42 | int height = source->Height(); 43 | 44 | const BYTE* srcp = src.GetReadPtr(); 45 | int srcPitch = src.GetStride(); 46 | 47 | BYTE* dstp = dst.GetWritePtr(); 48 | const int dstPitch = dst.GetStride(); 49 | memset(dstp, 0, static_cast(dstPitch) * height); 50 | 51 | // Create memory buffers. 52 | BYTE* LineAvgH = new BYTE[width]; 53 | BYTE* LineAvgV = new BYTE[height]; // may need to size mod 16 54 | PatternStep* HistoryH = new PatternStep[width + 2]; // +2 to store initial data to compare to 55 | PatternStep* HistoryV = new PatternStep[height + 2]; 56 | 57 | // Calculte current frame. 58 | if (blksize > 0) 59 | { 60 | CalcFrame(srcp, srcPitch, dstp, dstPitch, LineAvgH, HistoryH, str, false); 61 | } 62 | if (blksizev > 0) 63 | { 64 | CalcFrame(srcp, srcPitch, dstp, dstPitch, LineAvgV, HistoryV, str, true); 65 | } 66 | 67 | delete[] LineAvgH; 68 | delete[] LineAvgV; 69 | delete[] HistoryH; 70 | delete[] HistoryV; 71 | } 72 | 73 | void StripeMaskBase::CalcFrame(const BYTE* src, int srcPitch, BYTE* dst, int dstPitch, BYTE* lineAvg, PatternStep* history, BYTE strength, bool vertical) 74 | { 75 | int blk = !vertical ? blksize : blksizev; 76 | int over = !vertical ? overlap : overlapv; 77 | int width = !vertical ? source->Width() : source->Height(); 78 | int height = !vertical ? source->Height() : source->Width(); 79 | int compBck = (!vertical ? comp : compv) / 2; 80 | int compFwd = ((!vertical ? comp : compv) - 1) / 2; 81 | 82 | int i = 0; 83 | while (i < height - over) 84 | { 85 | if (i >= height - blk) 86 | { 87 | i = height - blk; 88 | } 89 | CalcBandAvg(src + (!vertical ? srcPitch * i : i), srcPitch, width, lineAvg, blk, vertical); 90 | CalcBand(dst + (!vertical ? dstPitch * i : i), dstPitch, width, lineAvg, history, blk, strength, vertical, compBck, compFwd); 91 | i += blk - over; 92 | } 93 | } 94 | 95 | // Calculates a band with the average value of each bar on the band. 96 | // The result will be stored in lineAvg which must be defined with the right size. 97 | // Allows calculating both horizontal and vertical bands. 98 | void StripeMaskBase::CalcBandAvg(const BYTE* src, int pitch, int size, BYTE* lineAvg, int blk, bool vertical) 99 | { 100 | int Sum; 101 | if (!vertical) 102 | { 103 | for (int i = 0; i < size; i++) 104 | { 105 | Sum = 0; 106 | for (int j = 0; j < blk; j++) 107 | { 108 | Sum += src[pitch * j]; 109 | } 110 | lineAvg[i] = Sum / blk; 111 | src++; 112 | } 113 | } 114 | else 115 | { 116 | for (int i = 0; i < size; i++) 117 | { 118 | Sum = 0; 119 | for (int j = 0; j < blk; j++) 120 | { 121 | Sum += src[j]; 122 | } 123 | lineAvg[i] = Sum / blk; 124 | src += pitch; 125 | } 126 | } 127 | } 128 | 129 | // Lightens the mask with the contrast between values. 130 | // From the contrast lines, find and mark regular patterns 131 | void StripeMaskBase::CalcBand(BYTE* dst, int dstPitch, int size, BYTE* lineAvg, PatternStep* history, int blk, BYTE strength, bool vertical, int compFwd, int compBck) 132 | { 133 | BYTE ValDif; 134 | // Alternate between 'on' and 'off' after binarizing contrasts, then scan for alternating states patterns. 135 | bool Alt = false; 136 | PatternStep AltVal; 137 | int AltPos = 0; 138 | history[0] = PatternStep(0, 0); 139 | history[1] = PatternStep(0, 0); 140 | int hLength = 2; 141 | int PatternStart = -1; 142 | int PatternEnd = -1; 143 | int PatternLength = 0; // 0=no pattern, 2=single-stripe pattern, 4=double-stripe pattern 144 | int PatternCont = 0; 145 | 146 | for (int i = 0; i < size; i++) 147 | { 148 | ValDif = GetDiff(lineAvg, i, size, compFwd, compBck); 149 | 150 | if (lines) 151 | { 152 | // Mark line contrasts. 153 | if (ValDif >= thr) 154 | { 155 | MarkArea(dst, dstPitch, i, i + 1, strength, blk, vertical); 156 | } 157 | } 158 | else 159 | { 160 | if ((ValDif >= thr && !Alt) || (ValDif < thr && Alt)) 161 | { 162 | // Build history of alternating states. 163 | Alt = !Alt; 164 | history[hLength++] = PatternStep(i, i - AltPos); 165 | AltPos = i; 166 | 167 | // Look through history to find patterns. 168 | if (!Alt && PatternLength == 0) 169 | { 170 | // 2 last alt match 2 previous ones, or 4 last alt match 4 previous ones. 171 | if (hLength >= 8) 172 | { 173 | PatternLength = CompareHistory(history, hLength, 4, blk) ? 4 : 0; 174 | } 175 | if (PatternLength == 0 && hLength >= 4) 176 | { 177 | PatternLength = CompareHistory(history, hLength, 2, blk) ? 2 : 0; 178 | } 179 | if (PatternLength > 0) 180 | { 181 | PatternStart = history[max(0, hLength - PatternLength * 2 - 2)].Pos; 182 | } 183 | } 184 | else if (PatternLength > 0) 185 | { 186 | // Once pattern is detected, detect when pattern breaks. 187 | if (CompareHistory(history, hLength, PatternLength, blk)) 188 | { 189 | PatternCont += 2; 190 | } 191 | else 192 | { 193 | PatternEnd = history[hLength - 3].Pos; 194 | PatternLength = 0; 195 | PatternCont = 0; 196 | if (hLength > 6) // if hLength=6, 0-1 is blank, 2-3 is 'pattern start' and 4-5 is pattern break. 197 | { 198 | MarkArea(dst, dstPitch, PatternStart, PatternEnd, strength, blk, vertical); 199 | } 200 | } 201 | } 202 | // If 2 full blocks are continuous white, mark it. 203 | if (!Alt && history[hLength - 1].Length > blk * 2) 204 | { 205 | MarkArea(dst, dstPitch, history[hLength - 2].Pos, i, strength, blk, vertical); 206 | } 207 | } 208 | } 209 | } 210 | 211 | if (!lines && PatternLength > 0) 212 | { 213 | MarkArea(dst, dstPitch, PatternStart, history[hLength - 1].Pos, strength, blk, vertical); 214 | } 215 | } 216 | 217 | // Calculate contrast between values 218 | // We take the difference between the max and min of several values. 219 | int StripeMaskBase::GetDiff(BYTE* lineAvg, int n, int size, int compBck, int compFwd) 220 | { 221 | if (n >= compBck && n < size - compFwd) 222 | { 223 | BYTE ValMin = lineAvg[n - compBck]; 224 | BYTE ValMax = ValMin; 225 | for (int i = -compBck + 1; i <= compFwd; i++) 226 | { 227 | ValMin = min(ValMin, lineAvg[n + i]); 228 | ValMax = max(ValMax, lineAvg[n + i]); 229 | } 230 | return ValMax - ValMin; 231 | } 232 | return 0; 233 | } 234 | 235 | void StripeMaskBase::MarkArea(BYTE* dst, int dstPitch, int patternStart, int patternEnd, BYTE strength, int blk, bool vertical) 236 | { 237 | if (!vertical) 238 | { 239 | for (int x = patternStart; x < patternEnd; x++) 240 | { 241 | for (int y = 0; y < blk; y++) 242 | { 243 | dst[x + dstPitch * y] = strength; 244 | } 245 | } 246 | } 247 | else 248 | { 249 | for (int x = patternStart; x < patternEnd; x++) 250 | { 251 | for (int y = 0; y < blk; y++) 252 | { 253 | dst[x * dstPitch + y] = strength; 254 | } 255 | } 256 | } 257 | } 258 | 259 | bool StripeMaskBase::CompareHistory(PatternStep* history, int hLength, int length, int blk) 260 | { 261 | PatternStep* Item1 = &history[hLength - 1]; 262 | PatternStep* Item2 = Item1 - length; 263 | for (int i = 0; i < length; i++) 264 | { 265 | // Maximum pattern step is blksize*2 266 | if (Item1->Length > blk * 2 || Item2->Length > blk * 2) 267 | { 268 | return false; 269 | } 270 | else if (abs(Item1->Length - Item2->Length) > (Item2->Length <= 4 ? 1 : Item2->Length <= 8 ? 2 : Item2->Length <= 16 ? 3 : 4)) 271 | { 272 | return false; 273 | } 274 | Item1--; 275 | Item2--; 276 | } 277 | return true; 278 | } 279 | -------------------------------------------------------------------------------- /Src/Common/StripeMaskBase.h: -------------------------------------------------------------------------------- 1 | #include "../Environments/Common.h" 2 | #include 3 | #include 4 | #include 5 | 6 | struct PatternStep { 7 | PatternStep() {}; 8 | PatternStep(int _pos, int _val) : Pos(_pos), Length(_val) {}; 9 | int Pos = 0; 10 | int Length = 0; 11 | }; 12 | 13 | enum MaskMode { 14 | Lines, 15 | Patterns 16 | }; 17 | 18 | class StripeMaskBase { 19 | public: 20 | static const char* PluginName; 21 | 22 | protected: 23 | StripeMaskBase(ICommonVideo* _child, ICommonEnvironment& env, int _blksize, int _blksizev, int _overlap, int _overlapv, int _thr, int _comp, int _compv, int _str, bool _lines); 24 | ~StripeMaskBase(); 25 | void ProcessFrame(ICommonFrame& src, ICommonFrame& dst, ICommonEnvironment& env); 26 | 27 | private: 28 | void CalcFrame(const BYTE* src, int srcPitch, BYTE* dst, int dstPitch, BYTE* lineAvg, PatternStep* history, BYTE strength, bool vertical); 29 | void CalcBandAvg(const BYTE* src, int pitch, int width, BYTE* lineAvg, int blk, bool vertical); 30 | void CalcBand(BYTE* dst, int dstPitch, int size, BYTE* lineAvg, PatternStep* history, int blk, BYTE strength, bool vertical, int compFwd, int compBck); 31 | int GetDiff(BYTE* lineAvg, int n, int size, int compBck, int compFwd); 32 | void MarkArea(BYTE* dst, int dstPitch, int patternStart, int patternEnd, BYTE strength, int blk, bool vertical); 33 | bool CompareHistory(PatternStep* history, int historySize, int length, int blk); 34 | 35 | protected: 36 | ICommonVideo* source; 37 | const int blksize; 38 | const int blksizev; 39 | const int overlap; 40 | const int overlapv; 41 | const int thr; 42 | const int comp; 43 | const int compv; 44 | const int str; 45 | const bool lines; 46 | }; 47 | -------------------------------------------------------------------------------- /Src/Common/merge.h: -------------------------------------------------------------------------------- 1 | // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. 2 | // http://www.avisynth.org 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 | // Avisynth filter: YUV merge 37 | // by Klaus Post 38 | // adapted by Richard Berg (avisynth-dev@richardberg.net) 39 | 40 | 41 | #ifndef __Merge_H__ 42 | #define __Merge_H__ 43 | 44 | #define AVS_UNUSED(x) x 45 | #include "../Environments/Common.h" 46 | 47 | 48 | 49 | /**************************************************** 50 | ****************************************************/ 51 | // 52 | //class MergeChroma : public GenericVideoFilter 53 | ///** 54 | // * Merge the chroma planes of one clip into another, preserving luma 55 | // **/ 56 | //{ 57 | //public: 58 | // MergeChroma(PClip _child, PClip _clip, float _weight, IScriptEnvironment* env); 59 | // PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); 60 | // 61 | // int __stdcall SetCacheHints(int cachehints, int frame_range) override { 62 | // AVS_UNUSED(frame_range); 63 | // return cachehints == CACHE_GET_MTMODE ? MT_NICE_FILTER : 0; 64 | // } 65 | // 66 | // static AVSValue __cdecl Create(AVSValue args, void* user_data, IScriptEnvironment* env); 67 | // 68 | //private: 69 | // PClip clip; 70 | // float weight; 71 | // int pixelsize; 72 | // int bits_per_pixel; 73 | //}; 74 | // 75 | // 76 | //class MergeLuma : public GenericVideoFilter 77 | ///** 78 | // * Merge the luma plane of one clip into another, preserving chroma 79 | // **/ 80 | //{ 81 | //public: 82 | // MergeLuma(PClip _child, PClip _clip, float _weight, IScriptEnvironment* env); 83 | // PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); 84 | // 85 | // int __stdcall SetCacheHints(int cachehints, int frame_range) override { 86 | // AVS_UNUSED(frame_range); 87 | // return cachehints == CACHE_GET_MTMODE ? MT_NICE_FILTER : 0; 88 | // } 89 | // 90 | // static AVSValue __cdecl Create(AVSValue args, void* user_data, IScriptEnvironment* env); 91 | // 92 | //private: 93 | // PClip clip; 94 | // float weight; 95 | // int pixelsize; 96 | // int bits_per_pixel; 97 | //}; 98 | // 99 | // 100 | //class MergeAll : public GenericVideoFilter 101 | ///** 102 | // * Merge the planes of one clip into another 103 | // **/ 104 | //{ 105 | //public: 106 | // MergeAll(PClip _child, PClip _clip, float _weight, IScriptEnvironment* env); 107 | // PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); 108 | // 109 | // int __stdcall SetCacheHints(int cachehints, int frame_range) override { 110 | // AVS_UNUSED(frame_range); 111 | // return cachehints == CACHE_GET_MTMODE ? MT_NICE_FILTER : 0; 112 | // } 113 | // 114 | // static AVSValue __cdecl Create(AVSValue args, void* user_data, IScriptEnvironment* env); 115 | // 116 | //private: 117 | // PClip clip; 118 | // float weight; 119 | // int pixelsize; 120 | // int bits_per_pixel; 121 | //}; 122 | 123 | typedef void(*MergeFuncPtr) (BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i); 124 | MergeFuncPtr getMergeFunc(int bits_per_pixel, int cpuFlags, BYTE *srcp, const BYTE *otherp, float weight_f, int &weight_i, int &invweight_i); 125 | 126 | template 127 | void weighted_merge_planar_uint16_sse2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i); 128 | 129 | void weighted_merge_planar_sse2(BYTE *p1,const BYTE *p2, int p1_pitch, int p2_pitch,int rowsize, int height, float weight_f, int weight_i, int invweight_i); 130 | void weighted_merge_planar_mmx(BYTE *p1,const BYTE *p2, int p1_pitch, int p2_pitch,int rowsize, int height, float weight_f, int weight_i, int invweight_i); 131 | template 132 | void weighted_merge_planar_c(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i); 133 | void weighted_merge_planar_c_float(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i); 134 | void weighted_merge_planar_sse2_float(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i); 135 | 136 | #endif // __Merge_H__ 137 | -------------------------------------------------------------------------------- /Src/Common/merge_avx2.cpp: -------------------------------------------------------------------------------- 1 | // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. 2 | // http://www.avisynth.org 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 | // Avisynth filter: YUV merge / Swap planes 37 | // by Klaus Post (kp@interact.dk) 38 | // adapted by Richard Berg (avisynth-dev@richardberg.net) 39 | // iSSE code by Ian Brabham 40 | 41 | 42 | // experimental simd includes for avx2 compiled files 43 | #if defined (__GNUC__) && ! defined (__INTEL_COMPILER) 44 | #include 45 | // x86intrin.h includes header files for whatever instruction 46 | // sets are specified on the compiler command line, such as: xopintrin.h, fma4intrin.h 47 | #else 48 | #include // MS version of immintrin.h covers AVX, AVX2 and FMA3 49 | #endif // __GNUC__ 50 | 51 | #if !defined(__FMA__) 52 | // Assume that all processors that have AVX2 also have FMA3 53 | #if defined (__GNUC__) && ! defined (__INTEL_COMPILER) && ! defined (__clang__) 54 | // Prevent error message in g++ when using FMA intrinsics with avx2: 55 | #pragma message "It is recommended to specify also option -mfma when using -mavx2 or higher" 56 | #else 57 | #define __FMA__ 1 58 | #endif 59 | #endif 60 | // FMA3 instruction set 61 | #if defined (__FMA__) && (defined(__GNUC__) || defined(__clang__)) && ! defined (__INTEL_COMPILER) 62 | #include 63 | #endif // __FMA__ 64 | 65 | #include "merge_avx2.h" 66 | #include "merge.h" 67 | #include "../Avisynth/avs/alignment.h" 68 | #include 69 | 70 | #ifndef _mm256_set_m128i 71 | #define _mm256_set_m128i(v0, v1) _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1) 72 | #endif 73 | 74 | #ifndef _mm256_set_m128 75 | #define _mm256_set_m128(v0, v1) _mm256_insertf128_ps(_mm256_castps128_ps256(v1), (v0), 1) 76 | #endif 77 | 78 | /* ----------------------------------- 79 | * average_plane 80 | * ----------------------------------- 81 | */ 82 | #define AVX2BUG_WORKAROUND 83 | // VS2017 15.5.1..2 optimizer generates illegal instructions for vmovntdqa 84 | // just a note, to be removed 85 | template 86 | void average_plane_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height) { 87 | _mm256_zeroupper(); 88 | // width is RowSize here 89 | int mod32_width = rowsize / 32 * 32; 90 | int mod16_width = rowsize / 16 * 16; 91 | 92 | for(int y = 0; y < height; y++) { 93 | for(int x = 0; x < mod32_width; x+=32) { 94 | #ifdef AVX2BUG_WORKAROUND 95 | __m256i src1 = _mm256_load_si256(reinterpret_cast<__m256i*>(p1 + x)); 96 | #else 97 | __m256i src1 = _mm256_stream_load_si256(reinterpret_cast<__m256i*>(p1+x)); 98 | #endif 99 | /* 100 | 00070 8d 40 20 lea eax, DWORD PTR [eax+32] 101 | 102 | ; 70 : __m256i src1 = _mm256_stream_load_si256(reinterpret_cast<__m256i*>(p1+x)); 103 | 104 | 00073 c5 fe 6f 40 e0 vmovdqu ymm0, YMMWORD PTR [eax-32] 105 | 00078 c4 e2 7d 2a c8 vmovntdqa ymm1, ymm0 ****CRASH HERE! ILLEGAL INSTRUCTION VS15.5.1!!!**** 106 | 107 | ; 71 : __m256i src2 = _mm256_stream_load_si256(const_cast<__m256i*>(reinterpret_cast(p2+x))); 108 | 109 | 0007d c5 fe 6f 44 02 e0 vmovdqu ymm0, YMMWORD PTR [edx+eax-32] 110 | 00083 c4 e2 7d 2a c0 vmovntdqa ymm0, ymm0 111 | 112 | */ 113 | #ifdef AVX2BUG_WORKAROUND 114 | __m256i src2 = _mm256_load_si256(const_cast<__m256i*>(reinterpret_cast(p2+x))); 115 | #else 116 | __m256i src2 = _mm256_stream_load_si256(const_cast<__m256i*>(reinterpret_cast(p2 + x))); 117 | #endif 118 | __m256i dst; 119 | if constexpr(sizeof(pixel_t) == 1) 120 | dst = _mm256_avg_epu8(src1, src2); // 16 pixels 121 | else // pixel_size == 2 122 | dst = _mm256_avg_epu16(src1, src2); // 8 pixels 123 | 124 | _mm256_store_si256(reinterpret_cast<__m256i*>(p1+x), dst); 125 | } 126 | 127 | for(int x = mod32_width; x < mod16_width; x+=16) { 128 | #ifdef AVX2BUG_WORKAROUND 129 | __m128i src1 = _mm_load_si128(reinterpret_cast<__m128i*>(p1 + x)); 130 | __m128i src2 = _mm_load_si128(const_cast<__m128i*>(reinterpret_cast(p2 + x))); 131 | #else 132 | __m128i src1 = _mm_stream_load_si128(reinterpret_cast<__m128i*>(p1+x)); 133 | __m128i src2 = _mm_stream_load_si128(const_cast<__m128i*>(reinterpret_cast(p2+x))); 134 | #endif 135 | __m128i dst; 136 | if constexpr(sizeof(pixel_t) == 1) 137 | dst = _mm_avg_epu8(src1, src2); // 8 pixels 138 | else // pixel_size == 2 139 | dst = _mm_avg_epu16(src1, src2); // 4 pixels 140 | 141 | _mm_store_si128(reinterpret_cast<__m128i*>(p1+x), dst); 142 | } 143 | 144 | if (mod16_width != rowsize) { 145 | for (size_t x = mod16_width / sizeof(pixel_t); x < rowsize/sizeof(pixel_t); ++x) { 146 | reinterpret_cast(p1)[x] = (int(reinterpret_cast(p1)[x]) + reinterpret_cast(p2)[x] + 1) >> 1; 147 | } 148 | } 149 | p1 += p1_pitch; 150 | p2 += p2_pitch; 151 | } 152 | _mm256_zeroupper(); 153 | } 154 | 155 | // instantiate to let them access from other modules 156 | template void average_plane_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height); 157 | template void average_plane_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height); 158 | 159 | 160 | /* ----------------------------------- 161 | * weighted_merge_planar 162 | * ----------------------------------- 163 | */ 164 | template 165 | void weighted_merge_planar_uint16_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i) { 166 | AVS_UNUSED(weight_f); 167 | __m128i mask_128 = _mm_set1_epi32( (weight_i << 16) + invweight_i); 168 | __m256i mask = _mm256_set1_epi32((weight_i << 16) + invweight_i); 169 | 170 | const __m128i signed_shifter_128 = _mm_set1_epi16(-32768); 171 | const __m256i signed_shifter = _mm256_set1_epi16(-32768); 172 | 173 | auto round_mask = _mm256_set1_epi32(0x4000); 174 | auto zero = _mm256_setzero_si256(); 175 | 176 | auto round_mask_128 = _mm_set1_epi32(0x4000); 177 | auto zero_128 = _mm_setzero_si128(); 178 | 179 | int wMod32 = (rowsize / 32) * 32; 180 | int wMod16 = (rowsize / 16) * 16; 181 | 182 | for (int y = 0; y < height; y++) { 183 | for (int x = 0; x < wMod32; x += 32) { 184 | __m256i px1, px2; 185 | px1 = _mm256_load_si256(reinterpret_cast(p1 + x)); // y7 y6 y5 y4 y3 y2 y1 y0 186 | px2 = _mm256_load_si256(reinterpret_cast(p2 + x)); // Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 187 | 188 | if (!lessthan16bit) { 189 | px1 = _mm256_add_epi16(px1, signed_shifter); 190 | px2 = _mm256_add_epi16(px2, signed_shifter); 191 | } 192 | 193 | auto p03 = _mm256_unpacklo_epi16(px1, px2); // Y11y11 Y10y10 Y9y9 Y8y8 Y3y3 Y2y2 Y1y1 Y0y0 194 | auto p47 = _mm256_unpackhi_epi16(px1, px2); // Yy15-12 Yy7-4 195 | 196 | p03 = _mm256_madd_epi16(p03, mask); // px1 * invweight + px2 * weight 197 | p47 = _mm256_madd_epi16(p47, mask); 198 | 199 | p03 = _mm256_add_epi32(p03, round_mask); 200 | p47 = _mm256_add_epi32(p47, round_mask); 201 | 202 | p03 = _mm256_srai_epi32(p03, 15); 203 | p47 = _mm256_srai_epi32(p47, 15); 204 | 205 | auto p07 = _mm256_packs_epi32(p03, p47); 206 | if (!lessthan16bit) { 207 | p07 = _mm256_add_epi16(p07, signed_shifter); 208 | } 209 | 210 | auto result = p07; 211 | _mm256_store_si256(reinterpret_cast<__m256i*>(p1 + x), result); 212 | } 213 | 214 | for (int x = wMod32; x < wMod16; x += 16) { 215 | __m128i px1, px2; 216 | px1 = _mm_load_si128(reinterpret_cast<__m128i*>(p1 + x)); // y7 y6 y5 y4 y3 y2 y1 y0 217 | px2 = _mm_load_si128(const_cast<__m128i*>(reinterpret_cast(p2 + x))); // Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 218 | if (!lessthan16bit) { 219 | px1 = _mm_add_epi16(px1, signed_shifter_128); 220 | px2 = _mm_add_epi16(px2, signed_shifter_128); 221 | } 222 | 223 | auto p03 = _mm_unpacklo_epi16(px1, px2); // Y11y11 Y10y10 Y9y9 Y8y8 Y3y3 Y2y2 Y1y1 Y0y0 224 | auto p47 = _mm_unpackhi_epi16(px1, px2); // Yy15-12 Yy7-4 225 | 226 | p03 = _mm_madd_epi16(p03, mask_128); // px1 * invweight + px2 * weight 227 | p47 = _mm_madd_epi16(p47, mask_128); 228 | 229 | p03 = _mm_add_epi32(p03, round_mask_128); 230 | p47 = _mm_add_epi32(p47, round_mask_128); 231 | 232 | p03 = _mm_srai_epi32(p03, 15); 233 | p47 = _mm_srai_epi32(p47, 15); 234 | 235 | auto p07 = _mm_packs_epi32(p03, p47); 236 | if (!lessthan16bit) { 237 | p07 = _mm_add_epi16(p07, signed_shifter_128); 238 | } 239 | 240 | auto result = p07; 241 | _mm_stream_si128(reinterpret_cast<__m128i*>(p1 + x), result); 242 | } 243 | 244 | for (size_t x = wMod16 / sizeof(uint16_t); x < rowsize / sizeof(uint16_t); x++) { 245 | reinterpret_cast(p1)[x] = (reinterpret_cast(p1)[x] * invweight_i + reinterpret_cast(p2)[x] * weight_i + 16384) >> 15; 246 | } 247 | 248 | p1 += p1_pitch; 249 | p2 += p2_pitch; 250 | } 251 | _mm256_zeroupper(); 252 | } 253 | 254 | // instantiate to let them access from other modules 255 | template void weighted_merge_planar_uint16_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i); 256 | template void weighted_merge_planar_uint16_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i); 257 | 258 | 259 | void weighted_merge_planar_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height, float weight_f, int weight_i, int invweight_i) { 260 | AVS_UNUSED(weight_f); 261 | auto round_mask = _mm256_set1_epi32(0x4000); 262 | auto zero = _mm256_setzero_si256(); 263 | auto mask = _mm256_set_epi16(weight_i, invweight_i, weight_i, invweight_i, weight_i, invweight_i, weight_i, invweight_i, weight_i, invweight_i, weight_i, invweight_i, weight_i, invweight_i, weight_i, invweight_i); 264 | 265 | auto round_mask_128 = _mm_set1_epi32(0x4000); 266 | auto zero_128 = _mm_setzero_si128(); 267 | auto mask_128 = _mm_set_epi16(weight_i, invweight_i, weight_i, invweight_i, weight_i, invweight_i, weight_i, invweight_i); 268 | 269 | int wMod32 = (rowsize / 32) * 32; 270 | int wMod16 = (rowsize / 16) * 16; 271 | 272 | for (int y = 0; y < height; y++) { 273 | for (int x = 0; x < wMod32; x += 32) { 274 | auto px1 = _mm256_load_si256(reinterpret_cast(p1 + x)); // y15y14 ... y7y6 y5y4 y3y2 y1y0 275 | auto px2 = _mm256_load_si256(reinterpret_cast(p2 + x)); // Y15Y14 ... Y7Y6 Y5Y4 Y3Y2 Y1Y0 276 | 277 | auto p07 = _mm256_unpacklo_epi8(px1, px2); // Y7y7 .. Y3y3 Y2y2 Y1y1 Y0y0 278 | auto p815 = _mm256_unpackhi_epi8(px1, px2); //Y15y15 ..Y11y11 Y10y10 Y9y9 Y8y8 279 | 280 | auto p03 = _mm256_unpacklo_epi8(p07, zero); //00Y3 00y3 00Y2 00y2 00Y1 00y1 00Y0 00y0 8*short 281 | auto p47 = _mm256_unpackhi_epi8(p07, zero); 282 | auto p811 = _mm256_unpacklo_epi8(p815, zero); 283 | auto p1215 = _mm256_unpackhi_epi8(p815, zero); 284 | 285 | p03 = _mm256_madd_epi16(p03, mask); 286 | p47 = _mm256_madd_epi16(p47, mask); 287 | p811 = _mm256_madd_epi16(p811, mask); 288 | p1215 = _mm256_madd_epi16(p1215, mask); 289 | 290 | p03 = _mm256_add_epi32(p03, round_mask); 291 | p47 = _mm256_add_epi32(p47, round_mask); 292 | p811 = _mm256_add_epi32(p811, round_mask); 293 | p1215 = _mm256_add_epi32(p1215, round_mask); 294 | 295 | p03 = _mm256_srli_epi32(p03, 15); 296 | p47 = _mm256_srli_epi32(p47, 15); 297 | p811 = _mm256_srli_epi32(p811, 15); 298 | p1215 = _mm256_srli_epi32(p1215, 15); 299 | 300 | p07 = _mm256_packs_epi32(p03, p47); 301 | p815 = _mm256_packs_epi32(p811, p1215); 302 | 303 | __m256i result = _mm256_packus_epi16(p07, p815); 304 | 305 | _mm256_store_si256(reinterpret_cast<__m256i*>(p1 + x), result); 306 | } 307 | 308 | for (int x = wMod32; x < wMod16; x += 16) { 309 | __m128i px1 = _mm_load_si128(reinterpret_cast(p1 + x)); // y15y14 ... y7y6 y5y4 y3y2 y1y0 310 | __m128i px2 = _mm_load_si128(reinterpret_cast(p2 + x)); // Y15Y14 ... Y7Y6 Y5Y4 Y3Y2 Y1Y0 311 | 312 | __m128i p07 = _mm_unpacklo_epi8(px1, px2); // Y7y7 .. Y3y3 Y2y2 Y1y1 Y0y0 313 | __m128i p815 = _mm_unpackhi_epi8(px1, px2); //Y15y15 ..Y11y11 Y10y10 Y9y9 Y8y8 314 | 315 | __m128i p03 = _mm_unpacklo_epi8(p07, zero_128); //00Y3 00y3 00Y2 00y2 00Y1 00y1 00Y0 00y0 8*short 316 | __m128i p47 = _mm_unpackhi_epi8(p07, zero_128); 317 | __m128i p811 = _mm_unpacklo_epi8(p815, zero_128); 318 | __m128i p1215 = _mm_unpackhi_epi8(p815, zero_128); 319 | 320 | p03 = _mm_madd_epi16(p03, mask_128); 321 | p47 = _mm_madd_epi16(p47, mask_128); 322 | p811 = _mm_madd_epi16(p811, mask_128); 323 | p1215 = _mm_madd_epi16(p1215, mask_128); 324 | 325 | p03 = _mm_add_epi32(p03, round_mask_128); 326 | p47 = _mm_add_epi32(p47, round_mask_128); 327 | p811 = _mm_add_epi32(p811, round_mask_128); 328 | p1215 = _mm_add_epi32(p1215, round_mask_128); 329 | 330 | p03 = _mm_srli_epi32(p03, 15); 331 | p47 = _mm_srli_epi32(p47, 15); 332 | p811 = _mm_srli_epi32(p811, 15); 333 | p1215 = _mm_srli_epi32(p1215, 15); 334 | 335 | p07 = _mm_packs_epi32(p03, p47); 336 | p815 = _mm_packs_epi32(p811, p1215); 337 | 338 | __m128i result = _mm_packus_epi16(p07, p815); 339 | 340 | _mm_store_si128(reinterpret_cast<__m128i*>(p1 + x), result); 341 | } 342 | 343 | for (size_t x = wMod16 / sizeof(uint8_t); x < rowsize / sizeof(uint8_t); x++) { 344 | reinterpret_cast(p1)[x] = (reinterpret_cast(p1)[x] * invweight_i + reinterpret_cast(p2)[x] * weight_i + 16384) >> 15; 345 | } 346 | 347 | p1 += p1_pitch; 348 | p2 += p2_pitch; 349 | } 350 | _mm256_zeroupper(); 351 | } 352 | -------------------------------------------------------------------------------- /Src/Common/merge_avx2.h: -------------------------------------------------------------------------------- 1 | #ifndef __Merge_AVX2_H__ 2 | #define __Merge_AVX2_H__ 3 | 4 | #include "../Environments/Common.h" 5 | template 6 | void average_plane_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height); 7 | 8 | template 9 | void weighted_merge_planar_uint16_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int width, int height, float weight_f, int weight_i, int invweight_i); 10 | void weighted_merge_planar_avx2(BYTE *p1,const BYTE *p2, int p1_pitch, int p2_pitch,int rowsize, int height, float weight_f, int weight_i, int invweight_i); 11 | 12 | #endif // __MergeAVX2_H__ 13 | -------------------------------------------------------------------------------- /Src/Environments/Avisynth.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Avisynth/avisynth.h" 3 | #include "Common.h" 4 | #include 5 | 6 | struct AvsEnvironment : public ICommonEnvironment { 7 | IScriptEnvironment* Env; 8 | 9 | AvsEnvironment(const char* pluginName, IScriptEnvironment* _env) : 10 | ICommonEnvironment(pluginName), 11 | Env(_env) 12 | { 13 | } 14 | 15 | void ThrowErrorInternal(const char* message) 16 | { 17 | Env->ThrowError(message); 18 | } 19 | 20 | void MakeWritable(ICommonFrame& frame) 21 | { 22 | Env->MakeWritable((PVideoFrame*)frame.Ref); 23 | } 24 | }; 25 | 26 | struct AvsVideo : public ICommonVideo 27 | { 28 | const VideoInfo VInfo; 29 | 30 | AvsVideo(PClip _video) : 31 | ICommonVideo(_video), 32 | VInfo(_video ? _video->GetVideoInfo() : VideoInfo()) 33 | { 34 | } 35 | 36 | int FpsNum() 37 | { 38 | return VInfo.fps_numerator; 39 | } 40 | 41 | int FpsDen() 42 | { 43 | return VInfo.fps_denominator; 44 | } 45 | 46 | int Height() 47 | { 48 | return VInfo.height; 49 | } 50 | 51 | int Width() 52 | { 53 | return VInfo.width; 54 | } 55 | 56 | int NumFrames() 57 | { 58 | return VInfo.num_frames; 59 | } 60 | 61 | int NumPlanes() 62 | { 63 | return IsPlanar() ? VInfo.NumComponents() : 1; 64 | } 65 | 66 | int BitsPerSample() 67 | { 68 | return VInfo.BitsPerComponent(); 69 | } 70 | 71 | bool IsPlanar() 72 | { 73 | return VInfo.IsPlanar(); 74 | } 75 | 76 | bool IsY() 77 | { 78 | return VInfo.IsY(); 79 | } 80 | 81 | bool IsYUV() 82 | { 83 | return VInfo.IsYUV(); 84 | } 85 | 86 | bool IsRGB() 87 | { 88 | return VInfo.IsRGB(); 89 | } 90 | 91 | bool IsYUY2() 92 | { 93 | return VInfo.IsYUY2(); 94 | } 95 | 96 | bool HasAlpha() 97 | { 98 | return VInfo.NumComponents() == 4; 99 | } 100 | }; 101 | 102 | struct AvsFrame : public ICommonFrame 103 | { 104 | const PVideoFrame& Frame; 105 | const VideoInfo VInfo; 106 | 107 | AvsFrame(PVideoFrame& _frame, const VideoInfo _vi) : 108 | ICommonFrame(&_frame), 109 | Frame(_frame), VInfo(_vi) 110 | { 111 | } 112 | 113 | bool HasValue() 114 | { 115 | return Frame; 116 | } 117 | 118 | // Convert plane index to Avisynth plane flag. 119 | int GetPlane(int plane) 120 | { 121 | if (VInfo.IsPlanar()) 122 | { 123 | if (VInfo.IsYUV()) 124 | { 125 | return plane == 0 ? PLANAR_Y : plane == 1 ? PLANAR_U : plane == 2 ? PLANAR_V : plane == 3 ? PLANAR_A : throw std::string("Invalid plane index."); 126 | } 127 | else if (VInfo.IsRGB()) 128 | { 129 | return plane == 0 ? PLANAR_R : plane == 1 ? PLANAR_G : plane == 2 ? PLANAR_B : plane == 3 ? PLANAR_A : throw std::string("Invalid plane index."); 130 | } 131 | } 132 | return plane == 0 ? 0 : throw std::string("Invalid plane index."); 133 | } 134 | 135 | int GetStride(int plane = 0) 136 | { 137 | return Frame->GetPitch(GetPlane(plane)); 138 | } 139 | 140 | int GetRowSize(int plane = 0) 141 | { 142 | return Frame->GetRowSize(GetPlane(plane)); 143 | } 144 | 145 | int GetWidth(int plane = 0) 146 | { 147 | return Frame->GetRowSize(GetPlane(plane)) / BytesPerSample(); 148 | } 149 | 150 | int GetHeight(int plane = 0) 151 | { 152 | return Frame->GetHeight(GetPlane(plane)); 153 | } 154 | 155 | int BitsPerSample() 156 | { 157 | return VInfo.BitsPerComponent(); 158 | } 159 | 160 | int BytesPerSample() 161 | { 162 | return VInfo.BitsPerComponent(); 163 | } 164 | 165 | BYTE* GetWritePtr(int plane = 0) 166 | { 167 | return Frame->GetWritePtr(GetPlane(plane)); 168 | } 169 | 170 | const BYTE* GetReadPtr(int plane = 0) 171 | { 172 | return Frame->GetReadPtr(GetPlane(plane)); 173 | } 174 | }; -------------------------------------------------------------------------------- /Src/Environments/Common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "instrset_detect.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma warning(disable:26812) 8 | 9 | typedef unsigned char BYTE; 10 | 11 | struct ICommonVideo 12 | { 13 | void* Ref = nullptr; 14 | ICommonVideo(void* ref) : 15 | Ref(ref) 16 | { 17 | } 18 | virtual ~ICommonVideo() {}; 19 | virtual int FpsNum() = 0; 20 | virtual int FpsDen() = 0; 21 | virtual int Height() = 0; 22 | virtual int Width() = 0; 23 | virtual int NumFrames() = 0; 24 | virtual int NumPlanes() = 0; 25 | 26 | virtual int BitsPerSample() = 0; 27 | virtual bool IsPlanar() = 0; 28 | virtual bool IsY() = 0; 29 | virtual bool IsYUV() = 0; 30 | virtual bool IsRGB() = 0; 31 | virtual bool IsYUY2() = 0; 32 | virtual bool HasAlpha() = 0; 33 | }; 34 | 35 | struct ICommonFrame 36 | { 37 | void* Ref = nullptr; 38 | ICommonFrame(void* ref) : 39 | Ref(ref) 40 | { 41 | } 42 | virtual ~ICommonFrame() {} 43 | virtual bool HasValue() = 0; 44 | virtual int GetStride(int plane = 0) = 0; 45 | virtual int GetRowSize(int plane = 0) = 0; 46 | virtual int GetWidth(int plane = 0) = 0; 47 | virtual int GetHeight(int plane = 0) = 0; 48 | virtual int BitsPerSample() = 0; 49 | virtual int BytesPerSample() = 0; 50 | virtual BYTE* GetWritePtr(int plane = 0) = 0; 51 | virtual const BYTE* GetReadPtr(int plane = 0) = 0; 52 | }; 53 | 54 | struct ICommonEnvironment 55 | { 56 | const char* PluginName; 57 | 58 | ICommonEnvironment(const char* pluginName) 59 | { 60 | PluginName = pluginName; 61 | } 62 | 63 | virtual ~ICommonEnvironment() {} 64 | 65 | //void ThrowError(const char* message) 66 | //{ 67 | // // Start the error message with plugin name. 68 | // const int MaxSize = 512; 69 | // const size_t NameLength = strlen(PluginName); 70 | // char Buffer[MaxSize]{ 0 }; 71 | // strcpy(Buffer, PluginName); 72 | // Buffer[NameLength] = ':'; 73 | // Buffer[NameLength + 1] = ' '; 74 | 75 | // // Add the error message. 76 | // strncpy(Buffer + NameLength + 2, message, 512 - NameLength - 2); 77 | 78 | // ThrowErrorInternal(Buffer); 79 | //} 80 | 81 | bool ThrowError(const char* format, ...) 82 | { 83 | // Start the error message with plugin name. 84 | const int MaxSize = 512; 85 | const size_t NameLength = strlen(PluginName); 86 | char Buffer[MaxSize]{ 0 }; 87 | strcpy_s(Buffer, PluginName); 88 | Buffer[NameLength] = ':'; 89 | Buffer[NameLength + 1] = ' '; 90 | 91 | // Add the error message. 92 | va_list args; 93 | va_start(args, format); 94 | vsnprintf(Buffer + NameLength + 2, 512 - NameLength - 2, format, args); 95 | va_end(args); 96 | 97 | ThrowErrorInternal(Buffer); 98 | return true; 99 | } 100 | 101 | //virtual void MakeWritable(ICommonFrame& frame) = 0; 102 | 103 | const int GetCpuSupport() 104 | { 105 | return instrset_detect(); 106 | } 107 | //const int ISET_NONE = 0; // 80386 instruction set 108 | //const int ISET_SSE = 1; // SSE (XMM) supported by CPU (not testing for O.S. support) 109 | //const int ISET_SSE2 = 2; // SSE2 110 | //const int ISET_SSE3 = 3; // SSE3 111 | //const int ISET_SSSE3 = 4; // Supplementary SSE3 (SSSE3) 112 | //const int ISET_SSE41 = 5; // SSE4.1 113 | //const int ISET_SSE42 = 6; // SSE4.2 114 | //const int ISET_AVX = 7; // AVX supported by CPU and operating system 115 | //const int ISET_AVX2 = 8; // AVX2 116 | //const int ISET_AVXS12F = 9; // AVX512F 117 | //const int ISET_AVX512VL = 10; // AVX512VL 118 | //const int ISET_AVX512BW = 11; // AVX512BW, AVX512DQ 119 | 120 | protected: 121 | virtual void ThrowErrorInternal(const char* message) = 0; 122 | }; 123 | -------------------------------------------------------------------------------- /Src/Environments/VapourSynth.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../VapourSynth/VapourSynth.h" 3 | #include "Common.h" 4 | #include "../VapourSynth/VSHelper.h" 5 | #include 6 | #include 7 | 8 | struct VpyEnvironment : public ICommonEnvironment 9 | { 10 | const VSAPI* Api; 11 | VSCore* Core; 12 | VSMap* Out = nullptr; 13 | VSFrameContext* FrameCtx = nullptr; 14 | 15 | VpyEnvironment(const char* pluginName, const VSAPI* _api, VSCore* _core, VSMap* out) : 16 | ICommonEnvironment(pluginName), 17 | Api(_api), Core(_core), Out(out) 18 | { 19 | } 20 | 21 | VpyEnvironment(const char* pluginName, const VSAPI* _api, VSCore* _core, VSFrameContext* frameCtx) : 22 | ICommonEnvironment(pluginName), 23 | Api(_api), Core(_core), FrameCtx(frameCtx) 24 | { 25 | } 26 | 27 | void ThrowErrorInternal(const char* message) 28 | { 29 | if (Out) 30 | { 31 | Api->setError(Out, message); 32 | } 33 | else if (FrameCtx) 34 | { 35 | Api->setFilterError(message, FrameCtx); 36 | } 37 | else 38 | { 39 | throw std::runtime_error{ message }; 40 | } 41 | } 42 | 43 | void MakeWritable(ICommonFrame& frame) 44 | { 45 | auto Copy = Api->copyFrame(static_cast(frame.Ref), Core); 46 | Api->freeFrame((VSFrameRef*)frame.Ref); 47 | frame.Ref = Copy; 48 | } 49 | 50 | VSNodeRef* InvokeClip(const char* ns, const char* func, VSMap* args, VSNodeRef* input) 51 | { 52 | VSNodeRef* Result = nullptr; 53 | auto Plugin = Api->getPluginByNs(ns, Core); 54 | auto ret = Api->invoke(Plugin, func, args); 55 | Api->freeNode(input); 56 | if (Api->getError(ret)) 57 | { 58 | ThrowError(Api->getError(ret)); 59 | } 60 | else 61 | { 62 | Result = Api->propGetNode(ret, "clip", 0, NULL); 63 | } 64 | Api->freeMap(ret); 65 | return Result; 66 | } 67 | }; 68 | 69 | struct VpyVideo : ICommonVideo 70 | { 71 | const VSVideoInfo* VInfo; 72 | 73 | VpyVideo(VSNodeRef* _video, const VSAPI* _api) : 74 | ICommonVideo(_video), 75 | VInfo(_video ? _api->getVideoInfo(_video) : nullptr) 76 | { 77 | } 78 | 79 | int FpsNum() 80 | { 81 | return (int)VInfo->fpsNum; 82 | } 83 | 84 | int FpsDen() 85 | { 86 | return (int)VInfo->fpsDen; 87 | } 88 | 89 | int Height() 90 | { 91 | return VInfo->height; 92 | } 93 | 94 | int Width() 95 | { 96 | return VInfo->width; 97 | } 98 | 99 | int NumFrames() 100 | { 101 | return VInfo->numFrames; 102 | } 103 | 104 | int NumPlanes() 105 | { 106 | return VInfo->format->numPlanes; 107 | } 108 | 109 | int BitsPerSample() 110 | { 111 | return VInfo->format->bitsPerSample; 112 | } 113 | 114 | bool IsPlanar() 115 | { 116 | return VInfo->format->numPlanes > 0; 117 | } 118 | 119 | bool IsY() 120 | { 121 | return VInfo->format->colorFamily == cmGray; 122 | } 123 | 124 | bool IsYUV() 125 | { 126 | return VInfo->format->colorFamily == cmYUV; 127 | } 128 | 129 | bool IsRGB() 130 | { 131 | return VInfo->format->colorFamily == cmRGB; 132 | } 133 | 134 | bool IsYUY2() 135 | { 136 | return VInfo->format->id == pfCompatYUY2; 137 | } 138 | 139 | bool HasAlpha() 140 | { 141 | return VInfo->format->numPlanes == 4 || VInfo->format->id == pfCompatBGR32; 142 | } 143 | }; 144 | 145 | struct VpyFrame : public ICommonFrame 146 | { 147 | const VSAPI* Api; 148 | VSFrameRef* Frame() 149 | { 150 | return (VSFrameRef*)Ref; 151 | } 152 | 153 | VpyFrame(VSFrameRef* _frame, const VSAPI* _api) : 154 | ICommonFrame(_frame), 155 | Api(_api) 156 | { 157 | } 158 | 159 | VpyFrame(const VSFrameRef* _frame, const VSAPI* _api) : 160 | ICommonFrame((VSFrameRef*)_frame), 161 | Api(_api) 162 | { 163 | } 164 | 165 | bool HasValue() 166 | { 167 | return Ref; 168 | } 169 | 170 | int GetStride(int plane = 0) 171 | { 172 | return Api->getStride(Frame(), plane); 173 | } 174 | 175 | int GetRowSize(int plane = 0) 176 | { 177 | return GetWidth(plane) * BytesPerSample(); 178 | } 179 | 180 | int GetWidth(int plane = 0) 181 | { 182 | return Api->getFrameWidth(Frame(), plane); 183 | } 184 | 185 | int GetHeight(int plane = 0) 186 | { 187 | return Api->getFrameHeight(Frame(), plane); 188 | } 189 | 190 | int BitsPerSample() 191 | { 192 | return Api->getFrameFormat(Frame())->bitsPerSample; 193 | } 194 | 195 | int BytesPerSample() 196 | { 197 | return Api->getFrameFormat(Frame())->bytesPerSample; 198 | } 199 | 200 | BYTE* GetWritePtr(int plane = 0) 201 | { 202 | return Api->getWritePtr(Frame(), plane); 203 | } 204 | 205 | const BYTE* GetReadPtr(int plane = 0) 206 | { 207 | return Api->getReadPtr(Frame(), plane); 208 | } 209 | }; 210 | -------------------------------------------------------------------------------- /Src/Environments/VpyFilter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "VapourSynth.hpp" 3 | #include "VpyPropReader.hpp" 4 | 5 | // Base class for VapourSynth filter where it initializes and calls a class. The class pointer is stored in instanceData, and the class itself holds the data. 6 | class VpyFilter 7 | { 8 | public: 9 | const char* PluginName2; 10 | VSNodeRef* Node; 11 | const VSVideoInfo* viSrc; 12 | VSVideoInfo viDst; 13 | // VpyEnvironment env; 14 | VSCore* core; 15 | const VSAPI* api; 16 | VSMap* Out; 17 | 18 | VpyFilter::VpyFilter(const char* pluginName, const VSMap* in, VSMap* out, VSNodeRef* node, VSCore* _core, const VSAPI* _api) : 19 | Node(node), viSrc(_api->getVideoInfo(node)), viDst(*viSrc), api(_api), core(_core), Out(out) 20 | { 21 | PluginName2 = pluginName; 22 | } 23 | 24 | ~VpyFilter() 25 | { 26 | } 27 | 28 | void CreateFilter(const VSMap* in, VSMap* out) 29 | { 30 | api->createFilter(in, out, "ContinuousMask", VpyFilter::Init, VpyFilter::GetFrame, VpyFilter::Free, fmParallel, 0, this, core); 31 | } 32 | 33 | bool HasError() 34 | { 35 | return api->getError(Out); 36 | } 37 | 38 | virtual void VpyFilter::Init(VSMap* in, VSMap* out, VSNode* node, VpyEnvironment& env) = 0; 39 | virtual VSFrameRef* VpyFilter::GetFrame(int n, int activationReason, void** frameData, VSFrameContext* frameCtx, VpyEnvironment& env) = 0; 40 | virtual void VpyFilter::Free() = 0; 41 | 42 | 43 | 44 | static void VS_CC VpyFilter::Init(VSMap* in, VSMap* out, void** instanceData, VSNode* node, VSCore* core, const VSAPI* api) 45 | { 46 | VpyFilter* filter = (VpyFilter*)*instanceData; 47 | filter->Init(in, out, node, VpyEnvironment(filter->PluginName2, api, core, out)); 48 | api->setVideoInfo(&filter->viDst, 1, node); 49 | } 50 | 51 | static const VSFrameRef* VS_CC VpyFilter::GetFrame(int n, int activationReason, void** instanceData, void** frameData, VSFrameContext* frameCtx, VSCore* core, const VSAPI* api) 52 | { 53 | VpyFilter* filter = (VpyFilter*)*instanceData; 54 | filter->core = core; 55 | return filter->GetFrame(n, activationReason, frameData, frameCtx, VpyEnvironment(filter->PluginName2, api, core, frameCtx)); 56 | } 57 | 58 | static void VS_CC VpyFilter::Free(void* instanceData, VSCore* core, const VSAPI* api) 59 | { 60 | VpyFilter* filter = (VpyFilter*)instanceData; 61 | filter->core = core; 62 | filter->Free(); 63 | api->freeNode(filter->Node); 64 | delete filter; 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /Src/Environments/VpyPropReader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "VapourSynth.hpp" 3 | #include 4 | 5 | class VpyPropReader 6 | { 7 | public: 8 | VpyPropReader(const VSAPI* _api, const VSMap* _map) : 9 | api(_api), map(_map) 10 | { 11 | } 12 | 13 | int64_t GetInt(const char* key, int64_t def = 0) 14 | { 15 | int err; 16 | auto result = api->propGetInt(map, key, 0, &err); 17 | return GetResult(result, def, err); 18 | } 19 | 20 | double GetFloat(const char* key, double def = 0) 21 | { 22 | int err; 23 | auto result = api->propGetFloat(map, key, 0, &err); 24 | return GetResult(result, def, err); 25 | } 26 | 27 | VSNodeRef* GetNode(const char* key, VSNodeRef* def = nullptr) 28 | { 29 | int err; 30 | auto result = api->propGetNode(map, key, 0, &err); 31 | return GetResult(result, def, err); 32 | } 33 | 34 | const VSFrameRef* GetFrame(const char* key, const VSFrameRef* def = nullptr) 35 | { 36 | int err; 37 | auto result = api->propGetFrame(map, key, 0, &err); 38 | return GetResult(result, def, err); 39 | } 40 | 41 | VSFuncRef* GetFunc(const char* key, VSFuncRef* def = nullptr) 42 | { 43 | int err; 44 | auto result = api->propGetFunc(map, key, 0, &err); 45 | return GetResult(result, def, err); 46 | } 47 | 48 | const char* GetData(const char* key, const char* def = nullptr) 49 | { 50 | int err; 51 | auto result = api->propGetData(map, key, 0, &err); 52 | return GetResult(result, def, err); 53 | } 54 | 55 | template 56 | T GetResult(T result, T def, int err) 57 | { 58 | return !err ? result : err != peType ? def : throw std::string("Invalid parameter type."); 59 | } 60 | 61 | private: 62 | const VSAPI* api; 63 | const VSMap* map; 64 | }; 65 | -------------------------------------------------------------------------------- /Src/Environments/cpufeatures.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 Fredrik Mellbin 3 | * 4 | * This file is part of VapourSynth. 5 | * 6 | * VapourSynth is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * VapourSynth is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with VapourSynth; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include 22 | 23 | #include "cpufeatures.h" 24 | 25 | #ifdef VS_TARGET_CPU_X86 26 | 27 | #ifdef _MSC_VER 28 | #include 29 | #else 30 | #include 31 | #endif 32 | 33 | static void vs_cpu_cpuid(int index, int* eax, int* ebx, int* ecx, int* edx) { 34 | *eax = 0; 35 | *ebx = 0; 36 | *ecx = 0; 37 | *edx = 0; 38 | #ifdef _MSC_VER 39 | int regs[4]; 40 | __cpuidex(regs, index, 0); 41 | *eax = regs[0]; 42 | *ebx = regs[1]; 43 | *ecx = regs[2]; 44 | *edx = regs[3]; 45 | #elif defined(__GNUC__) 46 | __cpuid_count(index, 0, *eax, *ebx, *ecx, *edx); 47 | #else 48 | #error "Unknown compiler, can't get cpuid" 49 | #endif 50 | } 51 | 52 | static unsigned long long vs_cpu_xgetbv(unsigned ecx) { 53 | #if defined(_MSC_VER) 54 | return _xgetbv(ecx); 55 | #elif defined(__GNUC__) 56 | unsigned eax, edx; 57 | __asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(ecx) : ); 58 | return (((unsigned long long)edx) << 32) | eax; 59 | #else 60 | return 0; 61 | #endif 62 | } 63 | 64 | static void doGetCPUFeatures(CPUFeatures* cpuFeatures) { 65 | memset(cpuFeatures, 0, sizeof(CPUFeatures)); 66 | 67 | int eax = 0; 68 | int ebx = 0; 69 | int ecx = 0; 70 | int edx = 0; 71 | long long xedxeax = 0; 72 | vs_cpu_cpuid(1, &eax, &ebx, &ecx, &edx); 73 | cpuFeatures->can_run_vs = !!(edx & (1 << 26)); //sse2 74 | cpuFeatures->sse3 = !!(ecx & 1); 75 | cpuFeatures->ssse3 = !!(ecx & (1 << 9)); 76 | cpuFeatures->sse4_1 = !!(ecx & (1 << 19)); 77 | cpuFeatures->sse4_2 = !!(ecx & (1 << 20)); 78 | cpuFeatures->fma3 = !!(ecx & (1 << 12)); 79 | cpuFeatures->f16c = !!(ecx & (1 << 29)); 80 | cpuFeatures->aes = !!(ecx & (1 << 25)); 81 | cpuFeatures->movbe = !!(ecx & (1 << 22)); 82 | cpuFeatures->popcnt = !!(ecx & (1 << 23)); 83 | 84 | if ((ecx & (1 << 27)) && (ecx & (1 << 28))) { 85 | xedxeax = vs_cpu_xgetbv(0); 86 | cpuFeatures->avx = ((xedxeax & 0x06) == 0x06); 87 | if (cpuFeatures->avx) { 88 | eax = 0; 89 | ebx = 0; 90 | ecx = 0; 91 | edx = 0; 92 | vs_cpu_cpuid(7, &eax, &ebx, &ecx, &edx); 93 | cpuFeatures->avx2 = !!(ebx & (1 << 5)); 94 | cpuFeatures->avx512_f = !!(ebx & (1 << 16)) && ((xedxeax & 0xE0) == 0xE0); 95 | 96 | if (cpuFeatures->avx512_f) { 97 | cpuFeatures->avx512_cd = !!(ebx & (1 << 28)); 98 | cpuFeatures->avx512_bw = !!(ebx & (1 << 30)); 99 | cpuFeatures->avx512_dq = !!(ebx & (1 << 17)); 100 | cpuFeatures->avx512_vl = !!(ebx & (1 << 31)); 101 | } 102 | } 103 | } 104 | } 105 | #else 106 | static void doGetCPUFeatures(CPUFeatures* cpuFeatures) { 107 | memset(cpuFeatures, 0, sizeof(CPUFeatures)); 108 | cpuFeatures->can_run_vs = 1; 109 | } 110 | #endif 111 | 112 | const CPUFeatures* getCPUFeatures(void) { 113 | static CPUFeatures features = []() 114 | { 115 | CPUFeatures tmp; 116 | doGetCPUFeatures(&tmp); 117 | return tmp; 118 | }(); 119 | 120 | return &features; 121 | } -------------------------------------------------------------------------------- /Src/Environments/cpufeatures.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2020 Fredrik Mellbin 3 | * 4 | * This file is part of VapourSynth. 5 | * 6 | * VapourSynth is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * VapourSynth is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with VapourSynth; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef CPUFEATURES_H 22 | #define CPUFEATURES_H 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | typedef struct CPUFeatures { 29 | // This is to determine if the cpu is up to the minimum requirements in terms of supported instructions 30 | // that the VapourSynth core uses. 31 | char can_run_vs; 32 | #ifdef VS_TARGET_CPU_X86 33 | // On x86, all features up to sse2 are required. 34 | char sse3; 35 | char ssse3; 36 | char sse4_1; 37 | char sse4_2; 38 | char fma3; 39 | char avx; 40 | char avx2; 41 | char f16c; 42 | char aes; 43 | char movbe; 44 | char popcnt; 45 | char avx512_f; 46 | char avx512_cd; 47 | char avx512_bw; 48 | char avx512_dq; 49 | char avx512_vl; 50 | #endif 51 | } CPUFeatures; 52 | 53 | const CPUFeatures* getCPUFeatures(void); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif -------------------------------------------------------------------------------- /Src/Environments/instrset_detect.cpp: -------------------------------------------------------------------------------- 1 | /************************** instrset_detect.cpp **************************** 2 | * Author: Agner Fog 3 | * Date created: 2012-05-30 4 | * Last modified: 2017-05-02 5 | * Version: 1.28 6 | * Project: vector classes 7 | * Description: 8 | * Functions for checking which instruction sets are supported. 9 | * 10 | * (c) Copyright 2012-2017 GNU General Public License http://www.gnu.org/licenses 11 | \*****************************************************************************/ 12 | 13 | #include "instrset_detect.h" 14 | 15 | #ifdef VCL_NAMESPACE 16 | namespace VCL_NAMESPACE { 17 | #endif 18 | 19 | // Define interface to cpuid instruction. 20 | // input: eax = functionnumber, ecx = 0 21 | // output: eax = output[0], ebx = output[1], ecx = output[2], edx = output[3] 22 | static inline void cpuid(int output[4], int functionnumber) { 23 | #if defined(__GNUC__) || defined(__clang__) // use inline assembly, Gnu/AT&T syntax 24 | 25 | int a, b, c, d; 26 | __asm("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(functionnumber), "c"(0) : ); 27 | output[0] = a; 28 | output[1] = b; 29 | output[2] = c; 30 | output[3] = d; 31 | 32 | #elif defined (_MSC_VER) || defined (__INTEL_COMPILER) // Microsoft or Intel compiler, intrin.h included 33 | 34 | __cpuidex(output, functionnumber, 0); // intrinsic function for CPUID 35 | 36 | #else // unknown platform. try inline assembly with masm/intel syntax 37 | 38 | __asm { 39 | mov eax, functionnumber 40 | xor ecx, ecx 41 | cpuid; 42 | mov esi, output 43 | mov[esi], eax 44 | mov[esi + 4], ebx 45 | mov[esi + 8], ecx 46 | mov[esi + 12], edx 47 | } 48 | 49 | #endif 50 | } 51 | 52 | // Define interface to xgetbv instruction 53 | static inline int64_t xgetbv(int ctr) { 54 | #if (defined (_MSC_FULL_VER) && _MSC_FULL_VER >= 160040000) || (defined (__INTEL_COMPILER) && __INTEL_COMPILER >= 1200) // Microsoft or Intel compiler supporting _xgetbv intrinsic 55 | 56 | return _xgetbv(ctr); // intrinsic function for XGETBV 57 | 58 | #elif defined(__GNUC__) // use inline assembly, Gnu/AT&T syntax 59 | 60 | uint32_t a, d; 61 | __asm("xgetbv" : "=a"(a), "=d"(d) : "c"(ctr) : ); 62 | return a | (uint64_t(d) << 32); 63 | 64 | #else // #elif defined (_WIN32) // other compiler. try inline assembly with masm/intel/MS syntax 65 | 66 | uint32_t a, d; 67 | __asm { 68 | mov ecx, ctr 69 | _emit 0x0f 70 | _emit 0x01 71 | _emit 0xd0; // xgetbv 72 | mov a, eax 73 | mov d, edx 74 | } 75 | return a | (uint64_t(d) << 32); 76 | 77 | #endif 78 | } 79 | 80 | 81 | /* find supported instruction set 82 | return value: 83 | 0 = 80386 instruction set 84 | 1 or above = SSE (XMM) supported by CPU (not testing for O.S. support) 85 | 2 or above = SSE2 86 | 3 or above = SSE3 87 | 4 or above = Supplementary SSE3 (SSSE3) 88 | 5 or above = SSE4.1 89 | 6 or above = SSE4.2 90 | 7 or above = AVX supported by CPU and operating system 91 | 8 or above = AVX2 92 | 9 or above = AVX512F 93 | 10 or above = AVX512VL 94 | 11 or above = AVX512BW, AVX512DQ 95 | */ 96 | int instrset_detect(void) { 97 | 98 | static int iset = -1; // remember value for next call 99 | if (iset >= 0) { 100 | return iset; // called before 101 | } 102 | iset = 0; // default value 103 | int abcd[4] = { 0,0,0,0 }; // cpuid results 104 | cpuid(abcd, 0); // call cpuid function 0 105 | if (abcd[0] == 0) return iset; // no further cpuid function supported 106 | cpuid(abcd, 1); // call cpuid function 1 for feature flags 107 | if ((abcd[3] & (1 << 0)) == 0) return iset; // no floating point 108 | if ((abcd[3] & (1 << 23)) == 0) return iset; // no MMX 109 | if ((abcd[3] & (1 << 15)) == 0) return iset; // no conditional move 110 | if ((abcd[3] & (1 << 24)) == 0) return iset; // no FXSAVE 111 | if ((abcd[3] & (1 << 25)) == 0) return iset; // no SSE 112 | iset = 1; // 1: SSE supported 113 | if ((abcd[3] & (1 << 26)) == 0) return iset; // no SSE2 114 | iset = 2; // 2: SSE2 supported 115 | if ((abcd[2] & (1 << 0)) == 0) return iset; // no SSE3 116 | iset = 3; // 3: SSE3 supported 117 | if ((abcd[2] & (1 << 9)) == 0) return iset; // no SSSE3 118 | iset = 4; // 4: SSSE3 supported 119 | if ((abcd[2] & (1 << 19)) == 0) return iset; // no SSE4.1 120 | iset = 5; // 5: SSE4.1 supported 121 | if ((abcd[2] & (1 << 23)) == 0) return iset; // no POPCNT 122 | if ((abcd[2] & (1 << 20)) == 0) return iset; // no SSE4.2 123 | iset = 6; // 6: SSE4.2 supported 124 | if ((abcd[2] & (1 << 27)) == 0) return iset; // no OSXSAVE 125 | if ((xgetbv(0) & 6) != 6) return iset; // AVX not enabled in O.S. 126 | if ((abcd[2] & (1 << 28)) == 0) return iset; // no AVX 127 | iset = 7; // 7: AVX supported 128 | cpuid(abcd, 7); // call cpuid leaf 7 for feature flags 129 | if ((abcd[1] & (1 << 5)) == 0) return iset; // no AVX2 130 | iset = 8; 131 | if ((abcd[1] & (1 << 16)) == 0) return iset; // no AVX512 132 | cpuid(abcd, 0xD); // call cpuid leaf 0xD for feature flags 133 | if ((abcd[0] & 0x60) != 0x60) return iset; // no AVX512 134 | iset = 9; 135 | cpuid(abcd, 7); // call cpuid leaf 7 for feature flags 136 | if ((abcd[1] & (1 << 31)) == 0) return iset; // no AVX512VL 137 | iset = 10; 138 | if ((abcd[1] & 0x40020000) != 0x40020000) return iset; // no AVX512BW, AVX512DQ 139 | iset = 11; 140 | return iset; 141 | } 142 | 143 | // detect if CPU supports the FMA3 instruction set 144 | bool hasFMA3(void) { 145 | if (instrset_detect() < 7) return false; // must have AVX 146 | int abcd[4]; // cpuid results 147 | cpuid(abcd, 1); // call cpuid function 1 148 | return ((abcd[2] & (1 << 12)) != 0); // ecx bit 12 indicates FMA3 149 | } 150 | 151 | // detect if CPU supports the FMA4 instruction set 152 | bool hasFMA4(void) { 153 | if (instrset_detect() < 7) return false; // must have AVX 154 | int abcd[4]; // cpuid results 155 | cpuid(abcd, 0x80000001); // call cpuid function 0x80000001 156 | return ((abcd[2] & (1 << 16)) != 0); // ecx bit 16 indicates FMA4 157 | } 158 | 159 | // detect if CPU supports the XOP instruction set 160 | bool hasXOP(void) { 161 | if (instrset_detect() < 7) return false; // must have AVX 162 | int abcd[4]; // cpuid results 163 | cpuid(abcd, 0x80000001); // call cpuid function 0x80000001 164 | return ((abcd[2] & (1 << 11)) != 0); // ecx bit 11 indicates XOP 165 | } 166 | 167 | // detect if CPU supports the F16C instruction set 168 | bool hasF16C(void) { 169 | if (instrset_detect() < 7) return false; // must have AVX 170 | int abcd[4]; // cpuid results 171 | cpuid(abcd, 1); // call cpuid function 1 172 | return ((abcd[2] & (1 << 29)) != 0); // ecx bit 29 indicates F16C 173 | } 174 | 175 | // detect if CPU supports the AVX512ER instruction set 176 | bool hasAVX512ER(void) { 177 | if (instrset_detect() < 9) return false; // must have AVX512F 178 | int abcd[4]; // cpuid results 179 | cpuid(abcd, 7); // call cpuid function 7 180 | return ((abcd[1] & (1 << 27)) != 0); // ebx bit 27 indicates AVX512ER 181 | } 182 | 183 | 184 | #ifdef VCL_NAMESPACE 185 | } 186 | #endif -------------------------------------------------------------------------------- /Src/Environments/instrset_detect.h: -------------------------------------------------------------------------------- 1 | /**************************** instrset.h ********************************** 2 | * Author: Agner Fog 3 | * Date created: 2012-05-30 4 | * Last modified: 2016-11-25 5 | * Version: 1.25 6 | * Project: vector classes 7 | * Description: 8 | * Header file for various compiler-specific tasks and other common tasks to 9 | * vector class library: 10 | * > selects the supported instruction set 11 | * > defines integer types 12 | * > defines compiler version macros 13 | * > undefines certain macros that prevent function overloading 14 | * > defines template class to represent compile-time integer constant 15 | * > defines template for compile-time error messages 16 | * 17 | * (c) Copyright 2012-2016 GNU General Public License www.gnu.org/licenses 18 | ******************************************************************************/ 19 | 20 | #ifndef INSTRSET_H 21 | #define INSTRSET_H 125 22 | 23 | const int ISET_NONE = 0; // 80386 instruction set 24 | const int ISET_SSE = 1; // SSE (XMM) supported by CPU (not testing for O.S. support) 25 | const int ISET_SSE2 = 2; // SSE2 26 | const int ISET_SSE3 = 3; // SSE3 27 | const int ISET_SSSE3 = 4; // Supplementary SSE3 (SSSE3) 28 | const int ISET_SSE41 = 5; // SSE4.1 29 | const int ISET_SSE42 = 6; // SSE4.2 30 | const int ISET_AVX = 7; // AVX supported by CPU and operating system 31 | const int ISET_AVX2 = 8; // AVX2 32 | const int ISET_AVXS12F = 9; // AVX512F 33 | const int ISET_AVX512VL = 10; // AVX512VL 34 | const int ISET_AVX512BW = 11; // AVX512BW, AVX512DQ 35 | 36 | // Detect 64 bit mode 37 | #if (defined(_M_AMD64) || defined(_M_X64) || defined(__amd64) ) && ! defined(__x86_64__) 38 | #define __x86_64__ 1 // There are many different macros for this, decide on only one 39 | #endif 40 | 41 | // Find instruction set from compiler macros if INSTRSET not defined 42 | // Note: Most of these macros are not defined in Microsoft compilers 43 | #ifndef INSTRSET 44 | #if defined ( __AVX512F__ ) || defined ( __AVX512__ ) 45 | #define INSTRSET 9 46 | #elif defined ( __AVX2__ ) 47 | #define INSTRSET 8 48 | #elif defined ( __AVX__ ) 49 | #define INSTRSET 7 50 | #elif defined ( __SSE4_2__ ) 51 | #define INSTRSET 6 52 | #elif defined ( __SSE4_1__ ) 53 | #define INSTRSET 5 54 | #elif defined ( __SSSE3__ ) 55 | #define INSTRSET 4 56 | #elif defined ( __SSE3__ ) 57 | #define INSTRSET 3 58 | #elif defined ( __SSE2__ ) || defined ( __x86_64__ ) 59 | #define INSTRSET 2 60 | #elif defined ( __SSE__ ) 61 | #define INSTRSET 1 62 | #elif defined ( _M_IX86_FP ) // Defined in MS compiler. 1: SSE, 2: SSE2 63 | #define INSTRSET _M_IX86_FP 64 | #else 65 | #define INSTRSET 0 66 | #endif // instruction set defines 67 | #endif // INSTRSET 68 | 69 | // Include the appropriate header file for intrinsic functions 70 | #if INSTRSET > 7 // AVX2 and later 71 | #if defined (__GNUC__) && ! defined (__INTEL_COMPILER) 72 | #include // x86intrin.h includes header files for whatever instruction 73 | // sets are specified on the compiler command line, such as: 74 | // xopintrin.h, fma4intrin.h 75 | #else 76 | #include // MS version of immintrin.h covers AVX, AVX2 and FMA3 77 | #endif // __GNUC__ 78 | #elif INSTRSET == 7 79 | #include // AVX 80 | #elif INSTRSET == 6 81 | #include // SSE4.2 82 | #elif INSTRSET == 5 83 | #include // SSE4.1 84 | #elif INSTRSET == 4 85 | #include // SSSE3 86 | #elif INSTRSET == 3 87 | #include // SSE3 88 | #elif INSTRSET == 2 89 | #include // SSE2 90 | #elif INSTRSET == 1 91 | #include // SSE 92 | #endif // INSTRSET 93 | 94 | #if INSTRSET >= 8 && !defined(__FMA__) 95 | // Assume that all processors that have AVX2 also have FMA3 96 | #if defined (__GNUC__) && ! defined (__INTEL_COMPILER) && ! defined (__clang__) 97 | // Prevent error message in g++ when using FMA intrinsics with avx2: 98 | #pragma message "It is recommended to specify also option -mfma when using -mavx2 or higher" 99 | #else 100 | #define __FMA__ 1 101 | #endif 102 | #endif 103 | 104 | // AMD instruction sets 105 | #if defined (__XOP__) || defined (__FMA4__) 106 | #ifdef __GNUC__ 107 | #include // AMD XOP (Gnu) 108 | #else 109 | #include // AMD XOP (Microsoft) 110 | #endif // __GNUC__ 111 | #elif defined (__SSE4A__) // AMD SSE4A 112 | #include 113 | #endif // __XOP__ 114 | 115 | // FMA3 instruction set 116 | #if defined (__FMA__) && (defined(__GNUC__) || defined(__clang__)) && ! defined (__INTEL_COMPILER) 117 | #include 118 | #endif // __FMA__ 119 | 120 | // FMA4 instruction set 121 | #if defined (__FMA4__) && (defined(__GNUC__) || defined(__clang__)) 122 | #include // must have both x86intrin.h and fma4intrin.h, don't know why 123 | #endif // __FMA4__ 124 | 125 | 126 | // Define integer types with known size 127 | #if defined(__GNUC__) || defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1600) 128 | // Compilers supporting C99 or C++0x have stdint.h defining these integer types 129 | #include 130 | #elif defined(_MSC_VER) 131 | // Older Microsoft compilers have their own definitions 132 | typedef signed __int8 int8_t; 133 | typedef unsigned __int8 uint8_t; 134 | typedef signed __int16 int16_t; 135 | typedef unsigned __int16 uint16_t; 136 | typedef signed __int32 int32_t; 137 | typedef unsigned __int32 uint32_t; 138 | typedef signed __int64 int64_t; 139 | typedef unsigned __int64 uint64_t; 140 | #ifndef _INTPTR_T_DEFINED 141 | #define _INTPTR_T_DEFINED 142 | #ifdef __x86_64__ 143 | typedef int64_t intptr_t; 144 | #else 145 | typedef int32_t intptr_t; 146 | #endif 147 | #endif 148 | #else 149 | // This works with most compilers 150 | typedef signed char int8_t; 151 | typedef unsigned char uint8_t; 152 | typedef signed short int int16_t; 153 | typedef unsigned short int uint16_t; 154 | typedef signed int int32_t; 155 | typedef unsigned int uint32_t; 156 | typedef long long int64_t; 157 | typedef unsigned long long uint64_t; 158 | #ifdef __x86_64__ 159 | typedef int64_t intptr_t; 160 | #else 161 | typedef int32_t intptr_t; 162 | #endif 163 | #endif 164 | 165 | #include // define abs(int) 166 | 167 | #ifdef _MSC_VER // Microsoft compiler or compatible Intel compiler 168 | #include // define _BitScanReverse(int), __cpuid(int[4],int), _xgetbv(int) 169 | #endif // _MSC_VER 170 | 171 | // functions in instrset_detect.cpp 172 | #ifdef VCL_NAMESPACE 173 | namespace VCL_NAMESPACE { 174 | #endif 175 | int instrset_detect(void); // tells which instruction sets are supported 176 | bool hasFMA3(void); // true if FMA3 instructions supported 177 | bool hasFMA4(void); // true if FMA4 instructions supported 178 | bool hasXOP(void); // true if XOP instructions supported 179 | bool hasAVX512ER(void); // true if AVX512ER instructions supported 180 | #ifdef VCL_NAMESPACE 181 | } 182 | #endif 183 | 184 | // GCC version 185 | #if defined(__GNUC__) && !defined (GCC_VERSION) && !defined (__clang__) 186 | #define GCC_VERSION ((__GNUC__) * 10000 + (__GNUC_MINOR__) * 100 + (__GNUC_PATCHLEVEL__)) 187 | #endif 188 | 189 | // Clang version 190 | #if defined (__clang__) 191 | #define CLANG_VERSION ((__clang_major__) * 10000 + (__clang_minor__) * 100 + (__clang_patchlevel__)) 192 | // Problem: The version number is not consistent across platforms 193 | // http://llvm.org/bugs/show_bug.cgi?id=12643 194 | // Apple bug 18746972 195 | #endif 196 | 197 | // Fix problem with non-overloadable macros named min and max in WinDef.h 198 | //#ifdef _MSC_VER 199 | //#if defined (_WINDEF_) && defined(min) && defined(max) 200 | //#undef min 201 | //#undef max 202 | //#endif 203 | //#ifndef NOMINMAX 204 | //#define NOMINMAX 205 | //#endif 206 | //#endif 207 | 208 | #ifdef VCL_NAMESPACE 209 | namespace VCL_NAMESPACE { 210 | #endif 211 | // Template class to represent compile-time integer constant 212 | template class Const_int_t {}; // represent compile-time signed integer constant 213 | template class Const_uint_t {}; // represent compile-time unsigned integer constant 214 | #define const_int(n) (Const_int_t ()) // n must be compile-time integer constant 215 | #define const_uint(n) (Const_uint_t()) // n must be compile-time unsigned integer constant 216 | 217 | // Template for compile-time error messages 218 | template class Static_error_check { 219 | public: Static_error_check() {}; 220 | }; 221 | template <> class Static_error_check { // generate compile-time error if false 222 | private: Static_error_check() {}; 223 | }; 224 | #ifdef VCL_NAMESPACE 225 | } 226 | #endif 227 | 228 | #endif // INSTRSET_H -------------------------------------------------------------------------------- /Src/FrameRateConverter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31321.278 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FrameRateConverter", "FrameRateConverter.vcxproj", "{65E5B18E-B47F-43CB-B398-02E6E82E632E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {65E5B18E-B47F-43CB-B398-02E6E82E632E}.Debug|x64.ActiveCfg = Debug|x64 17 | {65E5B18E-B47F-43CB-B398-02E6E82E632E}.Debug|x64.Build.0 = Debug|x64 18 | {65E5B18E-B47F-43CB-B398-02E6E82E632E}.Debug|x86.ActiveCfg = Debug|Win32 19 | {65E5B18E-B47F-43CB-B398-02E6E82E632E}.Debug|x86.Build.0 = Debug|Win32 20 | {65E5B18E-B47F-43CB-B398-02E6E82E632E}.Release|x64.ActiveCfg = Release|x64 21 | {65E5B18E-B47F-43CB-B398-02E6E82E632E}.Release|x64.Build.0 = Release|x64 22 | {65E5B18E-B47F-43CB-B398-02E6E82E632E}.Release|x86.ActiveCfg = Release|Win32 23 | {65E5B18E-B47F-43CB-B398-02E6E82E632E}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {8CF36F63-0081-4383-A982-660959B5890C} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Src/FrameRateConverter.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {65E5B18E-B47F-43CB-B398-02E6E82E632E} 24 | Win32Proj 25 | ConditionalFilterMT 26 | 10.0 27 | FrameRateConverter 28 | 29 | 30 | 31 | DynamicLibrary 32 | true 33 | v142 34 | MultiByte 35 | 36 | 37 | DynamicLibrary 38 | false 39 | v142 40 | true 41 | MultiByte 42 | 43 | 44 | DynamicLibrary 45 | true 46 | v142 47 | MultiByte 48 | 49 | 50 | DynamicLibrary 51 | false 52 | v142 53 | true 54 | MultiByte 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | FrameRateConverter 77 | 78 | 79 | true 80 | FrameRateConverter 81 | 82 | 83 | false 84 | FrameRateConverter 85 | 86 | 87 | false 88 | FrameRateConverter 89 | 90 | 91 | 92 | 93 | 94 | Level3 95 | Disabled 96 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 97 | 98 | 99 | Console 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | 110 | 111 | Console 112 | 113 | 114 | 115 | 116 | Level3 117 | 118 | 119 | MaxSpeed 120 | true 121 | true 122 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | 124 | 125 | 126 | 127 | Console 128 | true 129 | true 130 | 131 | 132 | 133 | 134 | Level3 135 | 136 | 137 | MaxSpeed 138 | true 139 | true 140 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 141 | 142 | 143 | Console 144 | true 145 | true 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /Src/FrameRateConverter.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {e3645ab9-05da-4c15-9743-20b3b16be7aa} 6 | 7 | 8 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 9 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 10 | 11 | 12 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 13 | h;hh;hpp;hxx;hm;inl;inc;xsd 14 | 15 | 16 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 17 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 18 | 19 | 20 | {951d852d-b9b9-4c85-bde2-39a08c16318e} 21 | 22 | 23 | {5e84bcbd-8b7a-4b50-9ffa-cd1eec15f801} 24 | 25 | 26 | 27 | 28 | Headers 29 | 30 | 31 | Headers 32 | 33 | 34 | Headers 35 | 36 | 37 | Headers 38 | 39 | 40 | Headers 41 | 42 | 43 | Headers 44 | 45 | 46 | Headers 47 | 48 | 49 | Headers 50 | 51 | 52 | Avisynth 53 | 54 | 55 | Avisynth 56 | 57 | 58 | Common 59 | 60 | 61 | Common 62 | 63 | 64 | Common 65 | 66 | 67 | Avisynth 68 | 69 | 70 | Avisynth 71 | 72 | 73 | Avisynth 74 | 75 | 76 | Environments 77 | 78 | 79 | Environments 80 | 81 | 82 | Environments 83 | 84 | 85 | Headers 86 | 87 | 88 | Headers 89 | 90 | 91 | Headers 92 | 93 | 94 | Headers 95 | 96 | 97 | Environments 98 | 99 | 100 | Common 101 | 102 | 103 | Common 104 | 105 | 106 | VapourSynth 107 | 108 | 109 | VapourSynth 110 | 111 | 112 | VapourSynth 113 | 114 | 115 | 116 | 117 | Avisynth 118 | 119 | 120 | Avisynth 121 | 122 | 123 | Avisynth 124 | 125 | 126 | Common 127 | 128 | 129 | Common 130 | 131 | 132 | Avisynth 133 | 134 | 135 | Avisynth 136 | 137 | 138 | Avisynth 139 | 140 | 141 | Common 142 | 143 | 144 | Environments 145 | 146 | 147 | Common 148 | 149 | 150 | Common 151 | 152 | 153 | Environments 154 | 155 | 156 | VapourSynth 157 | 158 | 159 | VapourSynth 160 | 161 | 162 | VapourSynth 163 | 164 | 165 | Environments 166 | 167 | 168 | VapourSynth 169 | 170 | 171 | -------------------------------------------------------------------------------- /Src/VapourSynth/ContinuousMaskVpy.cpp: -------------------------------------------------------------------------------- 1 | #include "ContinuousMaskVpy.h" 2 | 3 | void VS_CC ContinuousMaskVpy::Create(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api) 4 | { 5 | VpyPropReader prop = VpyPropReader(api, in); 6 | VSNodeRef* src = prop.GetNode("clip"); 7 | int radius = prop.GetInt("radius", 16); 8 | int thr = prop.GetInt("thr", 0); 9 | 10 | auto f = new ContinuousMaskVpy(in, out, src, core, api, radius, thr); 11 | f->CreateFilter(in, out); 12 | } 13 | 14 | ContinuousMaskVpy::ContinuousMaskVpy(const VSMap* in, VSMap* out, VSNodeRef* node, VSCore* core, const VSAPI* api, int _radius, int _thr) : 15 | VpyFilter(PluginName, in, out, node, core, api), 16 | ContinuousMaskBase(new VpyVideo(node, api), VpyEnvironment(PluginName, api, core, out), _radius, _thr) 17 | { 18 | } 19 | 20 | void ContinuousMaskVpy::Init(VSMap* in, VSMap* out, VSNode* node, VpyEnvironment& env) 21 | { 22 | } 23 | 24 | VSFrameRef* ContinuousMaskVpy::GetFrame(int n, int activationReason, void** frameData, VSFrameContext* frameCtx, VpyEnvironment& env) 25 | { 26 | if (activationReason == arInitial) 27 | { 28 | api->requestFrameFilter(n, Node, frameCtx); 29 | } 30 | else if (activationReason == arAllFramesReady) 31 | { 32 | const VSFrameRef* src = api->getFrameFilter(n, Node, frameCtx); 33 | VSFrameRef* dst = api->newVideoFrame(viSrc->format, viSrc->width, viSrc->height, src, core); 34 | 35 | ProcessFrame(VpyFrame(src, api), VpyFrame(dst, api)); 36 | 37 | api->freeFrame(src); 38 | return dst; 39 | } 40 | 41 | return nullptr; 42 | } 43 | 44 | void ContinuousMaskVpy::Free() 45 | { 46 | } 47 | -------------------------------------------------------------------------------- /Src/VapourSynth/ContinuousMaskVpy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Environments/VpyFilter.hpp" 3 | #include "../Common/ContinuousMaskBase.h" 4 | 5 | class ContinuousMaskVpy : public VpyFilter, public ContinuousMaskBase 6 | { 7 | public: 8 | static void VS_CC Create(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api); 9 | ContinuousMaskVpy(const VSMap* in, VSMap* out, VSNodeRef* node, VSCore* core, const VSAPI* vsapi, int _radius, int _thr); 10 | ~ContinuousMaskVpy() {} 11 | void VpyFilter::Init(VSMap* in, VSMap* out, VSNode* node, VpyEnvironment& env); 12 | VSFrameRef* VpyFilter::GetFrame(int n, int activationReason, void** frameData, VSFrameContext* frameCtx, VpyEnvironment& env); 13 | void VpyFilter::Free(); 14 | }; 15 | -------------------------------------------------------------------------------- /Src/VapourSynth/ConvertFpsLimitVpy.cpp: -------------------------------------------------------------------------------- 1 | #include "ConvertFpsLimitVpy.h" 2 | 3 | void VS_CC ConvertFpsLimitVpy::Create(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api) 4 | { 5 | VpyPropReader prop = VpyPropReader(api, in); 6 | VSNodeRef* src = prop.GetNode("clip"); 7 | uint32_t num = prop.GetInt("num"); 8 | uint32_t den = prop.GetInt("den"); 9 | float fps = prop.GetFloat("fps"); 10 | const char* preset = prop.GetData("preset"); 11 | VSNodeRef* match = prop.GetNode("match"); 12 | int ratio = prop.GetInt("ratio", 100); 13 | 14 | int ParamCount = 0; 15 | if (num) 16 | ParamCount++; 17 | if (fps) 18 | ParamCount++; 19 | if (preset) 20 | ParamCount++; 21 | if (match) 22 | ParamCount++; 23 | 24 | VpyEnvironment Env = VpyEnvironment(PluginName, api, core, out); 25 | if (ParamCount == 0) 26 | { 27 | Env.ThrowError("Must set one of the following parameters: num/den (fraction), fps (float), preset (string) or match (clip)."); 28 | } 29 | else if ((num > 0) != (den > 0)) 30 | { 31 | Env.ThrowError("Both num and den must be specified."); 32 | } 33 | else if (ParamCount > 1) 34 | { 35 | Env.ThrowError("Can only set one of the following parameters: num/den (fraction), fps (float), preset (string) or match (clip)."); 36 | } 37 | else 38 | { 39 | if (fps) 40 | { 41 | FloatToFPS(fps, num, den, Env); 42 | } 43 | else if (preset) 44 | { 45 | PresetToFPS(preset, num, den, Env); 46 | } 47 | else if (match) 48 | { 49 | auto vi = api->getVideoInfo(match); 50 | num = vi->fpsNum; 51 | den = vi->fpsDen; 52 | api->freeNode(match); 53 | } 54 | 55 | // VapourSynth only accepts reduced fractions. 56 | unsigned int div = gcd(num, den); 57 | num /= div; 58 | den /= div; 59 | 60 | auto f = new ConvertFpsLimitVpy(in, out, src, core, api, num, den, ratio); 61 | f->CreateFilter(in, out); 62 | } 63 | } 64 | 65 | ConvertFpsLimitVpy::ConvertFpsLimitVpy(const VSMap* in, VSMap* out, VSNodeRef* node, VSCore* core, const VSAPI* api, 66 | int new_numerator, int new_denominator, int _ratio) : 67 | VpyFilter(PluginName, in, out, node, core, api), 68 | ConvertFPSLimitBase(new VpyVideo(node, api), VpyEnvironment(PluginName, api, core, out), new_numerator, new_denominator, _ratio) 69 | { 70 | viDst.fpsNum = new_numerator; 71 | viDst.fpsDen = new_denominator; 72 | const int64_t num_frames = (viSrc->numFrames * fb + (fa >> 1)) / fa; 73 | if (num_frames > 0x7FFFFFFF) // MAXINT 74 | api->setError(out, "ConvertFpsLimit: Maximum number of frames exceeded."); 75 | viDst.numFrames = int(num_frames); 76 | } 77 | 78 | void ConvertFpsLimitVpy::Init(VSMap* in, VSMap* out, VSNode* node, VpyEnvironment& env) 79 | { 80 | } 81 | 82 | VSFrameRef* ConvertFpsLimitVpy::GetFrame(int n, int activationReason, void** frameData, VSFrameContext* frameCtx, VpyEnvironment& env) 83 | { 84 | if (activationReason == arInitial) 85 | { 86 | int nsrc = int(n * fa / fb); 87 | api->requestFrameFilter(nsrc, Node, frameCtx); 88 | api->requestFrameFilter(nsrc + 1, Node, frameCtx); 89 | } 90 | else if (activationReason == arAllFramesReady) 91 | { 92 | int nsrc = int(n * fa / fb); 93 | auto src = api->getFrameFilter(nsrc, Node, frameCtx); 94 | auto src2 = api->getFrameFilter(nsrc + 1, Node, frameCtx); 95 | auto srcCopy = api->copyFrame(src, core); 96 | api->freeFrame(src); 97 | 98 | auto dst = (VSFrameRef*)ProcessFrame(n, VpyFrame(srcCopy, api), VpyFrame(src2, api), env).Ref; 99 | 100 | api->freeFrame(dst == srcCopy ? src2 : srcCopy); 101 | return dst; 102 | } 103 | 104 | return nullptr; 105 | } 106 | 107 | void ConvertFpsLimitVpy::Free() 108 | { 109 | } 110 | 111 | unsigned int gcd(unsigned int u, unsigned int v) 112 | { 113 | // Base cases 114 | // gcd(n, n) = n 115 | if (u == v) 116 | return u; 117 | 118 | // Identity 1: gcd(0, n) = gcd(n, 0) = n 119 | if (u == 0) 120 | return v; 121 | if (v == 0) 122 | return u; 123 | 124 | if (u & 1) { // u is odd 125 | if (v % 2 == 0) // v is even 126 | return gcd(u, v / 2); // Identity 3 127 | // Identities 4 and 3 (u and v are odd, so u-v and v-u are known to be even) 128 | if (u > v) 129 | return gcd((u - v) / 2, v); 130 | else 131 | return gcd((v - u) / 2, u); 132 | } 133 | else { // u is even 134 | if (v & 1) // v is odd 135 | return gcd(u / 2, v); // Identity 3 136 | else // both u and v are even 137 | return 2 * gcd(u / 2, v / 2); // Identity 2 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /Src/VapourSynth/ConvertFpsLimitVpy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Common/ConvertFpsLimitBase.h" 3 | #include "../Environments/VpyFilter.hpp" 4 | #include "../Environments/VpyPropReader.hpp" 5 | 6 | class ConvertFpsLimitVpy: public VpyFilter, ConvertFPSLimitBase 7 | /** 8 | * Class to change the framerate, attempting to smooth the transitions 9 | **/ 10 | { 11 | public: 12 | static void VS_CC Create(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api); 13 | static void VS_CC CreateFloat(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api); 14 | static void VS_CC CreatePreset(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api); 15 | static void VS_CC CreateFromClip(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api); 16 | 17 | ConvertFpsLimitVpy(const VSMap* in, VSMap* out, VSNodeRef* node, VSCore* core, const VSAPI* vsapi, int new_numerator, int new_denominator, int _ratio); 18 | ~ConvertFpsLimitVpy() {} 19 | void VpyFilter::Init(VSMap* in, VSMap* out, VSNode* node, VpyEnvironment& env); 20 | VSFrameRef* VpyFilter::GetFrame(int n, int activationReason, void** frameData, VSFrameContext* frameCtx, VpyEnvironment& env); 21 | void VpyFilter::Free(); 22 | }; 23 | 24 | unsigned int gcd(unsigned int u, unsigned int v); -------------------------------------------------------------------------------- /Src/VapourSynth/FrcVapourSynth.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {3826CF45-A338-4BF5-A1F5-CFC79C1B1F60} 24 | Win32Proj 25 | ConditionalFilterMT 26 | 10.0 27 | FrcVapourSynth 28 | 29 | 30 | 31 | DynamicLibrary 32 | true 33 | v142 34 | MultiByte 35 | 36 | 37 | DynamicLibrary 38 | false 39 | v142 40 | true 41 | MultiByte 42 | 43 | 44 | DynamicLibrary 45 | true 46 | v142 47 | MultiByte 48 | 49 | 50 | DynamicLibrary 51 | false 52 | v142 53 | true 54 | MultiByte 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | FrameRateConverter 77 | 78 | 79 | true 80 | FrameRateConverter 81 | 82 | 83 | false 84 | FrameRateConverter 85 | 86 | 87 | false 88 | FrameRateConverter 89 | 90 | 91 | 92 | 93 | 94 | Level3 95 | Disabled 96 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 97 | 98 | 99 | Console 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | 110 | 111 | Console 112 | 113 | 114 | 115 | 116 | Level3 117 | 118 | 119 | MaxSpeed 120 | true 121 | true 122 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | 124 | 125 | 126 | 127 | Console 128 | true 129 | true 130 | 131 | 132 | 133 | 134 | Level3 135 | 136 | 137 | MaxSpeed 138 | true 139 | true 140 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 141 | 142 | 143 | Console 144 | true 145 | true 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /Src/VapourSynth/FrcVapourSynth.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {e3645ab9-05da-4c15-9743-20b3b16be7aa} 6 | 7 | 8 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 9 | h;hh;hpp;hxx;hm;inl;inc;xsd 10 | 11 | 12 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 13 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 14 | 15 | 16 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 17 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 18 | 19 | 20 | 21 | 22 | Headers 23 | 24 | 25 | Headers 26 | 27 | 28 | Headers 29 | 30 | 31 | Headers 32 | 33 | 34 | Headers 35 | 36 | 37 | Headers 38 | 39 | 40 | Headers 41 | 42 | 43 | Headers 44 | 45 | 46 | Common 47 | 48 | 49 | Common 50 | 51 | 52 | Common 53 | 54 | 55 | Common 56 | 57 | 58 | Common 59 | 60 | 61 | Headers 62 | 63 | 64 | Headers 65 | 66 | 67 | Headers 68 | 69 | 70 | 71 | 72 | Common 73 | 74 | 75 | Common 76 | 77 | 78 | Common 79 | 80 | 81 | Common 82 | 83 | 84 | Common 85 | 86 | 87 | VapourSynth 88 | 89 | 90 | -------------------------------------------------------------------------------- /Src/VapourSynth/InitVpy.cpp: -------------------------------------------------------------------------------- 1 | #include "VapourSynth.h" 2 | #include "VSHelper.h" 3 | #include "ContinuousMaskVpy.h" 4 | #include "StripeMaskVpy.h" 5 | #include "ConvertFpsLimitVpy.h" 6 | 7 | VS_EXTERNAL_API(void) VapourSynthPluginInit(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin) 8 | { 9 | configFunc("com.vapoursynth.frc", "frc", "Frame Rate Connverter", VAPOURSYNTH_API_VERSION, 1, plugin); 10 | registerFunc("ContinuousMask", 11 | "clip:clip;" 12 | "radius:int:opt;" 13 | "thr:int:opt;", 14 | ContinuousMaskVpy::Create, 0, plugin); 15 | registerFunc("StripeMaskPass", 16 | "clip:clip;" 17 | "blksize:int:opt;" 18 | "blksizev:int:opt;" 19 | "overlap:int:opt;" 20 | "overlapv:int:opt;" 21 | "thr:int:opt;" 22 | "range:int:opt;" 23 | "gamma:float:opt;" 24 | "comp:int:opt;" 25 | "compv:int:opt;" 26 | "str:int:opt;" 27 | "lines:int:opt;", 28 | StripeMaskVpy::Create, 0, plugin); 29 | registerFunc("ConvertFpsLimit", 30 | "clip:clip;" 31 | "num:int:opt;" 32 | "den:int:opt;" 33 | "fps:float:opt;" 34 | "preset:data:opt;" 35 | "match:clip:opt;" 36 | "ratio:int:opt;", 37 | ConvertFpsLimitVpy::Create, 0, plugin); 38 | } 39 | -------------------------------------------------------------------------------- /Src/VapourSynth/StripeMaskVpy.cpp: -------------------------------------------------------------------------------- 1 | #include "StripeMaskVpy.h" 2 | 3 | void VS_CC StripeMaskVpy::Create(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api) 4 | { 5 | VpyPropReader prop = VpyPropReader(api, in); 6 | auto Input = prop.GetNode("clip"); 7 | int BlkSize = prop.GetInt("blksize", 16); 8 | int BlkSizeV = prop.GetInt("blksizev", BlkSize > 0 ? BlkSize : 16); 9 | int Overlap = prop.GetInt("overlap", BlkSize / 4); 10 | int OverlapV = prop.GetInt("overlapv", BlkSizeV / 4); 11 | int Thr = prop.GetInt("thr", 15); 12 | int Range = prop.GetInt("range", 125); 13 | double Gamma = prop.GetFloat("gamma", 2.2); 14 | int Comp = prop.GetInt("comp", BlkSize <= 16 ? 2 : 3); 15 | int CompV = prop.GetInt("compv", Comp); 16 | int Str = prop.GetInt("str", 255); 17 | //int Strf = prop.GetInt("strf", 0); 18 | bool Lines = prop.GetInt("lines", false); 19 | 20 | bool SrcFullRange = prop.GetInt("_ColorRange", 1) == 0; 21 | 22 | auto Vi = api->getVideoInfo(Input); 23 | int BitDepth = Vi->format->bitsPerSample; 24 | 25 | VpyEnvironment Env = VpyEnvironment(PluginName, api, core, out); 26 | if (Vi->format->colorFamily != cmYUV && Vi->format->colorFamily != cmGray) 27 | { 28 | Env.ThrowError("clip must be Y or YUV format"); 29 | return; 30 | } 31 | else if (Range < 1 || Range > 255) 32 | { 33 | Env.ThrowError("range must be between 1 and 255."); 34 | return; 35 | } 36 | else if (Gamma <= 0 || Gamma > 100) 37 | { 38 | Env.ThrowError("gamma must be greater than 0 and less than 100."); 39 | return; 40 | } 41 | 42 | // Keep only Luma plane. 43 | VSMap* Args = api->createMap(); 44 | { 45 | api->propSetNode(Args, "clips", Input, paReplace); 46 | api->propSetInt(Args, "planes", 0, paReplace); 47 | api->propSetInt(Args, "colorfamily", cmGray, paReplace); 48 | Input = Env.InvokeClip("std", "ShufflePlanes", Args, Input); 49 | } 50 | 51 | // Convert to 8-bit. 52 | if (Input && BitDepth > 8) 53 | { 54 | api->clearMap(Args); 55 | api->propSetNode(Args, "clip", Input, paReplace); 56 | api->propSetInt(Args, "format", pfGray8, paReplace); 57 | Input = Env.InvokeClip("resize", "Point", Args, Input); 58 | } 59 | 60 | // Reduce range and apply gamma. 61 | if (Input) 62 | { 63 | //int RangeMin = (255 - Range) / 2; 64 | //int RangeMax = Range + RangeMin; 65 | api->clearMap(Args); 66 | api->propSetNode(Args, "clip", Input, paReplace); 67 | api->propSetFloat(Args, "gamma", 1.0 / Gamma, paReplace); 68 | api->propSetFloat(Args, "min_in", SrcFullRange ? 0 : 16, paReplace); 69 | api->propSetFloat(Args, "max_in", SrcFullRange ? 255 : 235, paReplace); 70 | api->propSetFloat(Args, "min_out", 0, paReplace); 71 | api->propSetFloat(Args, "max_out", Range, paReplace); 72 | Input = Env.InvokeClip("std", "Levels", Args, Input); 73 | } 74 | 75 | // Create StripeMask. 76 | if (Input) 77 | { 78 | auto f = new StripeMaskVpy(in, out, core, api, Input, BlkSize, BlkSizeV, Overlap, OverlapV, Thr, Comp, CompV, Str, Lines); 79 | f->CreateFilter(in, out); 80 | 81 | if (!f->HasError()) 82 | { 83 | VpyPropReader FilterProp = VpyPropReader(api, out); 84 | if (BitDepth > 8) 85 | { 86 | Input = FilterProp.GetNode("clip"); 87 | // Convert back to original bit depth. 88 | api->clearMap(Args); 89 | api->propSetNode(Args, "clip", Input, paReplace); 90 | api->propSetInt(Args, "format", BitDepth <= 16 ? pfGray16 : pfGrayS, paReplace); 91 | Input = Env.InvokeClip("resize", "Point", Args, Input); 92 | 93 | api->propSetNode(out, "clip", Input, paReplace); 94 | api->freeNode(Input); 95 | } 96 | } 97 | } 98 | 99 | api->freeMap(Args); 100 | } 101 | 102 | StripeMaskVpy::StripeMaskVpy(const VSMap* in, VSMap* out, VSCore* core, const VSAPI* api, VSNodeRef* node, 103 | int blkSize, int blkSizeV, int overlap, int overlapV, int thr, int comp, int compV, int str, bool lines) : 104 | VpyFilter(PluginName, in, out, node, core, api), 105 | StripeMaskBase(new VpyVideo(node, api), VpyEnvironment(PluginName, api, core, out), blkSize, blkSizeV, overlap, overlapV, thr, comp, compV, str, lines) 106 | { 107 | int b = viSrc->format->bitsPerSample; 108 | viDst.format = api->getFormatPreset(b <= 8 ? pfGray8 : b <= 16 ? pfGray16 : b == 32 ? pfGrayS : pfGray8, core); 109 | } 110 | 111 | void StripeMaskVpy::Init(VSMap* in, VSMap* out, VSNode* node, VpyEnvironment& env) 112 | { 113 | } 114 | 115 | VSFrameRef* StripeMaskVpy::GetFrame(int n, int activationReason, void** frameData, VSFrameContext* frameCtx, VpyEnvironment& env) 116 | { 117 | if (activationReason == arInitial) 118 | { 119 | api->requestFrameFilter(n, Node, frameCtx); 120 | } 121 | else if (activationReason == arAllFramesReady) 122 | { 123 | const VSFrameRef* src = api->getFrameFilter(n, Node, frameCtx); 124 | VSFrameRef* dst = api->newVideoFrame(viDst.format, viDst.width, viDst.height, src, core); 125 | ProcessFrame(VpyFrame(src, api), VpyFrame(dst, api), env); 126 | 127 | api->freeFrame(src); 128 | return dst; 129 | } 130 | 131 | return nullptr; 132 | } 133 | 134 | void StripeMaskVpy::Free() 135 | { 136 | } 137 | -------------------------------------------------------------------------------- /Src/VapourSynth/StripeMaskVpy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Environments/VpyFilter.hpp" 3 | #include "../Common/StripeMaskBase.h" 4 | 5 | class StripeMaskVpy : public VpyFilter, StripeMaskBase { 6 | public: 7 | static void VS_CC Create(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* api); 8 | StripeMaskVpy(const VSMap* in, VSMap* out, VSCore* core, const VSAPI* api, VSNodeRef* node, 9 | int _blksize, int _blksizev, int _overlap, int _overlapv, int _thr, int _comp, int _compv, int _str, bool _lines); 10 | ~StripeMaskVpy() {} 11 | virtual void VpyFilter::Init(VSMap* in, VSMap* out, VSNode* node, VpyEnvironment& env); 12 | virtual VSFrameRef* VpyFilter::GetFrame(int n, int activationReason, void** frameData, VSFrameContext* frameCtx, VpyEnvironment& env); 13 | virtual void VpyFilter::Free(); 14 | }; 15 | -------------------------------------------------------------------------------- /Src/VapourSynth/VSHelper.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright (c) 2012-2015 Fredrik Mellbin 3 | * --- Legal stuff --- 4 | * This program is free software. It comes without any warranty, to 5 | * the extent permitted by applicable law. You can redistribute it 6 | * and/or modify it under the terms of the Do What The Fuck You Want 7 | * To Public License, Version 2, as published by Sam Hocevar. See 8 | * http://sam.zoy.org/wtfpl/COPYING for more details. 9 | *****************************************************************************/ 10 | 11 | #ifndef VSHELPER_H 12 | #define VSHELPER_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #ifdef _WIN32 21 | #include 22 | #endif 23 | #include "VapourSynth.h" 24 | 25 | /* Visual Studio doesn't recognize inline in c mode */ 26 | #if defined(_MSC_VER) && !defined(__cplusplus) 27 | #define inline _inline 28 | #endif 29 | 30 | /* A kinda portable definition of the C99 restrict keyword (or its inofficial C++ equivalent) */ 31 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* Available in C99 */ 32 | #define VS_RESTRICT restrict 33 | #elif defined(__cplusplus) || defined(_MSC_VER) /* Almost all relevant C++ compilers support it so just assume it works */ 34 | #define VS_RESTRICT __restrict 35 | #else /* Not supported */ 36 | #define VS_RESTRICT 37 | #endif 38 | 39 | #ifdef _WIN32 40 | #define VS_ALIGNED_MALLOC(pptr, size, alignment) do { *(pptr) = _aligned_malloc((size), (alignment)); } while (0) 41 | #define VS_ALIGNED_FREE(ptr) do { _aligned_free((ptr)); } while (0) 42 | #else 43 | #define VS_ALIGNED_MALLOC(pptr, size, alignment) do { if(posix_memalign((void**)(pptr), (alignment), (size))) *((void**)pptr) = NULL; } while (0) 44 | #define VS_ALIGNED_FREE(ptr) do { free((ptr)); } while (0) 45 | #endif 46 | 47 | #define VSMAX(a,b) ((a) > (b) ? (a) : (b)) 48 | #define VSMIN(a,b) ((a) > (b) ? (b) : (a)) 49 | 50 | #ifdef __cplusplus 51 | /* A nicer templated malloc for all the C++ users out there */ 52 | #if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) 53 | template 54 | #else 55 | template 56 | #endif 57 | static inline T* vs_aligned_malloc(size_t size, size_t alignment) { 58 | #ifdef _WIN32 59 | return (T*)_aligned_malloc(size, alignment); 60 | #else 61 | void *tmp = NULL; 62 | if (posix_memalign(&tmp, alignment, size)) 63 | tmp = 0; 64 | return (T*)tmp; 65 | #endif 66 | } 67 | 68 | static inline void vs_aligned_free(void *ptr) { 69 | VS_ALIGNED_FREE(ptr); 70 | } 71 | #endif /* __cplusplus */ 72 | 73 | /* convenience function for checking if the format never changes between frames */ 74 | static inline int isConstantFormat(const VSVideoInfo *vi) { 75 | return vi->height > 0 && vi->width > 0 && vi->format; 76 | } 77 | 78 | /* convenience function to check for if two clips have the same format (unknown/changeable will be considered the same too) */ 79 | static inline int isSameFormat(const VSVideoInfo *v1, const VSVideoInfo *v2) { 80 | return v1->height == v2->height && v1->width == v2->width && v1->format == v2->format; 81 | } 82 | 83 | /* multiplies and divides a rational number, such as a frame duration, in place and reduces the result */ 84 | static inline void muldivRational(int64_t *num, int64_t *den, int64_t mul, int64_t div) { 85 | /* do nothing if the rational number is invalid */ 86 | if (!*den) 87 | return; 88 | 89 | /* nobody wants to accidentally divide by zero */ 90 | assert(div); 91 | 92 | int64_t a, b; 93 | *num *= mul; 94 | *den *= div; 95 | a = *num; 96 | b = *den; 97 | while (b != 0) { 98 | int64_t t = a; 99 | a = b; 100 | b = t % b; 101 | } 102 | if (a < 0) 103 | a = -a; 104 | *num /= a; 105 | *den /= a; 106 | } 107 | 108 | /* reduces a rational number */ 109 | static inline void vs_normalizeRational(int64_t *num, int64_t *den) { 110 | muldivRational(num, den, 1, 1); 111 | } 112 | 113 | /* add two rational numbers and reduces the result */ 114 | static inline void vs_addRational(int64_t *num, int64_t *den, int64_t addnum, int64_t addden) { 115 | /* do nothing if the rational number is invalid */ 116 | if (!*den) 117 | return; 118 | 119 | /* nobody wants to accidentally add an invalid rational number */ 120 | assert(addden); 121 | 122 | if (*den == addden) { 123 | *num += addnum; 124 | } else { 125 | int64_t temp = addden; 126 | addnum *= *den; 127 | addden *= *den; 128 | *num *= temp; 129 | *den *= temp; 130 | 131 | *num += addnum; 132 | 133 | vs_normalizeRational(num, den); 134 | } 135 | } 136 | 137 | /* converts an int64 to int with saturation, useful to silence warnings when reading int properties among other things */ 138 | static inline int int64ToIntS(int64_t i) { 139 | if (i > INT_MAX) 140 | return INT_MAX; 141 | else if (i < INT_MIN) 142 | return INT_MIN; 143 | else return (int)i; 144 | } 145 | 146 | static inline void vs_bitblt(void *dstp, int dst_stride, const void *srcp, int src_stride, size_t row_size, size_t height) { 147 | if (height) { 148 | if (src_stride == dst_stride && src_stride == (int)row_size) { 149 | memcpy(dstp, srcp, row_size * height); 150 | } else { 151 | const uint8_t *srcp8 = (const uint8_t *)srcp; 152 | uint8_t *dstp8 = (uint8_t *)dstp; 153 | size_t i; 154 | for (i = 0; i < height; i++) { 155 | memcpy(dstp8, srcp8, row_size); 156 | srcp8 += src_stride; 157 | dstp8 += dst_stride; 158 | } 159 | } 160 | } 161 | } 162 | 163 | /* check if the frame dimensions are valid for a given format */ 164 | /* returns non-zero for valid width and height */ 165 | static inline int areValidDimensions(const VSFormat *fi, int width, int height) { 166 | return !(width % (1 << fi->subSamplingW) || height % (1 << fi->subSamplingH)); 167 | } 168 | 169 | /* Visual Studio doesn't recognize inline in c mode */ 170 | #if defined(_MSC_VER) && !defined(__cplusplus) 171 | #undef inline 172 | #endif 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /Src/VapourSynth/VSScript.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2018 Fredrik Mellbin 3 | * 4 | * This file is part of VapourSynth. 5 | * 6 | * VapourSynth is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * VapourSynth is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with VapourSynth; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef VSSCRIPT_H 22 | #define VSSCRIPT_H 23 | 24 | #include "VapourSynth.h" 25 | 26 | #define VSSCRIPT_API_MAJOR 3 27 | #define VSSCRIPT_API_MINOR 2 28 | #define VSSCRIPT_API_VERSION ((VSSCRIPT_API_MAJOR << 16) | (VSSCRIPT_API_MINOR)) 29 | 30 | /* As of api 3.2 all functions are threadsafe */ 31 | 32 | typedef struct VSScript VSScript; 33 | 34 | typedef enum VSEvalFlags { 35 | efSetWorkingDir = 1, 36 | } VSEvalFlags; 37 | 38 | /* Get the api version */ 39 | VS_API(int) vsscript_getApiVersion(void); /* api 3.1 */ 40 | 41 | /* Initialize the available scripting runtimes, returns zero on failure */ 42 | VS_API(int) vsscript_init(void); 43 | 44 | /* Free all scripting runtimes */ 45 | VS_API(int) vsscript_finalize(void); 46 | 47 | /* 48 | * Pass a pointer to a null handle to create a new one 49 | * The values returned by the query functions are only valid during the lifetime of the VSScript 50 | * scriptFilename is if the error message should reference a certain file, NULL allowed in vsscript_evaluateScript() 51 | * core is to pass in an already created instance so that mixed environments can be used, 52 | * NULL creates a new core that can be fetched with vsscript_getCore() later OR implicitly uses the one associated with an already existing handle when passed 53 | * If efSetWorkingDir is passed to flags the current working directory will be changed to the path of the script 54 | * note that if scriptFilename is NULL in vsscript_evaluateScript() then __file__ won't be set and the working directory won't be changed 55 | * Set efSetWorkingDir to get the default and recommended behavior 56 | */ 57 | VS_API(int) vsscript_evaluateScript(VSScript **handle, const char *script, const char *scriptFilename, int flags); 58 | /* Convenience version of the above function that loads the script from a file */ 59 | VS_API(int) vsscript_evaluateFile(VSScript **handle, const char *scriptFilename, int flags); 60 | /* Create an empty environment for use in later invocations, mostly useful to set script variables before execution */ 61 | VS_API(int) vsscript_createScript(VSScript **handle); 62 | 63 | VS_API(void) vsscript_freeScript(VSScript *handle); 64 | VS_API(const char *) vsscript_getError(VSScript *handle); 65 | /* The node returned must be freed using freeNode() before calling vsscript_freeScript() */ 66 | VS_API(VSNodeRef *) vsscript_getOutput(VSScript *handle, int index); 67 | /* Both nodes returned must be freed using freeNode() before calling vsscript_freeScript(), the alpha node pointer will only be set if an alpha clip has been set in the script */ 68 | VS_API(VSNodeRef *) vsscript_getOutput2(VSScript *handle, int index, VSNodeRef **alpha); /* api 3.1 */ 69 | /* Unset an output index */ 70 | VS_API(int) vsscript_clearOutput(VSScript *handle, int index); 71 | /* The core is valid as long as the environment exists */ 72 | VS_API(VSCore *) vsscript_getCore(VSScript *handle); 73 | /* Convenience function for retrieving a vsapi pointer */ 74 | VS_API(const VSAPI *) vsscript_getVSApi(void); /* deprecated as of api 3.2 since it's impossible to tell the api version supported */ 75 | VS_API(const VSAPI *) vsscript_getVSApi2(int version); /* api 3.2, generally you should pass VAPOURSYNTH_API_VERSION */ 76 | 77 | /* Variables names that are not set or not of a convertible type will return an error */ 78 | VS_API(int) vsscript_getVariable(VSScript *handle, const char *name, VSMap *dst); 79 | VS_API(int) vsscript_setVariable(VSScript *handle, const VSMap *vars); 80 | VS_API(int) vsscript_clearVariable(VSScript *handle, const char *name); 81 | /* Tries to clear everything set in an environment, normally it is better to simply free an environment completely and create a new one */ 82 | VS_API(void) vsscript_clearEnvironment(VSScript *handle); 83 | 84 | #endif /* VSSCRIPT_H */ 85 | -------------------------------------------------------------------------------- /Src/VapourSynth/VapourSynth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2017 Fredrik Mellbin 3 | * 4 | * This file is part of VapourSynth. 5 | * 6 | * VapourSynth is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * VapourSynth is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with VapourSynth; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef VAPOURSYNTH_H 22 | #define VAPOURSYNTH_H 23 | 24 | #include 25 | 26 | #define VAPOURSYNTH_API_MAJOR 3 27 | #define VAPOURSYNTH_API_MINOR 5 28 | #define VAPOURSYNTH_API_VERSION ((VAPOURSYNTH_API_MAJOR << 16) | (VAPOURSYNTH_API_MINOR)) 29 | 30 | /* Convenience for C++ users. */ 31 | #ifdef __cplusplus 32 | # define VS_EXTERN_C extern "C" 33 | # if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) 34 | # define VS_NOEXCEPT noexcept 35 | # else 36 | # define VS_NOEXCEPT 37 | # endif 38 | #else 39 | # define VS_EXTERN_C 40 | # define VS_NOEXCEPT 41 | #endif 42 | 43 | #if defined(_WIN32) && !defined(_WIN64) 44 | # define VS_CC __stdcall 45 | #else 46 | # define VS_CC 47 | #endif 48 | 49 | /* And now for some symbol hide-and-seek... */ 50 | #if defined(_WIN32) /* Windows being special */ 51 | # define VS_EXTERNAL_API(ret) VS_EXTERN_C __declspec(dllexport) ret VS_CC 52 | #elif defined(__GNUC__) && __GNUC__ >= 4 53 | # define VS_EXTERNAL_API(ret) VS_EXTERN_C __attribute__((visibility("default"))) ret VS_CC 54 | #else 55 | # define VS_EXTERNAL_API(ret) VS_EXTERN_C ret VS_CC 56 | #endif 57 | 58 | #if !defined(VS_CORE_EXPORTS) && defined(_WIN32) 59 | # define VS_API(ret) VS_EXTERN_C __declspec(dllimport) ret VS_CC 60 | #else 61 | # define VS_API(ret) VS_EXTERNAL_API(ret) 62 | #endif 63 | 64 | typedef struct VSFrameRef VSFrameRef; 65 | typedef struct VSNodeRef VSNodeRef; 66 | typedef struct VSCore VSCore; 67 | typedef struct VSPlugin VSPlugin; 68 | typedef struct VSNode VSNode; 69 | typedef struct VSFuncRef VSFuncRef; 70 | typedef struct VSMap VSMap; 71 | typedef struct VSAPI VSAPI; 72 | typedef struct VSFrameContext VSFrameContext; 73 | 74 | typedef enum VSColorFamily { 75 | /* all planar formats */ 76 | cmGray = 1000000, 77 | cmRGB = 2000000, 78 | cmYUV = 3000000, 79 | cmYCoCg = 4000000, 80 | /* special for compatibility */ 81 | cmCompat = 9000000 82 | } VSColorFamily; 83 | 84 | typedef enum VSSampleType { 85 | stInteger = 0, 86 | stFloat = 1 87 | } VSSampleType; 88 | 89 | /* The +10 is so people won't be using the constants interchangably "by accident" */ 90 | typedef enum VSPresetFormat { 91 | pfNone = 0, 92 | 93 | pfGray8 = cmGray + 10, 94 | pfGray16, 95 | 96 | pfGrayH, 97 | pfGrayS, 98 | 99 | pfYUV420P8 = cmYUV + 10, 100 | pfYUV422P8, 101 | pfYUV444P8, 102 | pfYUV410P8, 103 | pfYUV411P8, 104 | pfYUV440P8, 105 | 106 | pfYUV420P9, 107 | pfYUV422P9, 108 | pfYUV444P9, 109 | 110 | pfYUV420P10, 111 | pfYUV422P10, 112 | pfYUV444P10, 113 | 114 | pfYUV420P16, 115 | pfYUV422P16, 116 | pfYUV444P16, 117 | 118 | pfYUV444PH, 119 | pfYUV444PS, 120 | 121 | pfYUV420P12, 122 | pfYUV422P12, 123 | pfYUV444P12, 124 | 125 | pfYUV420P14, 126 | pfYUV422P14, 127 | pfYUV444P14, 128 | 129 | pfRGB24 = cmRGB + 10, 130 | pfRGB27, 131 | pfRGB30, 132 | pfRGB48, 133 | 134 | pfRGBH, 135 | pfRGBS, 136 | 137 | /* special for compatibility, if you implement these in any filter I'll personally kill you */ 138 | /* I'll also change their ids around to break your stuff regularly */ 139 | pfCompatBGR32 = cmCompat + 10, 140 | pfCompatYUY2 141 | } VSPresetFormat; 142 | 143 | typedef enum VSFilterMode { 144 | fmParallel = 100, /* completely parallel execution */ 145 | fmParallelRequests = 200, /* for filters that are serial in nature but can request one or more frames they need in advance */ 146 | fmUnordered = 300, /* for filters that modify their internal state every request */ 147 | fmSerial = 400 /* for source filters and compatibility with other filtering architectures */ 148 | } VSFilterMode; 149 | 150 | typedef struct VSFormat { 151 | char name[32]; 152 | int id; 153 | int colorFamily; /* see VSColorFamily */ 154 | int sampleType; /* see VSSampleType */ 155 | int bitsPerSample; /* number of significant bits */ 156 | int bytesPerSample; /* actual storage is always in a power of 2 and the smallest possible that can fit the number of bits used per sample */ 157 | 158 | int subSamplingW; /* log2 subsampling factor, applied to second and third plane */ 159 | int subSamplingH; 160 | 161 | int numPlanes; /* implicit from colorFamily */ 162 | } VSFormat; 163 | 164 | typedef enum VSNodeFlags { 165 | nfNoCache = 1, 166 | nfIsCache = 2, 167 | nfMakeLinear = 4 /* api 3.3 */ 168 | } VSNodeFlags; 169 | 170 | typedef enum VSPropTypes { 171 | ptUnset = 'u', 172 | ptInt = 'i', 173 | ptFloat = 'f', 174 | ptData = 's', 175 | ptNode = 'c', 176 | ptFrame = 'v', 177 | ptFunction = 'm' 178 | } VSPropTypes; 179 | 180 | typedef enum VSGetPropErrors { 181 | peUnset = 1, 182 | peType = 2, 183 | peIndex = 4 184 | } VSGetPropErrors; 185 | 186 | typedef enum VSPropAppendMode { 187 | paReplace = 0, 188 | paAppend = 1, 189 | paTouch = 2 190 | } VSPropAppendMode; 191 | 192 | typedef struct VSCoreInfo { 193 | const char *versionString; 194 | int core; 195 | int api; 196 | int numThreads; 197 | int64_t maxFramebufferSize; 198 | int64_t usedFramebufferSize; 199 | } VSCoreInfo; 200 | 201 | typedef struct VSVideoInfo { 202 | const VSFormat *format; 203 | int64_t fpsNum; 204 | int64_t fpsDen; 205 | int width; 206 | int height; 207 | int numFrames; /* api 3.2 - no longer allowed to be 0 */ 208 | int flags; 209 | } VSVideoInfo; 210 | 211 | typedef enum VSActivationReason { 212 | arInitial = 0, 213 | arFrameReady = 1, 214 | arAllFramesReady = 2, 215 | arError = -1 216 | } VSActivationReason; 217 | 218 | typedef enum VSMessageType { 219 | mtDebug = 0, 220 | mtWarning = 1, 221 | mtCritical = 2, 222 | mtFatal = 3 223 | } VSMessageType; 224 | 225 | /* core entry point */ 226 | typedef const VSAPI *(VS_CC *VSGetVapourSynthAPI)(int version); 227 | 228 | /* plugin function and filter typedefs */ 229 | typedef void (VS_CC *VSPublicFunction)(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi); 230 | typedef void (VS_CC *VSRegisterFunction)(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin); 231 | typedef void (VS_CC *VSConfigPlugin)(const char *identifier, const char *defaultNamespace, const char *name, int apiVersion, int readonly, VSPlugin *plugin); 232 | typedef void (VS_CC *VSInitPlugin)(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin); 233 | typedef void (VS_CC *VSFreeFuncData)(void *userData); 234 | typedef void (VS_CC *VSFilterInit)(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi); 235 | typedef const VSFrameRef *(VS_CC *VSFilterGetFrame)(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi); 236 | typedef void (VS_CC *VSFilterFree)(void *instanceData, VSCore *core, const VSAPI *vsapi); 237 | 238 | /* other */ 239 | typedef void (VS_CC *VSFrameDoneCallback)(void *userData, const VSFrameRef *f, int n, VSNodeRef *, const char *errorMsg); 240 | typedef void (VS_CC *VSMessageHandler)(int msgType, const char *msg, void *userData); 241 | 242 | struct VSAPI { 243 | VSCore *(VS_CC *createCore)(int threads) VS_NOEXCEPT; 244 | void (VS_CC *freeCore)(VSCore *core) VS_NOEXCEPT; 245 | const VSCoreInfo *(VS_CC *getCoreInfo)(VSCore *core) VS_NOEXCEPT; 246 | 247 | const VSFrameRef *(VS_CC *cloneFrameRef)(const VSFrameRef *f) VS_NOEXCEPT; 248 | VSNodeRef *(VS_CC *cloneNodeRef)(VSNodeRef *node) VS_NOEXCEPT; 249 | VSFuncRef *(VS_CC *cloneFuncRef)(VSFuncRef *f) VS_NOEXCEPT; 250 | 251 | void (VS_CC *freeFrame)(const VSFrameRef *f) VS_NOEXCEPT; 252 | void (VS_CC *freeNode)(VSNodeRef *node) VS_NOEXCEPT; 253 | void (VS_CC *freeFunc)(VSFuncRef *f) VS_NOEXCEPT; 254 | 255 | VSFrameRef *(VS_CC *newVideoFrame)(const VSFormat *format, int width, int height, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT; 256 | VSFrameRef *(VS_CC *copyFrame)(const VSFrameRef *f, VSCore *core) VS_NOEXCEPT; 257 | void (VS_CC *copyFrameProps)(const VSFrameRef *src, VSFrameRef *dst, VSCore *core) VS_NOEXCEPT; 258 | 259 | void (VS_CC *registerFunction)(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT; 260 | VSPlugin *(VS_CC *getPluginById)(const char *identifier, VSCore *core) VS_NOEXCEPT; 261 | VSPlugin *(VS_CC *getPluginByNs)(const char *ns, VSCore *core) VS_NOEXCEPT; 262 | VSMap *(VS_CC *getPlugins)(VSCore *core) VS_NOEXCEPT; 263 | VSMap *(VS_CC *getFunctions)(VSPlugin *plugin) VS_NOEXCEPT; 264 | void (VS_CC *createFilter)(const VSMap *in, VSMap *out, const char *name, VSFilterInit init, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, int flags, void *instanceData, VSCore *core) VS_NOEXCEPT; 265 | void (VS_CC *setError)(VSMap *map, const char *errorMessage) VS_NOEXCEPT; /* use to signal errors outside filter getframe functions */ 266 | const char *(VS_CC *getError)(const VSMap *map) VS_NOEXCEPT; /* use to query errors, returns 0 if no error */ 267 | void (VS_CC *setFilterError)(const char *errorMessage, VSFrameContext *frameCtx) VS_NOEXCEPT; /* use to signal errors in the filter getframe function */ 268 | VSMap *(VS_CC *invoke)(VSPlugin *plugin, const char *name, const VSMap *args) VS_NOEXCEPT; 269 | 270 | const VSFormat *(VS_CC *getFormatPreset)(int id, VSCore *core) VS_NOEXCEPT; 271 | const VSFormat *(VS_CC *registerFormat)(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT; 272 | 273 | const VSFrameRef *(VS_CC *getFrame)(int n, VSNodeRef *node, char *errorMsg, int bufSize) VS_NOEXCEPT; /* do never use inside a filter's getframe function, for external applications using the core as a library or for requesting frames in a filter constructor */ 274 | void (VS_CC *getFrameAsync)(int n, VSNodeRef *node, VSFrameDoneCallback callback, void *userData) VS_NOEXCEPT; /* do never use inside a filter's getframe function, for external applications using the core as a library or for requesting frames in a filter constructor */ 275 | const VSFrameRef *(VS_CC *getFrameFilter)(int n, VSNodeRef *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ 276 | void (VS_CC *requestFrameFilter)(int n, VSNodeRef *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ 277 | void (VS_CC *queryCompletedFrame)(VSNodeRef **node, int *n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ 278 | void (VS_CC *releaseFrameEarly)(VSNodeRef *node, int n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ 279 | 280 | int (VS_CC *getStride)(const VSFrameRef *f, int plane) VS_NOEXCEPT; 281 | const uint8_t *(VS_CC *getReadPtr)(const VSFrameRef *f, int plane) VS_NOEXCEPT; 282 | uint8_t *(VS_CC *getWritePtr)(VSFrameRef *f, int plane) VS_NOEXCEPT; 283 | 284 | VSFuncRef *(VS_CC *createFunc)(VSPublicFunction func, void *userData, VSFreeFuncData free, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT; 285 | void (VS_CC *callFunc)(VSFuncRef *func, const VSMap *in, VSMap *out, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT; /* core and vsapi arguments are completely ignored, they only remain to preserve ABI */ 286 | 287 | /* property access functions */ 288 | VSMap *(VS_CC *createMap)(void) VS_NOEXCEPT; 289 | void (VS_CC *freeMap)(VSMap *map) VS_NOEXCEPT; 290 | void (VS_CC *clearMap)(VSMap *map) VS_NOEXCEPT; 291 | 292 | const VSVideoInfo *(VS_CC *getVideoInfo)(VSNodeRef *node) VS_NOEXCEPT; 293 | void (VS_CC *setVideoInfo)(const VSVideoInfo *vi, int numOutputs, VSNode *node) VS_NOEXCEPT; 294 | const VSFormat *(VS_CC *getFrameFormat)(const VSFrameRef *f) VS_NOEXCEPT; 295 | int (VS_CC *getFrameWidth)(const VSFrameRef *f, int plane) VS_NOEXCEPT; 296 | int (VS_CC *getFrameHeight)(const VSFrameRef *f, int plane) VS_NOEXCEPT; 297 | const VSMap *(VS_CC *getFramePropsRO)(const VSFrameRef *f) VS_NOEXCEPT; 298 | VSMap *(VS_CC *getFramePropsRW)(VSFrameRef *f) VS_NOEXCEPT; 299 | 300 | int (VS_CC *propNumKeys)(const VSMap *map) VS_NOEXCEPT; 301 | const char *(VS_CC *propGetKey)(const VSMap *map, int index) VS_NOEXCEPT; 302 | int (VS_CC *propNumElements)(const VSMap *map, const char *key) VS_NOEXCEPT; 303 | char (VS_CC *propGetType)(const VSMap *map, const char *key) VS_NOEXCEPT; 304 | 305 | int64_t(VS_CC *propGetInt)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 306 | double(VS_CC *propGetFloat)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 307 | const char *(VS_CC *propGetData)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 308 | int (VS_CC *propGetDataSize)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 309 | VSNodeRef *(VS_CC *propGetNode)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 310 | const VSFrameRef *(VS_CC *propGetFrame)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 311 | VSFuncRef *(VS_CC *propGetFunc)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 312 | 313 | int (VS_CC *propDeleteKey)(VSMap *map, const char *key) VS_NOEXCEPT; 314 | int (VS_CC *propSetInt)(VSMap *map, const char *key, int64_t i, int append) VS_NOEXCEPT; 315 | int (VS_CC *propSetFloat)(VSMap *map, const char *key, double d, int append) VS_NOEXCEPT; 316 | int (VS_CC *propSetData)(VSMap *map, const char *key, const char *data, int size, int append) VS_NOEXCEPT; 317 | int (VS_CC *propSetNode)(VSMap *map, const char *key, VSNodeRef *node, int append) VS_NOEXCEPT; 318 | int (VS_CC *propSetFrame)(VSMap *map, const char *key, const VSFrameRef *f, int append) VS_NOEXCEPT; 319 | int (VS_CC *propSetFunc)(VSMap *map, const char *key, VSFuncRef *func, int append) VS_NOEXCEPT; 320 | 321 | int64_t (VS_CC *setMaxCacheSize)(int64_t bytes, VSCore *core) VS_NOEXCEPT; 322 | int (VS_CC *getOutputIndex)(VSFrameContext *frameCtx) VS_NOEXCEPT; 323 | VSFrameRef *(VS_CC *newVideoFrame2)(const VSFormat *format, int width, int height, const VSFrameRef **planeSrc, const int *planes, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT; 324 | void (VS_CC *setMessageHandler)(VSMessageHandler handler, void *userData) VS_NOEXCEPT; 325 | int (VS_CC *setThreadCount)(int threads, VSCore *core) VS_NOEXCEPT; 326 | 327 | const char *(VS_CC *getPluginPath)(const VSPlugin *plugin) VS_NOEXCEPT; 328 | 329 | /* api 3.1 */ 330 | const int64_t *(VS_CC *propGetIntArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT; 331 | const double *(VS_CC *propGetFloatArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT; 332 | 333 | int (VS_CC *propSetIntArray)(VSMap *map, const char *key, const int64_t *i, int size) VS_NOEXCEPT; 334 | int (VS_CC *propSetFloatArray)(VSMap *map, const char *key, const double *d, int size) VS_NOEXCEPT; 335 | 336 | /* api 3.4 */ 337 | void (VS_CC *logMessage)(int msgType, const char *msg) VS_NOEXCEPT; 338 | }; 339 | 340 | VS_API(const VSAPI *) getVapourSynthAPI(int version) VS_NOEXCEPT; 341 | 342 | #endif /* VAPOURSYNTH_H */ 343 | --------------------------------------------------------------------------------