diff --git a/include/avisynth/avisynth.h b/include/avisynth/avisynth.h new file mode 100644 index 0000000..36fedf9 --- /dev/null +++ b/include/avisynth/avisynth.h @@ -0,0 +1,1924 @@ +// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. +// Avisynth v2.6. Copyright 2006 Klaus Post. +// Avisynth v2.6. Copyright 2009 Ian Brabham. +// Avisynth+ project +// 20160613: new 16 bit planar pixel_type constants go live! +// 20160725: pixel_type constants 10-12-14 bit + planar RGB + BRG48/64 +// 20161005: Fallback of VideoInfo functions to defaults if no function exists +// 20170117: global variables for VfW output OPT_xxxx +// 20170310: new MT mode: MT_SPECIAL_MT +// 20171103: (test with SIZETMOD define: Videoframe offsets to size_t, may affect x64) +// 20171207: C++ Standard Conformance (no change for plugin writers) +// 20180525: AVS_UNUSED define to supress parameter not used warnings +// 2020xxxx: AVS_WINDOWS and AVS_POSIX option see avs/config.h +// 20200305: ScriptEnvironment::VSprintf parameter (void *) changed back to va_list +// 20200330: removed __stdcall from variadic argument functions (Sprintf) +// (remove test SIZETMOD define for clarity) +// Integrate Avisynth Neo structures and interface, PFunction, PDevice +// 20200501: frame property support (NewVideoFrameP and other helpers) to legacy IScriptEnvironment. +// move some former IScriptEnvironment2 functions to IScriptEnvironment: +// GetEnvProperty (system prop), Allocate, Free (buffer pool) +// GetVarTry, GetVarBool/Int/String/Double/Long +// Invoke2, Invoke3, InvokeTry, Invoke2Try, Invoke3Try +// Interface Version to 8 (classic 2.6 = 6) +// 20200527 Add IScriptEnvironment_Avs25, used internally +// 20200607 AVS frame property enums to match existing Avisynth enum style +// 202112xx pre V9-MakePropertyWritable, IsPropertyWritable + +// http://www.avisynth.org + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// Linking Avisynth statically or dynamically with other modules is making +// a combined work based on Avisynth. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// +// As a special exception, the copyright holders of Avisynth give you +// permission to link Avisynth with independent modules that communicate +// with Avisynth solely through the interfaces defined in avisynth.h, +// regardless of the license terms of these independent modules, and to +// copy and distribute the resulting combined work under terms of your +// choice, provided that every copy of the combined work is accompanied +// by a complete copy of the source code of Avisynth (the version of +// Avisynth used to produce the combined work), being distributed under +// the terms of the GNU General Public License plus this exception. An +// independent module is a module which is not derived from or based on +// Avisynth, such as 3rd-party filters, import and export plugins, or +// graphical user interfaces. + + +#ifndef __AVISYNTH_9_H__ +#define __AVISYNTH_9_H__ + +#include "avs/config.h" +#include "avs/capi.h" +#include "avs/types.h" + +#ifdef AVS_POSIX +# include "avs/posix.h" +#endif + +#if defined(AVS_POSIX) +#if defined(AVS_HAIKU) +#undef __stdcall +#undef __cdecl +#endif +#define __stdcall +#define __cdecl +#endif + +// Important note on AVISYNTH_INTERFACE_VERSION V6->V8 change: +// Note 1: Those few plugins which were using earlier IScriptEnvironment2 despite the big Warning will crash have to be rebuilt. +// Note 2: How to support earlier avisynth interface with an up-to-date avisynth.h: +// Use the new frame property features adaptively after querying that at least v8 is supported +// AviSynth property support can be queried (cpp iface example): +// has_at_least_v8 = true; +// try { env->CheckVersion(8); } catch (const AvisynthError&) { has_at_least_v8 = false; } +// and use it: +// if (has_at_least_v8) dst = env->NewVideoFrameP(vi, &src); else dst = env->NewVideoFrame(vi); + +enum { + AVISYNTH_CLASSIC_INTERFACE_VERSION_25 = 3, + AVISYNTH_CLASSIC_INTERFACE_VERSION_26BETA = 5, + AVISYNTH_CLASSIC_INTERFACE_VERSION = 6, + AVISYNTH_INTERFACE_VERSION = 9, + AVISYNTHPLUS_INTERFACE_BUGFIX_VERSION = 2 // reset to zero whenever the normal interface version bumps +}; + +/* Compiler-specific crap */ + +// Tell MSVC to stop precompiling here +#if defined(_MSC_VER) && !defined(__clang__) + #pragma hdrstop +#endif + +// Set up debugging macros for MS compilers; for others, step down to the +// standard interface +#ifdef _MSC_VER + #include +#else + #undef _RPT0 + #undef _RPT1 + #undef _RPT2 + #undef _RPT3 + #undef _RPT4 + #undef _RPT5 + #define _RPT0(a,b) ((void)0) + #define _RPT1(a,b,c) ((void)0) + #define _RPT2(a,b,c,d) ((void)0) + #define _RPT3(a,b,c,d,e) ((void)0) + #define _RPT4(a,b,c,d,e,f) ((void)0) + #define _RPT5(a,b,c,d,e,f,g) ((void)0) + + #include + #undef _ASSERTE + #undef _ASSERT + #define _ASSERTE(x) assert(x) + #define _ASSERT(x) assert(x) +#endif + + + +// I had problems with Premiere wanting 1-byte alignment for its structures, +// so I now set the Avisynth struct alignment explicitly here. +#pragma pack(push,8) + +// The VideoInfo struct holds global information about a clip (i.e. +// information that does not depend on the frame number). The GetVideoInfo +// method in IClip returns this struct. + +enum {SAMPLE_INT8 = 1<<0, + SAMPLE_INT16 = 1<<1, + SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware. + SAMPLE_INT32 = 1<<3, + SAMPLE_FLOAT = 1<<4}; + +enum { + PLANAR_Y=1<<0, + PLANAR_U=1<<1, + PLANAR_V=1<<2, + PLANAR_ALIGNED=1<<3, + PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED, + PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED, + PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED, + PLANAR_A=1<<4, + PLANAR_R=1<<5, + PLANAR_G=1<<6, + PLANAR_B=1<<7, + PLANAR_A_ALIGNED=PLANAR_A|PLANAR_ALIGNED, + PLANAR_R_ALIGNED=PLANAR_R|PLANAR_ALIGNED, + PLANAR_G_ALIGNED=PLANAR_G|PLANAR_ALIGNED, + PLANAR_B_ALIGNED=PLANAR_B|PLANAR_ALIGNED, + }; + +class AvisynthError /* exception */ { +public: + const char* const msg; + AvisynthError(const char* _msg) : msg(_msg) {} + +// Ensure AvisynthError cannot be publicly assigned! +private: + AvisynthError& operator=(const AvisynthError&); +}; // end class AvisynthError + +enum AvsDeviceType { + DEV_TYPE_NONE = 0, + DEV_TYPE_CPU = 1, + DEV_TYPE_CUDA = 2, + DEV_TYPE_ANY = 0xFFFF +}; + +/* Forward references */ +#if defined(MSVC) + #define SINGLE_INHERITANCE __single_inheritance +#else + #define SINGLE_INHERITANCE +#endif +struct SINGLE_INHERITANCE VideoInfo; +class SINGLE_INHERITANCE VideoFrameBuffer; +class SINGLE_INHERITANCE VideoFrame; +class IClip; +class SINGLE_INHERITANCE PClip; +class SINGLE_INHERITANCE PVideoFrame; +class IScriptEnvironment; +class SINGLE_INHERITANCE AVSValue; +class INeoEnv; +class IFunction; +class SINGLE_INHERITANCE PFunction; +class Device; +class SINGLE_INHERITANCE PDevice; +class AVSMap; + + + +/* + * Avisynth C++ plugin API code function pointers. + * + * In order to maintain binary compatibility with + * future version do not change the order of the + * existing function pointers. It will be baked + * into all existing plugins. + * + * Add new function pointers to the end of the + * structure. The linkage macros generate some + * protection code to ensure newer plugin do not + * call non-existing functions in an older host. + */ + +struct AVS_Linkage { + + int Size; + +/**********************************************************************/ + +// struct VideoInfo + bool (VideoInfo::*HasVideo)() const; + bool (VideoInfo::*HasAudio)() const; + bool (VideoInfo::*IsRGB)() const; + bool (VideoInfo::*IsRGB24)() const; + bool (VideoInfo::*IsRGB32)() const; + bool (VideoInfo::*IsYUV)() const; + bool (VideoInfo::*IsYUY2)() const; + bool (VideoInfo::*IsYV24)() const; + bool (VideoInfo::*IsYV16)() const; + bool (VideoInfo::*IsYV12)() const; + bool (VideoInfo::*IsYV411)() const; + bool (VideoInfo::*IsY8)() const; + bool (VideoInfo::*IsColorSpace)(int c_space) const; + bool (VideoInfo::*Is)(int property) const; + bool (VideoInfo::*IsPlanar)() const; + bool (VideoInfo::*IsFieldBased)() const; + bool (VideoInfo::*IsParityKnown)() const; + bool (VideoInfo::*IsBFF)() const; + bool (VideoInfo::*IsTFF)() const; + bool (VideoInfo::*IsVPlaneFirst)() const; + int (VideoInfo::*BytesFromPixels)(int pixels) const; + int (VideoInfo::*RowSize)(int plane) const; + int (VideoInfo::*BMPSize)() const; + int64_t (VideoInfo::*AudioSamplesFromFrames)(int frames) const; + int (VideoInfo::*FramesFromAudioSamples)(int64_t samples) const; + int64_t (VideoInfo::*AudioSamplesFromBytes)(int64_t bytes) const; + int64_t (VideoInfo::*BytesFromAudioSamples)(int64_t samples) const; + int (VideoInfo::*AudioChannels)() const; + int (VideoInfo::*SampleType)() const; + bool (VideoInfo::*IsSampleType)(int testtype) const; + int (VideoInfo::*SamplesPerSecond)() const; + int (VideoInfo::*BytesPerAudioSample)() const; + void (VideoInfo::*SetFieldBased)(bool isfieldbased); + void (VideoInfo::*Set)(int property); + void (VideoInfo::*Clear)(int property); + int (VideoInfo::*GetPlaneWidthSubsampling)(int plane) const; + int (VideoInfo::*GetPlaneHeightSubsampling)(int plane) const; + int (VideoInfo::*BitsPerPixel)() const; + int (VideoInfo::*BytesPerChannelSample)() const; + void (VideoInfo::*SetFPS)(unsigned numerator, unsigned denominator); + void (VideoInfo::*MulDivFPS)(unsigned multiplier, unsigned divisor); + bool (VideoInfo::*IsSameColorspace)(const VideoInfo& vi) const; +// end struct VideoInfo + +/**********************************************************************/ + +// class VideoFrameBuffer + const BYTE* (VideoFrameBuffer::*VFBGetReadPtr)() const; + BYTE* (VideoFrameBuffer::*VFBGetWritePtr)(); + int (VideoFrameBuffer::*GetDataSize)() const; + int (VideoFrameBuffer::*GetSequenceNumber)() const; + int (VideoFrameBuffer::*GetRefcount)() const; +// end class VideoFrameBuffer + +/**********************************************************************/ + +// class VideoFrame + int (VideoFrame::*GetPitch)(int plane) const; + int (VideoFrame::*GetRowSize)(int plane) const; + int (VideoFrame::*GetHeight)(int plane) const; + VideoFrameBuffer* (VideoFrame::*GetFrameBuffer)() const; + int (VideoFrame::*GetOffset)(int plane) const; + const BYTE* (VideoFrame::*VFGetReadPtr)(int plane) const; + bool (VideoFrame::*IsWritable)() const; + BYTE* (VideoFrame::*VFGetWritePtr)(int plane) const; + void (VideoFrame::*VideoFrame_DESTRUCTOR)(); +// end class VideoFrame + +/**********************************************************************/ + +// class IClip + /* nothing */ +// end class IClip + +/**********************************************************************/ + +// class PClip + void (PClip::*PClip_CONSTRUCTOR0)(); + void (PClip::*PClip_CONSTRUCTOR1)(const PClip& x); + void (PClip::*PClip_CONSTRUCTOR2)(IClip* x); + void (PClip::*PClip_OPERATOR_ASSIGN0)(IClip* x); + void (PClip::*PClip_OPERATOR_ASSIGN1)(const PClip& x); + void (PClip::*PClip_DESTRUCTOR)(); +// end class PClip + +/**********************************************************************/ + +// class PVideoFrame + void (PVideoFrame::*PVideoFrame_CONSTRUCTOR0)(); + void (PVideoFrame::*PVideoFrame_CONSTRUCTOR1)(const PVideoFrame& x); + void (PVideoFrame::*PVideoFrame_CONSTRUCTOR2)(VideoFrame* x); + void (PVideoFrame::*PVideoFrame_OPERATOR_ASSIGN0)(VideoFrame* x); + void (PVideoFrame::*PVideoFrame_OPERATOR_ASSIGN1)(const PVideoFrame& x); + void (PVideoFrame::*PVideoFrame_DESTRUCTOR)(); +// end class PVideoFrame + +/**********************************************************************/ + +// class AVSValue + void (AVSValue::*AVSValue_CONSTRUCTOR0)(); + void (AVSValue::*AVSValue_CONSTRUCTOR1)(IClip* c); + void (AVSValue::*AVSValue_CONSTRUCTOR2)(const PClip& c); + void (AVSValue::*AVSValue_CONSTRUCTOR3)(bool b); + void (AVSValue::*AVSValue_CONSTRUCTOR4)(int i); + void (AVSValue::*AVSValue_CONSTRUCTOR5)(float f); + void (AVSValue::*AVSValue_CONSTRUCTOR6)(double f); + void (AVSValue::*AVSValue_CONSTRUCTOR7)(const char* s); + void (AVSValue::*AVSValue_CONSTRUCTOR8)(const AVSValue* a, int size); + void (AVSValue::*AVSValue_CONSTRUCTOR9)(const AVSValue& v); + void (AVSValue::*AVSValue_DESTRUCTOR)(); + AVSValue& (AVSValue::*AVSValue_OPERATOR_ASSIGN)(const AVSValue& v); + const AVSValue& (AVSValue::*AVSValue_OPERATOR_INDEX)(int index) const; + bool (AVSValue::*Defined)() const; + bool (AVSValue::*IsClip)() const; + bool (AVSValue::*IsBool)() const; + bool (AVSValue::*IsInt)() const; + bool (AVSValue::*IsFloat)() const; + bool (AVSValue::*IsString)() const; + bool (AVSValue::*IsArray)() const; + PClip (AVSValue::*AsClip)() const; + bool (AVSValue::*AsBool1)() const; + int (AVSValue::*AsInt1)() const; + const char* (AVSValue::*AsString1)() const; + double (AVSValue::*AsFloat1)() const; + bool (AVSValue::*AsBool2)(bool def) const; + int (AVSValue::*AsInt2)(int def) const; + double (AVSValue::*AsDblDef)(double def) const; + double (AVSValue::*AsFloat2)(float def) const; + const char* (AVSValue::*AsString2)(const char* def) const; + int (AVSValue::*ArraySize)() const; +// end class AVSValue + +/**********************************************************************/ + // Reserve pointer space so that we can keep compatibility with Avs "classic" even if it adds functions on its own + void (VideoInfo::*reserved[32])(); +/**********************************************************************/ + // AviSynth+ additions + int (VideoInfo::*NumComponents)() const; + int (VideoInfo::*ComponentSize)() const; + int (VideoInfo::*BitsPerComponent)() const; + bool (VideoInfo::*Is444)() const; + bool (VideoInfo::*Is422)() const; + bool (VideoInfo::*Is420)() const; + bool (VideoInfo::*IsY)() const; + bool (VideoInfo::*IsRGB48)() const; + bool (VideoInfo::*IsRGB64)() const; + bool (VideoInfo::*IsYUVA)() const; + bool (VideoInfo::*IsPlanarRGB)() const; + bool (VideoInfo::*IsPlanarRGBA)() const; + /**********************************************************************/ + + // frame property access + AVSMap& (VideoFrame::* getProperties)(); + const AVSMap& (VideoFrame::* getConstProperties)(); + void (VideoFrame::* setProperties)(const AVSMap& properties); + + // PFunction + void (AVSValue::* AVSValue_CONSTRUCTOR11)(const PFunction& o); + bool (AVSValue::* IsFunction)() const; + void (PFunction::* PFunction_CONSTRUCTOR0)(); + void (PFunction::* PFunction_CONSTRUCTOR1)(IFunction* p); + void (PFunction::* PFunction_CONSTRUCTOR2)(const PFunction& p); + PFunction& (PFunction::* PFunction_OPERATOR_ASSIGN0)(IFunction* other); + PFunction& (PFunction::* PFunction_OPERATOR_ASSIGN1)(const PFunction& other); + void (PFunction::* PFunction_DESTRUCTOR)(); + // end PFunction + + // extra VideoFrame functions + int (VideoFrame::* VideoFrame_CheckMemory)() const; + PDevice (VideoFrame::* VideoFrame_GetDevice)() const; + + // class PDevice, even if only CPU device + void (PDevice::* PDevice_CONSTRUCTOR0)(); + void (PDevice::* PDevice_CONSTRUCTOR1)(Device* p); + void (PDevice::* PDevice_CONSTRUCTOR2)(const PDevice& p); + PDevice& (PDevice::* PDevice_OPERATOR_ASSIGN0)(Device* other); + PDevice& (PDevice::* PDevice_OPERATOR_ASSIGN1)(const PDevice& other); + void (PDevice::* PDevice_DESTRUCTOR)(); + AvsDeviceType (PDevice::* PDevice_GetType)() const; + int (PDevice::* PDevice_GetId)() const; + int (PDevice::* PDevice_GetIndex)() const; + const char* (PDevice::* PDevice_GetName)() const; + // end class PDevice + + // V9: VideoFrame helper + bool (VideoFrame::* IsPropertyWritable)() const; + + /**********************************************************************/ + // Reserve pointer space for Avisynth+ + void (VideoInfo::* reserved2[64 - 24])(); + /**********************************************************************/ + + // AviSynth Neo additions + INeoEnv* (__stdcall *GetNeoEnv)(IScriptEnvironment* env); + // As of V8 most PDevice, PFunction linkage entries are moved to standard avs+ place. + /**********************************************************************/ + + // this part should be identical with AVS_Linkage entries in interface.cpp +}; + +#if defined(BUILDING_AVSCORE) || defined(AVS_STATIC_LIB) +/* Macro resolution for code inside Avisynth.dll */ +# define AVS_BakedCode(arg) ; +# define AVS_LinkCall(arg) +# define AVS_LinkCallV(arg) +# define AVS_LinkCallOpt(arg, argOpt) AVSLinkCall(arg) +# define AVS_LinkCallOptDefault(arg, argDefaultValue) AVSLinkCall(arg()) +# define CALL_MEMBER_FN(object,ptrToMember) + +#else +/* Macro resolution for code inside user plugin */ +# ifdef AVS_LINKAGE_DLLIMPORT +extern __declspec(dllimport) const AVS_Linkage* const AVS_linkage; +# else +extern const AVS_Linkage* AVS_linkage; +# endif + +# ifndef offsetof +# include +# endif + +# define AVS_BakedCode(arg) { arg ; } +# define AVS_LinkCall(arg) !AVS_linkage || offsetof(AVS_Linkage, arg) >= (size_t)AVS_linkage->Size ? 0 : (this->*(AVS_linkage->arg)) +# define AVS_LinkCall_Void(arg) !AVS_linkage || offsetof(AVS_Linkage, arg) >= (size_t)AVS_linkage->Size ? (void)0 : (this->*(AVS_linkage->arg)) +# define AVS_LinkCallV(arg) !AVS_linkage || offsetof(AVS_Linkage, arg) >= (size_t)AVS_linkage->Size ? *this : (this->*(AVS_linkage->arg)) +// Helper macros for fallback option when a function does not exists +#define CALL_MEMBER_FN(object,ptrToMember) ((object)->*(ptrToMember)) +#define AVS_LinkCallOpt(arg, argOpt) !AVS_linkage ? 0 : \ + ( offsetof(AVS_Linkage, arg) >= (size_t)AVS_linkage->Size ? \ + (offsetof(AVS_Linkage, argOpt) >= (size_t)AVS_linkage->Size ? 0 : CALL_MEMBER_FN(this, AVS_linkage->argOpt)() ) : \ + CALL_MEMBER_FN(this, AVS_linkage->arg)() ) +// AVS_LinkCallOptDefault puts automatically () only after arg +# define AVS_LinkCallOptDefault(arg, argDefaultValue) !AVS_linkage || offsetof(AVS_Linkage, arg) >= (size_t)AVS_linkage->Size ? (argDefaultValue) : ((this->*(AVS_linkage->arg))()) + +#endif + +class PDevice +{ +public: + PDevice() AVS_BakedCode(AVS_LinkCall_Void(PDevice_CONSTRUCTOR0)()) + PDevice(Device* p) AVS_BakedCode(AVS_LinkCall_Void(PDevice_CONSTRUCTOR1)(p)) + PDevice(const PDevice& p) AVS_BakedCode(AVS_LinkCall_Void(PDevice_CONSTRUCTOR2)(p)) + PDevice& operator=(Device* p) AVS_BakedCode(return AVS_LinkCallV(PDevice_OPERATOR_ASSIGN0)(p)) + PDevice& operator=(const PDevice& p) AVS_BakedCode(return AVS_LinkCallV(PDevice_OPERATOR_ASSIGN1)(p)) + ~PDevice() AVS_BakedCode(AVS_LinkCall_Void(PDevice_DESTRUCTOR)()) + + int operator!() const { return !e; } + operator void*() const { return e; } + Device* operator->() const { return e; } + + AvsDeviceType GetType() const AVS_BakedCode(return AVS_LinkCallOptDefault(PDevice_GetType, DEV_TYPE_NONE)) + int GetId() const AVS_BakedCode(return AVS_LinkCall(PDevice_GetId)()) + int GetIndex() const AVS_BakedCode(return AVS_LinkCall(PDevice_GetIndex)()) + const char* GetName() const AVS_BakedCode(return AVS_LinkCall(PDevice_GetName)()) + +private: + Device * e; + +#ifdef BUILDING_AVSCORE +public: + void CONSTRUCTOR0(); /* Damn compiler won't allow taking the address of reserved constructs, make a dummy interlude */ + void CONSTRUCTOR1(Device* p); + void CONSTRUCTOR2(const PDevice& p); + PDevice& OPERATOR_ASSIGN0(Device* p); + PDevice& OPERATOR_ASSIGN1(const PDevice& p); + void DESTRUCTOR(); +#endif +}; +struct VideoInfo { + int width, height; // width=0 means no video + unsigned fps_numerator, fps_denominator; + int num_frames; + // This is more extensible than previous versions. More properties can be added seeminglesly. + + // Colorspace properties. +/* + +Planar match mask 1111.1000.0000.0111.0000.0111.0000.0111 +Planar signature 10xx.1000.0000.00xx.0000.00xx.00xx.00xx ? +Planar signature 10xx.1000.0000.0xxx.0000.00xx.000x.x0xx ? *new +Planar filter mask 1111.1111.1111.1111.1111.1111.1110.0111 (typo from old header fixed) + +pixel_type mapping +================== +pixel_type bit-map PIYB.Z000.0???.0SSS.0000.0???.????.???? + planar YUV CCC HHH.000u.vWWW + planar RGB(A) CCC AR + nonplanar CCC 000.00wx xyAR +Legend +====== +Planar YUV: + Code Bits Remark + W 0-2 Planar Width Subsampling bits + Use (X+1) & 3 for GetPlaneWidthSubsampling + 000 => 1 YV12, YV16, YUV420, YUV422 + 001 => 2 YV411, YUV9 + 010 => reserved + 011 => 0 YV24, YUV444, RGBP + 1xx => reserved + v 3 VPlaneFirst YV12, YV16, YV24, YV411, YUV9 + u 4 UPlaneFirst I420 + H 7-9 Planar Height Subsampling bits + Use ((X>>8)+1) & 3 for GetPlaneHeightSubsampling + 000 => 1 YV12, YUV420 + 001 => 2 YUV9 + 010 => reserved + 011 => 0 YV16, YV24, YV411, YUV422, YUV444, RGBP + 1xx => reserved + +Planar RGB + Code Bits Remark + R 0 BGR, (with SSS bits for 8/16 bit/sample or float) + A 1 BGRA, (with SSS bits for 8/16 bit/sample or float) + + +Not Planar, Interleaved (I flag) +Code Bits Remark + R 0 BGR24, and BGRx in future (with SSS bits for 8/16 bit/sample or float) + A 1 BGR32, and BGRAx in future (with SSS bits for 8/16 bit/sample or float) + y 2 YUY2 + x 3-4 reserved + w 5 Raw32 + +General +Code Bits Remark + S 16-18 Sample resolution bits + 000 => 8 + 001 => 16 + 010 => 32 (float) + 011,100 => reserved + 101 => 10 bits + 110 => 12 bits + 111 => 14 bits +for packed RGB(A): only 8 and 16 bits are valid + +Other YV12 specific (not used?) + C 20-22 Chroma Placement values 0-4 see CS_xxx_CHROMA_PLACEMENT + +Color family and layout + Packed Planar Planar Planar +Code Bits Remark RGB/RGBA YUV YUY2 Y_Grey RGB/RGBA YUVA + R 0 1/0 - 0 - 1/0 - + A 1 0/1 - 0 - 0/1 - + y 2 - - 1 - 0 - + Z 27 YUVA 0 0 0 0 1 1 + B 28 BGR 1 0 0 0 1* 0 + Y 29 YUV 0 1 1 1 0 0 + I 30 Interleaved 1 0 1 1 0 0 + P 31 Planar 0 1 0 1 1 1 +* Planar RGB plane order: G,B,R(,A) + +*/ +enum { + CS_YUVA = 1<<27, + CS_BGR = 1<<28, + CS_YUV = 1<<29, + CS_INTERLEAVED = 1<<30, + CS_PLANAR = 1<<31, + + CS_Shift_Sub_Width = 0, + CS_Shift_Sub_Height = 8, + CS_Shift_Sample_Bits = 16, + + CS_Sub_Width_Mask = 7 << CS_Shift_Sub_Width, + CS_Sub_Width_1 = 3 << CS_Shift_Sub_Width, // YV24 + CS_Sub_Width_2 = 0 << CS_Shift_Sub_Width, // YV12, I420, YV16 + CS_Sub_Width_4 = 1 << CS_Shift_Sub_Width, // YUV9, YV411 + + CS_VPlaneFirst = 1 << 3, // YV12, YV16, YV24, YV411, YUV9 + CS_UPlaneFirst = 1 << 4, // I420 + + CS_Sub_Height_Mask = 7 << CS_Shift_Sub_Height, + CS_Sub_Height_1 = 3 << CS_Shift_Sub_Height, // YV16, YV24, YV411 + CS_Sub_Height_2 = 0 << CS_Shift_Sub_Height, // YV12, I420 + CS_Sub_Height_4 = 1 << CS_Shift_Sub_Height, // YUV9 + + CS_Sample_Bits_Mask = 7 << CS_Shift_Sample_Bits, + CS_Sample_Bits_8 = 0 << CS_Shift_Sample_Bits, + CS_Sample_Bits_10 = 5 << CS_Shift_Sample_Bits, + CS_Sample_Bits_12 = 6 << CS_Shift_Sample_Bits, + CS_Sample_Bits_14 = 7 << CS_Shift_Sample_Bits, + CS_Sample_Bits_16 = 1 << CS_Shift_Sample_Bits, + CS_Sample_Bits_32 = 2 << CS_Shift_Sample_Bits, + + CS_PLANAR_MASK = CS_PLANAR | CS_INTERLEAVED | CS_YUV | CS_BGR | CS_YUVA | CS_Sample_Bits_Mask + | CS_Sub_Height_Mask | CS_Sub_Width_Mask, + CS_PLANAR_FILTER = ~( CS_VPlaneFirst | CS_UPlaneFirst ), + + CS_RGB_TYPE = 1 << 0, + CS_RGBA_TYPE = 1 << 1, + + // Specific colorformats + CS_UNKNOWN = 0, + + CS_BGR24 = CS_RGB_TYPE | CS_BGR | CS_INTERLEAVED, + CS_BGR32 = CS_RGBA_TYPE | CS_BGR | CS_INTERLEAVED, + CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED, + // CS_YV12 = 1<<3 Reserved + // CS_I420 = 1<<4 Reserved + CS_RAW32 = 1<<5 | CS_INTERLEAVED, + + // YV12 must be 0xA000008 2.5 Baked API will see all new planar as YV12 + // I420 must be 0xA000010 + + CS_GENERIC_YUV420 = CS_PLANAR | CS_YUV | CS_VPlaneFirst | CS_Sub_Height_2 | CS_Sub_Width_2, // 4:2:0 planar + CS_GENERIC_YUV422 = CS_PLANAR | CS_YUV | CS_VPlaneFirst | CS_Sub_Height_1 | CS_Sub_Width_2, // 4:2:2 planar + CS_GENERIC_YUV444 = CS_PLANAR | CS_YUV | CS_VPlaneFirst | CS_Sub_Height_1 | CS_Sub_Width_1, // 4:4:4 planar + CS_GENERIC_Y = CS_PLANAR | CS_INTERLEAVED | CS_YUV, // Y only (4:0:0) + CS_GENERIC_RGBP = CS_PLANAR | CS_BGR | CS_RGB_TYPE, // planar RGB. Though name is RGB but plane order G,B,R + CS_GENERIC_RGBAP = CS_PLANAR | CS_BGR | CS_RGBA_TYPE, // planar RGBA + CS_GENERIC_YUVA420 = CS_PLANAR | CS_YUVA | CS_VPlaneFirst | CS_Sub_Height_2 | CS_Sub_Width_2, // 4:2:0:A planar + CS_GENERIC_YUVA422 = CS_PLANAR | CS_YUVA | CS_VPlaneFirst | CS_Sub_Height_1 | CS_Sub_Width_2, // 4:2:2:A planar + CS_GENERIC_YUVA444 = CS_PLANAR | CS_YUVA | CS_VPlaneFirst | CS_Sub_Height_1 | CS_Sub_Width_1, // 4:4:4:A planar + + CS_YV24 = CS_GENERIC_YUV444 | CS_Sample_Bits_8, // YVU 4:4:4 planar + CS_YV16 = CS_GENERIC_YUV422 | CS_Sample_Bits_8, // YVU 4:2:2 planar + CS_YV12 = CS_GENERIC_YUV420 | CS_Sample_Bits_8, // YVU 4:2:0 planar + CS_I420 = CS_PLANAR | CS_YUV | CS_Sample_Bits_8 | CS_UPlaneFirst | CS_Sub_Height_2 | CS_Sub_Width_2, // YUV 4:2:0 planar + CS_IYUV = CS_I420, + CS_YUV9 = CS_PLANAR | CS_YUV | CS_Sample_Bits_8 | CS_VPlaneFirst | CS_Sub_Height_4 | CS_Sub_Width_4, // YUV 4:1:0 planar + CS_YV411 = CS_PLANAR | CS_YUV | CS_Sample_Bits_8 | CS_VPlaneFirst | CS_Sub_Height_1 | CS_Sub_Width_4, // YUV 4:1:1 planar + + CS_Y8 = CS_GENERIC_Y | CS_Sample_Bits_8, // Y 4:0:0 planar + + //------------------------- + // AVS16: new planar constants go live! Experimental PF 160613 + // 10-12-14 bit + planar RGB + BRG48/64 160725 + + CS_YUV444P10 = CS_GENERIC_YUV444 | CS_Sample_Bits_10, // YUV 4:4:4 10bit samples + CS_YUV422P10 = CS_GENERIC_YUV422 | CS_Sample_Bits_10, // YUV 4:2:2 10bit samples + CS_YUV420P10 = CS_GENERIC_YUV420 | CS_Sample_Bits_10, // YUV 4:2:0 10bit samples + CS_Y10 = CS_GENERIC_Y | CS_Sample_Bits_10, // Y 4:0:0 10bit samples + + CS_YUV444P12 = CS_GENERIC_YUV444 | CS_Sample_Bits_12, // YUV 4:4:4 12bit samples + CS_YUV422P12 = CS_GENERIC_YUV422 | CS_Sample_Bits_12, // YUV 4:2:2 12bit samples + CS_YUV420P12 = CS_GENERIC_YUV420 | CS_Sample_Bits_12, // YUV 4:2:0 12bit samples + CS_Y12 = CS_GENERIC_Y | CS_Sample_Bits_12, // Y 4:0:0 12bit samples + + CS_YUV444P14 = CS_GENERIC_YUV444 | CS_Sample_Bits_14, // YUV 4:4:4 14bit samples + CS_YUV422P14 = CS_GENERIC_YUV422 | CS_Sample_Bits_14, // YUV 4:2:2 14bit samples + CS_YUV420P14 = CS_GENERIC_YUV420 | CS_Sample_Bits_14, // YUV 4:2:0 14bit samples + CS_Y14 = CS_GENERIC_Y | CS_Sample_Bits_14, // Y 4:0:0 14bit samples + + CS_YUV444P16 = CS_GENERIC_YUV444 | CS_Sample_Bits_16, // YUV 4:4:4 16bit samples + CS_YUV422P16 = CS_GENERIC_YUV422 | CS_Sample_Bits_16, // YUV 4:2:2 16bit samples + CS_YUV420P16 = CS_GENERIC_YUV420 | CS_Sample_Bits_16, // YUV 4:2:0 16bit samples + CS_Y16 = CS_GENERIC_Y | CS_Sample_Bits_16, // Y 4:0:0 16bit samples + + // 32 bit samples (float) + CS_YUV444PS = CS_GENERIC_YUV444 | CS_Sample_Bits_32, // YUV 4:4:4 32bit samples + CS_YUV422PS = CS_GENERIC_YUV422 | CS_Sample_Bits_32, // YUV 4:2:2 32bit samples + CS_YUV420PS = CS_GENERIC_YUV420 | CS_Sample_Bits_32, // YUV 4:2:0 32bit samples + CS_Y32 = CS_GENERIC_Y | CS_Sample_Bits_32, // Y 4:0:0 32bit samples + + // RGB packed + CS_BGR48 = CS_RGB_TYPE | CS_BGR | CS_INTERLEAVED | CS_Sample_Bits_16, // BGR 3x16 bit + CS_BGR64 = CS_RGBA_TYPE | CS_BGR | CS_INTERLEAVED | CS_Sample_Bits_16, // BGR 4x16 bit + // no packed 32 bit (float) support for these legacy types + + // RGB planar + CS_RGBP = CS_GENERIC_RGBP | CS_Sample_Bits_8, // Planar RGB 8 bit samples + CS_RGBP8 = CS_GENERIC_RGBP | CS_Sample_Bits_8, // Planar RGB 8 bit samples + CS_RGBP10 = CS_GENERIC_RGBP | CS_Sample_Bits_10, // Planar RGB 10bit samples + CS_RGBP12 = CS_GENERIC_RGBP | CS_Sample_Bits_12, // Planar RGB 12bit samples + CS_RGBP14 = CS_GENERIC_RGBP | CS_Sample_Bits_14, // Planar RGB 14bit samples + CS_RGBP16 = CS_GENERIC_RGBP | CS_Sample_Bits_16, // Planar RGB 16bit samples + CS_RGBPS = CS_GENERIC_RGBP | CS_Sample_Bits_32, // Planar RGB 32bit samples + + // RGBA planar + CS_RGBAP = CS_GENERIC_RGBAP | CS_Sample_Bits_8, // Planar RGBA 8 bit samples + CS_RGBAP8 = CS_GENERIC_RGBAP | CS_Sample_Bits_8, // Planar RGBA 8 bit samples + CS_RGBAP10 = CS_GENERIC_RGBAP | CS_Sample_Bits_10, // Planar RGBA 10bit samples + CS_RGBAP12 = CS_GENERIC_RGBAP | CS_Sample_Bits_12, // Planar RGBA 12bit samples + CS_RGBAP14 = CS_GENERIC_RGBAP | CS_Sample_Bits_14, // Planar RGBA 14bit samples + CS_RGBAP16 = CS_GENERIC_RGBAP | CS_Sample_Bits_16, // Planar RGBA 16bit samples + CS_RGBAPS = CS_GENERIC_RGBAP | CS_Sample_Bits_32, // Planar RGBA 32bit samples + + // Planar YUVA + CS_YUVA444 = CS_GENERIC_YUVA444 | CS_Sample_Bits_8, // YUVA 4:4:4 8bit samples + CS_YUVA422 = CS_GENERIC_YUVA422 | CS_Sample_Bits_8, // YUVA 4:2:2 8bit samples + CS_YUVA420 = CS_GENERIC_YUVA420 | CS_Sample_Bits_8, // YUVA 4:2:0 8bit samples + + CS_YUVA444P10 = CS_GENERIC_YUVA444 | CS_Sample_Bits_10, // YUVA 4:4:4 10bit samples + CS_YUVA422P10 = CS_GENERIC_YUVA422 | CS_Sample_Bits_10, // YUVA 4:2:2 10bit samples + CS_YUVA420P10 = CS_GENERIC_YUVA420 | CS_Sample_Bits_10, // YUVA 4:2:0 10bit samples + + CS_YUVA444P12 = CS_GENERIC_YUVA444 | CS_Sample_Bits_12, // YUVA 4:4:4 12bit samples + CS_YUVA422P12 = CS_GENERIC_YUVA422 | CS_Sample_Bits_12, // YUVA 4:2:2 12bit samples + CS_YUVA420P12 = CS_GENERIC_YUVA420 | CS_Sample_Bits_12, // YUVA 4:2:0 12bit samples + + CS_YUVA444P14 = CS_GENERIC_YUVA444 | CS_Sample_Bits_14, // YUVA 4:4:4 14bit samples + CS_YUVA422P14 = CS_GENERIC_YUVA422 | CS_Sample_Bits_14, // YUVA 4:2:2 14bit samples + CS_YUVA420P14 = CS_GENERIC_YUVA420 | CS_Sample_Bits_14, // YUVA 4:2:0 14bit samples + + CS_YUVA444P16 = CS_GENERIC_YUVA444 | CS_Sample_Bits_16, // YUVA 4:4:4 16bit samples + CS_YUVA422P16 = CS_GENERIC_YUVA422 | CS_Sample_Bits_16, // YUVA 4:2:2 16bit samples + CS_YUVA420P16 = CS_GENERIC_YUVA420 | CS_Sample_Bits_16, // YUVA 4:2:0 16bit samples + + CS_YUVA444PS = CS_GENERIC_YUVA444 | CS_Sample_Bits_32, // YUVA 4:4:4 32bit samples + CS_YUVA422PS = CS_GENERIC_YUVA422 | CS_Sample_Bits_32, // YUVA 4:2:2 32bit samples + CS_YUVA420PS = CS_GENERIC_YUVA420 | CS_Sample_Bits_32, // YUVA 4:2:0 32bit samples + + }; + + int pixel_type; // changed to int as of 2.5 + + + int audio_samples_per_second; // 0 means no audio + int sample_type; // as of 2.5 + int64_t num_audio_samples; // changed as of 2.5 + int nchannels; // as of 2.5 + + // Imagetype properties + + int image_type; + + enum { + IT_BFF = 1<<0, + IT_TFF = 1<<1, + IT_FIELDBASED = 1<<2 + }; + + // Chroma placement bits 20 -> 23 ::FIXME:: Really want a Class to support this + enum { + CS_UNKNOWN_CHROMA_PLACEMENT = 0 << 20, + CS_MPEG1_CHROMA_PLACEMENT = 1 << 20, + CS_MPEG2_CHROMA_PLACEMENT = 2 << 20, + CS_YUY2_CHROMA_PLACEMENT = 3 << 20, + CS_TOPLEFT_CHROMA_PLACEMENT = 4 << 20 + }; + + // useful functions of the above + bool HasVideo() const AVS_BakedCode(return AVS_LinkCall(HasVideo)()) + bool HasAudio() const AVS_BakedCode(return AVS_LinkCall(HasAudio)()) + bool IsRGB() const AVS_BakedCode(return AVS_LinkCall(IsRGB)()) + bool IsRGB24() const AVS_BakedCode(return AVS_LinkCall(IsRGB24)()) + bool IsRGB32() const AVS_BakedCode(return AVS_LinkCall(IsRGB32)()) + bool IsYUV() const AVS_BakedCode(return AVS_LinkCall(IsYUV)()) + bool IsYUY2() const AVS_BakedCode(return AVS_LinkCall(IsYUY2)()) + + bool IsYV24() const AVS_BakedCode(return AVS_LinkCall(IsYV24)()) + bool IsYV16() const AVS_BakedCode(return AVS_LinkCall(IsYV16)()) + bool IsYV12() const AVS_BakedCode(return AVS_LinkCall(IsYV12)()) + bool IsYV411() const AVS_BakedCode(return AVS_LinkCall(IsYV411)()) + //bool IsYUV9() const; + bool IsY8() const AVS_BakedCode(return AVS_LinkCall(IsY8)()) + + bool IsColorSpace(int c_space) const AVS_BakedCode(return AVS_LinkCall(IsColorSpace)(c_space)) + + bool Is(int property) const AVS_BakedCode(return AVS_LinkCall(Is)(property)) + bool IsPlanar() const AVS_BakedCode(return AVS_LinkCall(IsPlanar)()) + bool IsFieldBased() const AVS_BakedCode(return AVS_LinkCall(IsFieldBased)()) + bool IsParityKnown() const AVS_BakedCode(return AVS_LinkCall(IsParityKnown)()) + bool IsBFF() const AVS_BakedCode(return AVS_LinkCall(IsBFF)()) + bool IsTFF() const AVS_BakedCode(return AVS_LinkCall(IsTFF)()) + + bool IsVPlaneFirst() const AVS_BakedCode(return AVS_LinkCall(IsVPlaneFirst)()) // Don't use this + // Will not work on planar images, but will return only luma planes + int BytesFromPixels(int pixels) const AVS_BakedCode(return AVS_LinkCall(BytesFromPixels)(pixels)) + int RowSize(int plane = 0) const AVS_BakedCode(return AVS_LinkCall(RowSize)(plane)) + int BMPSize() const AVS_BakedCode(return AVS_LinkCall(BMPSize)()) + + int64_t AudioSamplesFromFrames(int frames) const AVS_BakedCode(return AVS_LinkCall(AudioSamplesFromFrames)(frames)) + int FramesFromAudioSamples(int64_t samples) const AVS_BakedCode(return AVS_LinkCall(FramesFromAudioSamples)(samples)) + int64_t AudioSamplesFromBytes(int64_t bytes) const AVS_BakedCode(return AVS_LinkCall(AudioSamplesFromBytes)(bytes)) + int64_t BytesFromAudioSamples(int64_t samples) const AVS_BakedCode(return AVS_LinkCall(BytesFromAudioSamples)(samples)) + int AudioChannels() const AVS_BakedCode(return AVS_LinkCall(AudioChannels)()) + int SampleType() const AVS_BakedCode(return AVS_LinkCall(SampleType)()) + bool IsSampleType(int testtype) const AVS_BakedCode(return AVS_LinkCall(IsSampleType)(testtype)) + int SamplesPerSecond() const AVS_BakedCode(return AVS_LinkCall(SamplesPerSecond)()) + int BytesPerAudioSample() const AVS_BakedCode(return AVS_LinkCall(BytesPerAudioSample)()) + void SetFieldBased(bool isfieldbased) AVS_BakedCode(AVS_LinkCall_Void(SetFieldBased)(isfieldbased)) + void Set(int property) AVS_BakedCode(AVS_LinkCall_Void(Set)(property)) + void Clear(int property) AVS_BakedCode(AVS_LinkCall_Void(Clear)(property)) + // Subsampling in bitshifts! + int GetPlaneWidthSubsampling(int plane) const AVS_BakedCode(return AVS_LinkCall(GetPlaneWidthSubsampling)(plane)) + int GetPlaneHeightSubsampling(int plane) const AVS_BakedCode(return AVS_LinkCall(GetPlaneHeightSubsampling)(plane)) + int BitsPerPixel() const AVS_BakedCode(return AVS_LinkCall(BitsPerPixel)()) + + int BytesPerChannelSample() const AVS_BakedCode(return AVS_LinkCall(BytesPerChannelSample)()) + + // useful mutator + void SetFPS(unsigned numerator, unsigned denominator) AVS_BakedCode(AVS_LinkCall_Void(SetFPS)(numerator, denominator)) + + // Range protected multiply-divide of FPS + void MulDivFPS(unsigned multiplier, unsigned divisor) AVS_BakedCode(AVS_LinkCall_Void(MulDivFPS)(multiplier, divisor)) + + // Test for same colorspace + bool IsSameColorspace(const VideoInfo& vi) const AVS_BakedCode(return AVS_LinkCall(IsSameColorspace)(vi)) + + // AVS+ extensions + // 20161005: + // Mapping of AVS+ extensions to classic 2.6 functions. + // In order to use these extended AVS+ functions for plugins that should work + // either with AVS+ or with Classic (8 bit) Avs 2.6 ans earlier AVS+ versions, there is an + // automatic fallback mechanism. + // From AVS+'s point of view these are not "baked" codes, the primary functions should exist. + // Examples: + // Is444() is mapped to IsYV24() for classic AVS2.6 + // ComponentSize() returns constant 1 (1 bytes per pixel component) + // BitsPerComponent() returns constant 8 (Classic AVS2.6 is 8 bit only) + + // Returns the number of color channels or planes in a frame + int NumComponents() const AVS_BakedCode(return AVS_LinkCallOptDefault(NumComponents, (((AVS_LinkCall(IsYUV)()) && !(AVS_LinkCall(IsY8)())) ? 3 : AVS_LinkCall(BytesFromPixels)(1)) ) ) + + // Returns the size in bytes of a single component of a pixel + int ComponentSize() const AVS_BakedCode(return AVS_LinkCallOptDefault(ComponentSize, 1)) + + // Returns the bit depth of a single component of a pixel + int BitsPerComponent() const AVS_BakedCode(return AVS_LinkCallOptDefault(BitsPerComponent, 8)) + + // like IsYV24, but bit-depth independent also for YUVA + bool Is444() const AVS_BakedCode(return AVS_LinkCallOpt(Is444, IsYV24) ) + + // like IsYV16, but bit-depth independent also for YUVA + bool Is422() const AVS_BakedCode(return AVS_LinkCallOpt(Is422, IsYV16) ) + + // like IsYV12, but bit-depth independent also for YUVA + bool Is420() const AVS_BakedCode( return AVS_LinkCallOpt(Is420, IsYV12) ) + + // like IsY8, but bit-depth independent + bool IsY() const AVS_BakedCode( return AVS_LinkCallOpt(IsY, IsY8) ) + + // like IsRGB24 for 16 bit samples + bool IsRGB48() const AVS_BakedCode( return AVS_LinkCallOptDefault(IsRGB48, false) ) + + // like IsRGB32 for 16 bit samples + bool IsRGB64() const AVS_BakedCode( return AVS_LinkCallOptDefault(IsRGB64, false) ) + + // YUVA? + bool IsYUVA() const AVS_BakedCode( return AVS_LinkCallOptDefault(IsYUVA, false) ) + + // Planar RGB? + bool IsPlanarRGB() const AVS_BakedCode( return AVS_LinkCallOptDefault(IsPlanarRGB, false) ) + + // Planar RGBA? + bool IsPlanarRGBA() const AVS_BakedCode( return AVS_LinkCallOptDefault(IsPlanarRGBA, false) ) + +}; // end struct VideoInfo + + + + +// VideoFrameBuffer holds information about a memory block which is used +// for video data. For efficiency, instances of this class are not deleted +// when the refcount reaches zero; instead they're stored in a linked list +// to be reused. The instances are deleted when the corresponding AVS +// file is closed. + +class VideoFrameBuffer { + BYTE* data; + int data_size; + // sequence_number is incremented every time the buffer is changed, so + // that stale views can tell they're no longer valid. + volatile long sequence_number; + + friend class VideoFrame; + friend class Cache; + friend class ScriptEnvironment; + volatile long refcount; + + // AVS+CUDA extension, does not break plugins if appended here + Device* device; + +protected: + VideoFrameBuffer(int size, int margin, Device* device); + VideoFrameBuffer(); + ~VideoFrameBuffer(); + +public: + const BYTE* GetReadPtr() const AVS_BakedCode( return AVS_LinkCall(VFBGetReadPtr)() ) + BYTE* GetWritePtr() AVS_BakedCode( return AVS_LinkCall(VFBGetWritePtr)() ) + int GetDataSize() const AVS_BakedCode( return AVS_LinkCall(GetDataSize)() ) + int GetSequenceNumber() const AVS_BakedCode( return AVS_LinkCall(GetSequenceNumber)() ) + int GetRefcount() const AVS_BakedCode( return AVS_LinkCall(GetRefcount)() ) + +// Ensure VideoFrameBuffer cannot be publicly assigned +private: + VideoFrameBuffer& operator=(const VideoFrameBuffer&); + +}; // end class VideoFrameBuffer + + +// smart pointer to VideoFrame +class PVideoFrame { + + VideoFrame* p; + + void Init(VideoFrame* x); + void Set(VideoFrame* x); + +public: + PVideoFrame() AVS_BakedCode(AVS_LinkCall_Void(PVideoFrame_CONSTRUCTOR0)()) + PVideoFrame(const PVideoFrame& x) AVS_BakedCode(AVS_LinkCall_Void(PVideoFrame_CONSTRUCTOR1)(x)) + PVideoFrame(VideoFrame* x) AVS_BakedCode(AVS_LinkCall_Void(PVideoFrame_CONSTRUCTOR2)(x)) + void operator=(VideoFrame* x) AVS_BakedCode(AVS_LinkCall_Void(PVideoFrame_OPERATOR_ASSIGN0)(x)) + void operator=(const PVideoFrame& x) AVS_BakedCode(AVS_LinkCall_Void(PVideoFrame_OPERATOR_ASSIGN1)(x)) + + VideoFrame* operator->() const { return p; } + + // for conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PVideoFrame() AVS_BakedCode(AVS_LinkCall_Void(PVideoFrame_DESTRUCTOR)()) +#ifdef BUILDING_AVSCORE +public: + void CONSTRUCTOR0(); /* Damn compiler won't allow taking the address of reserved constructs, make a dummy interlude */ + void CONSTRUCTOR1(const PVideoFrame& x); + void CONSTRUCTOR2(VideoFrame* x); + void OPERATOR_ASSIGN0(VideoFrame* x); + void OPERATOR_ASSIGN1(const PVideoFrame& x); + void DESTRUCTOR(); +#endif +}; // end class PVideoFrame + + +// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new +// is overloaded to recycle class instances. + +class VideoFrame { + volatile long refcount; + VideoFrameBuffer* vfb; + + // Due to technical reasons these members are not const, but should be treated as such. + // That means do not modify them once the class has been constructed. + int offset; + int pitch, row_size, height; + int offsetU, offsetV; // U&V offsets are from top of picture. + int pitchUV, row_sizeUV, heightUV; // for Planar RGB offsetU, offsetV is for the 2nd and 3rd Plane. + // for Planar RGB pitchUV and row_sizeUV = 0, because when no VideoInfo (MakeWriteable) + // the decision on existance of UV is checked by zero pitch + // AVS+ extension, does not break plugins if appended here + int offsetA; + int pitchA, row_sizeA; // 4th alpha plane support, pitch and row_size is 0 is none + + AVSMap *properties; + + friend class PVideoFrame; + void AddRef(); + void Release(); + + friend class ScriptEnvironment; + friend class Cache; + + VideoFrame(VideoFrameBuffer* _vfb, AVSMap* avsmap, int _offset, int _pitch, int _row_size, int _height); + VideoFrame(VideoFrameBuffer* _vfb, AVSMap* avsmap, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV, int _row_sizeUV, int _heightUV); + // for Alpha + VideoFrame(VideoFrameBuffer* _vfb, AVSMap* avsmap, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV, int _row_sizeUV, int _heightUV, int _offsetA); + void* operator new(size_t size); +// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard! +public: + int GetPitch(int plane=0) const AVS_BakedCode( return AVS_LinkCall(GetPitch)(plane) ) + int GetRowSize(int plane=0) const AVS_BakedCode( return AVS_LinkCall(GetRowSize)(plane) ) + int GetHeight(int plane=0) const AVS_BakedCode( return AVS_LinkCall(GetHeight)(plane) ) + + // generally you shouldn't use these three + VideoFrameBuffer* GetFrameBuffer() const AVS_BakedCode( return AVS_LinkCall(GetFrameBuffer)() ) + int GetOffset(int plane=0) const AVS_BakedCode( return AVS_LinkCall(GetOffset)(plane) ) + + // in plugins use env->SubFrame() -- because implementation code is only available inside avisynth.dll. Doh! + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const; + // for Alpha + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV, int rel_offsetA) const; + + const BYTE* GetReadPtr(int plane=0) const AVS_BakedCode( return AVS_LinkCall(VFGetReadPtr)(plane) ) + bool IsWritable() const AVS_BakedCode( return AVS_LinkCall(IsWritable)() ) + BYTE* GetWritePtr(int plane=0) const AVS_BakedCode( return AVS_LinkCall(VFGetWritePtr)(plane) ) + + AVSMap& getProperties() AVS_BakedCode(return AVS_LinkCallOptDefault(getProperties, (AVSMap&)*(AVSMap*)0)) + const AVSMap& getConstProperties() AVS_BakedCode(return AVS_LinkCallOptDefault(getConstProperties, (const AVSMap&)*(const AVSMap*)0)) + void setProperties(const AVSMap & _properties) AVS_BakedCode(AVS_LinkCall_Void(setProperties)(_properties)) + + PDevice GetDevice() const AVS_BakedCode(return AVS_LinkCall(VideoFrame_GetDevice)()) + + // 0: OK, 1: NG, -1: disabled or non CPU frame + int CheckMemory() const AVS_BakedCode(return AVS_LinkCall(VideoFrame_CheckMemory)()) + + bool IsPropertyWritable() const AVS_BakedCode(return AVS_LinkCall(IsPropertyWritable)()) + + ~VideoFrame() AVS_BakedCode( AVS_LinkCall_Void(VideoFrame_DESTRUCTOR)() ) +#ifdef BUILDING_AVSCORE +public: + void DESTRUCTOR(); /* Damn compiler won't allow taking the address of reserved constructs, make a dummy interlude */ +#endif + +// Ensure VideoFrame cannot be publicly assigned +private: + VideoFrame& operator=(const VideoFrame&); + +}; // end class VideoFrame + +enum CachePolicyHint { + // Values 0 to 5 are reserved for old 2.5 plugins + // do not use them in new plugins + + // New 2.6 explicitly defined cache hints. + CACHE_NOTHING=10, // Do not cache video. + CACHE_WINDOW=11, // Hard protect upto X frames within a range of X from the current frame N. + CACHE_GENERIC=12, // LRU cache upto X frames. + CACHE_FORCE_GENERIC=13, // LRU cache upto X frames, override any previous CACHE_WINDOW. + + CACHE_GET_POLICY=30, // Get the current policy. + CACHE_GET_WINDOW=31, // Get the current window h_span. + CACHE_GET_RANGE=32, // Get the current generic frame range. + + CACHE_AUDIO=50, // Explicitly cache audio, X byte cache. + CACHE_AUDIO_NOTHING=51, // Explicitly do not cache audio. + CACHE_AUDIO_NONE=52, // Audio cache off (auto mode), X byte intial cache. + CACHE_AUDIO_AUTO=53, // Audio cache on (auto mode), X byte intial cache. + + CACHE_GET_AUDIO_POLICY=70, // Get the current audio policy. + CACHE_GET_AUDIO_SIZE=71, // Get the current audio cache size. + + CACHE_PREFETCH_FRAME=100, // Queue request to prefetch frame N. + CACHE_PREFETCH_GO=101, // Action video prefetches. + + CACHE_PREFETCH_AUDIO_BEGIN=120, // Begin queue request transaction to prefetch audio (take critical section). + CACHE_PREFETCH_AUDIO_STARTLO=121, // Set low 32 bits of start. + CACHE_PREFETCH_AUDIO_STARTHI=122, // Set high 32 bits of start. + CACHE_PREFETCH_AUDIO_COUNT=123, // Set low 32 bits of length. + CACHE_PREFETCH_AUDIO_COMMIT=124, // Enqueue request transaction to prefetch audio (release critical section). + CACHE_PREFETCH_AUDIO_GO=125, // Action audio prefetches. + + CACHE_GETCHILD_CACHE_MODE=200, // Cache ask Child for desired video cache mode. + CACHE_GETCHILD_CACHE_SIZE=201, // Cache ask Child for desired video cache size. + CACHE_GETCHILD_AUDIO_MODE=202, // Cache ask Child for desired audio cache mode. + CACHE_GETCHILD_AUDIO_SIZE=203, // Cache ask Child for desired audio cache size. + + CACHE_GETCHILD_COST=220, // Cache ask Child for estimated processing cost. + CACHE_COST_ZERO=221, // Child response of zero cost (ptr arithmetic only). + CACHE_COST_UNIT=222, // Child response of unit cost (less than or equal 1 full frame blit). + CACHE_COST_LOW=223, // Child response of light cost. (Fast) + CACHE_COST_MED=224, // Child response of medium cost. (Real time) + CACHE_COST_HI=225, // Child response of heavy cost. (Slow) + + CACHE_GETCHILD_THREAD_MODE=240, // Cache ask Child for thread safetyness. + CACHE_THREAD_UNSAFE=241, // Only 1 thread allowed for all instances. 2.5 filters default! + CACHE_THREAD_CLASS=242, // Only 1 thread allowed for each instance. 2.6 filters default! + CACHE_THREAD_SAFE=243, // Allow all threads in any instance. + CACHE_THREAD_OWN=244, // Safe but limit to 1 thread, internally threaded. + + CACHE_GETCHILD_ACCESS_COST=260, // Cache ask Child for preferred access pattern. + CACHE_ACCESS_RAND=261, // Filter is access order agnostic. + CACHE_ACCESS_SEQ0=262, // Filter prefers sequential access (low cost) + CACHE_ACCESS_SEQ1=263, // Filter needs sequential access (high cost) + + CACHE_AVSPLUS_CONSTANTS = 500, // Smaller values are reserved for classic Avisynth + + CACHE_DONT_CACHE_ME, // Filters that don't need caching (eg. trim, cache etc.) should return 1 to this request + CACHE_SET_MIN_CAPACITY, + CACHE_SET_MAX_CAPACITY, + CACHE_GET_MIN_CAPACITY, + CACHE_GET_MAX_CAPACITY, + CACHE_GET_SIZE, + CACHE_GET_REQUESTED_CAP, + CACHE_GET_CAPACITY, + CACHE_GET_MTMODE, + + CACHE_IS_CACHE_REQ, + CACHE_IS_CACHE_ANS, + CACHE_IS_MTGUARD_REQ, + CACHE_IS_MTGUARD_ANS, + + CACHE_AVSPLUS_CUDA_CONSTANTS = 600, + + CACHE_GET_DEV_TYPE, // Device types a filter can return + CACHE_GET_CHILD_DEV_TYPE, // Device types a fitler can receive + + CACHE_USER_CONSTANTS = 1000 // Smaller values are reserved for the core + +}; + +// Base class for all filters. +class IClip { + friend class PClip; + friend class AVSValue; + volatile long refcnt; + void AddRef(); +#if BUILDING_AVSCORE +public: +#endif + void Release(); +public: + IClip() : refcnt(0) {} + virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } + virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; + virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame + virtual void __stdcall GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) = 0; // start and count are in samples + /* Need to check GetVersion first, pre v5 will return random crap from EAX reg. */ + virtual int __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter. + virtual const VideoInfo& __stdcall GetVideoInfo() = 0; + virtual ~IClip() {} +}; // end class IClip + + +// smart pointer to IClip +class PClip { + + IClip* p; + + IClip* GetPointerWithAddRef() const; + friend class AVSValue; + friend class VideoFrame; + + void Init(IClip* x); + void Set(IClip* x); + +public: + PClip() AVS_BakedCode( AVS_LinkCall_Void(PClip_CONSTRUCTOR0)() ) + PClip(const PClip& x) AVS_BakedCode( AVS_LinkCall_Void(PClip_CONSTRUCTOR1)(x) ) + PClip(IClip* x) AVS_BakedCode( AVS_LinkCall_Void(PClip_CONSTRUCTOR2)(x) ) + void operator=(IClip* x) AVS_BakedCode( AVS_LinkCall_Void(PClip_OPERATOR_ASSIGN0)(x) ) + void operator=(const PClip& x) AVS_BakedCode( AVS_LinkCall_Void(PClip_OPERATOR_ASSIGN1)(x) ) + + IClip* operator->() const { return p; } + + // useful in conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PClip() AVS_BakedCode( AVS_LinkCall_Void(PClip_DESTRUCTOR)() ) +#ifdef BUILDING_AVSCORE +public: + void CONSTRUCTOR0(); /* Damn compiler won't allow taking the address of reserved constructs, make a dummy interlude */ + void CONSTRUCTOR1(const PClip& x); + void CONSTRUCTOR2(IClip* x); + void OPERATOR_ASSIGN0(IClip* x); + void OPERATOR_ASSIGN1(const PClip& x); + void DESTRUCTOR(); +#endif +}; // end class PClip + +// enums for frame property functions +enum AVSPropTypes { + PROPTYPE_UNSET = 'u', // ptUnset + PROPTYPE_INT = 'i', // peType + PROPTYPE_FLOAT = 'f', // ptFloat + PROPTYPE_DATA = 's', // ptData + PROPTYPE_CLIP = 'c', // ptClip + PROPTYPE_FRAME = 'v' // ptFrame + // ptFunction = 'm' +}; + +enum AVSGetPropErrors { + GETPROPERROR_UNSET = 1, // peUnset + GETPROPERROR_TYPE = 2, // peType + GETPROPERROR_INDEX = 4 // peIndex +}; + +enum AVSPropAppendMode { + PROPAPPENDMODE_REPLACE = 0, // paReplace + PROPAPPENDMODE_APPEND = 1, // paAppend + PROPAPPENDMODE_TOUCH = 2 // paTouch +}; + + +class AVSValue { +public: + + AVSValue() AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR0)() ) + AVSValue(IClip* c) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR1)(c) ) + AVSValue(const PClip& c) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR2)(c) ) + AVSValue(bool b) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR3)(b) ) + AVSValue(int i) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR4)(i) ) +// AVSValue(int64_t l); + AVSValue(float f) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR5)(f) ) + AVSValue(double f) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR6)(f) ) + AVSValue(const char* s) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR7)(s) ) + AVSValue(const AVSValue* a, int size) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR8)(a, size) ) + AVSValue(const AVSValue& a, int size) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR8)(&a, size) ) + AVSValue(const AVSValue& v) AVS_BakedCode( AVS_LinkCall_Void(AVSValue_CONSTRUCTOR9)(v) ) + AVSValue(const PFunction& n) AVS_BakedCode(AVS_LinkCall_Void(AVSValue_CONSTRUCTOR11)(n)) + + ~AVSValue() AVS_BakedCode( AVS_LinkCall_Void(AVSValue_DESTRUCTOR)() ) + AVSValue& operator=(const AVSValue& v) AVS_BakedCode( return AVS_LinkCallV(AVSValue_OPERATOR_ASSIGN)(v) ) + + // Note that we transparently allow 'int' to be treated as 'float'. + // There are no int<->bool conversions, though. + + bool Defined() const AVS_BakedCode( return AVS_LinkCall(Defined)() ) + bool IsClip() const AVS_BakedCode( return AVS_LinkCall(IsClip)() ) + bool IsBool() const AVS_BakedCode( return AVS_LinkCall(IsBool)() ) + bool IsInt() const AVS_BakedCode( return AVS_LinkCall(IsInt)() ) +// bool IsLong() const; + bool IsFloat() const AVS_BakedCode( return AVS_LinkCall(IsFloat)() ) + bool IsString() const AVS_BakedCode( return AVS_LinkCall(IsString)() ) + bool IsArray() const AVS_BakedCode(return AVS_LinkCall(IsArray)()) + bool IsFunction() const AVS_BakedCode( return AVS_LinkCall(IsFunction)() ) + + PClip AsClip() const AVS_BakedCode( return AVS_LinkCall(AsClip)() ) + bool AsBool() const AVS_BakedCode( return AVS_LinkCall(AsBool1)() ) + int AsInt() const AVS_BakedCode( return AVS_LinkCall(AsInt1)() ) +// int AsLong() const; + const char* AsString() const AVS_BakedCode( return AVS_LinkCall(AsString1)() ) + double AsFloat() const AVS_BakedCode( return AVS_LinkCall(AsFloat1)() ) + float AsFloatf() const AVS_BakedCode( return float( AVS_LinkCall(AsFloat1)() ) ) + + bool AsBool(bool def) const AVS_BakedCode( return AVS_LinkCall(AsBool2)(def) ) + int AsInt(int def) const AVS_BakedCode( return AVS_LinkCall(AsInt2)(def) ) + double AsDblDef(double def) const AVS_BakedCode( return AVS_LinkCall(AsDblDef)(def) ) // Value is still a float + double AsFloat(float def) const AVS_BakedCode( return AVS_LinkCall(AsFloat2)(def) ) + float AsFloatf(float def) const AVS_BakedCode( return float( AVS_LinkCall(AsFloat2)(def) ) ) + const char* AsString(const char* def) const AVS_BakedCode( return AVS_LinkCall(AsString2)(def) ) + PFunction AsFunction() const; // internal use only + + int ArraySize() const AVS_BakedCode( return AVS_LinkCall(ArraySize)() ) + + const AVSValue& operator[](int index) const AVS_BakedCode( return AVS_LinkCallV(AVSValue_OPERATOR_INDEX)(index) ) + +private: + + short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, fu'n'ction, or RFU: 'l'ong ('d'ouble) + short array_size; + union { + IClip* clip; + bool boolean; + int integer; + float floating_pt; + const char* string; + const AVSValue* array; + IFunction* function; + #ifdef X86_64 + // if ever, only x64 will support. It breaks struct size on 32 bit + int64_t longlong; // 8 bytes + double double_pt; // 8 bytes + #endif + }; + + void Assign(const AVSValue* src, bool init); +#ifdef BUILDING_AVSCORE +public: + void CONSTRUCTOR0(); /* Damn compiler won't allow taking the address of reserved constructs, make a dummy interlude */ + void CONSTRUCTOR1(IClip* c); + void CONSTRUCTOR2(const PClip& c); + void CONSTRUCTOR3(bool b); + void CONSTRUCTOR4(int i); + void CONSTRUCTOR5(float f); + void CONSTRUCTOR6(double f); + void CONSTRUCTOR7(const char* s); + void CONSTRUCTOR8(const AVSValue* a, int size); + void CONSTRUCTOR9(const AVSValue& v); + void CONSTRUCTOR11(const PFunction& n); + void DESTRUCTOR(); + AVSValue& OPERATOR_ASSIGN(const AVSValue& v); + const AVSValue& OPERATOR_INDEX(int index) const; + + bool AsBool1() const; + int AsInt1() const; + const char* AsString1() const; + double AsFloat1() const; + + bool AsBool2(bool def) const; + int AsInt2(int def) const; + double AsFloat2(float def) const; + const char* AsString2(const char* def) const; + + void MarkArrayAsC(); // for C interface, no deep-copy and deep-free + void CONSTRUCTOR10(const AVSValue& v, bool c_arrays); + AVSValue(const AVSValue& v, bool c_arrays); + void Assign2(const AVSValue* src, bool init, bool c_arrays); + +#endif +}; // end class AVSValue + +#define AVS_UNUSED(x) (void)(x) + +// instantiable null filter +class GenericVideoFilter : public IClip { +protected: + PClip child; + VideoInfo vi; +public: + GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } + void __stdcall GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } + const VideoInfo& __stdcall GetVideoInfo() { return vi; } + bool __stdcall GetParity(int n) { return child->GetParity(n); } + int __stdcall SetCacheHints(int cachehints, int frame_range) { AVS_UNUSED(cachehints); AVS_UNUSED(frame_range); return 0; } // We do not pass cache requests upwards, only to the next filter. +}; + + +class PFunction +{ +public: + PFunction() AVS_BakedCode(AVS_LinkCall_Void(PFunction_CONSTRUCTOR0)()) + PFunction(IFunction* p) AVS_BakedCode(AVS_LinkCall_Void(PFunction_CONSTRUCTOR1)(p)) + PFunction(const PFunction& p) AVS_BakedCode(AVS_LinkCall_Void(PFunction_CONSTRUCTOR2)(p)) + PFunction& operator=(IFunction* p) AVS_BakedCode(return AVS_LinkCallV(PFunction_OPERATOR_ASSIGN0)(p)) + PFunction& operator=(const PFunction& p) AVS_BakedCode(return AVS_LinkCallV(PFunction_OPERATOR_ASSIGN1)(p)) + ~PFunction() AVS_BakedCode(AVS_LinkCall_Void(PFunction_DESTRUCTOR)()) + + int operator!() const { return !e; } + operator void*() const { return e; } + IFunction* operator->() const { return e; } + +private: + IFunction * e; + + friend class AVSValue; + IFunction * GetPointerWithAddRef() const; + void Init(IFunction* p); + void Set(IFunction* p); + +#ifdef BUILDING_AVSCORE +public: + void CONSTRUCTOR0(); /* Damn compiler won't allow taking the address of reserved constructs, make a dummy interlude */ + void CONSTRUCTOR1(IFunction* p); + void CONSTRUCTOR2(const PFunction& p); + PFunction& OPERATOR_ASSIGN0(IFunction* p); + PFunction& OPERATOR_ASSIGN1(const PFunction& p); + void DESTRUCTOR(); +#endif +}; + + +#undef CALL_MEMBER_FN +#undef AVS_LinkCallOptDefault +#undef AVS_LinkCallOpt +#undef AVS_LinkCallV +#undef AVS_LinkCall +#undef AVS_BakedCode + + +#include "avs/cpuid.h" + +// IScriptEnvironment GetEnvProperty +enum AvsEnvProperty +{ + AEP_PHYSICAL_CPUS = 1, + AEP_LOGICAL_CPUS = 2, + AEP_THREADPOOL_THREADS = 3, + AEP_FILTERCHAIN_THREADS = 4, + AEP_THREAD_ID = 5, + AEP_VERSION = 6, + AEP_HOST_SYSTEM_ENDIANNESS = 7, + AEP_INTERFACE_VERSION = 8, + AEP_INTERFACE_BUGFIX = 9, + + // Neo additionals + AEP_NUM_DEVICES = 901, + AEP_FRAME_ALIGN = 902, + AEP_PLANE_ALIGN = 903, + + AEP_SUPPRESS_THREAD = 921, + AEP_GETFRAME_RECURSIVE = 922, +}; + +// IScriptEnvironment Allocate +enum AvsAllocType +{ + AVS_NORMAL_ALLOC = 1, + AVS_POOLED_ALLOC = 2 +}; + + +class IScriptEnvironment { +public: + virtual ~IScriptEnvironment() {} + + virtual /*static*/ int __stdcall GetCPUFlags() = 0; + + virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; + virtual char* Sprintf(const char* fmt, ...) = 0; + // note: val is really a va_list; I hope everyone typedefs va_list to a pointer + // 20200305: (void *) changed back to va_list + virtual char* __stdcall VSprintf(const char* fmt, va_list val) = 0; + +#ifdef AVS_WINDOWS + __declspec(noreturn) virtual void ThrowError(const char* fmt, ...) = 0; +#else + virtual void ThrowError(const char* fmt, ...) = 0; +#endif + + class NotFound /*exception*/ {}; // thrown by Invoke and GetVar + + typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); + + virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; + virtual bool __stdcall FunctionExists(const char* name) = 0; + virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char* const* arg_names=0) = 0; + + virtual AVSValue __stdcall GetVar(const char* name) = 0; + virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; + virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; + + virtual void __stdcall PushContext(int level=0) = 0; + virtual void __stdcall PopContext() = 0; + + // note v8: deprecated in most cases, use NewVideoFrameP is possible + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0; + + virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; + + virtual void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; + + typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); + virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; + + virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; + + virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; + + virtual int __stdcall SetMemoryMax(int mem) = 0; + + virtual int __stdcall SetWorkingDir(const char * newdir) = 0; + + virtual void* __stdcall ManageCache(int key, void* data) = 0; + + enum PlanarChromaAlignmentMode { + PlanarChromaAlignmentOff, + PlanarChromaAlignmentOn, + PlanarChromaAlignmentTest }; + + virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0; + + virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, + int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; + + // **** AVISYNTH_INTERFACE_VERSION 5 **** defined since classic Avisynth 2.6 beta + virtual void __stdcall DeleteScriptEnvironment() = 0; + + virtual void __stdcall ApplyMessage(PVideoFrame* frame, const VideoInfo& vi, const char* message, int size, + int textcolor, int halocolor, int bgcolor) = 0; + + virtual const AVS_Linkage* __stdcall GetAVSLinkage() = 0; + + // **** AVISYNTH_INTERFACE_VERSION 6 **** defined since classic Avisynth 2.6 + // noThrow version of GetVar + virtual AVSValue __stdcall GetVarDef(const char* name, const AVSValue& def = AVSValue()) = 0; + + // **** AVISYNTH_INTERFACE_VERSION 8 **** AviSynth+ 3.6.0- + virtual PVideoFrame __stdcall SubframePlanarA(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, + int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV, int rel_offsetA) = 0; + + virtual void __stdcall copyFrameProps(const PVideoFrame& src, PVideoFrame& dst) = 0; + virtual const AVSMap* __stdcall getFramePropsRO(const PVideoFrame& frame) = 0; + virtual AVSMap* __stdcall getFramePropsRW(PVideoFrame& frame) = 0; + + virtual int __stdcall propNumKeys(const AVSMap* map) = 0; + + virtual const char* __stdcall propGetKey(const AVSMap* map, int index) = 0; + virtual int __stdcall propNumElements(const AVSMap* map, const char* key) = 0; + virtual char __stdcall propGetType(const AVSMap* map, const char* key) = 0; + + virtual int64_t __stdcall propGetInt(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual double __stdcall propGetFloat(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual const char* __stdcall propGetData(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual int __stdcall propGetDataSize(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual PClip __stdcall propGetClip(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual const PVideoFrame __stdcall propGetFrame(const AVSMap* map, const char* key, int index, int* error) = 0; + + virtual int __stdcall propDeleteKey(AVSMap* map, const char* key) = 0; + + virtual int __stdcall propSetInt(AVSMap* map, const char* key, int64_t i, int append) = 0; + virtual int __stdcall propSetFloat(AVSMap* map, const char* key, double d, int append) = 0; + virtual int __stdcall propSetData(AVSMap* map, const char* key, const char* d, int length, int append) = 0; + virtual int __stdcall propSetClip(AVSMap* map, const char* key, PClip& clip, int append) = 0; + virtual int __stdcall propSetFrame(AVSMap* map, const char* key, const PVideoFrame& frame, int append) = 0; + + virtual const int64_t* __stdcall propGetIntArray(const AVSMap* map, const char* key, int* error) = 0; + virtual const double* __stdcall propGetFloatArray(const AVSMap* map, const char* key, int* error) = 0; + virtual int __stdcall propSetIntArray(AVSMap* map, const char* key, const int64_t* i, int size) = 0; + virtual int __stdcall propSetFloatArray(AVSMap* map, const char* key, const double* d, int size) = 0; + + virtual AVSMap* __stdcall createMap() = 0; + virtual void __stdcall freeMap(AVSMap* map) = 0; + virtual void __stdcall clearMap(AVSMap* map) = 0; + + // NewVideoFrame with frame property source. + virtual PVideoFrame __stdcall NewVideoFrameP(const VideoInfo& vi, PVideoFrame* propSrc, int align = FRAME_ALIGN) = 0; + + // Note: do not declare existing names like 'NewVideoFrame' again with different parameters since MSVC will reorder it + // in the vtable and group it together with the first NewVideoFrame variant. + // This results in shifting all vtable method pointers after NewVideoFrame and breaks all plugins who expect the old order. + // E.g. ApplyMessage will be called instead of GetAVSLinkage + + // Generic query to ask for various system properties + virtual size_t __stdcall GetEnvProperty(AvsEnvProperty prop) = 0; + + // Support functions + virtual void* __stdcall Allocate(size_t nBytes, size_t alignment, AvsAllocType type) = 0; + virtual void __stdcall Free(void* ptr) = 0; + + // these GetVar versions (renamed differently) were moved from IScriptEnvironment2 + + // Returns TRUE and the requested variable. If the method fails, returns FALSE and does not touch 'val'. + virtual bool __stdcall GetVarTry(const char* name, AVSValue* val) const = 0; // ex virtual bool __stdcall GetVar(const char* name, AVSValue* val) const = 0; + // Return the value of the requested variable. + // If the variable was not found or had the wrong type, + // return the supplied default value. + virtual bool __stdcall GetVarBool(const char* name, bool def) const = 0; + virtual int __stdcall GetVarInt(const char* name, int def) const = 0; + virtual double __stdcall GetVarDouble(const char* name, double def) const = 0; + virtual const char* __stdcall GetVarString(const char* name, const char* def) const = 0; + // brand new in v8 - though no real int64 support yet + virtual int64_t __stdcall GetVarLong(const char* name, int64_t def) const = 0; + + // 'Invoke' functions moved here from internal ScriptEnvironments are renamed in order to keep vtable order + // Invoke functions with 'Try' will return false instead of throwing NotFound(). + // ex-IScriptEnvironment2 + virtual bool __stdcall InvokeTry(AVSValue* result, const char* name, const AVSValue& args, const char* const* arg_names = 0) = 0; + // Since V8 + virtual AVSValue __stdcall Invoke2(const AVSValue& implicit_last, const char* name, const AVSValue args, const char* const* arg_names = 0) = 0; + // Ex-INeo + virtual bool __stdcall Invoke2Try(AVSValue* result, const AVSValue& implicit_last, const char* name, const AVSValue args, const char* const* arg_names = 0) = 0; + virtual AVSValue __stdcall Invoke3(const AVSValue& implicit_last, const PFunction& func, const AVSValue args, const char* const* arg_names = 0) = 0; + virtual bool __stdcall Invoke3Try(AVSValue* result, const AVSValue& implicit_last, const PFunction& func, const AVSValue args, const char* const* arg_names = 0) = 0; + + // V9 + virtual bool __stdcall MakePropertyWritable(PVideoFrame* pvf) = 0; + +}; // end class IScriptEnvironment. Order is important. + +// used internally +class IScriptEnvironment_Avs25 { +public: + virtual ~IScriptEnvironment_Avs25() {} + + virtual /*static*/ int __stdcall GetCPUFlags() = 0; + + virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; + virtual char* Sprintf(const char* fmt, ...) = 0; + virtual char* __stdcall VSprintf(const char* fmt, va_list val) = 0; + +#ifdef AVS_WINDOWS + __declspec(noreturn) virtual void ThrowError(const char* fmt, ...) = 0; +#else + virtual void ThrowError(const char* fmt, ...) = 0; +#endif + + class NotFound /*exception*/ {}; // thrown by Invoke and GetVar + + typedef AVSValue(__cdecl* ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); + + virtual void __stdcall AddFunction25(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; + virtual bool __stdcall FunctionExists(const char* name) = 0; + virtual AVSValue __stdcall Invoke25(const char* name, const AVSValue args, const char* const* arg_names = 0) = 0; + + virtual AVSValue __stdcall GetVar(const char* name) = 0; + virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; + virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; + + virtual void __stdcall PushContext(int level = 0) = 0; + virtual void __stdcall PopContext() = 0; + + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align = FRAME_ALIGN) = 0; + + virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; + + virtual void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; + + typedef void(__cdecl* ShutdownFunc)(void* user_data, IScriptEnvironment* env); + virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; + + virtual void __stdcall CheckVersion(int version = AVISYNTH_CLASSIC_INTERFACE_VERSION_25) = 0; + + virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; + + virtual int __stdcall SetMemoryMax(int mem) = 0; + + virtual int __stdcall SetWorkingDir(const char* newdir) = 0; + + // specially returns 1 for key MC_QueryAvs25 to check if called from AVS2.5 interface + virtual void* __stdcall ManageCache25(int key, void* data) = 0; + + enum PlanarChromaAlignmentMode { + PlanarChromaAlignmentOff, + PlanarChromaAlignmentOn, + PlanarChromaAlignmentTest + }; + + virtual bool __stdcall PlanarChromaAlignment(IScriptEnvironment::PlanarChromaAlignmentMode key) = 0; + + virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, + int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; + + // Despite the name, we provide entries up to V6 in case someone requests + // a V3 interface and still wants to use V5-V6 functions + + // **** AVISYNTH_INTERFACE_VERSION 5 **** defined since classic Avisynth 2.6 beta + virtual void __stdcall DeleteScriptEnvironment() = 0; + + virtual void __stdcall ApplyMessage(PVideoFrame* frame, const VideoInfo& vi, const char* message, int size, + int textcolor, int halocolor, int bgcolor) = 0; + + virtual const AVS_Linkage* __stdcall GetAVSLinkage() = 0; + + // **** AVISYNTH_INTERFACE_VERSION 6 **** defined since classic Avisynth 2.6 + // noThrow version of GetVar + virtual AVSValue __stdcall GetVarDef(const char* name, const AVSValue& def = AVSValue()) = 0; + +}; // end class IScriptEnvironment_Avs25. Order is important. + + +enum MtMode +{ + MT_INVALID = 0, + MT_NICE_FILTER = 1, + MT_MULTI_INSTANCE = 2, + MT_SERIALIZED = 3, + MT_SPECIAL_MT = 4, + MT_MODE_COUNT = 5 +}; + +class IJobCompletion +{ +public: + + virtual ~IJobCompletion() {} + virtual void __stdcall Wait() = 0; + virtual AVSValue __stdcall Get(size_t i) = 0; + virtual size_t __stdcall Size() const = 0; + virtual size_t __stdcall Capacity() const = 0; + virtual void __stdcall Reset() = 0; + virtual void __stdcall Destroy() = 0; +}; + +class IScriptEnvironment2; +class Prefetcher; +typedef AVSValue (*ThreadWorkerFuncPtr)(IScriptEnvironment2* env, void* data); + + +/* ----------------------------------------------------------------------------- + Note to plugin authors: The interface in IScriptEnvironment2 is + preliminary / under construction / only for testing / non-final etc.! + As long as you see this note here, IScriptEnvironment2 might still change, + in which case your plugin WILL break. This also means that you are welcome + to test it and give your feedback about any ideas, improvements, or issues + you might have. + ----------------------------------------------------------------------------- */ +class IScriptEnvironment2 : public IScriptEnvironment{ +public: + virtual ~IScriptEnvironment2() {} + + // V8: SubframePlanarA, GetEnvProperty, GetVar versions, Allocate, Free, no-throw Invoke moved to IScriptEnvironment + + // Plugin functions + virtual bool __stdcall LoadPlugin(const char* filePath, bool throwOnError, AVSValue *result) = 0; + virtual void __stdcall AddAutoloadDir(const char* dirPath, bool toFront) = 0; + virtual void __stdcall ClearAutoloadDirs() = 0; + virtual void __stdcall AutoloadPlugins() = 0; + virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data, const char *exportVar) = 0; + virtual bool __stdcall InternalFunctionExists(const char* name) = 0; + + // Threading + virtual void __stdcall SetFilterMTMode(const char* filter, MtMode mode, bool force) = 0; // If filter is "DEFAULT_MT_MODE", sets the default MT mode + virtual IJobCompletion* __stdcall NewCompletion(size_t capacity) = 0; + virtual void __stdcall ParallelJob(ThreadWorkerFuncPtr jobFunc, void* jobData, IJobCompletion* completion) = 0; + + // These lines are needed so that we can overload the older functions from IScriptEnvironment. + using IScriptEnvironment::Invoke; + using IScriptEnvironment::AddFunction; + +}; // end class IScriptEnvironment2 + + +// To allow Avisynth+ add functions to IScriptEnvironment2, +// Neo defines another new interface, INeoEnv. +// INeoEnv and the legacy interfaces (IScriptEnvironment/IScriptEnvironment2) +// share the same ScriptEnvironment instance. The function with the same signature +// is exactly identical and there is no limitation to switch interfaces. +// You can use any interface you like. +// Note to plugin authors : The interface is not stable, see comments in IScriptEnvironment2 +class INeoEnv { +public: + virtual ~INeoEnv() {} + + typedef IScriptEnvironment::NotFound NotFound; + typedef IScriptEnvironment::ApplyFunc ApplyFunc; + typedef IScriptEnvironment::ShutdownFunc ShutdownFunc; + + virtual void __stdcall DeleteScriptEnvironment() = 0; + + virtual const AVS_Linkage* __stdcall GetAVSLinkage() = 0; + + // Get legacy interface (Avisynth+) + virtual IScriptEnvironment2* __stdcall GetEnv2() = 0; + // Get compatibility interface for AVS CPP 2.5 plugins + virtual IScriptEnvironment_Avs25* __stdcall GetEnv25() = 0; + + // Generic system to ask for various properties + virtual size_t __stdcall GetEnvProperty(AvsEnvProperty prop) = 0; + virtual int __stdcall GetCPUFlags() = 0; + + // Plugin functions + virtual bool __stdcall LoadPlugin(const char* filePath, bool throwOnError, AVSValue *result) = 0; + virtual void __stdcall AddAutoloadDir(const char* dirPath, bool toFront) = 0; + virtual void __stdcall ClearAutoloadDirs() = 0; + virtual void __stdcall AutoloadPlugins() = 0; + + virtual void __stdcall AddFunction( + const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; + virtual void __stdcall AddFunction( + const char* name, const char* params, ApplyFunc apply, void* user_data, const char *exportVar) = 0; + virtual bool __stdcall FunctionExists(const char* name) = 0; + virtual bool __stdcall InternalFunctionExists(const char* name) = 0; + + // Invoke function. Throws NotFound exception when the specified function does not exist. + virtual AVSValue __stdcall Invoke( + const char* name, const AVSValue args, const char* const* arg_names = 0) = 0; + virtual AVSValue __stdcall Invoke2( + const AVSValue& implicit_last, const char* name, const AVSValue args, const char* const* arg_names = 0) = 0; + virtual AVSValue __stdcall Invoke3( + const AVSValue& implicit_last, + const PFunction& func, const AVSValue args, const char* const* arg_names = 0) = 0; + + // These versions of Invoke will return false instead of throwing NotFound(). + virtual bool __stdcall InvokeTry( + AVSValue* result, const char* name, const AVSValue& args, const char* const* arg_names = 0) = 0; + virtual bool __stdcall Invoke2Try( + AVSValue* result, const AVSValue& implicit_last, + const char* name, const AVSValue args, const char* const* arg_names = 0) = 0; + virtual bool __stdcall Invoke3Try( + AVSValue* result, const AVSValue& implicit_last, + const PFunction& func, const AVSValue args, const char* const* arg_names = 0) = 0; + + // V9 + virtual bool __stdcall MakePropertyWritable(PVideoFrame* pvf) = 0; + + // Throws exception when the requested variable is not found. + virtual AVSValue __stdcall GetVar(const char* name) = 0; + + // noThrow version of GetVar + virtual AVSValue __stdcall GetVarDef(const char* name, const AVSValue& def = AVSValue()) = 0; + + // Returns TRUE and the requested variable. If the method fails, returns FALSE and does not touch 'val'. + virtual bool __stdcall GetVarTry(const char* name, AVSValue* val) const = 0; + + // Return the value of the requested variable. + // If the variable was not found or had the wrong type, + // return the supplied default value. + virtual bool __stdcall GetVarBool(const char* name, bool def) const = 0; + virtual int __stdcall GetVarInt(const char* name, int def) const = 0; + virtual double __stdcall GetVarDouble(const char* name, double def) const = 0; + virtual const char* __stdcall GetVarString(const char* name, const char* def) const = 0; + virtual int64_t __stdcall GetVarLong(const char* name, int64_t def) const = 0; + + virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; + virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; + + // Switch local variables + virtual void __stdcall PushContext(int level = 0) = 0; + virtual void __stdcall PopContext() = 0; + + // Global variable frame support + virtual void __stdcall PushContextGlobal() = 0; + virtual void __stdcall PopContextGlobal() = 0; + + // Allocate new video frame + // in PNeoEnv: align parameter is no longer supported + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi) = 0; // current device is used + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, const PDevice& device) = 0; + // as above but with property sources + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, PVideoFrame *propSrc) = 0; // current device is used + frame property source + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, const PDevice& device, PVideoFrame* propSrc) = 0; // current device is used + frame property source + + // Frame related operations + virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; + virtual void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; + + virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; + virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, + int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; + virtual PVideoFrame __stdcall SubframePlanarA(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, + int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV, int rel_offsetA) = 0; + + // frame properties support + virtual void __stdcall copyFrameProps(const PVideoFrame& src, PVideoFrame& dst) = 0; + virtual const AVSMap* __stdcall getFramePropsRO(const PVideoFrame& frame) = 0; + virtual AVSMap* __stdcall getFramePropsRW(PVideoFrame& frame) = 0; + + virtual int __stdcall propNumKeys(const AVSMap* map) = 0; + virtual const char* __stdcall propGetKey(const AVSMap* map, int index) = 0; + virtual int __stdcall propNumElements(const AVSMap* map, const char* key) = 0; + virtual char __stdcall propGetType(const AVSMap* map, const char* key) = 0; + + virtual int64_t __stdcall propGetInt(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual double __stdcall propGetFloat(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual const char* __stdcall propGetData(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual int __stdcall propGetDataSize(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual PClip __stdcall propGetClip(const AVSMap* map, const char* key, int index, int* error) = 0; + virtual const PVideoFrame __stdcall propGetFrame(const AVSMap* map, const char* key, int index, int* error) = 0; + + virtual int __stdcall propDeleteKey(AVSMap* map, const char* key) = 0; + + virtual int __stdcall propSetInt(AVSMap* map, const char* key, int64_t i, int append) = 0; + virtual int __stdcall propSetFloat(AVSMap* map, const char* key, double d, int append) = 0; + virtual int __stdcall propSetData(AVSMap* map, const char* key, const char* d, int length, int append) = 0; + virtual int __stdcall propSetClip(AVSMap* map, const char* key, PClip& clip, int append) = 0; + virtual int __stdcall propSetFrame(AVSMap* map, const char* key, const PVideoFrame& frame, int append) = 0; + + virtual const int64_t *__stdcall propGetIntArray(const AVSMap* map, const char* key, int* error) = 0; + virtual const double *__stdcall propGetFloatArray(const AVSMap* map, const char* key, int* error) = 0; + virtual int __stdcall propSetIntArray(AVSMap* map, const char* key, const int64_t* i, int size) = 0; + virtual int __stdcall propSetFloatArray(AVSMap* map, const char* key, const double* d, int size) = 0; + + virtual AVSMap* __stdcall createMap() = 0; + virtual void __stdcall freeMap(AVSMap* map) = 0; + virtual void __stdcall clearMap(AVSMap* map) = 0; + + // Support functions + virtual void* __stdcall Allocate(size_t nBytes, size_t alignment, AvsAllocType type) = 0; + virtual void __stdcall Free(void* ptr) = 0; + + virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; + virtual char* __stdcall SaveString(const char* s, int length, bool escape) = 0; + virtual char* Sprintf(const char* fmt, ...) = 0; + virtual char* __stdcall VSprintf(const char* fmt, va_list val) = 0; + + __declspec(noreturn) virtual void ThrowError(const char* fmt, ...) = 0; + + virtual void __stdcall ApplyMessage(PVideoFrame* frame, const VideoInfo& vi, const char* message, int size, + int textcolor, int halocolor, int bgcolor) = 0; + + // Setting + virtual int __stdcall SetMemoryMax(int mem) = 0; + virtual int __stdcall SetMemoryMax(AvsDeviceType type, int index, int mem) = 0; + + virtual bool __stdcall PlanarChromaAlignment(IScriptEnvironment::PlanarChromaAlignmentMode key) = 0; + virtual int __stdcall SetWorkingDir(const char * newdir) = 0; + virtual void* __stdcall ManageCache(int key, void* data) = 0; + + virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; + virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; + + // Threading + virtual void __stdcall SetFilterMTMode(const char* filter, MtMode mode, bool force) = 0; + virtual IJobCompletion* __stdcall NewCompletion(size_t capacity) = 0; + virtual void __stdcall ParallelJob(ThreadWorkerFuncPtr jobFunc, void* jobData, IJobCompletion* completion) = 0; + + // CUDA Support + virtual PDevice __stdcall GetDevice(AvsDeviceType dev_type, int dev_index) const = 0; + virtual PDevice __stdcall GetDevice() const = 0; // get current device + virtual AvsDeviceType __stdcall GetDeviceType() const = 0; + virtual int __stdcall GetDeviceId() const = 0; + virtual int __stdcall GetDeviceIndex() const = 0; + virtual void* __stdcall GetDeviceStream() const = 0; + virtual void __stdcall DeviceAddCallback(void(*cb)(void*), void* user_data) = 0; + + virtual PVideoFrame __stdcall GetFrame(PClip c, int n, const PDevice& device) = 0; + +}; + +// support interface conversion +struct PNeoEnv { + INeoEnv* p; + PNeoEnv() : p() { } + PNeoEnv(IScriptEnvironment* env) +#if defined(BUILDING_AVSCORE) || defined(AVS_STATIC_LIB) + ; +#else + : p(!AVS_linkage || offsetof(AVS_Linkage, GetNeoEnv) >= (size_t)AVS_linkage->Size ? 0 : AVS_linkage->GetNeoEnv(env)) { } +#endif + + int operator!() const { return !p; } + operator void*() const { return p; } + INeoEnv* operator->() const { return p; } +#ifdef BUILDING_AVSCORE + inline operator IScriptEnvironment2*(); + inline operator IScriptEnvironment_Avs25* (); +#else + operator IScriptEnvironment2*() { return p->GetEnv2(); } + operator IScriptEnvironment_Avs25* () { return p->GetEnv25(); } +#endif +}; + + +// avisynth.dll exports this; it's a way to use it as a library, without +// writing an AVS script or without going through AVIFile. +AVSC_API(IScriptEnvironment*, CreateScriptEnvironment)(int version = AVISYNTH_INTERFACE_VERSION); + + +// These are some global variables you can set in your script to change AviSynth's behavior. +#define VARNAME_AllowFloatAudio "OPT_AllowFloatAudio" // Allow WAVE_FORMAT_IEEE_FLOAT audio output +#define VARNAME_VDubPlanarHack "OPT_VDubPlanarHack" // Hack YV16 and YV24 chroma plane order for old VDub's +#define VARNAME_AVIPadScanlines "OPT_AVIPadScanlines" // Have scanlines mod4 padded in all pixel formats +#define VARNAME_UseWaveExtensible "OPT_UseWaveExtensible" // Use WAVEFORMATEXTENSIBLE when describing audio to Windows +#define VARNAME_dwChannelMask "OPT_dwChannelMask" // Integer audio channel mask. See description of WAVEFORMATEXTENSIBLE for more info. +#define VARNAME_Enable_V210 "OPT_Enable_V210" // AVS+ use V210 instead of P210 (VfW) +#define VARNAME_Enable_Y3_10_10 "OPT_Enable_Y3_10_10" // AVS+ use Y3[10][10] instead of P210 (VfW) +#define VARNAME_Enable_Y3_10_16 "OPT_Enable_Y3_10_16" // AVS+ use Y3[10][16] instead of P216 (VfW) +#define VARNAME_Enable_b64a "OPT_Enable_b64a" // AVS+ use b64a instead of BRA[64] (VfW) +#define VARNAME_Enable_PlanarToPackedRGB "OPT_Enable_PlanarToPackedRGB" // AVS+ convert Planar RGB to packed RGB (VfW) + +// C exports +#include "avs/capi.h" +AVSC_API(IScriptEnvironment2*, CreateScriptEnvironment2)(int version = AVISYNTH_INTERFACE_VERSION); + +#ifndef BUILDING_AVSCORE +#undef AVS_UNUSED +#endif + +#pragma pack(pop) + +#endif //__AVISYNTH_9_H__ diff --git a/include/avisynth/avisynth1.h b/include/avisynth/avisynth1.h deleted file mode 100644 index dd2f603..0000000 --- a/include/avisynth/avisynth1.h +++ /dev/null @@ -1,714 +0,0 @@ -// Avisynth v1.0 beta. Copyright 2000 Ben Rudiak-Gould. -// http://www.math.berkeley.edu/~benrg/avisynth.html - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit -// http://www.gnu.org/copyleft/gpl.html . - - -#pragma once - -#ifdef _MSC_VER -#include -#else -#define _ASSERTE(x) assert(x) -#include -#endif - - -enum { AVISYNTH_INTERFACE_VERSION = 1 }; - - -// I had problems with Premiere wanting 1-byte alignment for its structures, -// so I now set the Avisynth struct alignment explicitly here. -#pragma pack(push,8) - - -// The VideoInfo struct holds global information about a clip (i.e. -// information that does not depend on the frame number). The GetVideoInfo -// method in IClip returns this struct. - -struct VideoInfo -{ - int width, height; // width=0 means no video - unsigned fps_numerator, fps_denominator; - int num_frames; - enum { UNKNOWN = 0, BGR24 = 0x13, BGR32 = 0x14, YUY2 = 0x22 }; - unsigned char pixel_type; - bool field_based; - - int audio_samples_per_second; // 0 means no audio - int num_audio_samples; - bool stereo, sixteen_bit; - - // useful functions of the above - bool HasVideo() const - { - return !!width; - } - bool HasAudio() const - { - return !!audio_samples_per_second; - } - bool IsRGB() const - { - return !!(pixel_type & 0x10); - } - bool IsRGB24() const - { - return pixel_type == BGR24; - } - bool IsRGB32() const - { - return pixel_type == BGR32; - } - bool IsYUV() const - { - return !!(pixel_type & 0x20); - } - bool IsYUY2() const - { - return pixel_type == YUY2; - } - int BytesFromPixels(int pixels) const - { - return pixels * (pixel_type & 7); - } - int RowSize() const - { - return BytesFromPixels(width); - } - int BitsPerPixel() const - { - return (pixel_type & 7) * 8; - } - int BMPSize() const - { - return height * ((RowSize() + 3) & -4); - } - int AudioSamplesFromFrames(int frames) const - { - return int(__int64(frames) * audio_samples_per_second * fps_denominator / fps_numerator); - } - int FramesFromAudioSamples(int samples) const - { - return int(__int64(samples) * fps_numerator / fps_denominator / audio_samples_per_second); - } - int AudioSamplesFromBytes(int bytes) const - { - return bytes >> (stereo + sixteen_bit); - } - int BytesFromAudioSamples(int samples) const - { - return samples << (stereo + sixteen_bit); - } - int BytesPerAudioSample() const - { - return BytesFromAudioSamples(1); - } - - // useful mutator - void SetFPS(unsigned numerator, unsigned denominator) - { - unsigned x = numerator, y = denominator; - while(y) // find gcd - { - unsigned t = x % y; - x = y; - y = t; - } - fps_numerator = numerator / x; - fps_denominator = denominator / x; - } -}; - - -// VideoFrameBuffer holds information about a memory block which is used -// for video data. For efficiency, instances of this class are not deleted -// when the refcount reaches zero; instead they're stored in a linked list -// to be reused. The instances are deleted when the corresponding AVS -// file is closed. - -class VideoFrameBuffer -{ - unsigned char* const data; - const int data_size; - // sequence_number is incremented every time the buffer is changed, so - // that stale views can tell they're no longer valid. - long sequence_number; - - friend class VideoFrame; - friend class Cache; - long refcount; - -public: - VideoFrameBuffer(int size); - VideoFrameBuffer(); - ~VideoFrameBuffer(); - - const unsigned char* GetReadPtr() const - { - return data; - } - unsigned char* GetWritePtr() - { - ++sequence_number; - return data; - } - int GetDataSize() - { - return data_size; - } - int GetSequenceNumber() - { - return sequence_number; - } - int GetRefcount() - { - return refcount; - } -}; - - -class IClip; -class PClip; -class PVideoFrame; -class IScriptEnvironment; -class AVSValue; - - -// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new -// is overloaded to recycle class instances. - -class VideoFrame -{ - int refcount; - VideoFrameBuffer* const vfb; - const int offset, pitch, row_size, height; - - friend class PVideoFrame; - void AddRef() - { - ++refcount; - } - void Release() - { - if(refcount == 1) --vfb->refcount; - --refcount; - } - - friend class ScriptEnvironment; - friend class Cache; - - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); - - void* operator new(size_t size); - -public: - int GetPitch() const - { - return pitch; - } - int GetRowSize() const - { - return row_size; - } - int GetHeight() const - { - return height; - } - - // generally you shouldn't use these two - VideoFrameBuffer* GetFrameBuffer() const - { - return vfb; - } - int GetOffset() const - { - return offset; - } - - // in plugins use env->SubFrame() - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; - - const unsigned char* GetReadPtr() const - { - return vfb->GetReadPtr() + offset; - } - - bool IsWritable() const - { - return (refcount == 1 && vfb->refcount == 1); - } - - unsigned char* GetWritePtr() const - { - return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; - } - - ~VideoFrame() - { - --vfb->refcount; - } -}; - - -// Base class for all filters. -class IClip -{ - friend class PClip; - friend class AVSValue; - int refcnt; - void AddRef() - { - ++refcnt; - } - void Release() - { - if(!--refcnt) delete this; - } -public: - IClip() : refcnt(0) {} - - virtual int __stdcall GetVersion() - { - return AVISYNTH_INTERFACE_VERSION; - } - - virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; - virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame - virtual void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) = 0; // start and count are in samples - virtual const VideoInfo& __stdcall GetVideoInfo() = 0; - virtual __stdcall ~IClip() {} -}; - - -// smart pointer to IClip -class PClip -{ - - IClip* p; - - IClip* GetPointerWithAddRef() const - { - if(p) p->AddRef(); - return p; - } - friend class AVSValue; - friend class VideoFrame; - - void Init(IClip* x) - { - if(x) x->AddRef(); - p = x; - } - void Set(IClip* x) - { - if(x) x->AddRef(); - if(p) p->Release(); - p = x; - } - -public: - PClip() - { - p = 0; - } - PClip(const PClip& x) - { - Init(x.p); - } - PClip(IClip* x) - { - Init(x); - } - void operator=(IClip* x) - { - Set(x); - } - void operator=(const PClip& x) - { - Set(x.p); - } - - IClip* operator->() const - { - return p; - } - - // useful in conditional expressions - operator void*() const - { - return p; - } - bool operator!() const - { - return !p; - } - - ~PClip() - { - if(p) p->Release(); - } -}; - - -// smart pointer to VideoFrame -class PVideoFrame -{ - - VideoFrame* p; - - void Init(VideoFrame* x) - { - if(x) x->AddRef(); - p = x; - } - void Set(VideoFrame* x) - { - if(x) x->AddRef(); - if(p) p->Release(); - p = x; - } - -public: - PVideoFrame() - { - p = 0; - } - PVideoFrame(const PVideoFrame& x) - { - Init(x.p); - } - PVideoFrame(VideoFrame* x) - { - Init(x); - } - void operator=(VideoFrame* x) - { - Set(x); - } - void operator=(const PVideoFrame& x) - { - Set(x.p); - } - - VideoFrame* operator->() const - { - return p; - } - - // for conditional expressions - operator void*() const - { - return p; - } - bool operator!() const - { - return !p; - } - - ~PVideoFrame() - { - if(p) p->Release(); - } -}; - - -class AVSValue -{ -public: - - AVSValue() - { - type = 'v'; - } - AVSValue(IClip* c) - { - type = 'c'; - clip = c; - if(c) c->AddRef(); - } - AVSValue(const PClip& c) - { - type = 'c'; - clip = c.GetPointerWithAddRef(); - } - AVSValue(bool b) - { - type = 'b'; - boolean = b; - } - AVSValue(int i) - { - type = 'i'; - integer = i; - } - AVSValue(float f) - { - type = 'f'; - floating_pt = f; - } - AVSValue(double f) - { - type = 'f'; - floating_pt = float(f); - } - AVSValue(const char* s) - { - type = 's'; - string = s; - } - AVSValue(const AVSValue* a, int size) - { - type = 'a'; - array = a; - array_size = size; - } - AVSValue(const AVSValue& v) - { - Assign(&v, true); - } - - ~AVSValue() - { - if(IsClip() && clip) clip->Release(); - } - AVSValue& operator=(const AVSValue& v) - { - Assign(&v, false); - return *this; - } - - // Note that we transparently allow 'int' to be treated as 'float'. - // There are no int<->bool conversions, though. - - bool Defined() const - { - return type != 'v'; - } - bool IsClip() const - { - return type == 'c'; - } - bool IsBool() const - { - return type == 'b'; - } - bool IsInt() const - { - return type == 'i'; - } - bool IsFloat() const - { - return type == 'f' || type == 'i'; - } - bool IsString() const - { - return type == 's'; - } - bool IsArray() const - { - return type == 'a'; - } - - PClip AsClip() const - { - _ASSERTE(IsClip()); - return IsClip() ? clip : 0; - } - bool AsBool() const - { - _ASSERTE(IsBool()); - return boolean; - } - int AsInt() const - { - _ASSERTE(IsInt()); - return integer; - } - const char* AsString() const - { - _ASSERTE(IsString()); - return IsString() ? string : 0; - } - double AsFloat() const - { - _ASSERTE(IsFloat()); - return IsInt() ? integer : floating_pt; - } - - bool AsBool(bool def) const - { - _ASSERTE(IsBool() || !Defined()); - return IsBool() ? boolean : def; - } - int AsInt(int def) const - { - _ASSERTE(IsInt() || !Defined()); - return IsInt() ? integer : def; - } - double AsFloat(double def) const - { - _ASSERTE(IsFloat() || !Defined()); - return IsInt() ? integer : type == 'f' ? floating_pt : def; - } - const char* AsString(const char* def) const - { - _ASSERTE(IsString() || !Defined()); - return IsString() ? string : def; - } - - int ArraySize() const - { - _ASSERTE(IsArray()); - return IsArray() ? array_size : 1; - } - const AVSValue& operator[](int index) const - { - _ASSERTE(IsArray() && index >= 0 && index < array_size); - return (IsArray() && index >= 0 && index < array_size) ? array[index] : *this; - } - -private: - - short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, or 'v'oid - short array_size; - union - { - IClip* clip; - bool boolean; - int integer; - float floating_pt; - const char* string; - const AVSValue* array; - }; - - void Assign(const AVSValue* src, bool init) - { - if(src->IsClip() && src->clip) - src->clip->AddRef(); - if(!init && IsClip() && clip) - clip->Release(); - // make sure this copies the whole struct! - ((__int32*)this)[0] = ((__int32*)src)[0]; - ((__int32*)this)[1] = ((__int32*)src)[1]; - } -}; - - -// instantiable null filter -class GenericVideoFilter : public IClip -{ -protected: - PClip child; - VideoInfo vi; -public: - GenericVideoFilter(PClip _child) : child(_child) - { - vi = child->GetVideoInfo(); - } - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) - { - return child->GetFrame(n, env); - } - void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) - { - child->GetAudio(buf, start, count, env); - } - const VideoInfo& __stdcall GetVideoInfo() - { - return vi; - } - bool __stdcall GetParity(int n) - { - return child->GetParity(n); - } -}; - - -class AvisynthError /* exception */ -{ -public: - const char* const msg; - AvisynthError(const char* _msg) : msg(_msg) {} -}; - - -// For GetCPUFlags. These are the same as in VirtualDub. -enum -{ - CPUF_FORCE = 0x01, - CPUF_FPU = 0x02, - CPUF_MMX = 0x04, - CPUF_INTEGER_SSE = 0x08, // Athlon MMX extensions or Intel SSE - CPUF_SSE = 0x10, // Full SSE (PIII) - CPUF_SSE2 = 0x20, // (PIV) - CPUF_3DNOW = 0x40, - CPUF_3DNOW_EXT = 0x80, // Athlon 3DNow! extensions -}; - - -class IScriptEnvironment -{ -public: - virtual __stdcall ~IScriptEnvironment() {} - - virtual /*static*/ long __stdcall GetCPUFlags() = 0; - - virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; - virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; - // note: val is really a va_list; I hope everyone typedefs va_list to a pointer - virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; - - __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; - - class NotFound /*exception*/ {}; // thrown by Invoke and GetVar - - typedef AVSValue(__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); - - virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; - virtual bool __stdcall FunctionExists(const char* name) = 0; - virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names = 0) = 0; - - virtual AVSValue __stdcall GetVar(const char* name) = 0; - virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; - virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; - - virtual void __stdcall PushContext(int level = 0) = 0; - virtual void __stdcall PopContext() = 0; - - // align should be 4 or 8 - virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align = 8) = 0; - - virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; - - virtual /*static*/ void __stdcall BitBlt(unsigned char* dstp, int dst_pitch, const unsigned char* srcp, int src_pitch, int row_size, int height) = 0; - - typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); - virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; - - virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; - - virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; -}; - - -// avisynth.dll exports this; it's a way to use it as a library, without -// writing an AVS script or without going through AVIFile. -IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); - - -#pragma pack(pop) - diff --git a/include/avisynth/avisynth25.h b/include/avisynth/avisynth25.h deleted file mode 100644 index b67dc59..0000000 --- a/include/avisynth/avisynth25.h +++ /dev/null @@ -1,783 +0,0 @@ -// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. -// http://www.avisynth.org - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit -// http://www.gnu.org/copyleft/gpl.html . -// -// Linking Avisynth statically or dynamically with other modules is making a -// combined work based on Avisynth. Thus, the terms and conditions of the GNU -// General Public License cover the whole combination. -// -// As a special exception, the copyright holders of Avisynth give you -// permission to link Avisynth with independent modules that communicate with -// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license -// terms of these independent modules, and to copy and distribute the -// resulting combined work under terms of your choice, provided that -// every copy of the combined work is accompanied by a complete copy of -// the source code of Avisynth (the version of Avisynth used to produce the -// combined work), being distributed under the terms of the GNU General -// Public License plus this exception. An independent module is a module -// which is not derived from or based on Avisynth, such as 3rd-party filters, -// import and export plugins, or graphical user interfaces. - - - - -#ifndef __AVISYNTH_H__ -#define __AVISYNTH_H__ - -enum { AVISYNTH_INTERFACE_VERSION = 3 }; - - -/* Define all types necessary for interfacing with avisynth.dll - Moved from internal.h */ - -// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc. -#include - -#if (_MSC_VER >= 1400) -extern "C" LONG __cdecl _InterlockedIncrement(LONG volatile * pn); -extern "C" LONG __cdecl _InterlockedDecrement(LONG volatile * pn); -#pragma intrinsic(_InterlockedIncrement) -#pragma intrinsic(_InterlockedDecrement) -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#endif - -// COM interface macros -#include - - -// Raster types used by VirtualDub & Avisynth -#define in64 (__int64)(unsigned short) -typedef unsigned long Pixel; // this will break on 64-bit machines! -typedef unsigned long Pixel32; -typedef unsigned char Pixel8; -typedef long PixCoord; -typedef long PixDim; -typedef long PixOffset; - - -/* Compiler-specific crap */ - -// Tell MSVC to stop precompiling here -#ifdef _MSC_VER - #pragma hdrstop -#endif - -// Set up debugging macros for MS compilers; for others, step down to the -// standard interface -#ifdef _MSC_VER - #include -#else - #define _RPT0(a,b) ((void)0) - #define _RPT1(a,b,c) ((void)0) - #define _RPT2(a,b,c,d) ((void)0) - #define _RPT3(a,b,c,d,e) ((void)0) - #define _RPT4(a,b,c,d,e,f) ((void)0) - - #define _ASSERTE(x) assert(x) - #include -#endif - - - -// I had problems with Premiere wanting 1-byte alignment for its structures, -// so I now set the Avisynth struct alignment explicitly here. -#pragma pack(push,8) - -#define FRAME_ALIGN 16 -// Default frame alignment is 16 bytes, to help P4, when using SSE2 - -// The VideoInfo struct holds global information about a clip (i.e. -// information that does not depend on the frame number). The GetVideoInfo -// method in IClip returns this struct. - -// Audio Sample information -typedef float SFLOAT; - -enum {SAMPLE_INT8 = 1<<0, - SAMPLE_INT16 = 1<<1, - SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware. - SAMPLE_INT32 = 1<<3, - SAMPLE_FLOAT = 1<<4}; - -enum { - PLANAR_Y=1<<0, - PLANAR_U=1<<1, - PLANAR_V=1<<2, - PLANAR_ALIGNED=1<<3, - PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED, - PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED, - PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED - }; - -class AvisynthError /* exception */ { -public: - const char* const msg; - AvisynthError(const char* _msg) : msg(_msg) {} -}; - -struct VideoInfo { - int width, height; // width=0 means no video - unsigned fps_numerator, fps_denominator; - int num_frames; - // This is more extensible than previous versions. More properties can be added seeminglesly. - - // Colorspace properties. - enum { - CS_BGR = 1<<28, - CS_YUV = 1<<29, - CS_INTERLEAVED = 1<<30, - CS_PLANAR = 1<<31 - }; - - // Specific colorformats - enum { CS_UNKNOWN = 0, - CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED, - CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED, - CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED, - CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, 4:2:0 planar - CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, 4:2:0 planar - CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above - }; - int pixel_type; // changed to int as of 2.5 - - - int audio_samples_per_second; // 0 means no audio - int sample_type; // as of 2.5 - __int64 num_audio_samples; // changed as of 2.5 - int nchannels; // as of 2.5 - - // Imagetype properties - - int image_type; - - enum { - IT_BFF = 1<<0, - IT_TFF = 1<<1, - IT_FIELDBASED = 1<<2 - }; - - // useful functions of the above - bool HasVideo() const { return (width!=0); } - bool HasAudio() const { return (audio_samples_per_second!=0); } - bool IsRGB() const { return !!(pixel_type&CS_BGR); } - bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties - bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; } - bool IsYUV() const { return !!(pixel_type&CS_YUV ); } - bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; } - bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); } - bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); } - bool Is(int property) const { return ((pixel_type & property)==property ); } - bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); } - bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); } - bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); } - bool IsBFF() const { return !!(image_type & IT_BFF); } - bool IsTFF() const { return !!(image_type & IT_TFF); } - - bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this - int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes - int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images - int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); } - __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; } - int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; } - __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; } - __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); } - int AudioChannels() const { return HasAudio() ? nchannels : 0; } - int SampleType() const{ return sample_type;} - bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);} - int SamplesPerSecond() const { return audio_samples_per_second; } - int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();} - void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; } - void Set(int property) { image_type|=property; } - void Clear(int property) { image_type&=~property; } - - int BitsPerPixel() const { - switch (pixel_type) { - case CS_BGR24: - return 24; - case CS_BGR32: - return 32; - case CS_YUY2: - return 16; - case CS_YV12: - case CS_I420: - return 12; - default: - return 0; - } - } - - int BytesPerChannelSample() const { - switch (sample_type) { - case SAMPLE_INT8: - return sizeof(signed char); - case SAMPLE_INT16: - return sizeof(signed short); - case SAMPLE_INT24: - return 3; - case SAMPLE_INT32: - return sizeof(signed int); - case SAMPLE_FLOAT: - return sizeof(SFLOAT); - default: - _ASSERTE("Sample type not recognized!"); - return 0; - } - } - - // useful mutator - void SetFPS(unsigned numerator, unsigned denominator) { - if ((numerator == 0) || (denominator == 0)) { - fps_numerator = 0; - fps_denominator = 1; - } - else { - unsigned x=numerator, y=denominator; - while (y) { // find gcd - unsigned t = x%y; x = y; y = t; - } - fps_numerator = numerator/x; - fps_denominator = denominator/x; - } - } - - // Range protected multiply-divide of FPS - void MulDivFPS(unsigned multiplier, unsigned divisor) { - unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier); - unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor); - - unsigned __int64 x=numerator, y=denominator; - while (y) { // find gcd - unsigned __int64 t = x%y; x = y; y = t; - } - numerator /= x; // normalize - denominator /= x; - - unsigned __int64 temp = numerator | denominator; // Just looking top bit - unsigned u = 0; - while (temp & 0xffffffff80000000ull) { // or perhaps > 16777216*2 - temp = Int64ShrlMod32(temp, 1); - u++; - } - if (u) { // Scale to fit - const unsigned round = 1 << (u-1); - SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u), - (unsigned)Int64ShrlMod32(denominator + round, u) ); - } - else { - fps_numerator = (unsigned)numerator; - fps_denominator = (unsigned)denominator; - } - } - - // Test for same colorspace - bool IsSameColorspace(const VideoInfo& vi) const { - if (vi.pixel_type == pixel_type) return TRUE; - if (IsYV12() && vi.IsYV12()) return TRUE; - return FALSE; - } - -}; - - - - -// VideoFrameBuffer holds information about a memory block which is used -// for video data. For efficiency, instances of this class are not deleted -// when the refcount reaches zero; instead they're stored in a linked list -// to be reused. The instances are deleted when the corresponding AVS -// file is closed. - -class VideoFrameBuffer { - BYTE* const data; - const int data_size; - // sequence_number is incremented every time the buffer is changed, so - // that stale views can tell they're no longer valid. - volatile long sequence_number; - - friend class VideoFrame; - friend class Cache; - friend class CacheMT; - friend class ScriptEnvironment; - volatile long refcount; - -public: - VideoFrameBuffer(int size); - VideoFrameBuffer(); - ~VideoFrameBuffer(); - - const BYTE* GetReadPtr() const { return data; } - BYTE* GetWritePtr() { InterlockedIncrement(&sequence_number); return data; } - int GetDataSize() { return data_size; } - int GetSequenceNumber() { return sequence_number; } - int GetRefcount() { return refcount; } -}; - - -class IClip; -class PClip; -class PVideoFrame; -class IScriptEnvironment; -class AVSValue; - - -// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new -// is overloaded to recycle class instances. - -class VideoFrame { - volatile long refcount; - VideoFrameBuffer* const vfb; - const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. - - friend class PVideoFrame; - void AddRef() { InterlockedIncrement(&refcount); } - void Release() { VideoFrameBuffer* vfb_local = vfb; if (!InterlockedDecrement(&refcount)) InterlockedDecrement(&vfb_local->refcount); } - - friend class Cache; - friend class CacheMT; - friend class ScriptEnvironment; - - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV); - - void* operator new (size_t size); -// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard! -public: - int GetPitch() const { return pitch; } - int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; } - int GetRowSize() const { return row_size; } - __declspec(noinline) int GetRowSize(int plane) const { - switch (plane) { - case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0; - case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED: - if (pitchUV) { - int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize - if (r<=pitchUV) - return r; - return row_size>>1; - } else return 0; - case PLANAR_Y_ALIGNED: - int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize - if (r<=pitch) - return r; - return row_size; - } - return row_size; } - int GetHeight() const { return height; } - int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; } - - // generally you shouldn't use these three - VideoFrameBuffer* GetFrameBuffer() const { return vfb; } - int GetOffset() const { return offset; } - int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; } - - // in plugins use env->SubFrame() - //If you really want to use these remember to increase vfb->refcount before calling and decrement it afterwards. - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const; - - - const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; } - const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); } - - bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } - - BYTE* GetWritePtr() const { - if (vfb->GetRefcount()>1) { - _ASSERT(FALSE); - //throw AvisynthError("Internal Error - refcount was more than one!"); - } - return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; - } - - BYTE* GetWritePtr(int plane) const { - if (plane==PLANAR_Y) { - if (vfb->GetRefcount()>1) { - _ASSERT(FALSE); -// throw AvisynthError("Internal Error - refcount was more than one!"); - } - return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0; - } - return vfb->data + GetOffset(plane); - } - - ~VideoFrame() { VideoFrameBuffer* vfb_local = vfb; if (InterlockedDecrement(&refcount) >= 0) InterlockedDecrement(&vfb_local->refcount); } -}; - -enum { - CACHE_NOTHING=0, - CACHE_RANGE=1, - CACHE_ALL=2, - CACHE_AUDIO=3, - CACHE_AUDIO_NONE=4, - CACHE_AUDIO_AUTO=5 - }; - -// Base class for all filters. -class IClip { - friend class PClip; - friend class AVSValue; - volatile long refcnt; - void AddRef() { InterlockedIncrement(&refcnt); } - void Release() { if (!InterlockedDecrement(&refcnt)) delete this; } -public: - IClip() : refcnt(0) {} - - virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } - - virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; - virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame - virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples - virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter. - virtual const VideoInfo& __stdcall GetVideoInfo() = 0; - virtual ~IClip() {} -}; - - -// smart pointer to IClip -class PClip { - - IClip* p; - - IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } - friend class AVSValue; - friend class VideoFrame; - - void Init(IClip* x) { - if (x) x->AddRef(); - p=x; - } - void Set(IClip* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PClip() { p = 0; } - PClip(const PClip& x) { Init(x.p); } - PClip(IClip* x) { Init(x); } - void operator=(IClip* x) { Set(x); } - void operator=(const PClip& x) { Set(x.p); } - - IClip* operator->() const { return p; } - - // useful in conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PClip() { if (p) p->Release(); } -}; - - -// smart pointer to VideoFrame -class PVideoFrame { - - VideoFrame* p; - - void Init(VideoFrame* x) { - if (x) x->AddRef(); - p=x; - } - void Set(VideoFrame* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PVideoFrame() { p = 0; } - PVideoFrame(const PVideoFrame& x) { Init(x.p); } - PVideoFrame(VideoFrame* x) { Init(x); } - void operator=(VideoFrame* x) { Set(x); } - void operator=(const PVideoFrame& x) { Set(x.p); } - - VideoFrame* operator->() const { return p; } - - // for conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PVideoFrame() { if (p) p->Release();} -}; - - -class AVSValue { -public: - - AVSValue() { type = 'v'; } - AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } - AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } - AVSValue(bool b) { type = 'b'; boolean = b; } - AVSValue(int i) { type = 'i'; integer = i; } -// AVSValue(__int64 l) { type = 'l'; longlong = l; } - AVSValue(float f) { type = 'f'; floating_pt = f; } - AVSValue(double f) { type = 'f'; floating_pt = float(f); } - AVSValue(const char* s) { type = 's'; string = s; } - AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } - AVSValue(const AVSValue& v) { Assign(&v, true); } - - ~AVSValue() { if (IsClip() && clip) clip->Release(); } - AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } - - // Note that we transparently allow 'int' to be treated as 'float'. - // There are no int<->bool conversions, though. - - bool Defined() const { return type != 'v'; } - bool IsClip() const { return type == 'c'; } - bool IsBool() const { return type == 'b'; } - bool IsInt() const { return type == 'i'; } -// bool IsLong() const { return (type == 'l'|| type == 'i'); } - bool IsFloat() const { return type == 'f' || type == 'i'; } - bool IsString() const { return type == 's'; } - bool IsArray() const { return type == 'a'; } - - PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } - bool AsBool() const { _ASSERTE(IsBool()); return boolean; } - int AsInt() const { _ASSERTE(IsInt()); return integer; } -// int AsLong() const { _ASSERTE(IsLong()); return longlong; } - const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } - double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } - - bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } - int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } - double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } - const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } - - int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } - - const AVSValue& operator[](int index) const { - _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) - src->clip->AddRef(); - if (!init && IsClip() && clip) - clip->Release(); - // make sure this copies the whole struct! - /* UGH! what the- ? - ((__int32*)this)[0] = ((__int32*)src)[0]; - ((__int32*)this)[1] = ((__int32*)src)[1]; - */ - this->clip = src->clip; - this->type = src->type; - this->array_size = src->array_size; - } -}; - - -// instantiable null filter -class GenericVideoFilter : public IClip { -protected: - PClip child; - VideoInfo vi; -public: - GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } - void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } - const VideoInfo& __stdcall GetVideoInfo() { return vi; } - bool __stdcall GetParity(int n) { return child->GetParity(n); } - void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter. -}; - - - - - -/* Helper classes useful to plugin authors */ - -class AlignPlanar : public GenericVideoFilter -{ -public: - AlignPlanar(PClip _clip); - static PClip Create(PClip clip); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); -}; - - - -class FillBorder : public GenericVideoFilter -{ -public: - FillBorder(PClip _clip); - static PClip Create(PClip clip); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); -}; - - - -class ConvertAudio : public GenericVideoFilter -/** - * Helper class to convert audio to any format - **/ -{ -public: - ConvertAudio(PClip _clip, int prefered_format); - void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env); - void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache! - - static PClip Create(PClip clip, int sample_type, int prefered_type); - static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_8bit (AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_Any (AVSValue args, void*, IScriptEnvironment*); - virtual ~ConvertAudio(); - -private: - void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count); - void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count); - - __inline int Saturate_int8(float n); - __inline short Saturate_int16(float n); - __inline int Saturate_int24(float n); - __inline int Saturate_int32(float n); - - char src_format; - char dst_format; - int src_bps; - char *tempbuffer; - SFLOAT *floatbuffer; - int tempbuffer_size; -}; - - -// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. -enum { - /* slowest CPU to support extension */ - CPUF_FORCE = 0x01, // N/A - CPUF_FPU = 0x02, // 386/486DX - CPUF_MMX = 0x04, // P55C, K6, PII - CPUF_INTEGER_SSE = 0x08, // PIII, Athlon - CPUF_SSE = 0x10, // PIII, Athlon XP/MP - CPUF_SSE2 = 0x20, // PIV, Hammer - CPUF_3DNOW = 0x40, // K6-2 - CPUF_3DNOW_EXT = 0x80, // Athlon - CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which - // only Hammer will have anyway) - CPUF_SSE3 = 0x100, // PIV+, Hammer - CPUF_SSSE3 = 0x200, // prescott? - CPUF_SSE4 = 0x400, // penryn - CPUF_SSE4_2 = 0x800 // Core iX -}; - -//josh: changed these just bc winsdk defines them in BaseTsd.h -#define MAX_INT MAXINT32 -#define MIN_INT MININT32 // ::FIXME:: research why this is not 0x80000000 - - - -class IClipLocalStorage; - -class IScriptEnvironment { -public: - virtual ~IScriptEnvironment() {} - - virtual /*static*/ long __stdcall GetCPUFlags() = 0; - - virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; - virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; - // note: val is really a va_list; I hope everyone typedefs va_list to a pointer - virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; - - __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; - - class NotFound /*exception*/ {}; // thrown by Invoke and GetVar - - typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); - - virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; - virtual bool __stdcall FunctionExists(const char* name) = 0; - virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; - - virtual AVSValue __stdcall GetVar(const char* name) = 0; - virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; - virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; - - virtual void __stdcall PushContext(int level=0) = 0; - virtual void __stdcall PopContext() = 0; - - // align should be 4 or 8 - virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0; - - virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; - - virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; - - typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); - virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; - - virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; - - virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; - - virtual int __stdcall SetMemoryMax(int mem) = 0; - - virtual int __stdcall SetWorkingDir(const char * newdir) = 0; - - virtual void* __stdcall ManageCache(int key, void* data) = 0; - - enum PlanarChromaAlignmentMode { - PlanarChromaAlignmentOff, - PlanarChromaAlignmentOn, - PlanarChromaAlignmentTest }; - - virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0; - - virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; - - virtual void __stdcall SetMTMode(int mode,int threads,bool temporary)=0; - virtual int __stdcall GetMTMode(bool return_nthreads)=0; - - virtual IClipLocalStorage* __stdcall AllocClipLocalStorage()=0; - - virtual void __stdcall SaveClipLocalStorage()=0; - virtual void __stdcall RestoreClipLocalStorage()=0; -}; - - -// avisynth.dll exports this; it's a way to use it as a library, without -// writing an AVS script or without going through AVIFile. -IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); - - -#pragma pack(pop) - -#endif //__AVISYNTH_H__ diff --git a/include/avisynth/avs/alignment.h b/include/avisynth/avs/alignment.h new file mode 100644 index 0000000..170d9cc --- /dev/null +++ b/include/avisynth/avs/alignment.h @@ -0,0 +1,134 @@ +// Avisynth C Interface Version 0.20 +// Copyright 2003 Kevin Atkinson + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// As a special exception, I give you permission to link to the +// Avisynth C interface with independent modules that communicate with +// the Avisynth C interface solely through the interfaces defined in +// avisynth_c.h, regardless of the license terms of these independent +// modules, and to copy and distribute the resulting combined work +// under terms of your choice, provided that every copy of the +// combined work is accompanied by a complete copy of the source code +// of the Avisynth C interface and Avisynth itself (with the version +// used to produce the combined work), being distributed under the +// terms of the GNU General Public License plus this exception. An +// independent module is a module which is not derived from or based +// on Avisynth C Interface, such as 3rd-party filters, import and +// export plugins, or graphical user interfaces. + +#ifndef AVS_ALIGNMENT_H +#define AVS_ALIGNMENT_H + +// Functions and macros to help work with alignment requirements. + +// Tells if a number is a power of two. +#define IS_POWER2(n) ((n) && !((n) & ((n) - 1))) + +// Tells if the pointer "ptr" is aligned to "align" bytes. +#define IS_PTR_ALIGNED(ptr, align) (((uintptr_t)ptr & ((uintptr_t)(align-1))) == 0) + +// Rounds up the number "n" to the next greater multiple of "align" +#define ALIGN_NUMBER(n, align) (((n) + (align)-1) & (~((align)-1))) + +// Rounds up the pointer address "ptr" to the next greater multiple of "align" +#define ALIGN_POINTER(ptr, align) (((uintptr_t)(ptr) + (align)-1) & (~(uintptr_t)((align)-1))) + +#ifdef __cplusplus + +#include +#include +#include +#include "config.h" + +#if defined(MSVC) && _MSC_VER<1400 + // needed for VS2013, otherwise C++11 'alignas' works + #define avs_alignas(x) __declspec(align(x)) +#else + // assumes C++11 support + #define avs_alignas(x) alignas(x) +#endif + +template +static bool IsPtrAligned(T* ptr, size_t align) +{ + assert(IS_POWER2(align)); + return (bool)IS_PTR_ALIGNED(ptr, align); +} + +template +static T AlignNumber(T n, T align) +{ + assert(IS_POWER2(align)); + return ALIGN_NUMBER(n, align); +} + +template +static T* AlignPointer(T* ptr, size_t align) +{ + assert(IS_POWER2(align)); + return (T*)ALIGN_POINTER(ptr, align); +} + +extern "C" +{ +#else +#include +#endif // __cplusplus + +// Returns a new buffer that is at least the size "nbytes". +// The buffer will be aligned to "align" bytes. +// Returns NULL on error. On successful allocation, +// the returned buffer must be freed using "avs_free". +inline void* avs_malloc(size_t nbytes, size_t align) +{ + if (!IS_POWER2(align)) + return NULL; + + size_t offset = sizeof(void*) + align - 1; + + void *orig = malloc(nbytes + offset); + if (orig == NULL) + return NULL; + + void **aligned = (void**)(((uintptr_t)orig + (uintptr_t)offset) & (~(uintptr_t)(align-1))); + aligned[-1] = orig; + return aligned; +} + +// Buffers allocated using "avs_malloc" must be freed +// using "avs_free" instead of "free". +inline void avs_free(void *ptr) +{ + // Mirroring free()'s semantic requires us to accept NULLs + if (ptr == NULL) + return; + + free(((void**)ptr)[-1]); +} + +#ifdef __cplusplus +} // extern "C" + +// The point of these undef's is to force using the template functions +// if we are in C++ mode. For C, the user can rely only on the macros. +#undef IS_PTR_ALIGNED +#undef ALIGN_NUMBER +#undef ALIGN_POINTER + +#endif // __cplusplus + +#endif //AVS_ALIGNMENT_H diff --git a/include/avisynth/avs/capi.h b/include/avisynth/avs/capi.h new file mode 100644 index 0000000..7629296 --- /dev/null +++ b/include/avisynth/avs/capi.h @@ -0,0 +1,121 @@ +// Avisynth C Interface Version 0.20 +// Copyright 2003 Kevin Atkinson + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// As a special exception, I give you permission to link to the +// Avisynth C interface with independent modules that communicate with +// the Avisynth C interface solely through the interfaces defined in +// avisynth_c.h, regardless of the license terms of these independent +// modules, and to copy and distribute the resulting combined work +// under terms of your choice, provided that every copy of the +// combined work is accompanied by a complete copy of the source code +// of the Avisynth C interface and Avisynth itself (with the version +// used to produce the combined work), being distributed under the +// terms of the GNU General Public License plus this exception. An +// independent module is a module which is not derived from or based +// on Avisynth C Interface, such as 3rd-party filters, import and +// export plugins, or graphical user interfaces. + +#ifndef AVS_CAPI_H +#define AVS_CAPI_H + +#include "config.h" + +#ifdef AVS_POSIX +// this is also defined in avs/posix.h +#ifndef AVS_HAIKU +#define __declspec(x) +#endif +#endif + +#ifdef __cplusplus +# define EXTERN_C extern "C" +#else +# define EXTERN_C +#endif + +#ifdef AVS_WINDOWS +#ifdef BUILDING_AVSCORE +# if defined(GCC) && defined(X86_32) +# define AVSC_CC +# else // MSVC builds and 64-bit GCC +# ifndef AVSC_USE_STDCALL +# define AVSC_CC __cdecl +# else +# define AVSC_CC __stdcall +# endif +# endif +#else // needed for programs that talk to AviSynth+ +# ifndef AVSC_WIN32_GCC32 // see comment below +# ifndef AVSC_USE_STDCALL +# define AVSC_CC __cdecl +# else +# define AVSC_CC __stdcall +# endif +# else +# define AVSC_CC +# endif +#endif +# else +# define AVSC_CC +#endif + +// On 64-bit Windows, there's only one calling convention, +// so there is no difference between MSVC and GCC. On 32-bit, +// this isn't true. The convention that GCC needs to use to +// even build AviSynth+ as 32-bit makes anything that uses +// it incompatible with 32-bit MSVC builds of AviSynth+. +// The AVSC_WIN32_GCC32 define is meant to provide a user +// switchable way to make builds of FFmpeg to test 32-bit +// GCC builds of AviSynth+ without having to screw around +// with alternate headers, while still default to the usual +// situation of using 32-bit MSVC builds of AviSynth+. + +// Hopefully, this situation will eventually be resolved +// and a broadly compatible solution will arise so the +// same 32-bit FFmpeg build can handle either MSVC or GCC +// builds of AviSynth+. + +#define AVSC_INLINE static __inline + +#ifdef BUILDING_AVSCORE +#ifdef AVS_WINDOWS +# ifndef AVS_STATIC_LIB +# define AVSC_EXPORT __declspec(dllexport) +# else +# define AVSC_EXPORT +# endif +# define AVSC_API(ret, name) EXTERN_C AVSC_EXPORT ret AVSC_CC name +#else +# define AVSC_EXPORT EXTERN_C +# define AVSC_API(ret, name) EXTERN_C ret AVSC_CC name +#endif +#else +# define AVSC_EXPORT EXTERN_C __declspec(dllexport) +# ifndef AVS_STATIC_LIB +# define AVSC_IMPORT __declspec(dllimport) +# else +# define AVSC_IMPORT +# endif +# ifndef AVSC_NO_DECLSPEC +# define AVSC_API(ret, name) EXTERN_C AVSC_IMPORT ret AVSC_CC name +# else +# define AVSC_API(ret, name) typedef ret (AVSC_CC *name##_func) +# endif +#endif + +#endif //AVS_CAPI_H diff --git a/include/avisynth/avs/config.h b/include/avisynth/avs/config.h new file mode 100644 index 0000000..bdabf17 --- /dev/null +++ b/include/avisynth/avs/config.h @@ -0,0 +1,173 @@ +// Avisynth C Interface Version 0.20 +// Copyright 2003 Kevin Atkinson + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// As a special exception, I give you permission to link to the +// Avisynth C interface with independent modules that communicate with +// the Avisynth C interface solely through the interfaces defined in +// avisynth_c.h, regardless of the license terms of these independent +// modules, and to copy and distribute the resulting combined work +// under terms of your choice, provided that every copy of the +// combined work is accompanied by a complete copy of the source code +// of the Avisynth C interface and Avisynth itself (with the version +// used to produce the combined work), being distributed under the +// terms of the GNU General Public License plus this exception. An +// independent module is a module which is not derived from or based +// on Avisynth C Interface, such as 3rd-party filters, import and +// export plugins, or graphical user interfaces. + +#ifndef AVS_CONFIG_H +#define AVS_CONFIG_H + +// Undefine this to get cdecl calling convention +#define AVSC_USE_STDCALL 1 + +// NOTE TO PLUGIN AUTHORS: +// Because FRAME_ALIGN can be substantially higher than the alignment +// a plugin actually needs, plugins should not use FRAME_ALIGN to check for +// alignment. They should always request the exact alignment value they need. +// This is to make sure that plugins work over the widest range of AviSynth +// builds possible. +#define FRAME_ALIGN 64 + +#if defined(_M_AMD64) || defined(__x86_64) +# define X86_64 +#elif defined(_M_IX86) || defined(__i386__) +# define X86_32 +// VS2017 introduced _M_ARM64 +#elif defined(_M_ARM64) || defined(__aarch64__) +# define ARM64 +#elif defined(_M_ARM) || defined(__arm__) +# define ARM32 +#elif defined(__PPC64__) +# define PPC64 +#elif defined(_M_PPC) || defined(__PPC__) || defined(__POWERPC__) +# define PPC32 +#elif defined(__riscv) +# define RISCV +#elif defined(__sparc_v9__) +# define SPARC +#elif defined(__mips__) +# define MIPS +#else +# error Unsupported CPU architecture. +#endif + +// VC++ LLVM-Clang-cl MinGW-Gnu +// MSVC x x +// MSVC_PURE x +// CLANG x +// GCC x + +#if defined(__clang__) +// Check clang first. clang-cl also defines __MSC_VER +// We set MSVC because they are mostly compatible +# define CLANG +#if defined(_MSC_VER) +# define MSVC +# define AVS_FORCEINLINE __attribute__((always_inline)) +#else +# define AVS_FORCEINLINE __attribute__((always_inline)) inline +#endif +#elif defined(_MSC_VER) +# define MSVC +# define MSVC_PURE +# define AVS_FORCEINLINE __forceinline +#elif defined(__GNUC__) +# define GCC +# define AVS_FORCEINLINE __attribute__((always_inline)) inline +#elif defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER) +// Intel C++ Compilers with MSVC command line interface will not appear here rather at _MSC_VER +# define AVS_FORCEINLINE inline +# undef __forceinline +# define __forceinline inline +#else +# error Unsupported compiler. +# define AVS_FORCEINLINE inline +# undef __forceinline +# define __forceinline inline +#endif + +#if defined(_WIN32) +# define AVS_WINDOWS +#elif defined(__linux__) +# define AVS_LINUX +# define AVS_POSIX +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# define AVS_BSD +# define AVS_POSIX +#elif defined(__APPLE__) +# define AVS_MACOS +# define AVS_POSIX +#elif defined(__HAIKU__) +# define AVS_HAIKU +# define AVS_POSIX +#else +# error Operating system unsupported. +#endif + +// useful warnings disabler macros for supported compilers + +#if defined(_MSC_VER) +#define DISABLE_WARNING_PUSH __pragma(warning( push )) +#define DISABLE_WARNING_POP __pragma(warning( pop )) +#define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber )) + +#define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE DISABLE_WARNING(4101) +#define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(4505) +// other warnings you want to deactivate... + +#elif defined(__GNUC__) || defined(__clang__) +#define DO_PRAGMA(X) _Pragma(#X) +#define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push) +#define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop) +#define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName) + +#define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE DISABLE_WARNING(-Wunused-variable) +#define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(-Wunused-function) +// other warnings you want to deactivate... + +#else +#define DISABLE_WARNING_PUSH +#define DISABLE_WARNING_POP +#define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE +#define DISABLE_WARNING_UNREFERENCED_FUNCTION +// other warnings you want to deactivate... + +#endif + +#if defined(AVS_WINDOWS) && defined(_USING_V110_SDK71_) +// Windows XP does not have proper initialization for +// thread local variables. +// Use workaround instead __declspec(thread) +#define XP_TLS +#endif + +#ifndef MSVC +// GCC and Clang can be used on big endian systems, MSVC can't. +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define AVS_ENDIANNESS "little" +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define AVS_ENDIANNESS "big" +# else +# define AVS_ENDIANNESS "middle" +# endif +#else +#define AVS_ENDIANNESS "little" +#endif + +#endif //AVS_CONFIG_H diff --git a/include/avisynth/avs/cpuid.h b/include/avisynth/avs/cpuid.h new file mode 100644 index 0000000..024e843 --- /dev/null +++ b/include/avisynth/avs/cpuid.h @@ -0,0 +1,81 @@ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// Linking Avisynth statically or dynamically with other modules is making a +// combined work based on Avisynth. Thus, the terms and conditions of the GNU +// General Public License cover the whole combination. +// +// As a special exception, the copyright holders of Avisynth give you +// permission to link Avisynth with independent modules that communicate with +// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license +// terms of these independent modules, and to copy and distribute the +// resulting combined work under terms of your choice, provided that +// every copy of the combined work is accompanied by a complete copy of +// the source code of Avisynth (the version of Avisynth used to produce the +// combined work), being distributed under the terms of the GNU General +// Public License plus this exception. An independent module is a module +// which is not derived from or based on Avisynth, such as 3rd-party filters, +// import and export plugins, or graphical user interfaces. + +#ifndef AVSCORE_CPUID_H +#define AVSCORE_CPUID_H + +// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. +// ending with SSE4_2 +// For emulation see https://software.intel.com/en-us/articles/intel-software-development-emulator +enum { + /* oldest CPU to support extension */ + CPUF_FORCE = 0x01, // N/A + CPUF_FPU = 0x02, // 386/486DX + CPUF_MMX = 0x04, // P55C, K6, PII + CPUF_INTEGER_SSE = 0x08, // PIII, Athlon + CPUF_SSE = 0x10, // PIII, Athlon XP/MP + CPUF_SSE2 = 0x20, // PIV, K8 + CPUF_3DNOW = 0x40, // K6-2 + CPUF_3DNOW_EXT = 0x80, // Athlon + CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which + // only Hammer will have anyway) + CPUF_SSE3 = 0x100, // PIV+, K8 Venice + CPUF_SSSE3 = 0x200, // Core 2 + CPUF_SSE4 = 0x400, + CPUF_SSE4_1 = 0x400, // Penryn, Wolfdale, Yorkfield + CPUF_AVX = 0x800, // Sandy Bridge, Bulldozer + CPUF_SSE4_2 = 0x1000, // Nehalem + // AVS+ + CPUF_AVX2 = 0x2000, // Haswell + CPUF_FMA3 = 0x4000, + CPUF_F16C = 0x8000, + CPUF_MOVBE = 0x10000, // Big Endian move + CPUF_POPCNT = 0x20000, + CPUF_AES = 0x40000, + CPUF_FMA4 = 0x80000, + + CPUF_AVX512F = 0x100000, // AVX-512 Foundation. + CPUF_AVX512DQ = 0x200000, // AVX-512 DQ (Double/Quad granular) Instructions + CPUF_AVX512PF = 0x400000, // AVX-512 Prefetch + CPUF_AVX512ER = 0x800000, // AVX-512 Exponential and Reciprocal + CPUF_AVX512CD = 0x1000000, // AVX-512 Conflict Detection + CPUF_AVX512BW = 0x2000000, // AVX-512 BW (Byte/Word granular) Instructions + CPUF_AVX512VL = 0x4000000, // AVX-512 VL (128/256 Vector Length) Extensions + CPUF_AVX512IFMA = 0x8000000, // AVX-512 IFMA integer 52 bit + CPUF_AVX512VBMI = 0x10000000,// AVX-512 VBMI +}; + +#ifdef BUILDING_AVSCORE +int GetCPUFlags(); +void SetMaxCPU(int new_flags); +#endif + +#endif // AVSCORE_CPUID_H diff --git a/include/avisynth/avs/filesystem.h b/include/avisynth/avs/filesystem.h new file mode 100644 index 0000000..8544fd5 --- /dev/null +++ b/include/avisynth/avs/filesystem.h @@ -0,0 +1,15 @@ +#pragma once + +// Snippet copied from filesystem/README.md + +#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) +#if __has_include() +#define GHC_USE_STD_FS +#include +namespace fs = std::filesystem; +#endif +#endif +#ifndef GHC_USE_STD_FS +#include +namespace fs = ghc::filesystem; +#endif diff --git a/include/avisynth/avs/minmax.h b/include/avisynth/avs/minmax.h new file mode 100644 index 0000000..521ea58 --- /dev/null +++ b/include/avisynth/avs/minmax.h @@ -0,0 +1,54 @@ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// Linking Avisynth statically or dynamically with other modules is making a +// combined work based on Avisynth. Thus, the terms and conditions of the GNU +// General Public License cover the whole combination. +// +// As a special exception, the copyright holders of Avisynth give you +// permission to link Avisynth with independent modules that communicate with +// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license +// terms of these independent modules, and to copy and distribute the +// resulting combined work under terms of your choice, provided that +// every copy of the combined work is accompanied by a complete copy of +// the source code of Avisynth (the version of Avisynth used to produce the +// combined work), being distributed under the terms of the GNU General +// Public License plus this exception. An independent module is a module +// which is not derived from or based on Avisynth, such as 3rd-party filters, +// import and export plugins, or graphical user interfaces. + +#ifndef AVSCORE_MINMAX_H +#define AVSCORE_MINMAX_H + +template +T min(T v1, T v2) +{ + return v1 < v2 ? v1 : v2; +} + +template +T max(T v1, T v2) +{ + return v1 > v2 ? v1 : v2; +} + +template +T clamp(T n, T min, T max) +{ + n = n > max ? max : n; + return n < min ? min : n; +} + +#endif // AVSCORE_MINMAX_H diff --git a/include/avisynth/avs/posix.h b/include/avisynth/avs/posix.h new file mode 100644 index 0000000..3f72642 --- /dev/null +++ b/include/avisynth/avs/posix.h @@ -0,0 +1,129 @@ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// Linking Avisynth statically or dynamically with other modules is making a +// combined work based on Avisynth. Thus, the terms and conditions of the GNU +// General Public License cover the whole combination. +// +// As a special exception, the copyright holders of Avisynth give you +// permission to link Avisynth with independent modules that communicate with +// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license +// terms of these independent modules, and to copy and distribute the +// resulting combined work under terms of your choice, provided that +// every copy of the combined work is accompanied by a complete copy of +// the source code of Avisynth (the version of Avisynth used to produce the +// combined work), being distributed under the terms of the GNU General +// Public License plus this exception. An independent module is a module +// which is not derived from or based on Avisynth, such as 3rd-party filters, +// import and export plugins, or graphical user interfaces. + +#ifdef AVS_POSIX +#ifndef AVSCORE_POSIX_H +#define AVSCORE_POSIX_H + +#ifdef __cplusplus +#include +#endif +#include +#include + +// Define these MSVC-extension used in Avisynth +#define __single_inheritance + +// These things don't exist in Linux +#if defined(AVS_HAIKU) +#undef __declspec +#endif +#define __declspec(x) +#define lstrlen strlen +#define lstrcmp strcmp +#define lstrcmpi strcasecmp +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#define _strdup strdup +#define SetCurrentDirectory(x) chdir(x) +#define SetCurrentDirectoryW(x) chdir(x) +#define GetCurrentDirectoryW(x) getcwd(x) +#define _putenv putenv +#define _alloca alloca + +// Borrowing some compatibility macros from AvxSynth, slightly modified +#define UInt32x32To64(a, b) ((uint64_t)(((uint64_t)((uint32_t)(a))) * ((uint32_t)(b)))) +#define Int64ShrlMod32(a, b) ((uint64_t)((uint64_t)(a) >> (b))) +#define Int32x32To64(a, b) ((int64_t)(((int64_t)((long)(a))) * ((long)(b)))) + +#define InterlockedIncrement(x) __sync_add_and_fetch((x), 1) +#define InterlockedDecrement(x) __sync_sub_and_fetch((x), 1) +#define MulDiv(nNumber, nNumerator, nDenominator) (int32_t) (((int64_t) (nNumber) * (int64_t) (nNumerator) + (int64_t) ((nDenominator)/2)) / (int64_t) (nDenominator)) + +#ifndef TRUE +#define TRUE true +#endif + +#ifndef FALSE +#define FALSE false +#endif + +#define S_FALSE (0x00000001) +#define E_FAIL (0x80004005) +#define FAILED(hr) ((hr) & 0x80000000) +#define SUCCEEDED(hr) (!FAILED(hr)) + +// Statuses copied from comments in exception.cpp +#define STATUS_GUARD_PAGE_VIOLATION 0x80000001 +#define STATUS_DATATYPE_MISALIGNMENT 0x80000002 +#define STATUS_BREAKPOINT 0x80000003 +#define STATUS_SINGLE_STEP 0x80000004 +#define STATUS_ACCESS_VIOLATION 0xc0000005 +#define STATUS_IN_PAGE_ERROR 0xc0000006 +#define STATUS_INVALID_HANDLE 0xc0000008 +#define STATUS_NO_MEMORY 0xc0000017 +#define STATUS_ILLEGAL_INSTRUCTION 0xc000001d +#define STATUS_NONCONTINUABLE_EXCEPTION 0xc0000025 +#define STATUS_INVALID_DISPOSITION 0xc0000026 +#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xc000008c +#define STATUS_FLOAT_DENORMAL_OPERAND 0xc000008d +#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xc000008e +#define STATUS_FLOAT_INEXACT_RESULT 0xc000008f +#define STATUS_FLOAT_INVALID_OPERATION 0xc0000090 +#define STATUS_FLOAT_OVERFLOW 0xc0000091 +#define STATUS_FLOAT_STACK_CHECK 0xc0000092 +#define STATUS_FLOAT_UNDERFLOW 0xc0000093 +#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xc0000094 +#define STATUS_INTEGER_OVERFLOW 0xc0000095 +#define STATUS_PRIVILEGED_INSTRUCTION 0xc0000096 +#define STATUS_STACK_OVERFLOW 0xc00000fd + +// Calling convension +#ifndef AVS_HAIKU +#define __stdcall +#define __cdecl +#endif + +// PowerPC OS X is really niche these days, but this painless equivocation +// of the function/macro names used in posix_get_available_memory() +// is all it takes to let it work. The G5 was 64-bit, and if 10.5 Leopard +// can run in native 64-bit, it probably uses the names in that block as-is. +#ifdef AVS_MACOS +#ifdef PPC32 +#define vm_statistics64_data_t vm_statistics_data_t +#define HOST_VM_INFO64_COUNT HOST_VM_INFO_COUNT +#define HOST_VM_INFO64 HOST_VM_INFO +#define host_statistics64 host_statistics +#endif // PPC32 +#endif // AVS_MACOS + +#endif // AVSCORE_POSIX_H +#endif // AVS_POSIX diff --git a/include/avisynth/avs/types.h b/include/avisynth/avs/types.h new file mode 100644 index 0000000..19cc455 --- /dev/null +++ b/include/avisynth/avs/types.h @@ -0,0 +1,54 @@ +// Avisynth C Interface Version 0.20 +// Copyright 2003 Kevin Atkinson + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// As a special exception, I give you permission to link to the +// Avisynth C interface with independent modules that communicate with +// the Avisynth C interface solely through the interfaces defined in +// avisynth_c.h, regardless of the license terms of these independent +// modules, and to copy and distribute the resulting combined work +// under terms of your choice, provided that every copy of the +// combined work is accompanied by a complete copy of the source code +// of the Avisynth C interface and Avisynth itself (with the version +// used to produce the combined work), being distributed under the +// terms of the GNU General Public License plus this exception. An +// independent module is a module which is not derived from or based +// on Avisynth C Interface, such as 3rd-party filters, import and +// export plugins, or graphical user interfaces. + +#ifndef AVS_TYPES_H +#define AVS_TYPES_H + +// Define all types necessary for interfacing with avisynth.dll +#include +#include +#ifdef __cplusplus + #include + #include +#else + #include + #include +#endif + +// Raster types used by VirtualDub & Avisynth +typedef uint32_t Pixel32; +typedef uint8_t BYTE; + +// Audio Sample information +typedef float SFLOAT; + +#endif //AVS_TYPES_H diff --git a/include/avisynth/avs/win.h b/include/avisynth/avs/win.h new file mode 100644 index 0000000..6692021 --- /dev/null +++ b/include/avisynth/avs/win.h @@ -0,0 +1,54 @@ +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// Linking Avisynth statically or dynamically with other modules is making a +// combined work based on Avisynth. Thus, the terms and conditions of the GNU +// General Public License cover the whole combination. +// +// As a special exception, the copyright holders of Avisynth give you +// permission to link Avisynth with independent modules that communicate with +// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license +// terms of these independent modules, and to copy and distribute the +// resulting combined work under terms of your choice, provided that +// every copy of the combined work is accompanied by a complete copy of +// the source code of Avisynth (the version of Avisynth used to produce the +// combined work), being distributed under the terms of the GNU General +// Public License plus this exception. An independent module is a module +// which is not derived from or based on Avisynth, such as 3rd-party filters, +// import and export plugins, or graphical user interfaces. + +#ifndef AVSCORE_WIN_H +#define AVSCORE_WIN_H + +// Whenever you need windows headers, start by including this file, then the rest. + +// WWUUT? We require XP now? +#if !defined(NTDDI_VERSION) && !defined(_WIN32_WINNT) + #define NTDDI_VERSION 0x05020000 + #define _WIN32_WINNT 0x0502 +#endif + +#define WIN32_LEAN_AND_MEAN +#define STRICT +#if !defined(NOMINMAX) + #define NOMINMAX +#endif + +#include + +// Provision for UTF-8 max 4 bytes per code point +#define AVS_MAX_PATH MAX_PATH*4 + +#endif // AVSCORE_WIN_H diff --git a/src/subpic/MemSubPic.cpp b/src/subpic/MemSubPic.cpp index 79dbe3a..d1a6b09 100644 --- a/src/subpic/MemSubPic.cpp +++ b/src/subpic/MemSubPic.cpp @@ -82,9 +82,18 @@ bool fColorConvInitOK = false; const float(*MATRIX)[4] = MATRIX_BT_601; const float(*MATRIX_INV)[4] = MATRIX_BT_601_INV; const int(*RANGE)[4] = YUV_TV; + +static int g_lastMatrix = -1; +static int g_lastRange = -1; + void ColorConvInitOther(int inYCbCrMatrix, int inYCbCrRange) { - if(fColorConvInitOK) return; + if(fColorConvInitOK && g_lastMatrix == inYCbCrMatrix && g_lastRange == inYCbCrRange) + return; + + g_lastMatrix = inYCbCrMatrix; + g_lastRange = inYCbCrRange; + if (inYCbCrMatrix == YCbCrMatrix_BT601) { MATRIX = MATRIX_BT_601; @@ -252,11 +261,12 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) if(m_rcDirty.IsRectEmpty()) return S_OK; - if(m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_AYUV) + if(m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_AYUV || m_spd.type == MSP_YV16 + || m_spd.type == MSP_YV24) { ColorConvInitOther(m_eYCbCrMatrix, m_eYCbCrRange); - if(m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV) + if(m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_YV16) { m_rcDirty.left &= ~1; m_rcDirty.right = (m_rcDirty.right + 1)&~1; @@ -300,7 +310,7 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) } } } - else if(m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV) + else if(m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_YV16) { for(; top < bottom ; top += m_spd.pitch) { @@ -326,7 +336,7 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) } } } - else if(m_spd.type == MSP_AYUV) + else if(m_spd.type == MSP_AYUV || m_spd.type == MSP_YV24) { for(; top < bottom ; top += m_spd.pitch) { @@ -397,7 +407,7 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) { d = (BYTE*)dst.bits + dst.pitch * (rd.top - 1) + (rd.left * dst.bpp >> 3); } - else if(dst.type == MSP_YV12 || dst.type == MSP_IYUV) + else if(dst.type == MSP_YV12 || dst.type == MSP_IYUV || dst.type == MSP_YV16 || dst.type == MSP_YV24) { d = (BYTE*)dst.bits + dst.pitch * (rd.top - 1) + (rd.left * 8 >> 3); } @@ -564,7 +574,7 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) } } } - else if(dst.type == MSP_YV12 || dst.type == MSP_IYUV) + else if(dst.type == MSP_YV12 || dst.type == MSP_IYUV || dst.type == MSP_YV16) { BYTE* s2 = s; BYTE* s2end = s2 + w * 4; @@ -577,6 +587,17 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) } } } + else if (dst.type == MSP_YV24) + { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + BYTE* d2 = d; + for (; s2 < s2end; s2 += 4, d2++) + { + if (s2[3] < 0xff) + d2[0] = (((d2[0] - RANGE[0][3]) * s2[3]) >> 8) + s2[2]; + } + } else { return E_NOTIMPL; @@ -585,17 +606,20 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) dst.pitch = abs(dst.pitch); - if(dst.type == MSP_YV12 || dst.type == MSP_IYUV) + if(dst.type == MSP_YV12 || dst.type == MSP_IYUV || dst.type == MSP_YV16 || dst.type == MSP_YV24) { - int h2 = h / 2; + int h_loop = h; + if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) + h_loop = h / 2; if(!dst.pitchUV) { - dst.pitchUV = dst.pitch / 2; + if (dst.type == MSP_YV24) + dst.pitchUV = dst.pitch; + else + dst.pitchUV = dst.pitch / 2; } - int sizep4 = dst.pitchUV * dst.h / 2; - BYTE* ss[2]; ss[0] = (BYTE*)src.bits + src.pitch * rs.top + rs.left * 4; ss[1] = ss[0] + 4; @@ -603,7 +627,12 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) if(!dst.bitsU || !dst.bitsV) { dst.bitsU = (BYTE*)dst.bits + dst.pitch * dst.h; - dst.bitsV = dst.bitsU + dst.pitchUV * dst.h / 2; + + int u_height = dst.h; + if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) + u_height = dst.h / 2; + + dst.bitsV = dst.bitsU + dst.pitchUV * u_height; if(dst.type == MSP_YV12) { @@ -614,33 +643,68 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) } BYTE* dd[2]; - dd[0] = dst.bitsU + dst.pitchUV * rd.top / 2 + rd.left / 2; - dd[1] = dst.bitsV + dst.pitchUV * rd.top / 2 + rd.left / 2; + int v_shift = (dst.type == MSP_YV12 || dst.type == MSP_IYUV) ? 1 : 0; + int h_shift = (dst.type == MSP_YV24) ? 0 : 1; + + dd[0] = dst.bitsU + dst.pitchUV * (rd.top >> v_shift) + (rd.left >> h_shift); + dd[1] = dst.bitsV + dst.pitchUV * (rd.top >> v_shift) + (rd.left >> h_shift); if(rd.top > rd.bottom) { - dd[0] = dst.bitsU + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; - dd[1] = dst.bitsV + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; + dd[0] = dst.bitsU + dst.pitchUV * ((rd.top >> v_shift) - 1) + (rd.left >> h_shift); + dd[1] = dst.bitsV + dst.pitchUV * ((rd.top >> v_shift) - 1) + (rd.left >> h_shift); dst.pitchUV = -dst.pitchUV; } + int src_pitch_step = src.pitch; + if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) + src_pitch_step *= 2; + for(ptrdiff_t i = 0; i < 2; i++) { s = ss[i]; d = dd[i]; BYTE* is = ss[1-i]; - for(ptrdiff_t j = 0; j < h2; j++, s += src.pitch * 2, d += dst.pitchUV, is += src.pitch * 2) + + if (dst.type == MSP_YV24 && i == 1) + s = ss[0]; + + for(ptrdiff_t j = 0; j < h_loop; j++, s += src_pitch_step, d += dst.pitchUV, is += src_pitch_step) { BYTE* s2 = s; BYTE* s2end = s2 + w * 4; BYTE* d2 = d; BYTE* is2 = is; - for(; s2 < s2end; s2 += 8, d2++, is2 += 8) + if (dst.type == MSP_YV24) + { + int offset = (i == 0) ? 1 : 0; + + for (; s2 < s2end; s2 += 4, d2++) + { + if (s2[3] < 0xff) + *d2 = (((*d2 - RANGE[i + 1][3]) * s2[3]) >> 8) + s2[offset]; + } + } + else { - unsigned int ia = (s2[3] + s2[3+src.pitch] + is2[3] + is2[3+src.pitch]) >> 2; - if(ia < 0xff) + for (; s2 < s2end; s2 += 8, d2++, is2 += 8) { - *d2 = (((*d2 - RANGE[i+1][3]) * ia) >> 8) + ((s2[0] + s2[src.pitch]) >> 1); + unsigned int ia; + int val; + + if (dst.type == MSP_YV16) + { + ia = (s2[3] + is2[3]) >> 1; + val = s2[0]; + } + else + { + ia = (s2[3] + s2[3 + src.pitch] + is2[3] + is2[3 + src.pitch]) >> 2; + val = (s2[0] + s2[src.pitch]) >> 1; + } + + if (ia < 0xff) + *d2 = (((*d2 - RANGE[i + 1][3]) * ia) >> 8) + val; } } } diff --git a/src/subpic/MemSubPic.h b/src/subpic/MemSubPic.h index 96d45ce..95439cc 100644 --- a/src/subpic/MemSubPic.h +++ b/src/subpic/MemSubPic.h @@ -23,7 +23,7 @@ #include "ISubPic.h" -enum {MSP_RGB32, MSP_RGB24, MSP_RGB16, MSP_RGB15, MSP_YUY2, MSP_YV12, MSP_IYUV, MSP_AYUV, MSP_RGBA}; +enum {MSP_RGB32, MSP_RGB24, MSP_RGB16, MSP_RGB15, MSP_YUY2, MSP_YV12, MSP_IYUV, MSP_AYUV, MSP_RGBA, MSP_YV16, MSP_YV24}; enum YCbCrMatrix { YCbCrMatrix_BT601, diff --git a/src/vsfilter/VSFilterMod.rc b/src/vsfilter/VSFilterMod.rc index 43f7ba0..58beb67 100644 --- a/src/vsfilter/VSFilterMod.rc +++ b/src/vsfilter/VSFilterMod.rc @@ -13,7 +13,7 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// 匈牙利语(匈牙利) resources +// Hungarian (Hungary) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_HUN) LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT @@ -32,12 +32,12 @@ END #endif // APSTUDIO_INVOKED -#endif // 匈牙利语(匈牙利) resources +#endif // Hungarian (Hungary) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -// 英语(美国) resources +// English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US @@ -69,8 +69,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,5,2,7 - PRODUCTVERSION 2,5,2,7 + FILEVERSION 2,5,8,94 + PRODUCTVERSION 2,5,8,94 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -88,12 +88,12 @@ BEGIN VALUE "Comments", "http://code.google.com/p/vsfiltermod/" VALUE "CompanyName", "MPC-HC Team" VALUE "FileDescription", "VobSub & TextSubMod filter for DirectShow/VirtualDub/Avisynth/VapourSynth" - VALUE "FileVersion", "2.5.2.7" + VALUE "FileVersion", "2.5.8.94" VALUE "InternalName", "VSFilter" VALUE "LegalCopyright", "Copyright (C) 2001-2020 see AUTHORS file" VALUE "OriginalFilename", "VSFilterMod.dll" VALUE "ProductName", "VSFilterMod" - VALUE "ProductVersion", "2.5.2.7" + VALUE "ProductVersion", "2.5.8.94" END END BLOCK "VarFileInfo" @@ -583,7 +583,7 @@ BEGIN IDS_RT_STYLE "Style2" END -#endif // 英语(美国) resources +#endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/src/vsfilter/plugins.cpp b/src/vsfilter/plugins.cpp index 1d279ca..c24a5db 100644 --- a/src/vsfilter/plugins.cpp +++ b/src/vsfilter/plugins.cpp @@ -43,6 +43,31 @@ std::unique_ptr Utf8ToWideChar(const char* s_ansi) return w_string; } +int DetectMatrix(int isoValue, int width, int height) +{ + switch (isoValue) + { + case 1: return YCbCrMatrix_BT709; + case 5: + case 6: return YCbCrMatrix_BT601; + case 9: + case 10: return YCbCrMatrix_BT2020; + default: break; + } + + if (height >= 2160) + return YCbCrMatrix_BT2020; + else if (height >= 720 || width >= 1280) + return YCbCrMatrix_BT709; + + return YCbCrMatrix_BT601; +} + +int DetectRange(int isoValue) +{ + return (isoValue == 0) ? YCbCrRange_PC : YCbCrRange_TV; +} + // // Generic interface // @@ -62,11 +87,12 @@ class CFilter : public CAMThread, public CCritSec CComPtr m_pSubPicProvider; DWORD_PTR m_SubPicProviderId; +public: CSimpleTextSubtitle::YCbCrMatrix m_script_selected_yuv; CSimpleTextSubtitle::YCbCrRange m_script_selected_range; -public: - CFilter() : m_fps(-1), m_SubPicProviderId(0) + CFilter() : m_fps(-1), m_SubPicProviderId(0), m_script_selected_yuv(CSimpleTextSubtitle::YCbCrMatrix_AUTO), + m_script_selected_range(CSimpleTextSubtitle::YCbCrRange_AUTO) { CAMThread::Create(); } @@ -554,6 +580,7 @@ extern "C" __declspec(dllexport) void __cdecl VirtualdubFilterModuleDeinit(VDXFi // Avisynth interface // +/* namespace AviSynth1 { #include @@ -680,53 +707,411 @@ extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit(IScrip return(NULL); } } +*/ -namespace AviSynth25 +#include + +namespace AviSynthPlus { -#include +#include static bool s_fSwapUV = false; +class AVSFFrameBuf +{ +protected: + AVSFFrameBuf() + : subpic{} + , subpic2{} + { + } + +public: + virtual ~AVSFFrameBuf() {} + virtual void WriteTo(PVideoFrame& frame) = 0; + SubPicDesc subpic; + SubPicDesc subpic2; + +private: + AVSFFrameBuf(const AVSFFrameBuf*) = delete; + AVSFFrameBuf* operator = (const AVSFFrameBuf*) = delete; +}; + +template +class AVSFYUVBuf : public AVSFFrameBuf +{ + uint8_t* Buffer; + + uint8_t* BufDatas[3]; + uint8_t* BufDatas2[3]; + int BufStrides[3]; + + template + static inline void SplitBits(int sampleCount, const uint16_t* src, uint8_t* dst1, uint8_t* dst2) + { + auto srcEnd = src + sampleCount; + auto sse2End = src + sampleCount - 8; + if (uintptr_t(src) & 0xf) + sse2End = src; + + __m128i lomask = _mm_set1_epi16(0xffi16); + while (src <= sse2End) + { + __m128i buf = _mm_load_si128((const __m128i*)src); + __m128i hi, lo; + + if (BC == 16) + { + hi = _mm_srli_epi16(buf, 8); + hi = _mm_packus_epi16(hi, hi); + lo = _mm_and_si128(buf, lomask); + lo = _mm_packus_epi16(lo, lo); + } + else if (BC == 10) + { + hi = _mm_srli_epi16(buf, 2); + hi = _mm_packus_epi16(hi, hi); + lo = _mm_slli_epi16(buf, 6); + lo = _mm_and_si128(lo, lomask); + lo = _mm_packus_epi16(lo, lo); + } + _mm_storel_epi64((__m128i*)dst1, hi); + _mm_storel_epi64((__m128i*)dst2, lo); + dst1 += 8; + dst2 += 8; + src += 8; + } + + while (src < srcEnd) + { + if (BITDEPTH == 10) + { + *dst1 = ((*src) >> 2) & 0xff; + *dst2 = ((*src) << 6) & 0xff; + } + else if (BITDEPTH == 16) + { + *dst1 = ((*src) >> 8) & 0xff; + *dst2 = (*src) & 0xff; + } + + dst1 += 1; + dst2 += 1; + src += 1; + } + } + + template + static inline void MergeBits(int sampleCount, uint16_t* dst, const uint8_t* src1, const uint8_t* src2) + { + auto srcEnd = dst + sampleCount; + auto sse2End = dst + sampleCount - 8; + if (uintptr_t(dst) & 0xf) + sse2End = dst; + + while (dst < sse2End) + { + __m128i hbuf = _mm_loadl_epi64((const __m128i*) src1); + __m128i lbuf = _mm_loadl_epi64((const __m128i*) src2); + hbuf = _mm_unpacklo_epi8(hbuf, _mm_setzero_si128()); + hbuf = _mm_slli_epi16(hbuf, 8); + lbuf = _mm_unpacklo_epi8(lbuf, _mm_setzero_si128()); + hbuf = _mm_adds_epi16(hbuf, lbuf); + if (BC == 10) + hbuf = _mm_srli_epi16(hbuf, 6); + + _mm_store_si128((__m128i*)dst, hbuf); + src1 += 8; + src2 += 8; + dst += 8; + } + + while (dst < srcEnd) + { + *dst = (*src1 << 8) | *src2; + if (BC == 10) + *dst >>= 6; + src1 += 1; + src2 += 1; + dst += 1; + } + } + +public: + ~AVSFYUVBuf() + { + if (Buffer) + free(Buffer); + } + + AVSFYUVBuf(PVideoFrame& frame, const VideoInfo& vi) + { + int totalSize = 0; + const int planes[3] = { PLANAR_Y, PLANAR_U, PLANAR_V }; + + const int heightY = frame->GetHeight(planes[0]); + const int heightUV = frame->GetHeight(planes[1]); + + for (int i = 0; i < 3; ++i) + { + BufStrides[i] = frame->GetPitch(planes[i]); + totalSize += BufStrides[i] * frame->GetHeight(planes[i]); + } + + if (BITDEPTH > 8) + totalSize *= 2; + + Buffer = (uint8_t*)malloc(totalSize); + + if (BITDEPTH <= 8) + { + uint8_t* currPtr = Buffer; + for (int i = 0; i < 3; ++i) + { + BufDatas[i] = currPtr; + currPtr += static_cast(BufStrides[i]) * frame->GetHeight(planes[i]); + + const uint8_t* p = frame->GetReadPtr(planes[i]); + memcpy(BufDatas[i], p, static_cast(frame->GetPitch(planes[i]) * frame->GetHeight(planes[i]))); + } + } + else + { + for (int i = 0; i < 3; ++i) + BufStrides[i] /= 2; + + uint8_t* currPtr = Buffer; + + for (int i = 0; i < 3; ++i) + { + BufDatas[i] = currPtr; + currPtr += static_cast(BufStrides[i] * frame->GetHeight(planes[i])); + } + + for (int i = 0; i < 3; ++i) + { + BufDatas2[i] = currPtr; + currPtr += static_cast(BufStrides[i] * frame->GetHeight(planes[i])); + } + + for (int i = 0; i < 3; ++i) + { + const uint8_t* p = frame->GetReadPtr(planes[i]); + int srcStride = frame->GetPitch(planes[i]); + int wEnd = frame->GetRowSize(planes[i]) / 2; + int hEnd = frame->GetHeight(planes[i]); + + for (int h = 0; h < hEnd; ++h) + { + const uint16_t* pSample = reinterpret_cast(p + h * srcStride); + uint8_t* pDstSample = BufDatas[i] + h * BufStrides[i]; + uint8_t* pDstSample2 = BufDatas2[i] + h * BufStrides[i]; + SplitBits(wEnd, pSample, pDstSample, pDstSample2); + } + } + } + + subpic.w = vi.width; + subpic.h = vi.height; + subpic.pitch = BufStrides[0]; + subpic.pitchUV = BufStrides[1]; + subpic.bits = BufDatas[0]; + subpic.bitsU = BufDatas[1]; + subpic.bitsV = BufDatas[2]; + subpic.bpp = 8; + + if (BITDEPTH > 8) + { + subpic2.w = vi.width; + subpic2.h = vi.height; + subpic2.pitch = BufStrides[0]; + subpic2.pitchUV = BufStrides[1]; + subpic2.bits = BufDatas2[0]; + subpic2.bitsU = BufDatas2[1]; + subpic2.bitsV = BufDatas2[2]; + subpic2.bpp = 8; + } + + int mspType = -1; + + if (vi.Is444()) + mspType = MSP_YV24; + else if (vi.Is422()) + mspType = MSP_YV16; + else if (vi.IsYV12() || vi.pixel_type == VideoInfo::CS_IYUV) + mspType = s_fSwapUV ? MSP_IYUV : MSP_YV12; + + if (mspType == -1) + mspType = MSP_YV12; + + subpic.type = mspType; + + if (BITDEPTH > 8) + subpic2.type = mspType; + } + + void WriteTo(PVideoFrame& frame) override + { + const int planes[3] = { PLANAR_Y, PLANAR_U, PLANAR_V }; + + if (BITDEPTH <= 8) + { + for (int i = 0; i < 3; ++i) + { + int dstStride = frame->GetPitch(planes[i]); + uint8_t* pDst = frame->GetWritePtr(planes[i]); + int srcStride = BufStrides[i]; + const uint8_t* pSrc = BufDatas[i]; + int wEnd = frame->GetRowSize(planes[i]); + int hEnd = frame->GetHeight(planes[i]); + for (int h = 0; h < hEnd; ++h) + { + uint8_t* pDstRow = pDst + h * dstStride; + const uint8_t* pSrcRow = pSrc + h * srcStride; + memcpy(pDstRow, pSrcRow, wEnd); + } + } + } + else + { + for (int i = 0; i < 3; ++i) + { + int dstStride = frame->GetPitch(planes[i]); + uint8_t* pDst = frame->GetWritePtr(planes[i]); + int srcStride = BufStrides[i]; + const uint8_t* pSrc = BufDatas[i]; + const uint8_t* pSrc2 = BufDatas2[i]; + int wEnd = frame->GetRowSize(planes[i]) / 2; + int hEnd = frame->GetHeight(planes[i]); + for (int h = 0; h < hEnd; ++h) + { + uint16_t* pDstSample = reinterpret_cast(pDst + h * dstStride); + const uint8_t* pSrcSample = pSrc + h * srcStride; + const uint8_t* pSrcSample2 = pSrc2 + h * srcStride; + + MergeBits(wEnd, pDstSample, pSrcSample, pSrcSample2); + } + } + } + } +}; + + class CAvisynthFilter : public GenericVideoFilter, virtual public CFilter { + bool accurate; + const bool v8; + public: VFRTranslator *vfr; - CAvisynthFilter(PClip c, IScriptEnvironment* env, VFRTranslator *_vfr = 0) : GenericVideoFilter(c), vfr(_vfr) {} + CAvisynthFilter(PClip c, IScriptEnvironment* env, VFRTranslator *_vfr = 0, bool _accurate = false) + : GenericVideoFilter(c), vfr(_vfr), accurate(_accurate), v8(env->FunctionExists("propShow")) {} + + int __stdcall SetCacheHints(int cachehints, int frame_range) override + { + return cachehints == CACHE_GET_MTMODE ? MT_SERIALIZED : 0; + } PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { PVideoFrame frame = child->GetFrame(n, env); + if (m_script_selected_yuv == YCbCrMatrix_AUTO || m_script_selected_range == YCbCrRange_AUTO) + { + if (v8) + { + int64_t val = -1; + const AVSMap* props = env->getFramePropsRO(frame); + int error; + + if (m_script_selected_yuv == YCbCrMatrix_AUTO) + { + val = env->propGetInt(props, "_Matrix", 0, &error); + + if (error) + val = -1; + + m_script_selected_yuv = + static_cast(DetectMatrix(static_cast(val), vi.width, vi.height)); + } + + if (m_script_selected_range == YCbCrRange_AUTO) + { + val = env->propGetInt(props, "_ColorRange", 0, &error); + + if (error) + val = -1; + + m_script_selected_range = + static_cast(DetectRange(static_cast(val))); + } + } + else + { + if (m_script_selected_yuv == YCbCrMatrix_AUTO) + m_script_selected_yuv = static_cast(DetectMatrix(-1, vi.width, vi.height)); + + if (m_script_selected_range == YCbCrRange_AUTO) + m_script_selected_range = static_cast(YCbCrRange_TV); + } + } + env->MakeWritable(&frame); - SubPicDesc dst; - dst.w = vi.width; - dst.h = vi.height; - dst.pitch = frame->GetPitch(); - dst.pitchUV = frame->GetPitch(PLANAR_U); - dst.bits = (void**)frame->GetWritePtr(); - dst.bitsU = frame->GetWritePtr(PLANAR_U); - dst.bitsV = frame->GetWritePtr(PLANAR_V); - dst.bpp = dst.pitch / dst.w * 8; //vi.BitsPerPixel(); - dst.type = - vi.IsRGB32() ? (env->GetVar("RGBA").AsBool() ? MSP_RGBA : MSP_RGB32) : + if (vi.IsRGB() || vi.IsYUY2()) + { + SubPicDesc dst; + dst.w = vi.width; + dst.h = vi.height; + dst.pitch = frame->GetPitch(); + dst.bits = (void**)frame->GetWritePtr(); + dst.bpp = vi.BitsPerPixel(); + dst.type = + vi.IsRGB32() ? (env->GetVar("RGBA").AsBool() ? MSP_RGBA : MSP_RGB32) : vi.IsRGB24() ? MSP_RGB24 : vi.IsYUY2() ? MSP_YUY2 : - /*vi.IsYV12()*/ vi.pixel_type == VideoInfo::CS_YV12 ? (s_fSwapUV ? MSP_IYUV : MSP_YV12) : - /*vi.IsIYUV()*/ vi.pixel_type == VideoInfo::CS_IYUV ? (s_fSwapUV ? MSP_YV12 : MSP_IYUV) : -1; - float fps = m_fps > 0 ? m_fps : (float)vi.fps_numerator / vi.fps_denominator; + float fps = m_fps > 0 ? m_fps : (float)vi.fps_numerator / vi.fps_denominator; + + REFERENCE_TIME timestamp; - REFERENCE_TIME timestamp; + if (!vfr) + timestamp = (REFERENCE_TIME)(10000000i64 * n / fps); + else + timestamp = (REFERENCE_TIME)(10000000 * vfr->TimeStampFromFrameNumber(n)); - if(!vfr) - timestamp = (REFERENCE_TIME)(10000000i64 * n / fps); + Render(dst, timestamp, fps); + } else - timestamp = (REFERENCE_TIME)(10000000 * vfr->TimeStampFromFrameNumber(n)); + { + ::std::unique_ptr frameBuf; + + switch (vi.BitsPerComponent()) + { + case 8: frameBuf = ::std::make_unique>(frame, vi); break; + case 10: frameBuf = ::std::make_unique>(frame, vi); break; + case 16: frameBuf = ::std::make_unique>(frame, vi); break; + default: env->ThrowError("This is not supported format."); break; + } + + float fps = m_fps > 0 ? m_fps : (float)vi.fps_numerator / vi.fps_denominator; + + REFERENCE_TIME timestamp; + + if (!vfr) + timestamp = (REFERENCE_TIME)(10000000i64 * n / fps); + else + timestamp = (REFERENCE_TIME)(10000000 * vfr->TimeStampFromFrameNumber(n)); + + Render(frameBuf->subpic, timestamp, fps); - Render(dst, timestamp, fps); + if (accurate && frameBuf->subpic2.bits) + Render(frameBuf->subpic2, timestamp, fps); + + frameBuf->WriteTo(frame); + } return(frame); } @@ -735,9 +1120,9 @@ class CAvisynthFilter : public GenericVideoFilter, virtual public CFilter class CVobSubAvisynthFilter : public CVobSubFilter, public CAvisynthFilter { public: - CVobSubAvisynthFilter(PClip c, const char* fn, IScriptEnvironment* env, bool utf8) + CVobSubAvisynthFilter(PClip c, const char* fn, IScriptEnvironment* env, bool utf8, bool accurate) : CVobSubFilter(utf8 ? CString(Utf8ToWideChar(fn).get()) : CString(fn)) - , CAvisynthFilter(c, env) + , CAvisynthFilter(c, env, nullptr, accurate) { if(!m_pSubPicProvider) env->ThrowError("VobSub: Can't open \"%s\"", fn); @@ -749,15 +1134,15 @@ AVSValue __cdecl VobSubCreateS(AVSValue args, void* user_data, IScriptEnvironmen bool utf8 = false; if (args[2].Defined()) utf8 = args[2].AsBool(false); - return(new CVobSubAvisynthFilter(args[0].AsClip(), args[1].AsString(), env, utf8)); + return(new CVobSubAvisynthFilter(args[0].AsClip(), args[1].AsString(), env, utf8, args[3].AsBool(false))); } class CTextSubAvisynthFilter : public CTextSubFilter, public CAvisynthFilter { public: - CTextSubAvisynthFilter(PClip c, IScriptEnvironment* env, const char* fn, int CharSet = DEFAULT_CHARSET, float fps = -1, VFRTranslator *vfr = 0, bool utf8 = false) //vfr patch + CTextSubAvisynthFilter(PClip c, IScriptEnvironment* env, const char* fn, int CharSet = DEFAULT_CHARSET, float fps = -1, VFRTranslator *vfr = 0, bool utf8 = false, bool accurate = false) //vfr patch : CTextSubFilter(utf8 ? CString(Utf8ToWideChar(fn).get()) : CString(fn), CharSet, fps) - , CAvisynthFilter(c, env, vfr) + , CAvisynthFilter(c, env, vfr, accurate) { if(!m_pSubPicProvider) #ifdef _VSMOD @@ -791,7 +1176,8 @@ AVSValue __cdecl TextSubCreateGeneral(AVSValue args, void* user_data, IScriptEnv args[2].AsInt(DEFAULT_CHARSET), args[3].AsFloat(-1), vfr, - utf8)); + utf8, + args[6].AsBool(false))); } AVSValue __cdecl TextSubSwapUV(AVSValue args, void* user_data, IScriptEnvironment* env) @@ -851,16 +1237,22 @@ AVSValue __cdecl MaskSubCreate(AVSValue args, void* user_data, IScriptEnvironmen args[5].AsInt(DEFAULT_CHARSET), args[3].AsFloat(-1), vfr, - utf8)); + utf8, + args[8].AsBool(false))); } -extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) +const AVS_Linkage* AVS_linkage; + +extern "C" __declspec(dllexport) +const char* __stdcall AvisynthPluginInit3(IScriptEnvironment * env, const AVS_Linkage* const vectors) { - env->AddFunction("VobSub", "cs[utf8]b", VobSubCreateS, 0); + AVS_linkage = vectors; + + env->AddFunction("VobSub", "cs[utf8]b[accurate]b", VobSubCreateS, 0); #ifdef _VSMOD - env->AddFunction("TextSubMod", "c[file]s[charset]i[fps]f[vfr]s[utf8]b", TextSubCreateGeneral, 0); + env->AddFunction("TextSubMod", "c[file]s[charset]i[fps]f[vfr]s[utf8]b[accurate]b", TextSubCreateGeneral, 0); env->AddFunction("TextSubModSwapUV", "b", TextSubSwapUV, 0); - env->AddFunction("MaskSubMod", "[file]s[width]i[height]i[fps]f[length]i[charset]i[vfr]s[utf8]b", MaskSubCreate, 0); + env->AddFunction("MaskSubMod", "[file]s[width]i[height]i[fps]f[length]i[charset]i[vfr]s[utf8]b[accurate]b", MaskSubCreate, 0); #else env->AddFunction("TextSub", "c[file]s[charset]i[fps]f[vfr]s", TextSubCreateGeneral, 0); env->AddFunction("TextSubSwapUV", "b", TextSubSwapUV, 0); @@ -875,8 +1267,6 @@ extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScri // VapourSynth interface // -#include - namespace VapourSynth { #include #include @@ -1103,7 +1493,15 @@ namespace VapourSynth { subpic.bitsU = BufDatas[1]; subpic.bitsV = BufDatas[2]; subpic.bpp = 8; - subpic.type = MSP_YV12; + + int mspType = MSP_YV12; + + if (d->vi->format->subSamplingW == 0 && d->vi->format->subSamplingH == 0) + mspType = MSP_YV24; + else if (d->vi->format->subSamplingW == 1 && d->vi->format->subSamplingH == 0) + mspType = MSP_YV16; + + subpic.type = mspType; if (BITDEPTH > 8) { @@ -1115,7 +1513,7 @@ namespace VapourSynth { subpic2.bitsU = BufDatas2[1]; subpic2.bitsV = BufDatas2[2]; subpic2.bpp = 8; - subpic2.type = MSP_YV12; + subpic2.type = mspType; } } @@ -1245,6 +1643,37 @@ namespace VapourSynth { vsapi->requestFrameFilter(n, d->node, frameCtx); } else if (activationReason == arAllFramesReady) { const VSFrameRef * src = vsapi->getFrameFilter(n, d->node, frameCtx); + + CFilter* pFilter = d->textsub ? reinterpret_cast(d->textsub) : reinterpret_cast(d->vobsub); + + if (pFilter->m_script_selected_yuv == YCbCrMatrix_AUTO || pFilter->m_script_selected_range == YCbCrRange_AUTO) + { + const VSMap* props = vsapi->getFramePropsRO(src); + int err; + + if (pFilter->m_script_selected_yuv == YCbCrMatrix_AUTO) + { + int64_t val = vsapi->propGetInt(props, "_Matrix", 0, &err); + + if (err) + val = -1; + + pFilter->m_script_selected_yuv = + static_cast(DetectMatrix(static_cast(val), d->vi->width, d->vi->height)); + } + + if (pFilter->m_script_selected_range == YCbCrRange_AUTO) + { + int64_t val = vsapi->propGetInt(props, "_ColorRange", 0, &err); + + if (err) + val = -1; + + if (pFilter->m_script_selected_range == YCbCrRange_AUTO) + pFilter->m_script_selected_range = + static_cast(DetectRange(static_cast(val))); + } + } VSFrameRef * dst = vsapi->copyFrame(src, core); std::unique_ptr frameBuf;