diff --git a/LibP2P.sln b/LibP2P.sln
new file mode 100644
index 0000000..748fa51
--- /dev/null
+++ b/LibP2P.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31515.178
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibP2P", "LibP2P.vcxproj", "{D051C10D-15E9-4E57-B7B0-B05083B94040}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D051C10D-15E9-4E57-B7B0-B05083B94040}.Debug|x64.ActiveCfg = Debug|x64
+ {D051C10D-15E9-4E57-B7B0-B05083B94040}.Debug|x64.Build.0 = Debug|x64
+ {D051C10D-15E9-4E57-B7B0-B05083B94040}.Debug|x86.ActiveCfg = Debug|Win32
+ {D051C10D-15E9-4E57-B7B0-B05083B94040}.Debug|x86.Build.0 = Debug|Win32
+ {D051C10D-15E9-4E57-B7B0-B05083B94040}.Release|x64.ActiveCfg = Release|x64
+ {D051C10D-15E9-4E57-B7B0-B05083B94040}.Release|x64.Build.0 = Release|x64
+ {D051C10D-15E9-4E57-B7B0-B05083B94040}.Release|x86.ActiveCfg = Release|Win32
+ {D051C10D-15E9-4E57-B7B0-B05083B94040}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F3F623BC-3396-44F6-B28A-D67EFB695743}
+ EndGlobalSection
+EndGlobal
diff --git a/LibP2P.vcxproj b/LibP2P.vcxproj
new file mode 100644
index 0000000..4415e88
--- /dev/null
+++ b/LibP2P.vcxproj
@@ -0,0 +1,160 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+ 16.0
+ LibP2P
+ {d051c10d-15e9-4e57-b7b0-b05083b94040}
+ LibP2P
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C:\Program Files\VapourSynth\sdk\include\vapoursynth;$(IncludePath);.\
+ true
+
+
+ C:\Program Files\VapourSynth\sdk\include\vapoursynth;$(IncludePath);.\
+ false
+
+
+ C:\Program Files\VapourSynth\sdk\include\vapoursynth;$(IncludePath);.\
+ true
+
+
+ C:\Program Files\VapourSynth\sdk\include\vapoursynth;$(IncludePath);.\
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;LIBP2P_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;LIBP2P_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+
+
+ Windows
+ true
+ true
+ false
+ false
+
+
+
+
+ Level3
+ true
+ _DEBUG;LIBP2P_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;LIBP2P_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+
+
+ Windows
+ true
+ true
+ false
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LibP2P.vcxproj.filters b/LibP2P.vcxproj.filters
new file mode 100644
index 0000000..56fbe44
--- /dev/null
+++ b/LibP2P.vcxproj.filters
@@ -0,0 +1,33 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/LibP2P.vcxproj.user b/LibP2P.vcxproj.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/LibP2P.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..10280af
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# LibP2P-Vapoursynth
+
+Vapoursynth plugin for packing/unpacking of RGB clips.
diff --git a/src/headers/VSConstants4.h b/src/headers/VSConstants4.h
new file mode 100644
index 0000000..2b120de
--- /dev/null
+++ b/src/headers/VSConstants4.h
@@ -0,0 +1,93 @@
+/*
+* Copyright (c) 2021 Fredrik Mellbin
+*
+* This file is part of VapourSynth.
+*
+* VapourSynth is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* VapourSynth is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with VapourSynth; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef VSCONSTANTS4_H
+#define VSCONSTANTS4_H
+
+typedef enum VSColorRange {
+ VSC_RANGE_FULL = 0,
+ VSC_RANGE_LIMITED = 1
+} VSColorRange;
+
+typedef enum VSChromaLocation {
+ VSC_CHROMA_LEFT = 0,
+ VSC_CHROMA_CENTER = 1,
+ VSC_CHROMA_TOP_LEFT = 2,
+ VSC_CHROMA_TOP = 3,
+ VSC_CHROMA_BOTTOM_LEFT = 4,
+ VSC_CHROMA_BOTTOM = 5
+} VSChromaLocation;
+
+typedef enum VSFieldBased {
+ VSC_FIELD_PROGRESSIVE = 0,
+ VSC_FIELD_TOP = 1,
+ VSC_FIELD_BOTTOM = 2
+} VSFieldBased;
+
+typedef enum VSMatrixCoefficients {
+ VSC_MATRIX_RGB = 0,
+ VSC_MATRIX_BT709 = 1,
+ VSC_MATRIX_UNSPECIFIED = 2,
+ VSC_MATRIX_FCC = 4,
+ VSC_MATRIX_BT470_BG = 5,
+ VSC_MATRIX_ST170_M = 6, /* Equivalent to 5. */
+ VSC_MATRIX_ST240_M = 7,
+ VSC_MATRIX_YCGCO = 8,
+ VSC_MATRIX_BT2020_NCL = 9,
+ VSC_MATRIX_BT2020_CL = 10,
+ VSC_MATRIX_CHROMATICITY_DERIVED_NCL = 12,
+ VSC_MATRIX_CHROMATICITY_DERIVED_CL = 13,
+ VSC_MATRIX_ICTCP = 14
+} VSMatrixCoefficients;
+
+typedef enum VSTransferCharacteristics {
+ VSC_TRANSFER_BT709 = 1,
+ VSC_TRANSFER_UNSPECIFIED = 2,
+ VSC_TRANSFER_BT470_M = 4,
+ VSC_TRANSFER_BT470_BG = 5,
+ VSC_TRANSFER_BT601 = 6, /* Equivalent to 1. */
+ VSC_TRANSFER_ST240_M = 7,
+ VSC_TRANSFER_LINEAR = 8,
+ VSC_TRANSFER_LOG_100 = 9,
+ VSC_TRANSFER_LOG_316 = 10,
+ VSC_TRANSFER_IEC_61966_2_4 = 11,
+ VSC_TRANSFER_IEC_61966_2_1 = 13,
+ VSC_TRANSFER_BT2020_10 = 14, /* Equivalent to 1. */
+ VSC_TRANSFER_BT2020_12 = 15, /* Equivalent to 1. */
+ VSC_TRANSFER_ST2084 = 16,
+ VSC_TRANSFER_ARIB_B67 = 18
+} VSTransferCharacteristics;
+
+typedef enum VSColorPrimaries {
+ VSC_PRIMARIES_BT709 = 1,
+ VSC_PRIMARIES_UNSPECIFIED = 2,
+ VSC_PRIMARIES_BT470_M = 4,
+ VSC_PRIMARIES_BT470_BG = 5,
+ VSC_PRIMARIES_ST170_M = 6,
+ VSC_PRIMARIES_ST240_M = 7, /* Equivalent to 6. */
+ VSC_PRIMARIES_FILM = 8,
+ VSC_PRIMARIES_BT2020 = 9,
+ VSC_PRIMARIES_ST428 = 10,
+ VSC_PRIMARIES_ST431_2 = 11,
+ VSC_PRIMARIES_ST432_1 = 12,
+ VSC_PRIMARIES_EBU3213_E = 22
+} VSColorPrimaries;
+
+#endif /* VSCONSTANTS4_H */
diff --git a/src/headers/VSHelper.h b/src/headers/VSHelper.h
new file mode 100644
index 0000000..3d60441
--- /dev/null
+++ b/src/headers/VSHelper.h
@@ -0,0 +1,174 @@
+/*****************************************************************************
+* Copyright (c) 2012-2015 Fredrik Mellbin
+* --- Legal stuff ---
+* This program is free software. It comes without any warranty, to
+* the extent permitted by applicable law. You can redistribute it
+* and/or modify it under the terms of the Do What The Fuck You Want
+* To Public License, Version 2, as published by Sam Hocevar. See
+* http://sam.zoy.org/wtfpl/COPYING for more details.
+*****************************************************************************/
+
+#ifndef VSHELPER_H
+#define VSHELPER_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef _WIN32
+#include
+#endif
+#include "VapourSynth.h"
+
+/* Visual Studio doesn't recognize inline in c mode */
+#if defined(_MSC_VER) && !defined(__cplusplus)
+#define inline _inline
+#endif
+
+/* A kinda portable definition of the C99 restrict keyword (or its inofficial C++ equivalent) */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* Available in C99 */
+#define VS_RESTRICT restrict
+#elif defined(__cplusplus) || defined(_MSC_VER) /* Almost all relevant C++ compilers support it so just assume it works */
+#define VS_RESTRICT __restrict
+#else /* Not supported */
+#define VS_RESTRICT
+#endif
+
+#ifdef _WIN32
+#define VS_ALIGNED_MALLOC(pptr, size, alignment) do { *(pptr) = _aligned_malloc((size), (alignment)); } while (0)
+#define VS_ALIGNED_FREE(ptr) do { _aligned_free((ptr)); } while (0)
+#else
+#define VS_ALIGNED_MALLOC(pptr, size, alignment) do { if(posix_memalign((void**)(pptr), (alignment), (size))) *((void**)pptr) = NULL; } while (0)
+#define VS_ALIGNED_FREE(ptr) do { free((ptr)); } while (0)
+#endif
+
+#define VSMAX(a,b) ((a) > (b) ? (a) : (b))
+#define VSMIN(a,b) ((a) > (b) ? (b) : (a))
+
+#ifdef __cplusplus
+/* A nicer templated malloc for all the C++ users out there */
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
+template
+#else
+template
+#endif
+static inline T* vs_aligned_malloc(size_t size, size_t alignment) {
+#ifdef _WIN32
+ return (T*)_aligned_malloc(size, alignment);
+#else
+ void *tmp = NULL;
+ if (posix_memalign(&tmp, alignment, size))
+ tmp = 0;
+ return (T*)tmp;
+#endif
+}
+
+static inline void vs_aligned_free(void *ptr) {
+ VS_ALIGNED_FREE(ptr);
+}
+#endif /* __cplusplus */
+
+/* convenience function for checking if the format never changes between frames */
+static inline int isConstantFormat(const VSVideoInfo *vi) {
+ return vi->height > 0 && vi->width > 0 && vi->format;
+}
+
+/* convenience function to check for if two clips have the same format (unknown/changeable will be considered the same too) */
+static inline int isSameFormat(const VSVideoInfo *v1, const VSVideoInfo *v2) {
+ return v1->height == v2->height && v1->width == v2->width && v1->format == v2->format;
+}
+
+/* multiplies and divides a rational number, such as a frame duration, in place and reduces the result */
+static inline void muldivRational(int64_t *num, int64_t *den, int64_t mul, int64_t div) {
+ /* do nothing if the rational number is invalid */
+ if (!*den)
+ return;
+
+ /* nobody wants to accidentally divide by zero */
+ assert(div);
+
+ int64_t a, b;
+ *num *= mul;
+ *den *= div;
+ a = *num;
+ b = *den;
+ while (b != 0) {
+ int64_t t = a;
+ a = b;
+ b = t % b;
+ }
+ if (a < 0)
+ a = -a;
+ *num /= a;
+ *den /= a;
+}
+
+/* reduces a rational number */
+static inline void vs_normalizeRational(int64_t *num, int64_t *den) {
+ muldivRational(num, den, 1, 1);
+}
+
+/* add two rational numbers and reduces the result */
+static inline void vs_addRational(int64_t *num, int64_t *den, int64_t addnum, int64_t addden) {
+ /* do nothing if the rational number is invalid */
+ if (!*den)
+ return;
+
+ /* nobody wants to accidentally add an invalid rational number */
+ assert(addden);
+
+ if (*den == addden) {
+ *num += addnum;
+ } else {
+ int64_t temp = addden;
+ addnum *= *den;
+ addden *= *den;
+ *num *= temp;
+ *den *= temp;
+
+ *num += addnum;
+
+ vs_normalizeRational(num, den);
+ }
+}
+
+/* converts an int64 to int with saturation, useful to silence warnings when reading int properties among other things */
+static inline int int64ToIntS(int64_t i) {
+ if (i > INT_MAX)
+ return INT_MAX;
+ else if (i < INT_MIN)
+ return INT_MIN;
+ else return (int)i;
+}
+
+static inline void vs_bitblt(void *dstp, int dst_stride, const void *srcp, int src_stride, size_t row_size, size_t height) {
+ if (height) {
+ if (src_stride == dst_stride && src_stride == (int)row_size) {
+ memcpy(dstp, srcp, row_size * height);
+ } else {
+ const uint8_t *srcp8 = (const uint8_t *)srcp;
+ uint8_t *dstp8 = (uint8_t *)dstp;
+ size_t i;
+ for (i = 0; i < height; i++) {
+ memcpy(dstp8, srcp8, row_size);
+ srcp8 += src_stride;
+ dstp8 += dst_stride;
+ }
+ }
+ }
+}
+
+/* check if the frame dimensions are valid for a given format */
+/* returns non-zero for valid width and height */
+static inline int areValidDimensions(const VSFormat *fi, int width, int height) {
+ return !(width % (1 << fi->subSamplingW) || height % (1 << fi->subSamplingH));
+}
+
+/* Visual Studio doesn't recognize inline in c mode */
+#if defined(_MSC_VER) && !defined(__cplusplus)
+#undef inline
+#endif
+
+#endif
diff --git a/src/headers/VSHelper4.h b/src/headers/VSHelper4.h
new file mode 100644
index 0000000..9392c05
--- /dev/null
+++ b/src/headers/VSHelper4.h
@@ -0,0 +1,219 @@
+/*****************************************************************************
+* Copyright (c) 2012-2020 Fredrik Mellbin
+* --- Legal stuff ---
+* This program is free software. It comes without any warranty, to
+* the extent permitted by applicable law. You can redistribute it
+* and/or modify it under the terms of the Do What The Fuck You Want
+* To Public License, Version 2, as published by Sam Hocevar. See
+* http://sam.zoy.org/wtfpl/COPYING for more details.
+*****************************************************************************/
+
+#ifndef VSHELPER4_H
+#define VSHELPER4_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef _WIN32
+#include
+#endif
+#include "VapourSynth4.h"
+
+#define VSH_STD_PLUGIN_ID "com.vapoursynth.std"
+#define VSH_RESIZE_PLUGIN_ID "com.vapoursynth.resize"
+#define VSH_TEXT_PLUGIN_ID "com.vapoursynth.text"
+
+#ifdef __cplusplus
+namespace vsh {
+#define VSH4_MANGLE_FUNCTION_NAME(name) name
+#define VSH4_BOOLEAN_TYPE bool
+#else
+#define VSH4_MANGLE_FUNCTION_NAME(name) vsh_##name
+#define VSH4_BOOLEAN_TYPE int
+#endif
+
+/* Visual Studio doesn't recognize inline in c mode */
+#if defined(_MSC_VER) && !defined(__cplusplus)
+#define inline _inline
+#endif
+
+/* A kinda portable definition of the C99 restrict keyword (or its inofficial C++ equivalent) */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* Available in C99 */
+#define VS_RESTRICT restrict
+#elif defined(__cplusplus) || defined(_MSC_VER) /* Almost all relevant C++ compilers support it so just assume it works */
+#define VS_RESTRICT __restrict
+#else /* Not supported */
+#define VS_RESTRICT
+#endif
+
+#ifdef _WIN32
+#define VSH_ALIGNED_MALLOC(pptr, size, alignment) do { *(pptr) = _aligned_malloc((size), (alignment)); } while (0)
+#define VSH_ALIGNED_FREE(ptr) do { _aligned_free((ptr)); } while (0)
+#else
+#define VSH_ALIGNED_MALLOC(pptr, size, alignment) do { if(posix_memalign((void**)(pptr), (alignment), (size))) *((void**)pptr) = NULL; } while (0)
+#define VSH_ALIGNED_FREE(ptr) do { free((ptr)); } while (0)
+#endif
+
+#define VSMAX(a,b) ((a) > (b) ? (a) : (b))
+#define VSMIN(a,b) ((a) > (b) ? (b) : (a))
+
+#ifdef __cplusplus
+/* A nicer templated malloc for all the C++ users out there */
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
+template
+#else
+template
+#endif
+static inline T *vsh_aligned_malloc(size_t size, size_t alignment) {
+#ifdef _WIN32
+ return (T *)_aligned_malloc(size, alignment);
+#else
+ void *tmp = NULL;
+ if (posix_memalign(&tmp, alignment, size))
+ tmp = 0;
+ return (T *)tmp;
+#endif
+}
+
+static inline void vsh_aligned_free(void *ptr) {
+ VSH_ALIGNED_FREE(ptr);
+}
+#endif /* __cplusplus */
+
+/* convenience function for checking if the format never changes between frames */
+static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isConstantVideoFormat)(const VSVideoInfo *vi) {
+ return vi->height > 0 && vi->width > 0 && vi->format.colorFamily != cfUndefined;
+}
+
+/* convenience function to check for if two clips have the same format (unknown/changeable will be considered the same too) */
+static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameVideoFormat)(const VSVideoFormat *v1, const VSVideoFormat *v2) {
+ return v1->colorFamily == v2->colorFamily && v1->sampleType == v2->sampleType && v1->bitsPerSample == v2->bitsPerSample && v1->subSamplingW == v2->subSamplingW && v1->subSamplingH == v2->subSamplingH;
+}
+
+/* convenience function to check for if two clips have the same format (but not framerate) while also including width and height (unknown/changeable will be considered the same too) */
+static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameVideoInfo)(const VSVideoInfo *v1, const VSVideoInfo *v2) {
+ return v1->height == v2->height && v1->width == v2->width && VSH4_MANGLE_FUNCTION_NAME(isSameVideoFormat)(&v1->format, &v2->format);
+}
+
+/* convenience function to check for if two clips have the same format while also including samplerate (unknown/changeable will be considered the same too) */
+static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameAudioFormat)(const VSAudioFormat *a1, const VSAudioFormat *a2) {
+ return a1->bitsPerSample == a2->bitsPerSample && a1->sampleType == a2->sampleType && a1->channelLayout == a2->channelLayout;
+}
+
+/* convenience function to check for if two clips have the same format while also including samplerate (unknown/changeable will be considered the same too) */
+static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameAudioInfo)(const VSAudioInfo *a1, const VSAudioInfo *a2) {
+ return a1->sampleRate == a2->sampleRate && VSH4_MANGLE_FUNCTION_NAME(isSameAudioFormat)(&a1->format, &a2->format);
+}
+
+/* multiplies and divides a rational number, such as a frame duration, in place and reduces the result */
+static inline void VSH4_MANGLE_FUNCTION_NAME(muldivRational)(int64_t *num, int64_t *den, int64_t mul, int64_t div) {
+ /* do nothing if the rational number is invalid */
+ if (!*den)
+ return;
+
+ /* nobody wants to accidentally divide by zero */
+ assert(div);
+
+ int64_t a, b;
+ *num *= mul;
+ *den *= div;
+ a = *num;
+ b = *den;
+ while (b != 0) {
+ int64_t t = a;
+ a = b;
+ b = t % b;
+ }
+ if (a < 0)
+ a = -a;
+ *num /= a;
+ *den /= a;
+}
+
+/* reduces a rational number */
+static inline void VSH4_MANGLE_FUNCTION_NAME(reduceRational)(int64_t *num, int64_t *den) {
+ VSH4_MANGLE_FUNCTION_NAME(muldivRational)(num, den, 1, 1);
+}
+
+/* add two rational numbers and reduces the result */
+static inline void VSH4_MANGLE_FUNCTION_NAME(addRational)(int64_t *num, int64_t *den, int64_t addnum, int64_t addden) {
+ /* do nothing if the rational number is invalid */
+ if (!*den)
+ return;
+
+ /* nobody wants to accidentally add an invalid rational number */
+ assert(addden);
+
+ if (*den == addden) {
+ *num += addnum;
+ } else {
+ int64_t temp = addden;
+ addnum *= *den;
+ addden *= *den;
+ *num *= temp;
+ *den *= temp;
+
+ *num += addnum;
+
+ VSH4_MANGLE_FUNCTION_NAME(reduceRational)(num, den);
+ }
+}
+
+/* converts an int64 to int with saturation, useful to silence warnings when reading int properties among other things */
+static inline int VSH4_MANGLE_FUNCTION_NAME(int64ToIntS)(int64_t i) {
+ if (i > INT_MAX)
+ return INT_MAX;
+ else if (i < INT_MIN)
+ return INT_MIN;
+ else return (int)i;
+}
+
+/* converts a double to float with saturation, useful to silence warnings when reading float properties among other things */
+static inline float VSH4_MANGLE_FUNCTION_NAME(doubleToFloatS)(double d) {
+ if (!isfinite(d))
+ return (float)d;
+ else if (d > FLT_MAX)
+ return FLT_MAX;
+ else if (d < -FLT_MAX)
+ return -FLT_MAX;
+ else
+ return (float)d;
+}
+
+static inline void VSH4_MANGLE_FUNCTION_NAME(bitblt)(void *dstp, ptrdiff_t dst_stride, const void *srcp, ptrdiff_t src_stride, size_t row_size, size_t height) {
+ if (height) {
+ if (src_stride == dst_stride && src_stride == (ptrdiff_t)row_size) {
+ memcpy(dstp, srcp, row_size * height);
+ } else {
+ const uint8_t *srcp8 = (const uint8_t *)srcp;
+ uint8_t *dstp8 = (uint8_t *)dstp;
+ size_t i;
+ for (i = 0; i < height; i++) {
+ memcpy(dstp8, srcp8, row_size);
+ srcp8 += src_stride;
+ dstp8 += dst_stride;
+ }
+ }
+ }
+}
+
+/* check if the frame dimensions are valid for a given format */
+/* returns non-zero for valid width and height */
+static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(areValidDimensions)(const VSVideoFormat *fi, int width, int height) {
+ return !(width % (1 << fi->subSamplingW) || height % (1 << fi->subSamplingH));
+}
+
+/* Visual Studio doesn't recognize inline in c mode */
+#if defined(_MSC_VER) && !defined(__cplusplus)
+#undef inline
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/headers/VSScript.h b/src/headers/VSScript.h
new file mode 100644
index 0000000..637b592
--- /dev/null
+++ b/src/headers/VSScript.h
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2013-2018 Fredrik Mellbin
+*
+* This file is part of VapourSynth.
+*
+* VapourSynth is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* VapourSynth is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with VapourSynth; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef VSSCRIPT_H
+#define VSSCRIPT_H
+
+#include "VapourSynth.h"
+
+#define VSSCRIPT_API_MAJOR 3
+#define VSSCRIPT_API_MINOR 2
+#define VSSCRIPT_API_VERSION ((VSSCRIPT_API_MAJOR << 16) | (VSSCRIPT_API_MINOR))
+
+/* As of api 3.2 all functions are threadsafe */
+
+typedef struct VSScript VSScript;
+
+typedef enum VSEvalFlags {
+ efSetWorkingDir = 1,
+} VSEvalFlags;
+
+/* Get the api version */
+VS_API(int) vsscript_getApiVersion(void); /* api 3.1 */
+
+/* Initialize the available scripting runtimes, returns zero on failure */
+VS_API(int) vsscript_init(void);
+
+/* Free all scripting runtimes */
+VS_API(int) vsscript_finalize(void);
+
+/*
+* Pass a pointer to a null handle to create a new one
+* The values returned by the query functions are only valid during the lifetime of the VSScript
+* scriptFilename is if the error message should reference a certain file, NULL allowed in vsscript_evaluateScript()
+* core is to pass in an already created instance so that mixed environments can be used,
+* 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
+* If efSetWorkingDir is passed to flags the current working directory will be changed to the path of the script
+* note that if scriptFilename is NULL in vsscript_evaluateScript() then __file__ won't be set and the working directory won't be changed
+* Set efSetWorkingDir to get the default and recommended behavior
+*/
+VS_API(int) vsscript_evaluateScript(VSScript **handle, const char *script, const char *scriptFilename, int flags);
+/* Convenience version of the above function that loads the script from a file */
+VS_API(int) vsscript_evaluateFile(VSScript **handle, const char *scriptFilename, int flags);
+/* Create an empty environment for use in later invocations, mostly useful to set script variables before execution */
+VS_API(int) vsscript_createScript(VSScript **handle);
+
+VS_API(void) vsscript_freeScript(VSScript *handle);
+VS_API(const char *) vsscript_getError(VSScript *handle);
+VS_API(int) vsscript_getExitCode(VSScript *handle);
+/* The node returned must be freed using freeNode() before calling vsscript_freeScript() */
+VS_API(VSNodeRef *) vsscript_getOutput(VSScript *handle, int index);
+/* 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 */
+VS_API(VSNodeRef *) vsscript_getOutput2(VSScript *handle, int index, VSNodeRef **alpha); /* api 3.1 */
+/* Unset an output index */
+VS_API(int) vsscript_clearOutput(VSScript *handle, int index);
+/* The core is valid as long as the environment exists */
+VS_API(VSCore *) vsscript_getCore(VSScript *handle);
+/* Convenience function for retrieving a vsapi pointer */
+VS_API(const VSAPI *) vsscript_getVSApi(void); /* deprecated as of api 3.2 since it's impossible to tell the api version supported */
+VS_API(const VSAPI *) vsscript_getVSApi2(int version); /* api 3.2, generally you should pass VAPOURSYNTH_API_VERSION */
+
+/* Variables names that are not set or not of a convertible type will return an error */
+VS_API(int) vsscript_getVariable(VSScript *handle, const char *name, VSMap *dst);
+VS_API(int) vsscript_setVariable(VSScript *handle, const VSMap *vars);
+VS_API(int) vsscript_clearVariable(VSScript *handle, const char *name);
+/* Tries to clear everything set in an environment, normally it is better to simply free an environment completely and create a new one */
+VS_API(void) vsscript_clearEnvironment(VSScript *handle);
+
+#endif /* VSSCRIPT_H */
diff --git a/src/headers/VSScript4.h b/src/headers/VSScript4.h
new file mode 100644
index 0000000..1d4fb17
--- /dev/null
+++ b/src/headers/VSScript4.h
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2013-2020 Fredrik Mellbin
+*
+* This file is part of VapourSynth.
+*
+* VapourSynth is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* VapourSynth is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with VapourSynth; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef VSSCRIPT4_H
+#define VSSCRIPT4_H
+
+#include "VapourSynth4.h"
+
+#define VSSCRIPT_API_MAJOR 4
+#define VSSCRIPT_API_MINOR 0
+#define VSSCRIPT_API_VERSION VS_MAKE_VERSION(VSSCRIPT_API_MAJOR, VSSCRIPT_API_MINOR)
+
+typedef struct VSScript VSScript;
+typedef struct VSSCRIPTAPI VSSCRIPTAPI;
+
+typedef struct VSScriptOptions {
+ /* Must be set to sizeof(VSScriptOptions) */
+ int size;
+
+ /* Passed to createCore(), set to 0 to use the default options */
+ int coreCreationFlags;
+
+ /* Passed to addLogHandler() right after a core is created if messageHandler is not NULL */
+ VSLogHandler logHandler;
+ VSLogHandlerFree logHandlerFree;
+ void *logHandlerData;
+} VSScriptOptions;
+
+struct VSSCRIPTAPI {
+ /* Returns the higest supported VSSCRIPT_API_VERSION */
+ int (VS_CC *getAPIVersion)(void) VS_NOEXCEPT;
+
+ /* Convenience function for retrieving a VSAPI pointer without having to use the VapourSynth library. Always pass VAPOURSYNTH_API_VERSION */
+ const VSAPI *(VS_CC *getVSAPI)(int version) VS_NOEXCEPT;
+
+ /*
+ * Evaluates a script passed in the buffer argument. The scriptFilename is only used for display purposes. in Python
+ * it means that the main module won't be unnamed in error messages.
+ *
+ * It is possible to set variables in the script context before evaluation by passing a VSMap. This is useful in order
+ * to pass on command-line arguments to scripts or handle batch scripting. Only simple types like int, float and data are
+ * allowed. Note that the datatype hint may affect how data is handled. Pass NULL to not set any variables.
+ *
+ * The coreCreationFlags are simply passed on to the createCore() call. This should in most cases be set to 0 to use the defaults.
+ *
+ * Returns a VSScript pointer both on success and error. Call getError() to see if the script evaluation succeeded.
+ * Note that calling any function other than getError() and freeScript() on a VSScript object in the error state
+ * will result in undefined behavior.
+ */
+ VSScript *(VS_CC *evaluateBuffer)(const char *buffer, const char *scriptFilename, const VSMap *vars, const VSScriptOptions *options) VS_NOEXCEPT;
+
+ /* Convenience version of the above function that loads the script from scriptFilename and passes as the buffer to evaluateBuffer */
+ VSScript *(VS_CC *evaluateFile)(const char *scriptFilename, const VSMap *vars, const VSScriptOptions *options) VS_NOEXCEPT;
+
+ /* Returns NULL on success, otherwise an error message */
+ const char *(VS_CC *getError)(VSScript *handle) VS_NOEXCEPT;
+
+ /* Returns 0 on success, otherwise the exit code */
+ int (VS_CC *getExitCode)(VSScript *handle) VS_NOEXCEPT;
+
+ /*
+ * The returned nodes must be freed using freeNode() before calling freeScript() since they may depend on data in the VSScript
+ * environment. Returns NULL if no node was set as output in the script. Index 0 is used by default in scripts and other
+ * values are rarely used.
+ */
+ VSNode *(VS_CC *getOutputNode)(VSScript *handle, int index) VS_NOEXCEPT;
+ VSNode *(VS_CC *getOutputAlphaNode)(VSScript *handle, int index) VS_NOEXCEPT;
+
+ /*
+ * Fetches the options set in scripts. In Python this means the set_options() function. Only simple types like int, float
+ * and data are allowed as output. Returns zero on success.
+ */
+ int (VS_CC *getOptions)(VSScript *handle, VSMap *dst);
+
+ /* The core is valid as long as the environment exists, will trigger core creation if necessary and returns NULL on failures */
+ VSCore *(VS_CC *getCore)(VSScript *handle) VS_NOEXCEPT;
+
+ /* Unsets the logger specified in VSScriptOptions and does nothing if no logger was set, returns non-zero on success */
+ int (VS_CC *clearLogHandler)(VSScript *handle) VS_NOEXCEPT;
+
+ void (VS_CC *freeScript)(VSScript *handle) VS_NOEXCEPT;
+};
+
+VS_API(const VSSCRIPTAPI *) getVSScriptAPI(int version) VS_NOEXCEPT;
+
+#endif /* VSSCRIPT4_H */
diff --git a/src/headers/VapourSynth.h b/src/headers/VapourSynth.h
new file mode 100644
index 0000000..bd201e8
--- /dev/null
+++ b/src/headers/VapourSynth.h
@@ -0,0 +1,359 @@
+/*
+* Copyright (c) 2012-2017 Fredrik Mellbin
+*
+* This file is part of VapourSynth.
+*
+* VapourSynth is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* VapourSynth is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with VapourSynth; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef VAPOURSYNTH_H
+#define VAPOURSYNTH_H
+
+#include
+
+#define VAPOURSYNTH_API_MAJOR 3
+#define VAPOURSYNTH_API_MINOR 6
+#define VAPOURSYNTH_API_VERSION ((VAPOURSYNTH_API_MAJOR << 16) | (VAPOURSYNTH_API_MINOR))
+
+/* Convenience for C++ users. */
+#ifdef __cplusplus
+# define VS_EXTERN_C extern "C"
+# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
+# define VS_NOEXCEPT noexcept
+# else
+# define VS_NOEXCEPT
+# endif
+# if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900)
+# define VS_DEPRECATE(REASON) [[deprecated(REASON)]]
+# else
+# define VS_DEPRECATE(REASON)
+# endif
+#else
+# define VS_EXTERN_C
+# define VS_NOEXCEPT
+# define VS_DEPRECATE(REASON)
+#endif
+
+#if defined(_WIN32) && !defined(_WIN64)
+# define VS_CC __stdcall
+#else
+# define VS_CC
+#endif
+
+/* And now for some symbol hide-and-seek... */
+#if defined(_WIN32) /* Windows being special */
+# define VS_EXTERNAL_API(ret) VS_EXTERN_C __declspec(dllexport) ret VS_CC
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define VS_EXTERNAL_API(ret) VS_EXTERN_C __attribute__((visibility("default"))) ret VS_CC
+#else
+# define VS_EXTERNAL_API(ret) VS_EXTERN_C ret VS_CC
+#endif
+
+#if !defined(VS_CORE_EXPORTS) && defined(_WIN32)
+# define VS_API(ret) VS_EXTERN_C __declspec(dllimport) ret VS_CC
+#else
+# define VS_API(ret) VS_EXTERNAL_API(ret)
+#endif
+
+typedef struct VSFrameRef VSFrameRef;
+typedef struct VSNodeRef VSNodeRef;
+typedef struct VSCore VSCore;
+typedef struct VSPlugin VSPlugin;
+typedef struct VSNode VSNode;
+typedef struct VSFuncRef VSFuncRef;
+typedef struct VSMap VSMap;
+typedef struct VSAPI VSAPI;
+typedef struct VSFrameContext VSFrameContext;
+
+typedef enum VSColorFamily {
+ /* all planar formats */
+ cmGray = 1000000,
+ cmRGB = 2000000,
+ cmYUV = 3000000,
+ cmYCoCg = 4000000,
+ /* special for compatibility */
+ cmCompat = 9000000
+} VSColorFamily;
+
+typedef enum VSSampleType {
+ stInteger = 0,
+ stFloat = 1
+} VSSampleType;
+
+/* The +10 is so people won't be using the constants interchangably "by accident" */
+typedef enum VSPresetFormat {
+ pfNone = 0,
+
+ pfGray8 = cmGray + 10,
+ pfGray16,
+
+ pfGrayH,
+ pfGrayS,
+
+ pfYUV420P8 = cmYUV + 10,
+ pfYUV422P8,
+ pfYUV444P8,
+ pfYUV410P8,
+ pfYUV411P8,
+ pfYUV440P8,
+
+ pfYUV420P9,
+ pfYUV422P9,
+ pfYUV444P9,
+
+ pfYUV420P10,
+ pfYUV422P10,
+ pfYUV444P10,
+
+ pfYUV420P16,
+ pfYUV422P16,
+ pfYUV444P16,
+
+ pfYUV444PH,
+ pfYUV444PS,
+
+ pfYUV420P12,
+ pfYUV422P12,
+ pfYUV444P12,
+
+ pfYUV420P14,
+ pfYUV422P14,
+ pfYUV444P14,
+
+ pfRGB24 = cmRGB + 10,
+ pfRGB27,
+ pfRGB30,
+ pfRGB48,
+
+ pfRGBH,
+ pfRGBS,
+
+ /* special for compatibility, if you implement these in any filter I'll personally kill you */
+ /* I'll also change their ids around to break your stuff regularly */
+ pfCompatBGR32 = cmCompat + 10,
+ pfCompatYUY2
+} VSPresetFormat;
+
+typedef enum VSFilterMode {
+ fmParallel = 100, /* completely parallel execution */
+ fmParallelRequests = 200, /* for filters that are serial in nature but can request one or more frames they need in advance */
+ fmUnordered = 300, /* for filters that modify their internal state every request */
+ fmSerial = 400 /* for source filters and compatibility with other filtering architectures */
+} VSFilterMode;
+
+typedef struct VSFormat {
+ char name[32];
+ int id;
+ int colorFamily; /* see VSColorFamily */
+ int sampleType; /* see VSSampleType */
+ int bitsPerSample; /* number of significant bits */
+ 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 */
+
+ int subSamplingW; /* log2 subsampling factor, applied to second and third plane */
+ int subSamplingH;
+
+ int numPlanes; /* implicit from colorFamily */
+} VSFormat;
+
+typedef enum VSNodeFlags {
+ nfNoCache = 1,
+ nfIsCache = 2,
+ nfMakeLinear = 4 /* api 3.3 */
+} VSNodeFlags;
+
+typedef enum VSPropTypes {
+ ptUnset = 'u',
+ ptInt = 'i',
+ ptFloat = 'f',
+ ptData = 's',
+ ptNode = 'c',
+ ptFrame = 'v',
+ ptFunction = 'm'
+} VSPropTypes;
+
+typedef enum VSGetPropErrors {
+ peUnset = 1,
+ peType = 2,
+ peIndex = 4
+} VSGetPropErrors;
+
+typedef enum VSPropAppendMode {
+ paReplace = 0,
+ paAppend = 1,
+ paTouch = 2
+} VSPropAppendMode;
+
+typedef struct VSCoreInfo {
+ const char *versionString;
+ int core;
+ int api;
+ int numThreads;
+ int64_t maxFramebufferSize;
+ int64_t usedFramebufferSize;
+} VSCoreInfo;
+
+typedef struct VSVideoInfo {
+ const VSFormat *format;
+ int64_t fpsNum;
+ int64_t fpsDen;
+ int width;
+ int height;
+ int numFrames; /* api 3.2 - no longer allowed to be 0 */
+ int flags;
+} VSVideoInfo;
+
+typedef enum VSActivationReason {
+ arInitial = 0,
+ arFrameReady = 1,
+ arAllFramesReady = 2,
+ arError = -1
+} VSActivationReason;
+
+typedef enum VSMessageType {
+ mtDebug = 0,
+ mtWarning = 1,
+ mtCritical = 2,
+ mtFatal = 3
+} VSMessageType;
+
+/* core entry point */
+typedef const VSAPI *(VS_CC *VSGetVapourSynthAPI)(int version);
+
+/* plugin function and filter typedefs */
+typedef void (VS_CC *VSPublicFunction)(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi);
+typedef void (VS_CC *VSRegisterFunction)(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin);
+typedef void (VS_CC *VSConfigPlugin)(const char *identifier, const char *defaultNamespace, const char *name, int apiVersion, int readonly, VSPlugin *plugin);
+typedef void (VS_CC *VSInitPlugin)(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin);
+typedef void (VS_CC *VSFreeFuncData)(void *userData);
+typedef void (VS_CC *VSFilterInit)(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi);
+typedef const VSFrameRef *(VS_CC *VSFilterGetFrame)(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi);
+typedef void (VS_CC *VSFilterFree)(void *instanceData, VSCore *core, const VSAPI *vsapi);
+
+/* other */
+typedef void (VS_CC *VSFrameDoneCallback)(void *userData, const VSFrameRef *f, int n, VSNodeRef *, const char *errorMsg);
+typedef void (VS_CC *VSMessageHandler)(int msgType, const char *msg, void *userData);
+typedef void (VS_CC *VSMessageHandlerFree)(void *userData);
+
+struct VSAPI {
+ VSCore *(VS_CC *createCore)(int threads) VS_NOEXCEPT;
+ void (VS_CC *freeCore)(VSCore *core) VS_NOEXCEPT;
+
+ VS_DEPRECATE("getCoreInfo has been deprecated as of api 3.6, use getCoreInfo2 instead")
+ const VSCoreInfo *(VS_CC *getCoreInfo)(VSCore *core) VS_NOEXCEPT;
+
+ const VSFrameRef *(VS_CC *cloneFrameRef)(const VSFrameRef *f) VS_NOEXCEPT;
+ VSNodeRef *(VS_CC *cloneNodeRef)(VSNodeRef *node) VS_NOEXCEPT;
+ VSFuncRef *(VS_CC *cloneFuncRef)(VSFuncRef *f) VS_NOEXCEPT;
+
+ void (VS_CC *freeFrame)(const VSFrameRef *f) VS_NOEXCEPT;
+ void (VS_CC *freeNode)(VSNodeRef *node) VS_NOEXCEPT;
+ void (VS_CC *freeFunc)(VSFuncRef *f) VS_NOEXCEPT;
+
+ VSFrameRef *(VS_CC *newVideoFrame)(const VSFormat *format, int width, int height, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT;
+ VSFrameRef *(VS_CC *copyFrame)(const VSFrameRef *f, VSCore *core) VS_NOEXCEPT;
+ void (VS_CC *copyFrameProps)(const VSFrameRef *src, VSFrameRef *dst, VSCore *core) VS_NOEXCEPT;
+
+ void (VS_CC *registerFunction)(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT;
+ VSPlugin *(VS_CC *getPluginById)(const char *identifier, VSCore *core) VS_NOEXCEPT;
+ VSPlugin *(VS_CC *getPluginByNs)(const char *ns, VSCore *core) VS_NOEXCEPT;
+ VSMap *(VS_CC *getPlugins)(VSCore *core) VS_NOEXCEPT;
+ VSMap *(VS_CC *getFunctions)(VSPlugin *plugin) VS_NOEXCEPT;
+ 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;
+ void (VS_CC *setError)(VSMap *map, const char *errorMessage) VS_NOEXCEPT; /* use to signal errors outside filter getframe functions */
+ const char *(VS_CC *getError)(const VSMap *map) VS_NOEXCEPT; /* use to query errors, returns 0 if no error */
+ void (VS_CC *setFilterError)(const char *errorMessage, VSFrameContext *frameCtx) VS_NOEXCEPT; /* use to signal errors in the filter getframe function */
+ VSMap *(VS_CC *invoke)(VSPlugin *plugin, const char *name, const VSMap *args) VS_NOEXCEPT;
+
+ const VSFormat *(VS_CC *getFormatPreset)(int id, VSCore *core) VS_NOEXCEPT;
+ const VSFormat *(VS_CC *registerFormat)(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT;
+
+ 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 */
+ 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 */
+ const VSFrameRef *(VS_CC *getFrameFilter)(int n, VSNodeRef *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */
+ void (VS_CC *requestFrameFilter)(int n, VSNodeRef *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */
+ void (VS_CC *queryCompletedFrame)(VSNodeRef **node, int *n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */
+ void (VS_CC *releaseFrameEarly)(VSNodeRef *node, int n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */
+
+ int (VS_CC *getStride)(const VSFrameRef *f, int plane) VS_NOEXCEPT;
+ const uint8_t *(VS_CC *getReadPtr)(const VSFrameRef *f, int plane) VS_NOEXCEPT;
+ uint8_t *(VS_CC *getWritePtr)(VSFrameRef *f, int plane) VS_NOEXCEPT;
+
+ VSFuncRef *(VS_CC *createFunc)(VSPublicFunction func, void *userData, VSFreeFuncData free, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT;
+ 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 */
+
+ /* property access functions */
+ VSMap *(VS_CC *createMap)(void) VS_NOEXCEPT;
+ void (VS_CC *freeMap)(VSMap *map) VS_NOEXCEPT;
+ void (VS_CC *clearMap)(VSMap *map) VS_NOEXCEPT;
+
+ const VSVideoInfo *(VS_CC *getVideoInfo)(VSNodeRef *node) VS_NOEXCEPT;
+ void (VS_CC *setVideoInfo)(const VSVideoInfo *vi, int numOutputs, VSNode *node) VS_NOEXCEPT;
+ const VSFormat *(VS_CC *getFrameFormat)(const VSFrameRef *f) VS_NOEXCEPT;
+ int (VS_CC *getFrameWidth)(const VSFrameRef *f, int plane) VS_NOEXCEPT;
+ int (VS_CC *getFrameHeight)(const VSFrameRef *f, int plane) VS_NOEXCEPT;
+ const VSMap *(VS_CC *getFramePropsRO)(const VSFrameRef *f) VS_NOEXCEPT;
+ VSMap *(VS_CC *getFramePropsRW)(VSFrameRef *f) VS_NOEXCEPT;
+
+ int (VS_CC *propNumKeys)(const VSMap *map) VS_NOEXCEPT;
+ const char *(VS_CC *propGetKey)(const VSMap *map, int index) VS_NOEXCEPT;
+ int (VS_CC *propNumElements)(const VSMap *map, const char *key) VS_NOEXCEPT;
+ char (VS_CC *propGetType)(const VSMap *map, const char *key) VS_NOEXCEPT;
+
+ int64_t(VS_CC *propGetInt)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ double(VS_CC *propGetFloat)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ const char *(VS_CC *propGetData)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ int (VS_CC *propGetDataSize)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ VSNodeRef *(VS_CC *propGetNode)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ const VSFrameRef *(VS_CC *propGetFrame)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ VSFuncRef *(VS_CC *propGetFunc)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+
+ int (VS_CC *propDeleteKey)(VSMap *map, const char *key) VS_NOEXCEPT;
+ int (VS_CC *propSetInt)(VSMap *map, const char *key, int64_t i, int append) VS_NOEXCEPT;
+ int (VS_CC *propSetFloat)(VSMap *map, const char *key, double d, int append) VS_NOEXCEPT;
+ int (VS_CC *propSetData)(VSMap *map, const char *key, const char *data, int size, int append) VS_NOEXCEPT;
+ int (VS_CC *propSetNode)(VSMap *map, const char *key, VSNodeRef *node, int append) VS_NOEXCEPT;
+ int (VS_CC *propSetFrame)(VSMap *map, const char *key, const VSFrameRef *f, int append) VS_NOEXCEPT;
+ int (VS_CC *propSetFunc)(VSMap *map, const char *key, VSFuncRef *func, int append) VS_NOEXCEPT;
+
+ int64_t (VS_CC *setMaxCacheSize)(int64_t bytes, VSCore *core) VS_NOEXCEPT;
+ int (VS_CC *getOutputIndex)(VSFrameContext *frameCtx) VS_NOEXCEPT;
+ VSFrameRef *(VS_CC *newVideoFrame2)(const VSFormat *format, int width, int height, const VSFrameRef **planeSrc, const int *planes, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT;
+
+ VS_DEPRECATE("setMessageHandler has been deprecated as of api 3.6, use addMessageHandler and removeMessageHandler instead")
+ void (VS_CC *setMessageHandler)(VSMessageHandler handler, void *userData) VS_NOEXCEPT;
+
+ int (VS_CC *setThreadCount)(int threads, VSCore *core) VS_NOEXCEPT;
+
+ const char *(VS_CC *getPluginPath)(const VSPlugin *plugin) VS_NOEXCEPT;
+
+ /* api 3.1 */
+ const int64_t *(VS_CC *propGetIntArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT;
+ const double *(VS_CC *propGetFloatArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT;
+
+ int (VS_CC *propSetIntArray)(VSMap *map, const char *key, const int64_t *i, int size) VS_NOEXCEPT;
+ int (VS_CC *propSetFloatArray)(VSMap *map, const char *key, const double *d, int size) VS_NOEXCEPT;
+
+ /* api 3.4 */
+ void (VS_CC *logMessage)(int msgType, const char *msg) VS_NOEXCEPT;
+
+ /* api 3.6 */
+ int (VS_CC *addMessageHandler)(VSMessageHandler handler, VSMessageHandlerFree free, void *userData) VS_NOEXCEPT;
+ int (VS_CC *removeMessageHandler)(int id) VS_NOEXCEPT;
+ void (VS_CC *getCoreInfo2)(VSCore *core, VSCoreInfo *info) VS_NOEXCEPT;
+};
+
+VS_API(const VSAPI *) getVapourSynthAPI(int version) VS_NOEXCEPT;
+
+#endif /* VAPOURSYNTH_H */
diff --git a/src/headers/VapourSynth4.h b/src/headers/VapourSynth4.h
new file mode 100644
index 0000000..4f69556
--- /dev/null
+++ b/src/headers/VapourSynth4.h
@@ -0,0 +1,483 @@
+/*
+* Copyright (c) 2012-2021 Fredrik Mellbin
+*
+* This file is part of VapourSynth.
+*
+* VapourSynth is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* VapourSynth is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with VapourSynth; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef VAPOURSYNTH4_H
+#define VAPOURSYNTH4_H
+
+#include
+#include
+
+#define VS_MAKE_VERSION(major, minor) (((major) << 16) | (minor))
+#define VAPOURSYNTH_API_MAJOR 4
+#define VAPOURSYNTH_API_MINOR 0
+#define VAPOURSYNTH_API_VERSION VS_MAKE_VERSION(VAPOURSYNTH_API_MAJOR, VAPOURSYNTH_API_MINOR)
+
+#define VS_AUDIO_FRAME_SAMPLES 3072
+
+/* Convenience for C++ users. */
+#ifdef __cplusplus
+# define VS_EXTERN_C extern "C"
+# if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L)
+# define VS_NOEXCEPT noexcept
+# else
+# define VS_NOEXCEPT
+# endif
+#else
+# define VS_EXTERN_C
+# define VS_NOEXCEPT
+#endif
+
+#if defined(_WIN32) && !defined(_WIN64)
+# define VS_CC __stdcall
+#else
+# define VS_CC
+#endif
+
+/* And now for some symbol hide-and-seek... */
+#if defined(_WIN32) /* Windows being special */
+# define VS_EXTERNAL_API(ret) VS_EXTERN_C __declspec(dllexport) ret VS_CC
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define VS_EXTERNAL_API(ret) VS_EXTERN_C __attribute__((visibility("default"))) ret VS_CC
+#else
+# define VS_EXTERNAL_API(ret) VS_EXTERN_C ret VS_CC
+#endif
+
+#if !defined(VS_CORE_EXPORTS) && defined(_WIN32)
+# define VS_API(ret) VS_EXTERN_C __declspec(dllimport) ret VS_CC
+#else
+# define VS_API(ret) VS_EXTERNAL_API(ret)
+#endif
+
+typedef struct VSFrame VSFrame;
+typedef struct VSNode VSNode;
+typedef struct VSCore VSCore;
+typedef struct VSPlugin VSPlugin;
+typedef struct VSPluginFunction VSPluginFunction;
+typedef struct VSFunction VSFunction;
+typedef struct VSMap VSMap;
+typedef struct VSLogHandle VSLogHandle;
+typedef struct VSFrameContext VSFrameContext;
+typedef struct VSPLUGINAPI VSPLUGINAPI;
+typedef struct VSAPI VSAPI;
+
+typedef enum VSColorFamily {
+ cfUndefined = 0,
+ cfGray = 1,
+ cfRGB = 2,
+ cfYUV = 3
+} VSColorFamily;
+
+typedef enum VSSampleType {
+ stInteger = 0,
+ stFloat = 1
+} VSSampleType;
+
+#define VS_MAKE_VIDEO_ID(colorFamily, sampleType, bitsPerSample, subSamplingW, subSamplingH) ((colorFamily << 28) | (sampleType << 24) | (bitsPerSample << 16) | (subSamplingW << 8) | (subSamplingH << 0))
+
+typedef enum VSPresetFormat {
+ pfNone = 0,
+
+ pfGray8 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 8, 0, 0),
+ pfGray16 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 16, 0, 0),
+ pfGray32 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 32, 0, 0),
+
+ pfGrayH = VS_MAKE_VIDEO_ID(cfGray, stFloat, 16, 0, 0),
+ pfGrayS = VS_MAKE_VIDEO_ID(cfGray, stFloat, 32, 0, 0),
+
+ pfYUV410P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 2, 2),
+ pfYUV411P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 2, 0),
+ pfYUV440P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 0, 1),
+
+ pfYUV420P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 1, 1),
+ pfYUV422P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 1, 0),
+ pfYUV444P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 0, 0),
+
+ pfYUV420P9 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 9, 1, 1),
+ pfYUV422P9 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 9, 1, 0),
+ pfYUV444P9 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 9, 0, 0),
+
+ pfYUV420P10 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 10, 1, 1),
+ pfYUV422P10 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 10, 1, 0),
+ pfYUV444P10 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 10, 0, 0),
+
+ pfYUV420P12 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 12, 1, 1),
+ pfYUV422P12 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 12, 1, 0),
+ pfYUV444P12 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 12, 0, 0),
+
+ pfYUV420P14 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 14, 1, 1),
+ pfYUV422P14 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 14, 1, 0),
+ pfYUV444P14 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 14, 0, 0),
+
+ pfYUV420P16 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 16, 1, 1),
+ pfYUV422P16 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 16, 1, 0),
+ pfYUV444P16 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 16, 0, 0),
+
+ pfYUV444PH = VS_MAKE_VIDEO_ID(cfYUV, stFloat, 16, 0, 0),
+ pfYUV444PS = VS_MAKE_VIDEO_ID(cfYUV, stFloat, 32, 0, 0),
+
+ pfRGB24 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 8, 0, 0),
+ pfRGB30 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 10, 0, 0),
+ pfRGB36 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 12, 0, 0),
+ pfRGB42 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 14, 0, 0),
+ pfRGB48 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 16, 0, 0),
+
+ pfRGBH = VS_MAKE_VIDEO_ID(cfRGB, stFloat, 16, 0, 0),
+ pfRGBS = VS_MAKE_VIDEO_ID(cfRGB, stFloat, 32, 0, 0),
+} VSPresetFormat;
+
+#undef VS_MAKE_VIDEO_ID
+
+
+typedef enum VSFilterMode {
+ fmParallel = 0, /* completely parallel execution */
+ fmParallelRequests = 1, /* for filters that are serial in nature but can request one or more frames they need in advance */
+ fmUnordered = 2, /* for filters that modify their internal state every request like source filters that read a file */
+ fmFrameState = 3 /* DO NOT USE UNLESS ABSOLUTELY NECESSARY, for compatibility with external code that can only keep the processing state of a single frame at a time */
+} VSFilterMode;
+
+typedef enum VSMediaType {
+ mtVideo = 1,
+ mtAudio = 2
+} VSMediaType;
+
+typedef struct VSVideoFormat {
+ int colorFamily; /* see VSColorFamily */
+ int sampleType; /* see VSSampleType */
+ int bitsPerSample; /* number of significant bits */
+ 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 */
+
+ int subSamplingW; /* log2 subsampling factor, applied to second and third plane */
+ int subSamplingH; /* log2 subsampling factor, applied to second and third plane */
+
+ int numPlanes; /* implicit from colorFamily */
+} VSVideoFormat;
+
+typedef enum VSAudioChannels {
+ acFrontLeft = 0,
+ acFrontRight = 1,
+ acFrontCenter = 2,
+ acLowFrequency = 3,
+ acBackLeft = 4,
+ acBackRight = 5,
+ acFrontLeftOFCenter = 6,
+ acFrontRightOFCenter = 7,
+ acBackCenter = 8,
+ acSideLeft = 9,
+ acSideRight = 10,
+ acTopCenter = 11,
+ acTopFrontLeft = 12,
+ acTopFrontCenter = 13,
+ acTopFrontRight = 14,
+ acTopBackLeft = 15,
+ acTopBackCenter = 16,
+ acTopBackRight = 17,
+ acStereoLeft = 29,
+ acStereoRight = 30,
+ acWideLeft = 31,
+ acWideRight = 32,
+ acSurroundDirectLeft = 33,
+ acSurroundDirectRight = 34,
+ acLowFrequency2 = 35
+} VSAudioChannels;
+
+typedef struct VSAudioFormat {
+ int sampleType;
+ int bitsPerSample;
+ int bytesPerSample; /* implicit from bitsPerSample */
+ int numChannels; /* implicit from channelLayout */
+ uint64_t channelLayout;
+} VSAudioFormat;
+
+typedef enum VSFilterFlags {
+ ffStrictSpatial = 1
+} VSFilterFlags;
+
+typedef enum VSPropertyType {
+ ptUnset = 0,
+ ptInt = 1,
+ ptFloat = 2,
+ ptData = 3,
+ ptFunction = 4,
+ ptVideoNode = 5,
+ ptAudioNode = 6,
+ ptVideoFrame = 7,
+ ptAudioFrame = 8
+} VSPropertyType;
+
+typedef enum VSMapPropertyError {
+ peSuccess = 0,
+ peUnset = 1, /* no key exists */
+ peType = 2, /* key exists but not of a compatible type */
+ peIndex = 4, /* index out of bounds */
+ peError = 3 /* map has error state set */
+} VSMapPropertyError;
+
+typedef enum VSMapAppendMode {
+ maReplace = 0,
+ maAppend = 1
+} VSMapAppendMode;
+
+typedef struct VSCoreInfo {
+ const char *versionString;
+ int core;
+ int api;
+ int numThreads;
+ int64_t maxFramebufferSize;
+ int64_t usedFramebufferSize;
+} VSCoreInfo;
+
+typedef struct VSVideoInfo {
+ VSVideoFormat format;
+ int64_t fpsNum;
+ int64_t fpsDen;
+ int width;
+ int height;
+ int numFrames;
+} VSVideoInfo;
+
+typedef struct VSAudioInfo {
+ VSAudioFormat format;
+ int sampleRate;
+ int64_t numSamples;
+ int numFrames; /* the total number of audio frames needed to hold numSamples, implicit from numSamples when calling createAudioFilter */
+} VSAudioInfo;
+
+typedef enum VSActivationReason {
+ arInitial = 0,
+ arAllFramesReady = 1,
+ arError = -1
+} VSActivationReason;
+
+typedef enum VSMessageType {
+ mtDebug = 0,
+ mtInformation = 1,
+ mtWarning = 2,
+ mtCritical = 3,
+ mtFatal = 4 /* also terminates the process, should generally not be used by normal filters */
+} VSMessageType;
+
+typedef enum VSCoreCreationFlags {
+ ccfEnableGraphInspection = 1,
+ ccfDisableAutoLoading = 2,
+ ccfDisableLibraryUnloading = 4
+} VSCoreCreationFlags;
+
+typedef enum VSPluginConfigFlags {
+ pcModifiable = 1
+} VSPluginConfigFlags;
+
+typedef enum VSDataTypeHint {
+ dtUnknown = -1,
+ dtBinary = 0,
+ dtUtf8 = 1
+} VSDataTypeHint;
+
+typedef enum VSRequestPattern {
+ rpGeneral = 0, /* General pattern */
+ rpNoFrameReuse = 1, /* When requesting all output frames from the filter no frame will be requested more than once from this input clip, never requests frames beyond the end of the clip */
+ rpStrictSpatial = 2 /* Always (and only) requests frame n from input clip when generating output frame n, never requests frames beyond the end of the clip */
+} VSRequestPattern;
+
+/* Core entry point */
+typedef const VSAPI *(VS_CC *VSGetVapourSynthAPI)(int version);
+
+/* Plugin, function and filter related */
+typedef void (VS_CC *VSPublicFunction)(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi);
+typedef void (VS_CC *VSInitPlugin)(VSPlugin *plugin, const VSPLUGINAPI *vspapi);
+typedef void (VS_CC *VSFreeFunctionData)(void *userData);
+typedef const VSFrame *(VS_CC *VSFilterGetFrame)(int n, int activationReason, void *instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi);
+typedef void (VS_CC *VSFilterFree)(void *instanceData, VSCore *core, const VSAPI *vsapi);
+
+/* Other */
+typedef void (VS_CC *VSFrameDoneCallback)(void *userData, const VSFrame *f, int n, VSNode *node, const char *errorMsg);
+typedef void (VS_CC *VSLogHandler)(int msgType, const char *msg, void *userData);
+typedef void (VS_CC *VSLogHandlerFree)(void *userData);
+
+struct VSPLUGINAPI {
+ int (VS_CC *getAPIVersion)(void) VS_NOEXCEPT; /* returns VAPOURSYNTH_API_VERSION of the library */
+ int (VS_CC *configPlugin)(const char *identifier, const char *pluginNamespace, const char *name, int pluginVersion, int apiVersion, int flags, VSPlugin *plugin) VS_NOEXCEPT; /* use the VS_MAKE_VERSION macro for pluginVersion */
+ int (VS_CC *registerFunction)(const char *name, const char *args, const char *returnType, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT; /* non-zero return value on success */
+};
+
+typedef struct VSFilterDependency {
+ VSNode *source;
+ int requestPattern; /* VSRequestPattern */
+} VSFilterDependency;
+
+struct VSAPI {
+ /* Audio and video filter related including nodes */
+ void (VS_CC *createVideoFilter)(VSMap *out, const char *name, const VSVideoInfo *vi, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT; /* output nodes are appended to the clip key in the out map */
+ VSNode *(VS_CC *createVideoFilter2)(const char *name, const VSVideoInfo *vi, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT; /* same as createVideoFilter but returns a pointer to the VSNode directly or NULL on failure */
+ void (VS_CC *createAudioFilter)(VSMap *out, const char *name, const VSAudioInfo *ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT; /* output nodes are appended to the clip key in the out map */
+ VSNode *(VS_CC *createAudioFilter2)(const char *name, const VSAudioInfo *ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT; /* same as createAudioFilter but returns a pointer to the VSNode directly or NULL on failure */
+ int (VS_CC *setLinearFilter)(VSNode *node) VS_NOEXCEPT; /* Use right after create*Filter*, sets the correct cache mode for using the cacheFrame API and returns the recommended upper number of additional frames to cache per request */
+ void (VS_CC *setCacheMode)(VSNode *node, int mode) VS_NOEXCEPT; /* -1: default (auto), 0: force disable, 1: force enable, changing the cache mode also resets all options to their default */
+ void (VS_CC *setCacheOptions)(VSNode *node, int fixedSize, int maxSize, int maxHistorySize) VS_NOEXCEPT; /* passing -1 means no change */
+
+ void (VS_CC *freeNode)(VSNode *node) VS_NOEXCEPT;
+ VSNode *(VS_CC *addNodeRef)(VSNode *node) VS_NOEXCEPT;
+ int (VS_CC *getNodeType)(VSNode *node) VS_NOEXCEPT; /* returns VSMediaType */
+ const VSVideoInfo *(VS_CC *getVideoInfo)(VSNode *node) VS_NOEXCEPT;
+ const VSAudioInfo *(VS_CC *getAudioInfo)(VSNode *node) VS_NOEXCEPT;
+
+ /* Frame related functions */
+ VSFrame *(VS_CC *newVideoFrame)(const VSVideoFormat *format, int width, int height, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT;
+ VSFrame *(VS_CC *newVideoFrame2)(const VSVideoFormat *format, int width, int height, const VSFrame **planeSrc, const int *planes, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT; /* same as newVideoFrame but allows the specified planes to be effectively copied from the source frames */
+ VSFrame *(VS_CC *newAudioFrame)(const VSAudioFormat *format, int numSamples, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT;
+ VSFrame *(VS_CC *newAudioFrame2)(const VSAudioFormat *format, int numSamples, const VSFrame **channelSrc, const int *channels, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT; /* same as newAudioFrame but allows the specified channels to be effectively copied from the source frames */
+ void (VS_CC *freeFrame)(const VSFrame *f) VS_NOEXCEPT;
+ const VSFrame *(VS_CC *addFrameRef)(const VSFrame *f) VS_NOEXCEPT;
+ VSFrame *(VS_CC *copyFrame)(const VSFrame *f, VSCore *core) VS_NOEXCEPT;
+ const VSMap *(VS_CC *getFramePropertiesRO)(const VSFrame *f) VS_NOEXCEPT;
+ VSMap *(VS_CC *getFramePropertiesRW)(VSFrame *f) VS_NOEXCEPT;
+
+ ptrdiff_t (VS_CC *getStride)(const VSFrame *f, int plane) VS_NOEXCEPT;
+ const uint8_t *(VS_CC *getReadPtr)(const VSFrame *f, int plane) VS_NOEXCEPT;
+ uint8_t *(VS_CC *getWritePtr)(VSFrame *f, int plane) VS_NOEXCEPT; /* calling this function invalidates previously gotten read pointers to the same frame */
+
+ const VSVideoFormat *(VS_CC *getVideoFrameFormat)(const VSFrame *f) VS_NOEXCEPT;
+ const VSAudioFormat *(VS_CC *getAudioFrameFormat)(const VSFrame *f) VS_NOEXCEPT;
+ int (VS_CC *getFrameType)(const VSFrame *f) VS_NOEXCEPT; /* returns VSMediaType */
+ int (VS_CC *getFrameWidth)(const VSFrame *f, int plane) VS_NOEXCEPT;
+ int (VS_CC *getFrameHeight)(const VSFrame *f, int plane) VS_NOEXCEPT;
+ int (VS_CC *getFrameLength)(const VSFrame *f) VS_NOEXCEPT; /* returns the number of samples for audio frames */
+
+ /* General format functions */
+ int (VS_CC *getVideoFormatName)(const VSVideoFormat *format, char *buffer) VS_NOEXCEPT; /* up to 32 characters including terminating null may be written to the buffer, non-zero return value on success */
+ int (VS_CC *getAudioFormatName)(const VSAudioFormat *format, char *buffer) VS_NOEXCEPT; /* up to 32 characters including terminating null may be written to the buffer, non-zero return value on success */
+ int (VS_CC *queryVideoFormat)(VSVideoFormat *format, int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT; /* non-zero return value on success */
+ int (VS_CC *queryAudioFormat)(VSAudioFormat *format, int sampleType, int bitsPerSample, uint64_t channelLayout, VSCore *core) VS_NOEXCEPT; /* non-zero return value on success */
+ uint32_t (VS_CC *queryVideoFormatID)(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT; /* returns 0 on failure */
+ int (VS_CC *getVideoFormatByID)(VSVideoFormat *format, uint32_t id, VSCore *core) VS_NOEXCEPT; /* non-zero return value on success */
+
+ /* Frame request and filter getframe functions */
+ const VSFrame *(VS_CC *getFrame)(int n, VSNode *node, char *errorMsg, int bufSize) VS_NOEXCEPT; /* only for external applications using the core as a library or for requesting frames in a filter constructor, do not use inside a filter's getframe function */
+ void (VS_CC *getFrameAsync)(int n, VSNode *node, VSFrameDoneCallback callback, void *userData) VS_NOEXCEPT; /* only for external applications using the core as a library or for requesting frames in a filter constructor, do not use inside a filter's getframe function */
+ const VSFrame *(VS_CC *getFrameFilter)(int n, VSNode *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */
+ void (VS_CC *requestFrameFilter)(int n, VSNode *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */
+ void (VS_CC *releaseFrameEarly)(VSNode *node, int n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function, unless this function is called a requested frame is kept in memory until the end of processing the current frame */
+ void (VS_CC *cacheFrame)(const VSFrame *frame, int n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* used to store intermediate frames in cache, useful for filters where random access is slow, must call setLinearFilter on the node before using or the result is undefined */
+ void (VS_CC *setFilterError)(const char *errorMessage, VSFrameContext *frameCtx) VS_NOEXCEPT; /* used to signal errors in the filter getframe function */
+
+ /* External functions */
+ VSFunction *(VS_CC *createFunction)(VSPublicFunction func, void *userData, VSFreeFunctionData free, VSCore *core) VS_NOEXCEPT;
+ void (VS_CC *freeFunction)(VSFunction *f) VS_NOEXCEPT;
+ VSFunction *(VS_CC *addFunctionRef)(VSFunction *f) VS_NOEXCEPT;
+ void (VS_CC *callFunction)(VSFunction *func, const VSMap *in, VSMap *out) VS_NOEXCEPT;
+
+ /* Map and property access functions */
+ VSMap *(VS_CC *createMap)(void) VS_NOEXCEPT;
+ void (VS_CC *freeMap)(VSMap *map) VS_NOEXCEPT;
+ void (VS_CC *clearMap)(VSMap *map) VS_NOEXCEPT;
+ void (VS_CC *copyMap)(const VSMap *src, VSMap *dst) VS_NOEXCEPT; /* copies all values in src to dst, if a key already exists in dst it's replaced */
+
+ void (VS_CC *mapSetError)(VSMap *map, const char *errorMessage) VS_NOEXCEPT; /* used to signal errors outside filter getframe function */
+ const char *(VS_CC *mapGetError)(const VSMap *map) VS_NOEXCEPT; /* used to query errors, returns 0 if no error */
+
+ int (VS_CC *mapNumKeys)(const VSMap *map) VS_NOEXCEPT;
+ const char *(VS_CC *mapGetKey)(const VSMap *map, int index) VS_NOEXCEPT;
+ int (VS_CC *mapDeleteKey)(VSMap *map, const char *key) VS_NOEXCEPT;
+ int (VS_CC *mapNumElements)(const VSMap *map, const char *key) VS_NOEXCEPT; /* returns -1 if a key doesn't exist */
+ int (VS_CC *mapGetType)(const VSMap *map, const char *key) VS_NOEXCEPT; /* returns VSPropertyType */
+ int (VS_CC *mapSetEmpty)(VSMap *map, const char *key, int type) VS_NOEXCEPT;
+
+ int64_t (VS_CC *mapGetInt)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ int (VS_CC *mapGetIntSaturated)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ const int64_t *(VS_CC *mapGetIntArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT;
+ int (VS_CC *mapSetInt)(VSMap *map, const char *key, int64_t i, int append) VS_NOEXCEPT;
+ int (VS_CC *mapSetIntArray)(VSMap *map, const char *key, const int64_t *i, int size) VS_NOEXCEPT;
+
+ double (VS_CC *mapGetFloat)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ float (VS_CC *mapGetFloatSaturated)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ const double *(VS_CC *mapGetFloatArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT;
+ int (VS_CC *mapSetFloat)(VSMap *map, const char *key, double d, int append) VS_NOEXCEPT;
+ int (VS_CC *mapSetFloatArray)(VSMap *map, const char *key, const double *d, int size) VS_NOEXCEPT;
+
+ const char *(VS_CC *mapGetData)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ int (VS_CC *mapGetDataSize)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ int (VS_CC *mapGetDataTypeHint)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; /* returns VSDataTypeHint */
+ int (VS_CC *mapSetData)(VSMap *map, const char *key, const char *data, int size, int type, int append) VS_NOEXCEPT;
+
+ VSNode *(VS_CC *mapGetNode)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ int (VS_CC *mapSetNode)(VSMap *map, const char *key, VSNode *node, int append) VS_NOEXCEPT; /* returns 0 on success */
+ int (VS_CC *mapConsumeNode)(VSMap *map, const char *key, VSNode *node, int append) VS_NOEXCEPT; /* always consumes the reference, even on error */
+
+ const VSFrame *(VS_CC *mapGetFrame)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ int (VS_CC *mapSetFrame)(VSMap *map, const char *key, const VSFrame *f, int append) VS_NOEXCEPT; /* returns 0 on success */
+ int (VS_CC *mapConsumeFrame)(VSMap *map, const char *key, const VSFrame *f, int append) VS_NOEXCEPT; /* always consumes the reference, even on error */
+
+ VSFunction *(VS_CC *mapGetFunction)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT;
+ int (VS_CC *mapSetFunction)(VSMap *map, const char *key, VSFunction *func, int append) VS_NOEXCEPT; /* returns 0 on success */
+ int (VS_CC *mapConsumeFunction)(VSMap *map, const char *key, VSFunction *func, int append) VS_NOEXCEPT; /* always consumes the reference, even on error */
+
+ /* Plugin and plugin function related */
+ int (VS_CC *registerFunction)(const char *name, const char *args, const char *returnType, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT; /* non-zero return value on success */
+ VSPlugin *(VS_CC *getPluginByID)(const char *identifier, VSCore *core) VS_NOEXCEPT;
+ VSPlugin *(VS_CC *getPluginByNamespace)(const char *ns, VSCore *core) VS_NOEXCEPT;
+ VSPlugin *(VS_CC *getNextPlugin)(VSPlugin *plugin, VSCore *core) VS_NOEXCEPT; /* pass NULL to get the first plugin */
+ const char *(VS_CC *getPluginName)(VSPlugin *plugin) VS_NOEXCEPT;
+ const char *(VS_CC *getPluginID)(VSPlugin *plugin) VS_NOEXCEPT;
+ const char *(VS_CC *getPluginNamespace)(VSPlugin *plugin) VS_NOEXCEPT;
+ VSPluginFunction *(VS_CC *getNextPluginFunction)(VSPluginFunction *func, VSPlugin *plugin) VS_NOEXCEPT; /* pass NULL to get the first plugin function */
+ VSPluginFunction *(VS_CC *getPluginFunctionByName)(const char *name, VSPlugin *plugin) VS_NOEXCEPT;
+ const char *(VS_CC *getPluginFunctionName)(VSPluginFunction *func) VS_NOEXCEPT;
+ const char *(VS_CC *getPluginFunctionArguments)(VSPluginFunction *func) VS_NOEXCEPT; /* returns an argument format string */
+ const char *(VS_CC *getPluginFunctionReturnType)(VSPluginFunction *func) VS_NOEXCEPT; /* returns an argument format string */
+ const char *(VS_CC *getPluginPath)(const VSPlugin *plugin) VS_NOEXCEPT; /* the full path to the loaded library file containing the plugin entry point */
+ int (VS_CC *getPluginVersion)(const VSPlugin *plugin) VS_NOEXCEPT;
+ VSMap *(VS_CC *invoke)(VSPlugin *plugin, const char *name, const VSMap *args) VS_NOEXCEPT; /* user must free the returned VSMap */
+
+ /* Core and information */
+ VSCore *(VS_CC *createCore)(int flags) VS_NOEXCEPT; /* flags uses the VSCoreFlags enum */
+ void (VS_CC *freeCore)(VSCore *core) VS_NOEXCEPT; /* only call this function after all node, frame and function references belonging to the core have been freed */
+ int64_t(VS_CC *setMaxCacheSize)(int64_t bytes, VSCore *core) VS_NOEXCEPT; /* the total cache size at which vapoursynth more aggressively tries to reclaim memory, it is not a hard limit */
+ int (VS_CC *setThreadCount)(int threads, VSCore *core) VS_NOEXCEPT; /* setting threads to 0 means automatic detection */
+ void (VS_CC *getCoreInfo)(VSCore *core, VSCoreInfo *info) VS_NOEXCEPT;
+ int (VS_CC *getAPIVersion)(void) VS_NOEXCEPT;
+
+ /* Message handler */
+ void (VS_CC *logMessage)(int msgType, const char *msg, VSCore *core) VS_NOEXCEPT;
+ VSLogHandle *(VS_CC *addLogHandler)(VSLogHandler handler, VSLogHandlerFree free, void *userData, VSCore *core) VS_NOEXCEPT; /* free and userData can be NULL, returns a handle that can be passed to removeLogHandler */
+ int (VS_CC *removeLogHandler)(VSLogHandle *handle, VSCore *core) VS_NOEXCEPT; /* returns non-zero if successfully removed */
+
+#ifdef VS_GRAPH_API
+ /* Graph information */
+
+ /*
+ * NOT PART OF THE STABLE API!
+ * These functions only exist to retrieve internal details for debug purposes and graph visualization
+ * They will only only work properly when used on a core created with cfEnableGraphInspection and are
+ * not safe to use concurrently with frame requests or other API functions
+ * NOT PART OF THE STABLE API!
+ */
+
+ const char *(VS_CC *getNodeCreationFunctionName)(VSNode *node, int level) VS_NOEXCEPT; /* level=0 returns the name of the function that created the filter, specifying a higher level will retrieve the function above that invoked it or NULL if a non-existent level is requested */
+ const VSMap *(VS_CC *getNodeCreationFunctionArguments)(VSNode *node, int level) VS_NOEXCEPT; /* level=0 returns a copy of the arguments passed to the function that created the filter, returns NULL if a non-existent level is requested */
+ const char *(VS_CC *getNodeName)(VSNode *node) VS_NOEXCEPT; /* the name passed to create*Filter */
+ int (VS_CC *getNodeFilterMode)(VSNode *node) VS_NOEXCEPT; /* VSFilterMode */
+ int64_t (VS_CC *getNodeFilterTime)(VSNode *node) VS_NOEXCEPT; /* time spent processing frames in nanoseconds */
+ const VSFilterDependency *(VS_CC *getNodeDependencies)(VSNode *node) VS_NOEXCEPT;
+ int (VS_CC *getNumNodeDependencies)(VSNode *node) VS_NOEXCEPT;
+#endif
+};
+
+VS_API(const VSAPI *) getVapourSynthAPI(int version) VS_NOEXCEPT;
+
+#endif /* VAPOURSYNTH4_H */
diff --git a/src/libp2p_plugin.cpp b/src/libp2p_plugin.cpp
new file mode 100644
index 0000000..4655d35
--- /dev/null
+++ b/src/libp2p_plugin.cpp
@@ -0,0 +1,197 @@
+#include
+#include
+
+#include "p2p_api.h"
+#include
+
+typedef struct {
+ VSVideoInfo vi;
+ uint32_t src_format;
+ VSNode* node;
+ p2p_packing p2p_output_format;
+} PackRGB32Data;
+
+typedef struct {
+ VSVideoInfo vi;
+ VSNode* node;
+ p2p_packing p2p_input_format;
+} UnpackRGB32Data;
+
+static const VSFrame* VS_CC packGetFrame(int n, int activationReason, void* instanceData, void** frameData, VSFrameContext* frameCtx, VSCore* core, const VSAPI* vsapi) {
+ PackRGB32Data* d = reinterpret_cast(instanceData);
+
+ if (activationReason == arInitial) {
+ vsapi->requestFrameFilter(n, d->node, frameCtx);
+ }
+ else if (activationReason == arAllFramesReady) {
+ const VSFrame* src = vsapi->getFrameFilter(n, d->node, frameCtx);
+ VSFrame* dst = vsapi->newVideoFrame(&d->vi.format, d->vi.width, d->vi.height, src, core);
+
+ p2p_buffer_param p = {};
+ p.packing = d->p2p_output_format;
+ p.width = d->vi.width;
+ p.height = d->vi.height;
+ p.dst[0] = vsapi->getWritePtr(dst, 0);
+ p.dst_stride[0] = vsapi->getStride(dst, 0);
+
+ for (int plane = 0; plane < 3; plane++) {
+ p.src[plane] = vsapi->getReadPtr(src, plane);
+ p.src_stride[plane] = vsapi->getStride(src, plane);
+ }
+
+ p2p_pack_frame(&p, P2P_ALPHA_SET_ONE);
+
+ VSMap* m = vsapi->getFramePropertiesRW(dst);
+ vsapi->mapSetInt(m, "_P2PInputFormat", d->src_format, maReplace);
+
+ vsapi->freeFrame(src);
+
+ return dst;
+ }
+
+ return nullptr;
+}
+
+static void VS_CC packFree(void* instanceData, VSCore* core, const VSAPI* vsapi) {
+ PackRGB32Data* d = reinterpret_cast(instanceData);
+ vsapi->freeNode(d->node);
+ free(d);
+}
+
+static void VS_CC packCreate(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* vsapi) {
+ std::unique_ptr d(new PackRGB32Data());
+
+ d->node = vsapi->mapGetNode(in, "clip", 0, 0);
+ const VSVideoInfo* vi = vsapi->getVideoInfo(d->node);
+ d->src_format = vsapi->queryVideoFormatID(vi->format.colorFamily, vi->format.sampleType, vi->format.bitsPerSample, vi->format.subSamplingW, vi->format.subSamplingH, core);
+
+ switch (d->src_format)
+ {
+ case pfRGB24:
+ d->p2p_output_format = p2p_argb32;
+ break;
+ case pfRGB30:
+ d->p2p_output_format = p2p_rgb30;
+ break;
+ case pfRGB48:
+ d->p2p_output_format = p2p_argb64;
+ break;
+ default:
+ vsapi->mapSetError(out, "Pack: only RGB24, RGB30 and RGB48 inputs are supported!");
+ vsapi->freeNode(d->node);
+ return;
+ }
+
+ d->vi = *vi;
+ vsapi->getVideoFormatByID(&d->vi.format, pfGray32, core);
+
+ if (d->src_format == pfRGB48) {
+ d->vi.width *= 2;
+ }
+
+ VSFilterDependency deps[] = { {d->node, rpStrictSpatial} };
+ vsapi->createVideoFilter(out, "Pack", &d->vi, packGetFrame, packFree, fmParallel, deps, 1, d.get(), core);
+ d.release();
+}
+
+static const VSFrame* VS_CC unpackGetFrame(int n, int activationReason, void* instanceData, void** frameData, VSFrameContext* frameCtx, VSCore* core, const VSAPI* vsapi) {
+ UnpackRGB32Data* d = reinterpret_cast(instanceData);
+
+ if (activationReason == arInitial) {
+ vsapi->requestFrameFilter(n, d->node, frameCtx);
+ }
+ else if (activationReason == arAllFramesReady) {
+ const VSFrame* src = vsapi->getFrameFilter(n, d->node, frameCtx);
+ VSFrame* dst = vsapi->newVideoFrame(&d->vi.format, d->vi.width, d->vi.height, src, core);
+
+ p2p_buffer_param p = {};
+ p.packing = d->p2p_input_format;
+ p.width = d->vi.width;
+ p.height = d->vi.height;
+ p.src[0] = vsapi->getReadPtr(src, 0);
+ p.src_stride[0] = vsapi->getStride(src, 0);
+
+ for (int plane = 0; plane < 3; plane++) {
+ p.dst[plane] = vsapi->getWritePtr(dst, plane);
+ p.dst_stride[plane] = vsapi->getStride(dst, plane);
+ }
+
+ p2p_unpack_frame(&p, 0);
+
+ vsapi->freeFrame(src);
+
+ return dst;
+ }
+
+ return nullptr;
+}
+
+static void VS_CC unpackFree(void* instanceData, VSCore* core, const VSAPI* vsapi) {
+ UnpackRGB32Data* d = reinterpret_cast(instanceData);
+ vsapi->freeNode(d->node);
+ free(d);
+}
+
+static void VS_CC unpackCreate(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* vsapi) {
+ std::unique_ptr d(new UnpackRGB32Data());
+
+ d->node = vsapi->mapGetNode(in, "clip", 0, 0);
+ const VSVideoInfo* vi = vsapi->getVideoInfo(d->node);
+
+ if (vsapi->queryVideoFormatID(vi->format.colorFamily, vi->format.sampleType, vi->format.bitsPerSample, vi->format.subSamplingW, vi->format.subSamplingH, core) != pfGray32) {
+ vsapi->mapSetError(out, "Unpack: only pfGray32 intput is supported!");
+ vsapi->freeNode(d->node);
+ return;
+ }
+
+ char errorMsg[1024] = {0};
+ const VSFrame* frame0 = vsapi->getFrame(0, d->node, errorMsg, 1024);
+ if (!frame0) {
+ vsapi->mapSetError(out, ("Unpack: failed to retrieve first frame from clip. Error message: " + std::string{ errorMsg }).c_str());
+ vsapi->freeNode(d->node);
+ return;
+ }
+
+ const VSMap* m = vsapi->getFramePropertiesRO(frame0);
+
+ int err;
+ uint32_t input_format = static_cast(vsapi->mapGetInt(m, "_P2PInputFormat", 0, &err));
+
+ vsapi->freeFrame(frame0);
+
+ if (err)
+ return;
+
+ switch (input_format)
+ {
+ case pfRGB24:
+ d->p2p_input_format = p2p_argb32;
+ break;
+ case pfRGB30:
+ d->p2p_input_format = p2p_rgb30;
+ break;
+ case pfRGB48:
+ d->p2p_input_format = p2p_argb64;
+ break;
+ default:
+ vsapi->mapSetError(out, "Unpack: unsupported source format!");
+ return;
+ }
+
+ d->vi = *vi;
+ vsapi->getVideoFormatByID(&d->vi.format, input_format, core);
+
+ if (input_format == pfRGB48) {
+ d->vi.width /= 2;
+ }
+
+ VSFilterDependency deps[] = { {d->node, rpStrictSpatial} };
+ vsapi->createVideoFilter(out, "Unpack", &d->vi, unpackGetFrame, unpackFree, fmParallel, deps, 1, d.get(), core);
+ d.release();
+}
+
+VS_EXTERNAL_API(void) VapourSynthPluginInit2(VSPlugin* plugin, const VSPLUGINAPI* vspapi) {
+ vspapi->configPlugin("com.djatom.libp2p", "libp2p", "libp2p rgb formats packer/unpacker", VS_MAKE_VERSION(1, 0), VAPOURSYNTH_API_VERSION, 0, plugin);
+ vspapi->registerFunction("Pack", "clip:vnode;", "clip:vnode;", packCreate, NULL, plugin);
+ vspapi->registerFunction("Unpack", "clip:vnode;", "clip:vnode;", unpackCreate, NULL, plugin);
+}
\ No newline at end of file
diff --git a/src/p2p.h b/src/p2p.h
new file mode 100644
index 0000000..613d6c2
--- /dev/null
+++ b/src/p2p.h
@@ -0,0 +1,668 @@
+/*
+* Copyright (c) 2018 Hoppsan G. Pig
+*
+* This file is part of VapourSynth.
+*
+* VapourSynth is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* VapourSynth is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with VapourSynth; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef P2P_H_
+#define P2P_H_
+
+#include
+#include
+#include
+#include
+
+#ifdef _WIN32
+ #include // _byteswap_x
+#endif
+
+#ifdef P2P_USER_NAMESPACE
+ #define P2P_NAMESPACE P2P_USER_NAMESPACE
+#else
+ #define P2P_NAMESPACE p2p
+#endif
+
+#ifdef _WIN32
+ #define P2P_LITTLE_ENDIAN
+#elif defined(__BYTE_ORDER__)
+ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ #define P2P_BIG_ENDIAN
+ #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ #define P2P_LITTLE_ENDIAN
+ #endif
+#endif
+
+static_assert(CHAR_BIT == 8, "8-bit char required");
+
+namespace P2P_NAMESPACE {
+
+// Tag types for endian.
+struct little_endian_t {};
+struct big_endian_t {};
+
+#if defined(P2P_BIG_ENDIAN)
+ typedef big_endian_t native_endian_t;
+#elif defined(P2P_LITTLE_ENDIAN)
+ typedef little_endian_t native_endian_t;
+#else
+ #error wrong endian
+#endif
+
+#undef P2P_BIG_ENDIAN
+#undef P2P_LITTLE_ENDIAN
+
+namespace detail {
+
+// Size of object in bits.
+template
+struct bit_size {
+ static const size_t value = sizeof(T) * CHAR_BIT;
+};
+
+
+// Make integers from bytes.
+constexpr uint16_t make_u16(uint8_t a, uint8_t b)
+{
+ return (a << 8) | b;
+}
+
+constexpr uint32_t make_u32(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
+{
+ return (static_cast(make_u16(a, b)) << 16) | make_u16(c, d);
+}
+
+constexpr uint64_t make_u64(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g, uint8_t h)
+{
+ return (static_cast(make_u32(a, b, c, d)) << 32) | make_u32(e, f, g, h);
+}
+
+template
+constexpr uint8_t get_u8(T x, unsigned i)
+{
+ return static_cast((x >> (bit_size::value - 8 * i - 8)) & 0xFF);
+}
+
+
+// Fake 24 and 48-bit integers.
+struct uint24 {
+ uint8_t x[3];
+
+ uint24() = default;
+
+ constexpr uint24(uint8_t a, uint8_t b, uint8_t c) : x{ a, b, c }
+ {
+ }
+
+ template
+ explicit constexpr uint24(uint32_t val,
+ typename std::enable_if::value>::type * = 0) :
+ x{ get_u8(val, 1), get_u8(val, 2), get_u8(val, 3) }
+ {
+ }
+
+ template
+ explicit constexpr uint24(uint32_t val,
+ typename std::enable_if::value>::type * = 0) :
+ x{ get_u8(val, 3), get_u8(val, 2), get_u8(val, 1) }
+ {
+ }
+
+ template ::value>::type * = nullptr>
+ constexpr uint32_t to_u32() const
+ {
+ return make_u32(0, x[0], x[1], x[2]);
+ }
+
+ template ::value>::type * = nullptr>
+ constexpr uint32_t to_u32() const
+ {
+ return make_u32(0, x[2], x[1], x[0]);
+ }
+
+ constexpr operator uint32_t() const { return to_u32(); }
+};
+
+struct uint48 {
+ uint8_t x[6];
+
+ uint48() = default;
+
+ constexpr uint48(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f) : x{ a, b, c, d, e, f }
+ {
+ }
+
+ template
+ explicit constexpr uint48(uint64_t val,
+ typename std::enable_if::value>::type * = 0) :
+ x{ get_u8(val, 2), get_u8(val, 3), get_u8(val, 4), get_u8(val, 5), get_u8(val, 6), get_u8(val, 7) }
+ {
+ }
+
+ template
+ explicit constexpr uint48(uint64_t val,
+ typename std::enable_if::value>::type * = 0) :
+ x{ get_u8(val, 7), get_u8(val, 6), get_u8(val, 5), get_u8(val, 4), get_u8(val, 3), get_u8(val, 2) }
+ {
+ }
+
+ template ::value>::type * = nullptr>
+ constexpr uint64_t to_u64() const
+ {
+ return make_u64(0, 0, x[0], x[1], x[2], x[3], x[4], x[5]);
+ }
+
+ template ::value>::type * = nullptr>
+ constexpr uint64_t to_u64() const
+ {
+ return make_u64(0, 0, x[5], x[4], x[3], x[2], x[1], x[0]);
+ }
+
+ constexpr operator uint64_t() const { return to_u64(); }
+};
+
+static_assert(std::is_pod::value, "uint24 must be POD");
+static_assert(std::is_pod::value, "uint48 must be POD");
+static_assert(sizeof(uint24) == 3, "uint24 must not have padding");
+static_assert(sizeof(uint48) == 6, "uint48 must not have padding");
+
+
+// Endian conversions.
+template ::value>::type * = nullptr>
+T endian_swap(T x)
+{
+ return x;
+}
+
+template ::value>::type * = nullptr>
+uint16_t endian_swap(uint16_t x)
+{
+#ifdef _WIN32
+ return _byteswap_ushort(x);
+#else
+ return __builtin_bswap16(x);
+#endif
+}
+
+template ::value>::type * = nullptr>
+uint32_t endian_swap(uint32_t x)
+{
+#ifdef _WIN32
+ return _byteswap_ulong(x);
+#else
+ return __builtin_bswap32(x);
+#endif
+}
+
+template ::value>::type * = nullptr>
+uint64_t endian_swap(uint64_t x)
+{
+#ifdef _WIN32
+ return _byteswap_uint64(x);
+#else
+ return __builtin_bswap64(x);
+#endif
+}
+
+template ::value>::type * = nullptr>
+uint24 endian_swap(uint24 x)
+{
+ return{ x.x[2], x.x[1], x.x[0] };
+}
+
+template ::value>::type * = nullptr>
+uint48 endian_swap(uint48 x)
+{
+ return{ x.x[5], x.x[4], x.x[3], x.x[2], x.x[1], x.x[0] };
+}
+
+
+// Treat u32 as array of u8.
+struct mask4 {
+ uint32_t x;
+
+ constexpr uint8_t operator[](unsigned i) const { return get_u8(x, i); }
+ constexpr bool contains(unsigned val) const
+ {
+ return (*this)[0] == val || (*this)[1] == val || (*this)[2] == val || (*this)[3] == val;
+ }
+ constexpr unsigned find(uint8_t val) const
+ {
+ return (*this)[0] == val ? 0 : (*this)[1] == val ? 1 : (*this)[2] == val ? 2 : (*this)[3] == val ? 3 : ~0U;
+ }
+};
+
+
+// Native integer type for arithmetic.
+template
+struct numeric_type {
+ typedef T type;
+};
+
+template <>
+struct numeric_type {
+ typedef uint32_t type;
+};
+
+template <>
+struct numeric_type {
+ typedef uint64_t type;
+};
+
+} // namespace detail
+
+
+enum {
+ C_Y = 0,
+ C_U = 1,
+ C_V = 2,
+ C_R = 0,
+ C_G = 1,
+ C_B = 2,
+ C_A = 3,
+ C__ = 0xFF,
+};
+
+
+// Packed integer constants for template parameters.
+constexpr uint32_t make_mask(uint8_t x)
+{
+ return detail::make_u32(x, x, x, x);
+}
+
+constexpr uint32_t make_mask(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
+{
+ return detail::make_u32(a, b, c, d);
+}
+
+
+// Select type by endian.
+template
+struct endian_select {
+ typedef typename std::conditional::value, Big, Little>::type type;
+};
+
+
+template
+struct pack_traits {
+ static_assert(std::is_pod::value, "must be POD");
+ static_assert(std::is_pod::value, "must be POD");
+
+ typedef Planar planar_type;
+ typedef Packed packed_type;
+ typedef Endian endian;
+
+ static const unsigned pel_per_pack = PelPerPack;
+ static const unsigned subsampling = Subsampling;
+
+ static constexpr detail::mask4 component_mask{ ComponentMask };
+ static constexpr detail::mask4 shift_mask{ ShiftMask };
+ static constexpr detail::mask4 depth_mask{ DepthMask };
+};
+
+template
+constexpr detail::mask4 pack_traits::component_mask;
+
+template
+constexpr detail::mask4 pack_traits::shift_mask;
+
+template
+constexpr detail::mask4 pack_traits::depth_mask;
+
+
+// Base template for 4:4:4 packings.
+//
+// Much literature treats 4:4:4 triplets as single machine words, implying a
+// reversed component order on LE and BE.
+//
+// The _be and _le templates accept a component mask beginning from the MSB of
+// the packed word to accomodate this.
+template
+using byte_packed_444_be = pack_traits<
+ Planar, Packed, big_endian_t, 1, 0,
+ ComponentMask,
+ make_mask(3, 2, 1, 0) * detail::bit_size::value,
+ make_mask(detail::bit_size::value)>;
+
+template
+using byte_packed_444_le = pack_traits<
+ Planar, Packed, little_endian_t, 1, 0,
+ ComponentMask,
+ make_mask(3, 2, 1, 0) * detail::bit_size::value,
+ make_mask(detail::bit_size::value)>;
+
+// Common 444 packings.
+using packed_rgb24_be = byte_packed_444_be;
+using packed_rgb24_le = byte_packed_444_le;
+using packed_rgb24 = endian_select::type;
+
+using packed_argb32_be = byte_packed_444_be;
+using packed_argb32_le = byte_packed_444_le;
+using packed_argb32 = endian_select::type;
+
+using packed_ayuv_be = packed_argb32_be;
+using packed_ayuv_le = packed_argb32_le;
+using packed_ayuv = packed_argb32;
+
+using packed_rgb48_be = byte_packed_444_be;
+using packed_rgb48_le = byte_packed_444_le;
+using packed_rgb48 = endian_select::type;
+
+using packed_argb64_be = byte_packed_444_be;
+using packed_argb64_le = byte_packed_444_le;
+using packed_argb64 = endian_select::type;
+
+using packed_rgba32_be = byte_packed_444_be;
+using packed_rgba32_le = byte_packed_444_le;
+using packed_rgba32 = endian_select::type;
+
+using packed_rgba64_be = byte_packed_444_be;
+using packed_rgba64_le = byte_packed_444_le;
+using packed_rgba64 = endian_select::type;
+
+using packed_abgr64_be = byte_packed_444_be;
+using packed_abgr64_le = byte_packed_444_le;
+using packed_abgr64 = endian_select::type;
+
+using packed_bgr48_be = byte_packed_444_be;
+using packed_bgr48_le = byte_packed_444_le;
+using packed_bgr48 = endian_select::type;
+
+using packed_bgra64_be = byte_packed_444_be;
+using packed_bgra64_le = byte_packed_444_le;
+using packed_bgra64 = endian_select::type;
+
+// D3D A2R10G10B10.
+using packed_rgb30_be = pack_traits<
+ uint16_t, uint32_t, big_endian_t, 1, 0,
+ make_mask(C_A, C_R, C_G, C_B),
+ make_mask(30, 20, 10, 0),
+ make_mask(2, 10, 10, 10)>;
+using packed_rgb30_le = pack_traits<
+ uint16_t, uint32_t, little_endian_t, 1, 0,
+ make_mask(C_A, C_R, C_G, C_B),
+ make_mask(30, 20, 10, 0),
+ make_mask(2, 10, 10, 10)>;
+using packed_rgb30 = endian_select::type;
+
+// MS Y410 and Y416 formats.
+using packed_y410_be = pack_traits<
+ uint16_t, uint32_t, big_endian_t, 1, 0,
+ make_mask(C_A, C_V, C_Y, C_U),
+ make_mask(30, 20, 10, 0),
+ make_mask(2, 10, 10, 10)>;
+using packed_y410_le = pack_traits<
+ uint16_t, uint32_t, little_endian_t, 1, 0,
+ make_mask(C_A, C_V, C_Y, C_U),
+ make_mask(30, 20, 10, 0),
+ make_mask(2, 10, 10, 10)>;
+using packed_y410 = endian_select::type;
+
+using packed_y416_be = byte_packed_444_be;
+using packed_y416_le = byte_packed_444_le;
+using packed_y416 = endian_select::type;
+
+
+// Base template for YUY2-like 4:2:2 packings.
+//
+// The component order in both BE and LE is the same. Only the bytes of the
+// individual component words are reversed.
+//
+// The _be and _le templates accept a component mask beginning from the low
+// memory address of the packed word to accomodate this.
+template
+using byte_packed_422_be = pack_traits<
+ Planar, Packed, big_endian_t, 2, 1,
+ ComponentMask,
+ make_mask(3, 2, 1, 0) * detail::bit_size::value + make_mask(ExtraShift),
+ make_mask(detail::bit_size::value) - make_mask(ExtraShift)>;
+
+template
+using byte_packed_422_le = pack_traits<
+ Planar, Packed, little_endian_t, 2, 1,
+ ComponentMask,
+ make_mask(0, 1, 2, 3) * detail::bit_size::value + make_mask(ExtraShift),
+ make_mask(detail::bit_size::value) - make_mask(ExtraShift)>;
+
+// YUY2.
+using packed_yuy2 = byte_packed_422_be;
+using packed_uyvy = byte_packed_422_be;
+
+// MS Y210 and Y216 formats.
+using packed_y210_be = byte_packed_422_be;
+using packed_y210_le = byte_packed_422_le;
+using packed_y210 = endian_select::type;
+
+using packed_y216_be = byte_packed_422_be;
+using packed_y216_le = byte_packed_422_le;
+using packed_y216 = endian_select::type;
+
+// Apple v210 format. Handled by special-case code. Only the LE ordering is found in Qt files.
+struct packed_v210_be {};
+struct packed_v210_le {};
+using packed_v210 = endian_select::type;
+
+// Apple v216 format. Only the LE ordering is found in Qt files.
+using packed_v216_be = byte_packed_422_be;
+using packed_v216_le = byte_packed_422_le;
+using packed_v216 = endian_select::type;
+
+
+// Base template for chroma-interleaved half packings.
+//
+// The literature treats UV pairs as single machine words, implying a reversed
+// component order between BE and LE.
+template
+using byte_packed_nv_be = pack_traits<
+ Planar, Packed, big_endian_t, 2, 1,
+ make_mask(C__, C__, C_V, C_U),
+ make_mask(0, 0, 1, 0) * detail::bit_size::value + make_mask(ExtraShift),
+ make_mask(detail::bit_size::value) - make_mask(ExtraShift)>;
+
+template
+using byte_packed_nv_le = pack_traits<
+ Planar, Packed, little_endian_t, 2, 1,
+ make_mask(C__, C__, C_V, C_U),
+ make_mask(0, 0, 1, 0) * detail::bit_size::value + make_mask(ExtraShift),
+ make_mask(detail::bit_size::value) - make_mask(ExtraShift)>;
+
+using packed_nv12_be = byte_packed_nv_be; // AKA NV21.
+using packed_nv12_le = byte_packed_nv_le;
+using packed_nv12 = endian_select::type;
+
+// MS P010, P016, P210, and P216 formats.
+using packed_p010_be = byte_packed_nv_be;
+using packed_p010_le = byte_packed_nv_le;
+using packed_p010 = endian_select::type;
+
+using packed_p016_be = byte_packed_nv_be;
+using packed_p016_le = byte_packed_nv_le;
+using packed_p016 = endian_select::type;
+
+using packed_p210_be = packed_p010_be;
+using packed_p210_le = packed_p010_le;
+using packed_p210 = packed_p010;
+
+using packed_p216_be = packed_p016_be;
+using packed_p216_le = packed_p016_le;
+using packed_p216 = packed_p016;
+
+
+// Conversions.
+template
+class packed_to_planar {
+ typedef typename Traits::planar_type planar_type;
+ typedef typename Traits::packed_type packed_type;
+ typedef typename detail::numeric_type::type numeric_type;
+
+ typedef typename Traits::endian endian;
+
+ static numeric_type get_mask(unsigned c)
+ {
+ return ~static_cast(0) >> (detail::bit_size::value - Traits::depth_mask[c]);
+ }
+
+ static planar_type get_component(numeric_type x, unsigned c)
+ {
+ return static_cast((x >> Traits::shift_mask[c]) & get_mask(c));
+ }
+public:
+ static void unpack(const void *src, void * const dst[4], unsigned left, unsigned right)
+ {
+ const packed_type *src_p = static_cast(src);
+ planar_type *dst_p[4] = {
+ static_cast(dst[0]), static_cast(dst[1]),
+ static_cast(dst[2]), static_cast(dst[3]),
+ };
+ bool alpha_enabled = dst[C_A] != nullptr;
+
+ // Adjust pointers.
+ src_p += left / Traits::pel_per_pack;
+ dst_p[0] += Traits::component_mask.contains(0) ? left : 0;
+ dst_p[1] += Traits::component_mask.contains(1) ? (left >> Traits::subsampling) : 0;
+ dst_p[2] += Traits::component_mask.contains(2) ? (left >> Traits::subsampling) : 0;
+ dst_p[3] += Traits::component_mask.contains(3) ? left : 0;
+
+#define P2P_COMPONENT_ENABLED(c) ((Traits::component_mask[c] != C__) && (Traits::component_mask[c] != C_A || alpha_enabled))
+ for (unsigned i = left; i < right; i += Traits::pel_per_pack) {
+ numeric_type x = detail::endian_swap(*src_p++);
+
+ if (P2P_COMPONENT_ENABLED(0))
+ *dst_p[Traits::component_mask[0]]++ = get_component(x, 0);
+ if (P2P_COMPONENT_ENABLED(1))
+ *dst_p[Traits::component_mask[1]]++ = get_component(x, 1);
+ if (P2P_COMPONENT_ENABLED(2))
+ *dst_p[Traits::component_mask[2]]++ = get_component(x, 2);
+ if (P2P_COMPONENT_ENABLED(3))
+ *dst_p[Traits::component_mask[3]]++ = get_component(x, 3);
+ }
+#undef P2P_COMPONENT_ENABLED
+ }
+};
+
+template
+class planar_to_packed {
+ typedef typename Traits::planar_type planar_type;
+ typedef typename Traits::packed_type packed_type;
+ typedef typename detail::numeric_type::type numeric_type;
+
+ typedef typename Traits::endian endian;
+
+ static numeric_type get_mask(unsigned c)
+ {
+ return ~static_cast(0) >> (detail::bit_size::value - Traits::depth_mask[c]);
+ }
+
+ static numeric_type get_component(planar_type x, unsigned c)
+ {
+ return (static_cast(x) & get_mask(c)) << Traits::shift_mask[c];
+ }
+public:
+ static void pack(const void * const src[4], void *dst, unsigned left, unsigned right)
+ {
+ const planar_type *src_p[4] = {
+ static_cast(src[0]), static_cast(src[1]),
+ static_cast(src[2]), static_cast(src[3]),
+ };
+ packed_type *dst_p = static_cast(dst);
+ bool alpha_enabled = src[C_A] != nullptr;
+
+ // Adjust pointers.
+ src_p[0] += Traits::component_mask.contains(0) ? left : 0;
+ src_p[1] += Traits::component_mask.contains(1) ? (left >> Traits::subsampling) : 0;
+ src_p[2] += Traits::component_mask.contains(2) ? (left >> Traits::subsampling) : 0;
+ src_p[3] += Traits::component_mask.contains(3) ? left : 0;
+ dst_p += left / Traits::pel_per_pack;
+
+#define P2P_COMPONENT_ENABLED(c) ((Traits::component_mask[c] != C__) && (Traits::component_mask[c] != C_A || alpha_enabled))
+ for (unsigned i = left; i < right; i += Traits::pel_per_pack) {
+ numeric_type x = 0;
+
+ if (AlphaOneFill && Traits::component_mask.contains(C_A) && !alpha_enabled)
+ x |= get_component(~static_cast(0), Traits::component_mask.find(C_A));
+
+ if (P2P_COMPONENT_ENABLED(0))
+ x |= get_component(*src_p[Traits::component_mask[0]]++, 0);
+ if (P2P_COMPONENT_ENABLED(1))
+ x |= get_component(*src_p[Traits::component_mask[1]]++, 1);
+ if (P2P_COMPONENT_ENABLED(2))
+ x |= get_component(*src_p[Traits::component_mask[2]]++, 2);
+ if (P2P_COMPONENT_ENABLED(3))
+ x |= get_component(*src_p[Traits::component_mask[3]]++, 3);
+
+ *dst_p++ = detail::endian_swap(static_cast(x));
+ }
+ }
+#undef P2P_COMPONENT_ENABLED
+};
+
+// v210 specializations.
+template <>
+class packed_to_planar {
+public:
+ static void unpack(const void *src, void * const dst[4], unsigned left, unsigned right);
+};
+
+template <>
+class packed_to_planar {
+public:
+ static void unpack(const void *src, void * const dst[4], unsigned left, unsigned right);
+};
+
+template <>
+class planar_to_packed {
+public:
+ static void pack(const void * const src[4], void *dst, unsigned left, unsigned right);
+};
+
+template <>
+class planar_to_packed {
+public:
+ static void pack(const void * const src[4], void *dst, unsigned left, unsigned right);
+};
+
+template <>
+class planar_to_packed {
+public:
+ static void pack(const void * const src[4], void *dst, unsigned left, unsigned right);
+};
+
+template <>
+class planar_to_packed {
+public:
+ static void pack(const void * const src[4], void *dst, unsigned left, unsigned right);
+};
+
+} // namespace p2p
+
+#endif // P2P_H_
diff --git a/src/p2p_api.cpp b/src/p2p_api.cpp
new file mode 100644
index 0000000..0317d34
--- /dev/null
+++ b/src/p2p_api.cpp
@@ -0,0 +1,225 @@
+/*
+* Copyright (c) 2018 Hoppsan G. Pig
+*
+* This file is part of VapourSynth.
+*
+* VapourSynth is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* VapourSynth is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with VapourSynth; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include
+#include
+#include
+#include "p2p.h"
+#include "p2p_api.h"
+
+#ifdef P2P_USER_NAMESPACE
+ #error API build must not use custom namespace
+#endif
+
+namespace {
+
+struct packing_traits {
+ enum p2p_packing packing;
+ p2p_unpack_func unpack;
+ p2p_pack_func pack;
+ p2p_pack_func pack_one_fill;
+ bool native_endian;
+ unsigned char subsample_w;
+ unsigned char subsample_h;
+ bool is_nv;
+ unsigned char bytes_per_sample; // Only used to copy luma plane for NV12.
+ unsigned char nv_shift; // Extra LSB to shift away for MS P010/P210, etc.
+};
+
+#define CASE(x, ...) \
+ { p2p_##x, &p2p::packed_to_planar::unpack, &p2p::planar_to_packed::pack, &p2p::planar_to_packed::pack, ##__VA_ARGS__ }
+#define CASE2(x, ...) \
+ CASE(x##_be, std::is_same::value, ##__VA_ARGS__), \
+ CASE(x##_le, std::is_same::value, ##__VA_ARGS__), \
+ CASE(x, true, ##__VA_ARGS__)
+const packing_traits traits_table[] = {
+ CASE2(rgb24, 0, 0),
+ CASE2(argb32, 0, 0),
+ CASE2(ayuv, 0, 0),
+ CASE2(rgb48, 0, 0),
+ CASE2(argb64, 0, 0),
+ CASE2(rgb30, 0, 0),
+ CASE2(y410, 0, 0),
+ CASE2(y416, 0, 0),
+ CASE(yuy2, true, 1, 0),
+ CASE(uyvy, true, 1, 0),
+ CASE2(y210, 1, 0),
+ CASE2(y216, 1, 0),
+ CASE2(nv12, 1, 1, true, 1),
+ CASE2(p010, 1, 1, true, 2, 6),
+ CASE2(p016, 1, 1, true, 2),
+ CASE2(p210, 1, 0, true, 2, 6),
+ CASE2(p216, 1, 0, true, 2),
+ CASE2(rgba32, 0, 0),
+ CASE2(rgba64, 0, 0),
+ CASE2(abgr64, 0, 0),
+ CASE2(bgr48, 0, 0),
+ CASE2(bgra64, 0, 0),
+};
+#undef CASE2
+#undef CASE
+
+const packing_traits &lookup_traits(enum p2p_packing packing)
+{
+ assert(packing >= 0);
+ assert(packing < sizeof(traits_table) / sizeof(traits_table[0]));
+
+ const packing_traits &traits = traits_table[packing];
+ assert(traits.packing == packing);
+ assert(traits.subsample_h == 0 || traits.is_nv);
+ return traits;
+}
+
+template
+T *increment_ptr(T *ptr, ptrdiff_t n)
+{
+ return (T *)((const unsigned char *)ptr + n);
+}
+
+void copy_plane_fast(const void *src, void *dst, ptrdiff_t src_stride, ptrdiff_t dst_stride,
+ unsigned linesize, unsigned height)
+{
+ for (unsigned i = 0; i < height; ++i) {
+ memcpy(dst, src, linesize);
+
+ src = increment_ptr(src, src_stride);
+ dst = increment_ptr(dst, dst_stride);
+ }
+}
+
+void unpack_nv16_plane(const void *src, void *dst, ptrdiff_t src_stride, ptrdiff_t dst_stride,
+ const packing_traits &traits, unsigned width, unsigned height)
+{
+ assert(traits.bytes_per_sample == 2);
+
+ for (unsigned i = 0; i < height; ++i) {
+ std::transform(static_cast(src), static_cast(src) + width, static_cast(dst), [=](uint16_t x)
+ {
+ x = traits.native_endian ? x : (x >> 8) | (x << 8);
+ return x >> traits.nv_shift;
+ });
+
+ src = increment_ptr(src, src_stride);
+ dst = increment_ptr(dst, dst_stride);
+ }
+}
+
+void pack_nv16_plane(const void *src, void *dst, ptrdiff_t src_stride, ptrdiff_t dst_stride,
+ const packing_traits &traits, unsigned width, unsigned height)
+{
+ assert(traits.bytes_per_sample == 2);
+
+ for (unsigned i = 0; i < height; ++i) {
+ std::transform(static_cast(src), static_cast(src) + width, static_cast(dst), [=](uint16_t x)
+ {
+ x = x << traits.nv_shift;
+ return traits.native_endian ? x : (x >> 8) | (x << 8);
+ });
+
+ src = increment_ptr(src, src_stride);
+ dst = increment_ptr(dst, dst_stride);
+ }
+}
+
+} // namespace
+
+
+p2p_unpack_func p2p_select_unpack_func(enum p2p_packing packing)
+{
+ return lookup_traits(packing).unpack;
+}
+
+p2p_pack_func p2p_select_pack_func(enum p2p_packing packing)
+{
+ return p2p_select_pack_func_ex(packing, 0);
+}
+
+p2p_pack_func p2p_select_pack_func_ex(enum p2p_packing packing, int alpha_one_fill)
+{
+ const packing_traits &traits = lookup_traits(packing);
+ return alpha_one_fill ? traits.pack_one_fill : traits.pack;
+}
+
+void p2p_unpack_frame(const struct p2p_buffer_param *param, unsigned long flags)
+{
+ const packing_traits &traits = lookup_traits(param->packing);
+
+ // Process interleaved plane.
+ const void *src_p = traits.is_nv ? param->src[1] : param->src[0];
+ ptrdiff_t src_stride = traits.is_nv ? param->src_stride[1] : param->src_stride[0];
+
+ void *dst_p[4] = { param->dst[0], param->dst[1], param->dst[2], param->dst[3] };
+
+ for (unsigned i = 0; i < (param->height >> traits.subsample_h); ++i) {
+ traits.unpack(src_p, dst_p, 0, param->width);
+
+ src_p = increment_ptr(src_p, src_stride);
+
+ if (!traits.is_nv) {
+ dst_p[0] = increment_ptr(dst_p[0], param->dst_stride[0]);
+ dst_p[3] = increment_ptr(dst_p[3], param->dst_stride[3]);
+ }
+ dst_p[1] = increment_ptr(dst_p[1], param->dst_stride[1]);
+ dst_p[2] = increment_ptr(dst_p[2], param->dst_stride[2]);
+ }
+
+ if (traits.is_nv && !(flags & P2P_SKIP_UNPACKED_PLANES) && param->src[0] && param->dst[0]) {
+ if ((traits.bytes_per_sample == 1 || traits.native_endian) && !traits.nv_shift) {
+ copy_plane_fast(param->src[0], param->dst[0], param->src_stride[0], param->dst_stride[0],
+ traits.bytes_per_sample * param->width, param->height);
+ } else {
+ unpack_nv16_plane(param->src[0], param->dst[0], param->src_stride[0], param->dst_stride[0], traits, param->width, param->height);
+ }
+ }
+}
+
+void p2p_pack_frame(const struct p2p_buffer_param *param, unsigned long flags)
+{
+ const packing_traits &traits = lookup_traits(param->packing);
+ p2p_pack_func pack_func = flags & P2P_ALPHA_SET_ONE ? traits.pack_one_fill : traits.pack;
+
+ // Process interleaved plane.
+ const void *src_p[4] = { param->src[0], param->src[1], param->src[2], param->src[3] };
+
+ void *dst_p = traits.is_nv ? param->dst[1] : param->dst[0];
+ ptrdiff_t dst_stride = traits.is_nv ? param->dst_stride[1] : param->dst_stride[0];
+
+ for (unsigned i = 0; i < (param->height >> traits.subsample_h); ++i) {
+ pack_func(src_p, dst_p, 0, param->width);
+
+ if (!traits.is_nv) {
+ src_p[0] = increment_ptr(src_p[0], param->src_stride[0]);
+ src_p[3] = increment_ptr(src_p[3], param->src_stride[3]);
+ }
+ src_p[1] = increment_ptr(src_p[1], param->src_stride[1]);
+ src_p[2] = increment_ptr(src_p[2], param->src_stride[2]);
+
+ dst_p = increment_ptr(dst_p, dst_stride);
+ }
+
+ if (traits.is_nv && !(flags & P2P_SKIP_UNPACKED_PLANES) && param->src[0] && param->dst[0]) {
+ if ((traits.bytes_per_sample == 1 || traits.native_endian) && !traits.nv_shift) {
+ copy_plane_fast(param->src[0], param->dst[0], param->src_stride[0], param->dst_stride[0],
+ traits.bytes_per_sample * param->width, param->height);
+ } else {
+ pack_nv16_plane(param->src[0], param->dst[0], param->src_stride[0], param->dst_stride[0], traits, param->width, param->height);
+ }
+ }
+}
diff --git a/src/p2p_api.h b/src/p2p_api.h
new file mode 100644
index 0000000..4d69633
--- /dev/null
+++ b/src/p2p_api.h
@@ -0,0 +1,171 @@
+/*
+* Copyright (c) 2018 Hoppsan G. Pig
+*
+* This file is part of VapourSynth.
+*
+* VapourSynth is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* VapourSynth is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with VapourSynth; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef P2P_API_H_
+#define P2P_API_H_
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Notation: [Xa-Ya-Za]
+ *
+ * [] denotes a machine word of the specified endianness. Xa-Ya-Za denote
+ * component X, Y, and Z packed in the word, with bit depths a, b, c, in order
+ * from MSB to LSB. Padding bits are represented by the component '!'.
+ */
+enum p2p_packing {
+ /** [R8-G8-B8] */
+ p2p_rgb24_be, /* RGB */
+ p2p_rgb24_le, /* BGR */
+ p2p_rgb24,
+ /** [A8-R8-G8-B8] */
+ p2p_argb32_be, /* ARGB */
+ p2p_argb32_le, /* BGRA */
+ p2p_argb32,
+ /** [A8-Y8-U8-V8] */
+ p2p_ayuv_be, /* AYUV */
+ p2p_ayuv_le, /* VUYA */
+ p2p_ayuv,
+ /** [R16-G16-B16] */
+ p2p_rgb48_be, /* RGB, big-endian components */
+ p2p_rgb48_le, /* BGR, little-endian components */
+ p2p_rgb48,
+ /** [A16-R16-G16-B16] */
+ p2p_argb64_be, /* ARGB big-endian components */
+ p2p_argb64_le, /* BGRA little-endian components */
+ p2p_argb64,
+ /** [A2-R10-G10-B10] */
+ p2p_rgb30_be, /* ARGB packed in big-endian DWORD */
+ p2p_rgb30_le, /* ARGB packed in little-endian DWORD */
+ p2p_rgb30,
+ /** [A2-V10-Y10-U10] */
+ p2p_y410_be, /* AVYU packed in big-endian DWORD */
+ p2p_y410_le, /* AVYU packed in little-endian DWORD */
+ p2p_y410,
+ /** [A16-V16-Y16-U16] */
+ p2p_y416_be, /* AVYU, big-endian components */
+ p2p_y416_le, /* UYVA, little-endian components */
+ p2p_y416,
+ /** [Y8] [U8] [Y8] [V8] */
+ p2p_yuy2,
+ /** [U8] [Y8] [V8] [Y8] */
+ p2p_uyvy,
+ /** [Y10-!6] [U10-!6] [Y10-!6] [V10-!6] */
+ p2p_y210_be, /* YUYV, big-endian components, lower 6 bits zero */
+ p2p_y210_le, /* YUYV, little-endian components, lower 6 bits zero. Microsoft Y210. */
+ p2p_y210,
+ /** [Y16] [U16] [Y16] [V16] */
+ p2p_y216_be, /* YUYV, big-endian components */
+ p2p_y216_le, /* YUYV, little-endian components. Microsoft Y216. */
+ p2p_y216,
+ /** [!2-V10-Y10-U10] [!2-Y10-U10-Y10] [!2-U10-Y10-V10] [!2-Y10-V10-Y10] */
+ p2p_v210_be, /* v210 with big-endian DWORDs */
+ p2p_v210_le, /* Apple/QuickTime v210 */
+ p2p_v210,
+ /** [U16] [Y16] [V16] [Y16] */
+ p2p_v216_be, /* UYVY, big-endian components */
+ p2p_v216_le, /* UYVY, little-endian components. Apple/QuickTime v216. */
+ p2p_v216,
+ /** [U8-V8] */
+ p2p_nv12_be, /* aka NV21, V first */
+ p2p_nv12_le, /* NV12 */
+ p2p_nv12,
+ /** [U10-!6-V10-!6] */
+ p2p_p010_be, /* NV21, big-endian components, lower 6 bits zero */
+ p2p_p010_le, /* NV12, little-endian components, lower 6 bits zero. Microsoft P010. */
+ p2p_p010,
+ /** [U16-V16] */
+ p2p_p016_be, /* NV21, big-endian components */
+ p2p_p016_le, /* NV12, little-endian components. Microsoft P016. */
+ p2p_p016,
+ /** [U10-!6-V10-!6] */
+ p2p_p210_be, /* NV21, big-endian components, lower 6 bits zero */
+ p2p_p210_le, /* NV12, little-endian components, lower 6 bits zero. Microsoft P210. */
+ p2p_p210,
+ /** [U16-V16] */
+ p2p_p216_be, /* NV21, big-endian components */
+ p2p_p216_le, /* NV12, little-endian components. Microsoft P216. */
+ p2p_p216,
+ /** [R8-G8-B8-A8] */
+ p2p_rgba32_be, /* RGBA */
+ p2p_rgba32_le, /* ABGR */
+ p2p_rgba32,
+ /** [R16-G16-B16-A16] */
+ p2p_rgba64_be, /* RGBA, big-endian components */
+ p2p_rgba64_le, /* ABGR, little-endian components */
+ p2p_rgba64,
+ /** [A16-B16-G16-R16] */
+ p2p_abgr64_be, /* ABGR, big-endian components */
+ p2p_abgr64_le, /* RGBA, little-endian components */
+ p2p_abgr64,
+ /** [B16-G16-R16] */
+ p2p_bgr48_be, /* BGR, big-endian components */
+ p2p_bgr48_le, /* RGB, little-endian components */
+ p2p_bgr48,
+ /** [B16-G16-R16-A16] */
+ p2p_bgra64_be, /* BGRA, big-endian components */
+ p2p_bgra64_le, /* ARGB, little-endian components */
+ p2p_bgra64,
+
+ p2p_packing_max,
+};
+
+struct p2p_buffer_param {
+ /**
+ * Planar order: R-G-B-A or Y-U-V-A. Alpha is optional.
+ * Packed order: Y-UV if NV12/21, else single plane. Y optional for NV12/21.
+ */
+ const void *src[4];
+ void *dst[4];
+ ptrdiff_t src_stride[4];
+ ptrdiff_t dst_stride[4];
+ unsigned width;
+ unsigned height;
+ enum p2p_packing packing;
+};
+
+/** Pack/unpack a range of pixels from a scanline. */
+typedef void (*p2p_unpack_func)(const void *src, void * const dst[4], unsigned left, unsigned right);
+typedef void (*p2p_pack_func)(const void * const src[4], void *dst, unsigned left, unsigned right);
+
+/** Select a line pack/unpack function. */
+p2p_unpack_func p2p_select_unpack_func(enum p2p_packing packing);
+p2p_pack_func p2p_select_pack_func(enum p2p_packing packing);
+p2p_pack_func p2p_select_pack_func_ex(enum p2p_packing packing, int alpha_one_fill);
+
+
+/** When processing formats like NV12, ignore the unpacked plane. */
+#define P2P_SKIP_UNPACKED_PLANES (1UL << 0)
+/** When packing, store a bit pattern of all ones in the alpha channel instead of all zeros. */
+#define P2P_ALPHA_SET_ONE (1UL << 1)
+
+/** Helper function to pack/unpack between memory locations. */
+void p2p_unpack_frame(const struct p2p_buffer_param *param, unsigned long flags);
+void p2p_pack_frame(const struct p2p_buffer_param *param, unsigned long flags);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* P2P_API_H_ */