From cc52424c0ebf8283d46f8100ad4fd34f5f0cfbbf Mon Sep 17 00:00:00 2001 From: DJATOM Date: Tue, 24 Aug 2021 01:15:51 +0300 Subject: [PATCH] Initial commit --- LibP2P.sln | 31 ++ LibP2P.vcxproj | 160 +++++++++ LibP2P.vcxproj.filters | 33 ++ LibP2P.vcxproj.user | 4 + README.md | 3 + src/headers/VSConstants4.h | 93 ++++++ src/headers/VSHelper.h | 174 ++++++++++ src/headers/VSHelper4.h | 219 ++++++++++++ src/headers/VSScript.h | 85 +++++ src/headers/VSScript4.h | 103 ++++++ src/headers/VapourSynth.h | 359 ++++++++++++++++++++ src/headers/VapourSynth4.h | 483 +++++++++++++++++++++++++++ src/libp2p_plugin.cpp | 197 +++++++++++ src/p2p.h | 668 +++++++++++++++++++++++++++++++++++++ src/p2p_api.cpp | 225 +++++++++++++ src/p2p_api.h | 171 ++++++++++ 16 files changed, 3008 insertions(+) create mode 100644 LibP2P.sln create mode 100644 LibP2P.vcxproj create mode 100644 LibP2P.vcxproj.filters create mode 100644 LibP2P.vcxproj.user create mode 100644 README.md create mode 100644 src/headers/VSConstants4.h create mode 100644 src/headers/VSHelper.h create mode 100644 src/headers/VSHelper4.h create mode 100644 src/headers/VSScript.h create mode 100644 src/headers/VSScript4.h create mode 100644 src/headers/VapourSynth.h create mode 100644 src/headers/VapourSynth4.h create mode 100644 src/libp2p_plugin.cpp create mode 100644 src/p2p.h create mode 100644 src/p2p_api.cpp create mode 100644 src/p2p_api.h 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_ */