├── .gitignore ├── .gitmodules ├── Include ├── FilterInterfaces.h ├── FilterInterfacesImpl.h ├── VSScript4.h ├── VapourSynth4.h ├── Version.h ├── avisynth.h └── avs │ ├── capi.h │ ├── config.h │ ├── cpuid.h │ └── types.h ├── LICENSE.txt ├── MpcScriptSource.sln ├── Readme.md ├── Source ├── AviSynthStream.cpp ├── AviSynthStream.h ├── Helper.cpp ├── Helper.h ├── IScriptSource.h ├── MpcScriptSource.def ├── MpcScriptSource.rc ├── MpcScriptSource.vcxproj ├── MpcScriptSource.vcxproj.filters ├── PropPage.cpp ├── PropPage.h ├── ScriptSource.cpp ├── ScriptSource.h ├── Utils │ ├── StringUtil.cpp │ ├── StringUtil.h │ ├── Util.cpp │ └── Util.h ├── VUIOptions.cpp ├── VUIOptions.h ├── VapourSynthStream.cpp ├── VapourSynthStream.h ├── dllmain.cpp ├── res │ └── MpcScriptSource.rc2 ├── resource.h ├── stdafx.cpp └── stdafx.h ├── build_scriptsource.cmd ├── common.props ├── distrib ├── Install_MpcScriptSource_32.cmd ├── Install_MpcScriptSource_64.cmd ├── Reset_Settings.cmd ├── Uninstall_MpcScriptSource_32.cmd └── Uninstall_MpcScriptSource_64.cmd ├── external ├── BaseClasses.vcxproj └── BaseClasses.vcxproj.filters ├── history.txt ├── platform.props ├── sign.cmd └── update_revision.cmd /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.aps 3 | /.vs 4 | /_bin 5 | /revision.h 6 | /signinfo.txt 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/BaseClasses"] 2 | path = external/BaseClasses 3 | url = https://github.com/v0lt/BaseClasses.git 4 | -------------------------------------------------------------------------------- /Include/FilterInterfaces.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2017-2024 see Authors.txt 3 | * 4 | * This file is part of MPC-BE. 5 | * 6 | * MPC-BE is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * MPC-BE is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | */ 20 | 21 | #pragma once 22 | 23 | interface __declspec(uuid("3F56FEBC-633C-4C76-8455-0787FC62C8F8")) IExFilterInfo : public IUnknown 24 | { 25 | // The memory for strings and binary data is allocated by the callee 26 | // by using LocalAlloc. It is the caller's responsibility to release the 27 | // memory by calling LocalFree. 28 | STDMETHOD(GetPropertyInt )(LPCSTR field, int *value) PURE; 29 | STDMETHOD(GetPropertyString)(LPCSTR field, LPWSTR *value, unsigned *chars) PURE; 30 | STDMETHOD(GetPropertyBin )(LPCSTR field, LPVOID *value, unsigned *size ) PURE; 31 | }; 32 | // return values: 33 | // E_NOTIMPL - method not implemented, any parameters will be ignored. 34 | // E_POINTER - invalid pointer 35 | // E_INVALIDARG - wrong name or type of field 36 | // E_ABORT - field is correct, but the value is undefined 37 | // S_OK - operation successful 38 | // 39 | // available info fields: 40 | // name type filter valid values 41 | // VIDEO_PROFILE int MatroskaSplitter 42 | // VIDEO_PIXEL_FORMAT int MatroskaSplitter 43 | // VIDEO_INTERLACED int MatroskaSplitter,MP4Splitter,RawVideoSplitter 0-progressive, 1-tff, 2-bff 44 | // VIDEO_FLAG_ONLY_DTS int MatroskaSplitter,MP4Splitter 0-no, 1-yes 45 | // VIDEO_DELAY int MP4Splitter 46 | // PALETTE bin MP4Splitter 47 | // VIDEO_COLOR_SPACE bin MatroskaSplitter 48 | // HDR_MASTERING_METADATA bin MatroskaSplitter 49 | // HDR_CONTENT_LIGHT_LEVEL bin MatroskaSplitter 50 | 51 | interface __declspec(uuid("37CBDF10-D65E-4E5A-8F37-40E0C8EA1695")) IExFilterConfig : public IUnknown 52 | { 53 | // The memory for strings and binary data is allocated by the callee 54 | // by using LocalAlloc. It is the caller's responsibility to release the 55 | // memory by calling LocalFree. 56 | STDMETHOD(Flt_GetBool )(LPCSTR field, bool *value) PURE; 57 | STDMETHOD(Flt_GetInt )(LPCSTR field, int *value) PURE; 58 | STDMETHOD(Flt_GetInt64 )(LPCSTR field, __int64 *value) PURE; 59 | STDMETHOD(Flt_GetDouble)(LPCSTR field, double *value) PURE; 60 | STDMETHOD(Flt_GetString)(LPCSTR field, LPWSTR *value, unsigned *chars) PURE; 61 | STDMETHOD(Flt_GetBin )(LPCSTR field, LPVOID *value, unsigned *size ) PURE; 62 | 63 | STDMETHOD(Flt_SetBool )(LPCSTR field, bool value) PURE; 64 | STDMETHOD(Flt_SetInt )(LPCSTR field, int value) PURE; 65 | STDMETHOD(Flt_SetInt64 )(LPCSTR field, __int64 value) PURE; 66 | STDMETHOD(Flt_SetDouble)(LPCSTR field, double value) PURE; 67 | STDMETHOD(Flt_SetString)(LPCSTR field, LPWSTR value, int chars) PURE; 68 | STDMETHOD(Flt_SetBin )(LPCSTR field, LPVOID value, int size ) PURE; 69 | }; 70 | // available settings: 71 | // name type filter mode valid values 72 | // stereodownmix bool MpaDecFilter set true/false 73 | // queueDuration int BaseSplitter set/get 100...15000 milliseconds 74 | // networkTimeout int BaseSplitter set/get 2000...20000 milliseconds (reserved) 75 | // version int64 MpcVideoRenderer get 0.3.3.886 or newer 76 | // statsEnable bool MpcVideoRenderer set/get true/false 77 | // cmd_redraw bool MpcVideoRenderer set true 78 | // playbackState int MpcVideoRenderer get 0-State_Stopped, 1-State_Paused, 2-State_Running 79 | // rotation int MpcVideoRenderer get 0, 90, 180, 270 (reserved) 80 | -------------------------------------------------------------------------------- /Include/FilterInterfacesImpl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2017-2024 see Authors.txt 3 | * 4 | * This file is part of MPC-BE. 5 | * 6 | * MPC-BE is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * MPC-BE is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "FilterInterfaces.h" 24 | 25 | class CExFilterInfoImpl : public IExFilterInfo 26 | { 27 | STDMETHODIMP GetPropertyInt (LPCSTR field, int *value) { return E_NOTIMPL; }; 28 | STDMETHODIMP GetPropertyString(LPCSTR field, LPWSTR *value, unsigned *chars) { return E_NOTIMPL; }; 29 | STDMETHODIMP GetPropertyBin (LPCSTR field, LPVOID *value, unsigned *size ) { return E_NOTIMPL; }; 30 | }; 31 | 32 | class CExFilterConfigImpl : public IExFilterConfig 33 | { 34 | STDMETHODIMP Flt_GetBool (LPCSTR field, bool *value) { return E_NOTIMPL; }; 35 | STDMETHODIMP Flt_GetInt (LPCSTR field, int *value) { return E_NOTIMPL; }; 36 | STDMETHODIMP Flt_GetInt64 (LPCSTR field, __int64 *value) { return E_NOTIMPL; }; 37 | STDMETHODIMP Flt_GetDouble(LPCSTR field, double *value) { return E_NOTIMPL; }; 38 | STDMETHODIMP Flt_GetString(LPCSTR field, LPWSTR *value, unsigned *chars) { return E_NOTIMPL; }; 39 | STDMETHODIMP Flt_GetBin (LPCSTR field, LPVOID *value, unsigned *size ) { return E_NOTIMPL; }; 40 | 41 | STDMETHODIMP Flt_SetBool (LPCSTR field, bool value) { return E_NOTIMPL; }; 42 | STDMETHODIMP Flt_SetInt (LPCSTR field, int value) { return E_NOTIMPL; }; 43 | STDMETHODIMP Flt_SetInt64 (LPCSTR field, __int64 value) { return E_NOTIMPL; }; 44 | STDMETHODIMP Flt_SetDouble(LPCSTR field, double value) { return E_NOTIMPL; }; 45 | STDMETHODIMP Flt_SetString(LPCSTR field, LPWSTR value, int chars) { return E_NOTIMPL; }; 46 | STDMETHODIMP Flt_SetBin (LPCSTR field, LPVOID value, int size ) { return E_NOTIMPL; }; 47 | }; 48 | -------------------------------------------------------------------------------- /Include/VSScript4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2020 Fredrik Mellbin 3 | * 4 | * This file is part of VapourSynth. 5 | * 6 | * VapourSynth is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * VapourSynth is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with VapourSynth; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef VSSCRIPT4_H 22 | #define VSSCRIPT4_H 23 | 24 | #include "VapourSynth4.h" 25 | 26 | #define VSSCRIPT_API_MAJOR 4 27 | #define VSSCRIPT_API_MINOR 1 28 | #define VSSCRIPT_API_VERSION VS_MAKE_VERSION(VSSCRIPT_API_MAJOR, VSSCRIPT_API_MINOR) 29 | 30 | typedef struct VSScript VSScript; 31 | typedef struct VSSCRIPTAPI VSSCRIPTAPI; 32 | 33 | struct VSSCRIPTAPI { 34 | /* Returns the highest supported VSSCRIPT_API_VERSION */ 35 | int (VS_CC *getAPIVersion)(void) VS_NOEXCEPT; 36 | 37 | /* Convenience function for retrieving a VSAPI pointer without having to use the VapourSynth library. Always pass VAPOURSYNTH_API_VERSION */ 38 | const VSAPI *(VS_CC *getVSAPI)(int version) VS_NOEXCEPT; 39 | 40 | /* 41 | * Providing a pre-created core is useful for setting core creation flags, log callbacks, preload specific plugins and many other things. 42 | * You must create a VSScript object before evaluating a script. Always takes ownership of the core even on failure. Returns NULL on failure. 43 | * Pass NULL to have a core automatically created with the default options. 44 | */ 45 | VSScript *(VS_CC *createScript)(VSCore *core) VS_NOEXCEPT; 46 | 47 | /* The core is valid as long as the environment exists, return NULL on error */ 48 | VSCore *(VS_CC *getCore)(VSScript *handle) VS_NOEXCEPT; 49 | 50 | /* 51 | * Evaluates a script passed in the buffer argument. The scriptFilename is only used for display purposes. in Python 52 | * it means that the main module won't be unnamed in error messages. 53 | * 54 | * Returns 0 on success. 55 | * 56 | * Note that calling any function other than getError() and freeScript() on a VSScript object in the error state 57 | * will result in undefined behavior. 58 | */ 59 | int (VS_CC *evaluateBuffer)(VSScript *handle, const char *buffer, const char *scriptFilename) VS_NOEXCEPT; 60 | 61 | /* Convenience version of the above function that loads the script from scriptFilename and passes as the buffer to evaluateBuffer */ 62 | int (VS_CC *evaluateFile)(VSScript *handle, const char *scriptFilename) VS_NOEXCEPT; 63 | 64 | /* Returns NULL on success, otherwise an error message */ 65 | const char *(VS_CC *getError)(VSScript *handle) VS_NOEXCEPT; 66 | 67 | /* Returns the script's reported exit code */ 68 | int (VS_CC *getExitCode)(VSScript *handle) VS_NOEXCEPT; 69 | 70 | /* Fetches a variable of any VSMap storable type set in a script. It is stored in the key with the same name in dst. Returns 0 on success. */ 71 | int (VS_CC *getVariable)(VSScript *handle, const char *name, VSMap *dst) VS_NOEXCEPT; 72 | 73 | /* Sets all keys in the provided VSMap as variables in the script. Returns 0 on success. */ 74 | int (VS_CC *setVariables)(VSScript *handle, const VSMap *vars) VS_NOEXCEPT; 75 | 76 | /* 77 | * The returned nodes must be freed using freeNode() before calling freeScript() since they may depend on data in the VSScript 78 | * environment. Returns NULL if no node was set as output in the script. Index 0 is used by default in scripts and other 79 | * values are rarely used. 80 | */ 81 | VSNode *(VS_CC *getOutputNode)(VSScript *handle, int index) VS_NOEXCEPT; 82 | VSNode *(VS_CC *getOutputAlphaNode)(VSScript *handle, int index) VS_NOEXCEPT; 83 | int (VS_CC *getAltOutputMode)(VSScript *handle, int index) VS_NOEXCEPT; 84 | 85 | void (VS_CC *freeScript)(VSScript *handle) VS_NOEXCEPT; 86 | 87 | /* 88 | * Set whether or not the working directory is temporarily changed to the same 89 | * location as the script file when evaluateFile is called. Off by default. 90 | */ 91 | void (VS_CC *evalSetWorkingDir)(VSScript *handle, int setCWD) VS_NOEXCEPT; 92 | 93 | }; 94 | 95 | VS_API(const VSSCRIPTAPI *) getVSScriptAPI(int version) VS_NOEXCEPT; 96 | 97 | #endif /* VSSCRIPT4_H */ 98 | -------------------------------------------------------------------------------- /Include/Version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../revision.h" 4 | 5 | #ifndef REV_DATE 6 | #define REV_DATE 0 7 | #endif 8 | 9 | #ifndef REV_HASH 10 | #define REV_HASH 0 11 | #endif 12 | 13 | #ifndef REV_NUM 14 | #define REV_NUM 0 15 | #endif 16 | 17 | #define DO_MAKE_STR(x) #x 18 | #define MAKE_STR(x) DO_MAKE_STR(x) 19 | 20 | #define VER_RELEASE 1 21 | 22 | #define VER_MAJOR 0 23 | #define VER_MINOR 2 24 | #define VER_BUILD 7 25 | 26 | #define VERSION_NUM VER_MAJOR,VER_MINOR,VER_BUILD,REV_NUM 27 | #define VERSION_STR MAKE_STR(VER_MAJOR) "." MAKE_STR(VER_MINOR) "." MAKE_STR(VER_BUILD) "." MAKE_STR(REV_NUM) 28 | -------------------------------------------------------------------------------- /Include/avs/capi.h: -------------------------------------------------------------------------------- 1 | // Avisynth C Interface Version 0.20 2 | // Copyright 2003 Kevin Atkinson 3 | 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 17 | // http://www.gnu.org/copyleft/gpl.html . 18 | // 19 | // As a special exception, I give you permission to link to the 20 | // Avisynth C interface with independent modules that communicate with 21 | // the Avisynth C interface solely through the interfaces defined in 22 | // avisynth_c.h, regardless of the license terms of these independent 23 | // modules, and to copy and distribute the resulting combined work 24 | // under terms of your choice, provided that every copy of the 25 | // combined work is accompanied by a complete copy of the source code 26 | // of the Avisynth C interface and Avisynth itself (with the version 27 | // used to produce the combined work), being distributed under the 28 | // terms of the GNU General Public License plus this exception. An 29 | // independent module is a module which is not derived from or based 30 | // on Avisynth C Interface, such as 3rd-party filters, import and 31 | // export plugins, or graphical user interfaces. 32 | 33 | #ifndef AVS_CAPI_H 34 | #define AVS_CAPI_H 35 | 36 | #include "config.h" 37 | 38 | #ifdef AVS_POSIX 39 | // this is also defined in avs/posix.h 40 | #ifndef AVS_HAIKU 41 | #define __declspec(x) 42 | #endif 43 | #endif 44 | 45 | #ifdef __cplusplus 46 | # define EXTERN_C extern "C" 47 | #else 48 | # define EXTERN_C 49 | #endif 50 | 51 | #ifdef AVS_WINDOWS 52 | #ifdef BUILDING_AVSCORE 53 | # if defined(GCC) && defined(X86_32) 54 | # define AVSC_CC 55 | # else // MSVC builds and 64-bit GCC 56 | # ifndef AVSC_USE_STDCALL 57 | # define AVSC_CC __cdecl 58 | # else 59 | # define AVSC_CC __stdcall 60 | # endif 61 | # endif 62 | #else // needed for programs that talk to AviSynth+ 63 | # ifndef AVSC_WIN32_GCC32 // see comment below 64 | # ifndef AVSC_USE_STDCALL 65 | # define AVSC_CC __cdecl 66 | # else 67 | # define AVSC_CC __stdcall 68 | # endif 69 | # else 70 | # define AVSC_CC 71 | # endif 72 | #endif 73 | # else 74 | # define AVSC_CC 75 | #endif 76 | 77 | // On 64-bit Windows, there's only one calling convention, 78 | // so there is no difference between MSVC and GCC. On 32-bit, 79 | // this isn't true. The convention that GCC needs to use to 80 | // even build AviSynth+ as 32-bit makes anything that uses 81 | // it incompatible with 32-bit MSVC builds of AviSynth+. 82 | // The AVSC_WIN32_GCC32 define is meant to provide a user 83 | // switchable way to make builds of FFmpeg to test 32-bit 84 | // GCC builds of AviSynth+ without having to screw around 85 | // with alternate headers, while still default to the usual 86 | // situation of using 32-bit MSVC builds of AviSynth+. 87 | 88 | // Hopefully, this situation will eventually be resolved 89 | // and a broadly compatible solution will arise so the 90 | // same 32-bit FFmpeg build can handle either MSVC or GCC 91 | // builds of AviSynth+. 92 | 93 | #define AVSC_INLINE static __inline 94 | 95 | #ifdef BUILDING_AVSCORE 96 | #ifdef AVS_WINDOWS 97 | # ifndef AVS_STATIC_LIB 98 | # define AVSC_EXPORT __declspec(dllexport) 99 | # else 100 | # define AVSC_EXPORT 101 | # endif 102 | # define AVSC_API(ret, name) EXTERN_C AVSC_EXPORT ret AVSC_CC name 103 | #else 104 | # define AVSC_EXPORT EXTERN_C 105 | # define AVSC_API(ret, name) EXTERN_C ret AVSC_CC name 106 | #endif 107 | #else 108 | # define AVSC_EXPORT EXTERN_C __declspec(dllexport) 109 | # ifndef AVS_STATIC_LIB 110 | # define AVSC_IMPORT __declspec(dllimport) 111 | # else 112 | # define AVSC_IMPORT 113 | # endif 114 | # ifndef AVSC_NO_DECLSPEC 115 | # define AVSC_API(ret, name) EXTERN_C AVSC_IMPORT ret AVSC_CC name 116 | # else 117 | # define AVSC_API(ret, name) typedef ret (AVSC_CC *name##_func) 118 | # endif 119 | #endif 120 | 121 | #endif //AVS_CAPI_H 122 | -------------------------------------------------------------------------------- /Include/avs/config.h: -------------------------------------------------------------------------------- 1 | // Avisynth C Interface Version 0.20 2 | // Copyright 2003 Kevin Atkinson 3 | 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 17 | // http://www.gnu.org/copyleft/gpl.html . 18 | // 19 | // As a special exception, I give you permission to link to the 20 | // Avisynth C interface with independent modules that communicate with 21 | // the Avisynth C interface solely through the interfaces defined in 22 | // avisynth_c.h, regardless of the license terms of these independent 23 | // modules, and to copy and distribute the resulting combined work 24 | // under terms of your choice, provided that every copy of the 25 | // combined work is accompanied by a complete copy of the source code 26 | // of the Avisynth C interface and Avisynth itself (with the version 27 | // used to produce the combined work), being distributed under the 28 | // terms of the GNU General Public License plus this exception. An 29 | // independent module is a module which is not derived from or based 30 | // on Avisynth C Interface, such as 3rd-party filters, import and 31 | // export plugins, or graphical user interfaces. 32 | 33 | #ifndef AVS_CONFIG_H 34 | #define AVS_CONFIG_H 35 | 36 | // Undefine this to get cdecl calling convention 37 | #define AVSC_USE_STDCALL 1 38 | 39 | // NOTE TO PLUGIN AUTHORS: 40 | // Because FRAME_ALIGN can be substantially higher than the alignment 41 | // a plugin actually needs, plugins should not use FRAME_ALIGN to check for 42 | // alignment. They should always request the exact alignment value they need. 43 | // This is to make sure that plugins work over the widest range of AviSynth 44 | // builds possible. 45 | #define FRAME_ALIGN 64 46 | 47 | #if defined(_M_AMD64) || defined(__x86_64) 48 | # define X86_64 49 | #elif defined(_M_IX86) || defined(__i386__) 50 | # define X86_32 51 | // VS2017 introduced _M_ARM64 52 | #elif defined(_M_ARM64) || defined(__aarch64__) 53 | # define ARM64 54 | #elif defined(_M_ARM) || defined(__arm__) 55 | # define ARM32 56 | #elif defined(__PPC64__) 57 | # define PPC64 58 | #elif defined(_M_PPC) || defined(__PPC__) || defined(__POWERPC__) 59 | # define PPC32 60 | #elif defined(__riscv) 61 | # define RISCV 62 | #elif defined(__sparc_v9__) 63 | # define SPARC 64 | #elif defined(__mips__) 65 | # define MIPS 66 | #else 67 | # error Unsupported CPU architecture. 68 | #endif 69 | 70 | // VC++ LLVM-Clang-cl MinGW-Gnu 71 | // MSVC x x 72 | // MSVC_PURE x 73 | // CLANG x 74 | // GCC x 75 | 76 | #if defined(__clang__) 77 | // Check clang first. clang-cl also defines __MSC_VER 78 | // We set MSVC because they are mostly compatible 79 | # define CLANG 80 | #if defined(_MSC_VER) 81 | # define MSVC 82 | # define AVS_FORCEINLINE __attribute__((always_inline)) 83 | #else 84 | # define AVS_FORCEINLINE __attribute__((always_inline)) inline 85 | #endif 86 | #elif defined(_MSC_VER) 87 | # define MSVC 88 | # define MSVC_PURE 89 | # define AVS_FORCEINLINE __forceinline 90 | #elif defined(__GNUC__) 91 | # define GCC 92 | # define AVS_FORCEINLINE __attribute__((always_inline)) inline 93 | #elif defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER) 94 | // Intel C++ Compilers with MSVC command line interface will not appear here rather at _MSC_VER 95 | # define AVS_FORCEINLINE inline 96 | # undef __forceinline 97 | # define __forceinline inline 98 | #else 99 | # error Unsupported compiler. 100 | # define AVS_FORCEINLINE inline 101 | # undef __forceinline 102 | # define __forceinline inline 103 | #endif 104 | 105 | #if defined(_WIN32) 106 | # define AVS_WINDOWS 107 | #elif defined(__linux__) 108 | # define AVS_LINUX 109 | # define AVS_POSIX 110 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 111 | # define AVS_BSD 112 | # define AVS_POSIX 113 | #elif defined(__APPLE__) 114 | # define AVS_MACOS 115 | # define AVS_POSIX 116 | #elif defined(__HAIKU__) 117 | # define AVS_HAIKU 118 | # define AVS_POSIX 119 | #else 120 | # error Operating system unsupported. 121 | #endif 122 | 123 | // useful warnings disabler macros for supported compilers 124 | 125 | #if defined(_MSC_VER) 126 | #define DISABLE_WARNING_PUSH __pragma(warning( push )) 127 | #define DISABLE_WARNING_POP __pragma(warning( pop )) 128 | #define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber )) 129 | 130 | #define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE DISABLE_WARNING(4101) 131 | #define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(4505) 132 | // other warnings you want to deactivate... 133 | 134 | #elif defined(__GNUC__) || defined(__clang__) 135 | #define DO_PRAGMA(X) _Pragma(#X) 136 | #define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push) 137 | #define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop) 138 | #define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName) 139 | 140 | #define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE DISABLE_WARNING(-Wunused-variable) 141 | #define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(-Wunused-function) 142 | // other warnings you want to deactivate... 143 | 144 | #else 145 | #define DISABLE_WARNING_PUSH 146 | #define DISABLE_WARNING_POP 147 | #define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE 148 | #define DISABLE_WARNING_UNREFERENCED_FUNCTION 149 | // other warnings you want to deactivate... 150 | 151 | #endif 152 | 153 | #if defined(AVS_WINDOWS) && defined(_USING_V110_SDK71_) 154 | // Windows XP does not have proper initialization for 155 | // thread local variables. 156 | // Use workaround instead __declspec(thread) 157 | #define XP_TLS 158 | #endif 159 | 160 | #ifndef MSVC 161 | // GCC and Clang can be used on big endian systems, MSVC can't. 162 | # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 163 | # define AVS_ENDIANNESS "little" 164 | # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 165 | # define AVS_ENDIANNESS "big" 166 | # else 167 | # define AVS_ENDIANNESS "middle" 168 | # endif 169 | #else 170 | #define AVS_ENDIANNESS "little" 171 | #endif 172 | 173 | #endif //AVS_CONFIG_H 174 | -------------------------------------------------------------------------------- /Include/avs/cpuid.h: -------------------------------------------------------------------------------- 1 | // This program is free software; you can redistribute it and/or modify 2 | // it under the terms of the GNU General Public License as published by 3 | // the Free Software Foundation; either version 2 of the License, or 4 | // (at your option) any later version. 5 | // 6 | // This program is distributed in the hope that it will be useful, 7 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | // GNU General Public License for more details. 10 | // 11 | // You should have received a copy of the GNU General Public License 12 | // along with this program; if not, write to the Free Software 13 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 14 | // http://www.gnu.org/copyleft/gpl.html . 15 | // 16 | // Linking Avisynth statically or dynamically with other modules is making a 17 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU 18 | // General Public License cover the whole combination. 19 | // 20 | // As a special exception, the copyright holders of Avisynth give you 21 | // permission to link Avisynth with independent modules that communicate with 22 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license 23 | // terms of these independent modules, and to copy and distribute the 24 | // resulting combined work under terms of your choice, provided that 25 | // every copy of the combined work is accompanied by a complete copy of 26 | // the source code of Avisynth (the version of Avisynth used to produce the 27 | // combined work), being distributed under the terms of the GNU General 28 | // Public License plus this exception. An independent module is a module 29 | // which is not derived from or based on Avisynth, such as 3rd-party filters, 30 | // import and export plugins, or graphical user interfaces. 31 | 32 | #ifndef AVSCORE_CPUID_H 33 | #define AVSCORE_CPUID_H 34 | 35 | // For GetCPUFlags. These are backwards-compatible with those in VirtualDub. 36 | // ending with SSE4_2 37 | // For emulation see https://software.intel.com/en-us/articles/intel-software-development-emulator 38 | enum { 39 | /* oldest CPU to support extension */ 40 | CPUF_FORCE = 0x01, // N/A 41 | CPUF_FPU = 0x02, // 386/486DX 42 | CPUF_MMX = 0x04, // P55C, K6, PII 43 | CPUF_INTEGER_SSE = 0x08, // PIII, Athlon 44 | CPUF_SSE = 0x10, // PIII, Athlon XP/MP 45 | CPUF_SSE2 = 0x20, // PIV, K8 46 | CPUF_3DNOW = 0x40, // K6-2 47 | CPUF_3DNOW_EXT = 0x80, // Athlon 48 | CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which 49 | // only Hammer will have anyway) 50 | CPUF_SSE3 = 0x100, // PIV+, K8 Venice 51 | CPUF_SSSE3 = 0x200, // Core 2 52 | CPUF_SSE4 = 0x400, 53 | CPUF_SSE4_1 = 0x400, // Penryn, Wolfdale, Yorkfield 54 | CPUF_AVX = 0x800, // Sandy Bridge, Bulldozer 55 | CPUF_SSE4_2 = 0x1000, // Nehalem 56 | // AVS+ 57 | CPUF_AVX2 = 0x2000, // Haswell 58 | CPUF_FMA3 = 0x4000, 59 | CPUF_F16C = 0x8000, 60 | CPUF_MOVBE = 0x10000, // Big Endian move 61 | CPUF_POPCNT = 0x20000, 62 | CPUF_AES = 0x40000, 63 | CPUF_FMA4 = 0x80000, 64 | 65 | CPUF_AVX512F = 0x100000, // AVX-512 Foundation. 66 | CPUF_AVX512DQ = 0x200000, // AVX-512 DQ (Double/Quad granular) Instructions 67 | CPUF_AVX512PF = 0x400000, // AVX-512 Prefetch 68 | CPUF_AVX512ER = 0x800000, // AVX-512 Exponential and Reciprocal 69 | CPUF_AVX512CD = 0x1000000, // AVX-512 Conflict Detection 70 | CPUF_AVX512BW = 0x2000000, // AVX-512 BW (Byte/Word granular) Instructions 71 | CPUF_AVX512VL = 0x4000000, // AVX-512 VL (128/256 Vector Length) Extensions 72 | CPUF_AVX512IFMA = 0x8000000, // AVX-512 IFMA integer 52 bit 73 | CPUF_AVX512VBMI = 0x10000000,// AVX-512 VBMI 74 | }; 75 | 76 | #ifdef BUILDING_AVSCORE 77 | int GetCPUFlags(); 78 | void SetMaxCPU(int new_flags); 79 | #endif 80 | 81 | #endif // AVSCORE_CPUID_H 82 | -------------------------------------------------------------------------------- /Include/avs/types.h: -------------------------------------------------------------------------------- 1 | // Avisynth C Interface Version 0.20 2 | // Copyright 2003 Kevin Atkinson 3 | 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit 17 | // http://www.gnu.org/copyleft/gpl.html . 18 | // 19 | // As a special exception, I give you permission to link to the 20 | // Avisynth C interface with independent modules that communicate with 21 | // the Avisynth C interface solely through the interfaces defined in 22 | // avisynth_c.h, regardless of the license terms of these independent 23 | // modules, and to copy and distribute the resulting combined work 24 | // under terms of your choice, provided that every copy of the 25 | // combined work is accompanied by a complete copy of the source code 26 | // of the Avisynth C interface and Avisynth itself (with the version 27 | // used to produce the combined work), being distributed under the 28 | // terms of the GNU General Public License plus this exception. An 29 | // independent module is a module which is not derived from or based 30 | // on Avisynth C Interface, such as 3rd-party filters, import and 31 | // export plugins, or graphical user interfaces. 32 | 33 | #ifndef AVS_TYPES_H 34 | #define AVS_TYPES_H 35 | 36 | // Define all types necessary for interfacing with avisynth.dll 37 | #include 38 | #include 39 | #ifdef __cplusplus 40 | #include 41 | #include 42 | #else 43 | #include 44 | #include 45 | #endif 46 | 47 | // Raster types used by VirtualDub & Avisynth 48 | typedef uint32_t Pixel32; 49 | typedef uint8_t BYTE; 50 | 51 | // Audio Sample information 52 | typedef float SFLOAT; 53 | 54 | #endif //AVS_TYPES_H 55 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /MpcScriptSource.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.35122.118 5 | MinimumVisualStudioVersion = 15.0.27130.2036 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MpcScriptSource", "Source\MpcScriptSource.vcxproj", "{DAF59106-BC83-478F-95D9-4516C2A52970}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Include", "Include", "{C7CAE27C-03BC-45F2-BF8E-DEE05DBF37B8}" 9 | ProjectSection(SolutionItems) = preProject 10 | Include\avisynth.h = Include\avisynth.h 11 | Include\FilterInterfaces.h = Include\FilterInterfaces.h 12 | Include\FilterInterfacesImpl.h = Include\FilterInterfacesImpl.h 13 | Include\VapourSynth4.h = Include\VapourSynth4.h 14 | Include\Version.h = Include\Version.h 15 | Include\VSScript4.h = Include\VSScript4.h 16 | EndProjectSection 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "avs", "avs", "{5FDFFC8B-BC55-4214-BE2B-19331F617146}" 19 | ProjectSection(SolutionItems) = preProject 20 | Include\avs\capi.h = Include\avs\capi.h 21 | Include\avs\config.h = Include\avs\config.h 22 | Include\avs\cpuid.h = Include\avs\cpuid.h 23 | Include\avs\types.h = Include\avs\types.h 24 | EndProjectSection 25 | EndProject 26 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BaseClasses", "external\BaseClasses.vcxproj", "{E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}" 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|x64 = Debug|x64 31 | Debug|x86 = Debug|x86 32 | Release|x64 = Release|x64 33 | Release|x86 = Release|x86 34 | EndGlobalSection 35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 36 | {DAF59106-BC83-478F-95D9-4516C2A52970}.Debug|x64.ActiveCfg = Debug|x64 37 | {DAF59106-BC83-478F-95D9-4516C2A52970}.Debug|x64.Build.0 = Debug|x64 38 | {DAF59106-BC83-478F-95D9-4516C2A52970}.Debug|x86.ActiveCfg = Debug|Win32 39 | {DAF59106-BC83-478F-95D9-4516C2A52970}.Debug|x86.Build.0 = Debug|Win32 40 | {DAF59106-BC83-478F-95D9-4516C2A52970}.Release|x64.ActiveCfg = Release|x64 41 | {DAF59106-BC83-478F-95D9-4516C2A52970}.Release|x64.Build.0 = Release|x64 42 | {DAF59106-BC83-478F-95D9-4516C2A52970}.Release|x86.ActiveCfg = Release|Win32 43 | {DAF59106-BC83-478F-95D9-4516C2A52970}.Release|x86.Build.0 = Release|Win32 44 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}.Debug|x64.ActiveCfg = Debug|x64 45 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}.Debug|x64.Build.0 = Debug|x64 46 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}.Debug|x86.ActiveCfg = Debug|Win32 47 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}.Debug|x86.Build.0 = Debug|Win32 48 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}.Release|x64.ActiveCfg = Release|x64 49 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}.Release|x64.Build.0 = Release|x64 50 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}.Release|x86.ActiveCfg = Release|Win32 51 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA}.Release|x86.Build.0 = Release|Win32 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | GlobalSection(NestedProjects) = preSolution 57 | {5FDFFC8B-BC55-4214-BE2B-19331F617146} = {C7CAE27C-03BC-45F2-BF8E-DEE05DBF37B8} 58 | EndGlobalSection 59 | GlobalSection(ExtensibilityGlobals) = postSolution 60 | SolutionGuid = {5D7781ED-53B1-4197-9C68-D2EDD94EC59B} 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # MPC Script Source 2 | 3 | MPC Script Source is a free and open-source DirectShow filter. The filter allows to open AviSynth+ and VapourSynth script files in video players. 4 | 5 | ## Minimum system requirements 6 | 7 | * An SSE2-capable CPU 8 | * Windows 7 or newer 9 | 10 | ## License 11 | 12 | MPC Script Source's code is licensed under [LGPL v2.1]. 13 | 14 | ## Links 15 | 16 | Topic in MPC-BE forum (Russian) - 17 | 18 | MPC-BE video player - 19 | 20 | ## Donate 21 | 22 | ЮMoney - https://yoomoney.ru/to/4100115126389817 23 | -------------------------------------------------------------------------------- /Source/AviSynthStream.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #include "stdafx.h" 8 | #include "VUIOptions.h" 9 | #include "ScriptSource.h" 10 | 11 | #include "AviSynthStream.h" 12 | 13 | #include 14 | 15 | const AVS_Linkage* AVS_linkage = NULL; 16 | 17 | // 18 | // CAviSynthFile 19 | // 20 | 21 | CAviSynthFile::CAviSynthFile(const WCHAR* name, CSource* pParent, HRESULT* phr) 22 | { 23 | try { 24 | m_hAviSynthDll = LoadLibraryW(L"Avisynth.dll"); 25 | if (!m_hAviSynthDll) { 26 | throw std::exception("Failed to load AviSynth+"); 27 | } 28 | 29 | IScriptEnvironment* (WINAPI* CreateScriptEnvironment)(int version) = 30 | (IScriptEnvironment * (WINAPI*)(int)) GetProcAddress(m_hAviSynthDll, "CreateScriptEnvironment"); 31 | 32 | if (!CreateScriptEnvironment) { 33 | throw std::exception("Cannot resolve AviSynth+ CreateScriptEnvironment function"); 34 | } 35 | 36 | m_ScriptEnvironment = CreateScriptEnvironment(6); 37 | if (!m_ScriptEnvironment) { 38 | throw std::exception("A newer AviSynth+ version is required"); 39 | } 40 | 41 | AVS_linkage = m_Linkage = m_ScriptEnvironment->GetAVSLinkage(); 42 | } 43 | catch ([[maybe_unused]] const std::exception& e) { 44 | DLog(A2WStr(e.what())); 45 | *phr = E_FAIL; 46 | return; 47 | } 48 | 49 | HRESULT hr; 50 | std::wstring error; 51 | 52 | try { 53 | std::string utf8file = ConvertWideToUtf8(name); 54 | AVSValue args[2] = { utf8file.c_str(), true }; 55 | const char* const arg_names[2] = { 0, "utf8" }; 56 | try { 57 | m_AVSValue = m_ScriptEnvironment->Invoke("Import", AVSValue(args, 2), arg_names); 58 | } 59 | catch (const AvisynthError& e) { 60 | error = ConvertUtf8ToWide(e.msg); 61 | throw std::exception("Failure to open Avisynth script file."); 62 | } 63 | 64 | if (!m_AVSValue.IsClip()) { 65 | throw std::exception("AviSynth+ script does not return a video clip"); 66 | } 67 | 68 | auto Clip = m_AVSValue.AsClip(); 69 | auto VInfo = Clip->GetVideoInfo(); 70 | 71 | if (VInfo.HasVideo()) { 72 | auto& Format = GetFormatParamsAviSynth(VInfo.pixel_type); 73 | if (Format.fourcc == DWORD(-1)) { 74 | throw std::exception(std::format("Unsuported pixel_type {:#010x} ({})", (uint32_t)VInfo.pixel_type, VInfo.pixel_type).c_str()); 75 | } 76 | 77 | auto pVideoStream = new CAviSynthVideoStream(this, pParent, &hr); 78 | if (FAILED(hr)) { 79 | pParent->RemovePin(pVideoStream); 80 | delete pVideoStream; 81 | throw std::exception("AviSynth+ script returned unsupported video"); 82 | } 83 | else { 84 | m_FileInfo.append(pVideoStream->GetInfo()); 85 | m_FileInfo += (L'\n'); 86 | } 87 | } 88 | 89 | if (VInfo.HasAudio()) { 90 | auto pAudioStream = new CAviSynthAudioStream(this, pParent, &hr); 91 | if (FAILED(hr)) { 92 | DLog(L"AviSynth+ script returned unsupported audio"); 93 | } 94 | else { 95 | m_FileInfo.append(pAudioStream->GetInfo()); 96 | m_FileInfo += (L'\n'); 97 | } 98 | } 99 | 100 | hr = S_OK; 101 | } 102 | catch ([[maybe_unused]] const std::exception& e) { 103 | DLog(L"{}\n{}", A2WStr(e.what()), error); 104 | 105 | new CAviSynthVideoStream(error, pParent, &hr); 106 | if (SUCCEEDED(hr)) { 107 | hr = S_FALSE; 108 | } else { 109 | hr = E_FAIL; 110 | } 111 | } 112 | 113 | *phr = hr; 114 | } 115 | 116 | CAviSynthFile::~CAviSynthFile() 117 | { 118 | AVS_linkage = m_Linkage; 119 | 120 | m_AVSValue = 0; 121 | 122 | if (m_ScriptEnvironment) { 123 | m_ScriptEnvironment->DeleteScriptEnvironment(); 124 | m_ScriptEnvironment = nullptr; 125 | } 126 | 127 | AVS_linkage = nullptr; 128 | m_Linkage = nullptr; 129 | 130 | if (m_hAviSynthDll) { 131 | FreeLibrary(m_hAviSynthDll); 132 | } 133 | } 134 | 135 | // 136 | // CAviSynthVideoStream 137 | // 138 | 139 | CAviSynthVideoStream::CAviSynthVideoStream(CAviSynthFile* pAviSynthFile, CSource* pParent, HRESULT* phr) 140 | : CSourceStream(L"Video", phr, pParent, L"Video") 141 | , CSourceSeeking(L"Video", (IPin*)this, phr, &m_cSharedState) 142 | , m_pAviSynthFile(pAviSynthFile) 143 | { 144 | CAutoLock cAutoLock(&m_cSharedState); 145 | 146 | HRESULT hr; 147 | std::wstring error; 148 | 149 | try { 150 | auto Clip = m_pAviSynthFile->m_AVSValue.AsClip(); 151 | auto VInfo = Clip->GetVideoInfo(); 152 | 153 | m_Format = GetFormatParamsAviSynth(VInfo.pixel_type); 154 | if (m_Format.fourcc == DWORD(-1)) { 155 | throw std::exception(std::format("Unsuported pixel_type {:#010x} ({})", (uint32_t)VInfo.pixel_type, VInfo.pixel_type).c_str()); 156 | } 157 | 158 | UINT bitdepth = VInfo.BitsPerPixel(); 159 | 160 | auto VFrame = Clip->GetFrame(0, m_pAviSynthFile->m_ScriptEnvironment); 161 | m_Pitch = VFrame->GetPitch(); 162 | 163 | m_Width = VInfo.width; 164 | m_Height = VInfo.height; 165 | m_PitchBuff = m_Pitch; 166 | m_BufferSize = m_PitchBuff * m_Height * m_Format.buffCoeff / 2; 167 | 168 | m_fpsNum = VInfo.fps_numerator; 169 | m_fpsDen = VInfo.fps_denominator; 170 | m_NumFrames = VInfo.num_frames; 171 | m_AvgTimePerFrame = UNITS * m_fpsDen / m_fpsNum; // no need any MulDiv here 172 | m_rtDuration = m_rtStop = llMulDiv(UNITS * m_NumFrames, m_fpsDen, m_fpsNum, 0); 173 | 174 | if (VInfo.IsPlanar()) { 175 | if (VInfo.IsYUV() || VInfo.IsYUVA()) { 176 | m_Planes[0] = PLANAR_Y; 177 | if (VInfo.IsYV12() || VInfo.IsYV16() || VInfo.IsYV24()) { 178 | m_Planes[1] = PLANAR_V; 179 | m_Planes[2] = PLANAR_U; 180 | } else { 181 | m_Planes[1] = PLANAR_U; 182 | m_Planes[2] = PLANAR_V; 183 | } 184 | } 185 | else if (VInfo.IsRGB()) { 186 | m_Planes[0] = PLANAR_G; 187 | m_Planes[1] = PLANAR_B; 188 | m_Planes[2] = PLANAR_R; 189 | } 190 | m_Planes[3] = PLANAR_A; 191 | } 192 | 193 | UINT color_info = 0; 194 | 195 | m_StreamInfo = std::format( 196 | L"Script type : AviSynth\n" 197 | L"Video stream: {} {}x{} {:.3f} fps", 198 | m_Format.str, m_Width, m_Height, (double)m_fpsNum/m_fpsDen 199 | ); 200 | 201 | bool has_at_least_v9 = true; 202 | try { 203 | m_pAviSynthFile->m_ScriptEnvironment->CheckVersion(9); 204 | } 205 | catch (const AvisynthError&) { 206 | has_at_least_v9 = false; 207 | } 208 | 209 | if (has_at_least_v9) { 210 | auto& avsMap = VFrame->getConstProperties(); 211 | int numKeys = m_pAviSynthFile->m_ScriptEnvironment->propNumKeys(&avsMap); 212 | if (numKeys > 0) { 213 | m_StreamInfo += std::format(L"\nProperties [{}]:", numKeys); 214 | } 215 | 216 | for (int i = 0; i < numKeys; i++) { 217 | const char* keyName = m_pAviSynthFile->m_ScriptEnvironment->propGetKey(&avsMap, i); 218 | if (keyName) { 219 | int64_t val_Int = 0; 220 | double val_Float = 0; 221 | const char* val_Data = 0; 222 | int err = 0; 223 | const char keyType = m_pAviSynthFile->m_ScriptEnvironment->propGetType(&avsMap, keyName); 224 | 225 | m_StreamInfo += std::format(L"\n{:>2}: <{}> '{}'", i, keyType, A2WStr(keyName)); 226 | 227 | switch (keyType) { 228 | case PROPTYPE_INT: 229 | val_Int = m_pAviSynthFile->m_ScriptEnvironment->propGetInt(&avsMap, keyName, 0, &err); 230 | if (!err) { 231 | m_StreamInfo += std::format(L" = {}", val_Int); 232 | if (strcmp(keyName, "_SARNum") == 0) { 233 | m_Sar.num = val_Int; 234 | } 235 | else if (strcmp(keyName, "_SARDen") == 0) { 236 | m_Sar.den = val_Int; 237 | } 238 | else { 239 | SetColorInfoFromFrameFrops(color_info, keyName, val_Int); 240 | } 241 | } 242 | break; 243 | case PROPTYPE_FLOAT: 244 | val_Float = m_pAviSynthFile->m_ScriptEnvironment->propGetFloat(&avsMap, keyName, 0, &err); 245 | if (!err) { 246 | m_StreamInfo += std::format(L" = {:.3f}", val_Float); 247 | } 248 | break; 249 | case PROPTYPE_DATA: 250 | val_Data = m_pAviSynthFile->m_ScriptEnvironment->propGetData(&avsMap, keyName, 0, &err); 251 | if (!err) { 252 | const int dataSize = m_pAviSynthFile->m_ScriptEnvironment->propGetDataSize(&avsMap, keyName, 0, &err); 253 | if (!err) { 254 | if (dataSize == 1 && strcmp(keyName, "_PictType") == 0) { 255 | m_StreamInfo += std::format(L" = {}", val_Data[0]); 256 | } else { 257 | m_StreamInfo += std::format(L", {} bytes", dataSize); 258 | } 259 | } 260 | } 261 | break; 262 | } 263 | } 264 | } 265 | } 266 | 267 | if (color_info) { 268 | m_ColorInfo = color_info | (AMCONTROL_USED | AMCONTROL_COLORINFO_PRESENT); 269 | } 270 | 271 | InitVideoMediaType(); 272 | 273 | DLog(m_StreamInfo); 274 | 275 | hr = S_OK; 276 | } 277 | catch ([[maybe_unused]] const std::exception& e) { 278 | DLog(L"{}\n{}", A2WStr(e.what()), error); 279 | 280 | hr = E_FAIL; 281 | } 282 | 283 | *phr = hr; 284 | } 285 | 286 | CAviSynthVideoStream::CAviSynthVideoStream(std::wstring_view error_str, CSource* pParent, HRESULT* phr) 287 | : CSourceStream(L"Video", phr, pParent, L"Video") 288 | , CSourceSeeking(L"Video", (IPin*)this, phr, &m_cSharedState) 289 | , m_pAviSynthFile(nullptr) 290 | { 291 | m_Format = GetFormatParamsAviSynth(VideoInfo::CS_BGR32); 292 | 293 | m_Width = 640; 294 | m_Height = 360; 295 | m_Pitch = m_Width * 4; 296 | m_PitchBuff = m_Pitch; 297 | m_BufferSize = m_PitchBuff * m_Height * m_Format.buffCoeff / 2; 298 | m_Sar = {}; 299 | 300 | m_fpsNum = 1; 301 | m_fpsDen = 1; 302 | m_NumFrames = 10; 303 | m_AvgTimePerFrame = UNITS; 304 | m_rtDuration = m_rtStop = UNITS * m_NumFrames; 305 | 306 | std::wstring str(error_str); 307 | m_BitmapError = GetBitmapWithText(str, m_Width, m_Height); 308 | 309 | if (m_BitmapError) { 310 | *phr = S_FALSE; 311 | InitVideoMediaType(); 312 | } else { 313 | *phr = E_FAIL; 314 | } 315 | } 316 | 317 | CAviSynthVideoStream::~CAviSynthVideoStream() 318 | { 319 | } 320 | 321 | STDMETHODIMP CAviSynthVideoStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) 322 | { 323 | CheckPointer(ppv, E_POINTER); 324 | 325 | return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) 326 | : CSourceStream::NonDelegatingQueryInterface(riid, ppv); 327 | } 328 | 329 | HRESULT CAviSynthVideoStream::OnThreadCreate() 330 | { 331 | CAutoLock cAutoLockShared(&m_cSharedState); 332 | 333 | m_FrameCounter = 0; 334 | m_CurrentFrame = (int)llMulDiv(m_rtStart, m_fpsNum, m_fpsDen * UNITS, 0); // round down 335 | 336 | return CSourceStream::OnThreadCreate(); 337 | } 338 | 339 | HRESULT CAviSynthVideoStream::OnThreadStartPlay() 340 | { 341 | m_bDiscontinuity = TRUE; 342 | return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); 343 | } 344 | 345 | void CAviSynthVideoStream::UpdateFromSeek() 346 | { 347 | if (ThreadExists()) { 348 | // next time around the loop, the worker thread will 349 | // pick up the position change. 350 | // We need to flush all the existing data - we must do that here 351 | // as our thread will probably be blocked in GetBuffer otherwise 352 | 353 | m_bFlushing = TRUE; 354 | 355 | DeliverBeginFlush(); 356 | // make sure we have stopped pushing 357 | Stop(); 358 | // complete the flush 359 | DeliverEndFlush(); 360 | 361 | m_bFlushing = FALSE; 362 | 363 | // restart 364 | Run(); 365 | } 366 | } 367 | 368 | HRESULT CAviSynthVideoStream::SetRate(double dRate) 369 | { 370 | if (dRate <= 0) { 371 | return E_INVALIDARG; 372 | } 373 | 374 | { 375 | CAutoLock lock(CSourceSeeking::m_pLock); 376 | m_dRateSeeking = dRate; 377 | } 378 | 379 | UpdateFromSeek(); 380 | 381 | return S_OK; 382 | } 383 | 384 | HRESULT CAviSynthVideoStream::ChangeStart() 385 | { 386 | { 387 | CAutoLock lock(CSourceSeeking::m_pLock); 388 | m_FrameCounter = 0; 389 | m_CurrentFrame = (int)llMulDiv(m_rtStart, m_fpsNum, m_fpsDen * UNITS, 0); // round down 390 | } 391 | 392 | UpdateFromSeek(); 393 | 394 | return S_OK; 395 | } 396 | 397 | HRESULT CAviSynthVideoStream::ChangeStop() 398 | { 399 | { 400 | CAutoLock lock(CSourceSeeking::m_pLock); 401 | if (m_CurrentFrame < m_NumFrames) { 402 | return S_OK; 403 | } 404 | } 405 | 406 | // We're already past the new stop time -- better flush the graph. 407 | UpdateFromSeek(); 408 | 409 | return S_OK; 410 | } 411 | 412 | void CAviSynthVideoStream::InitVideoMediaType() 413 | { 414 | m_mt.InitMediaType(); 415 | m_mt.SetType(&MEDIATYPE_Video); 416 | m_mt.SetSubtype(&m_Format.subtype); 417 | m_mt.SetFormatType(&FORMAT_VideoInfo2); 418 | m_mt.SetTemporalCompression(FALSE); 419 | m_mt.SetSampleSize(m_BufferSize); 420 | 421 | VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)m_mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER2)); 422 | ZeroMemory(vih2, sizeof(VIDEOINFOHEADER2)); 423 | vih2->rcSource = { 0, 0, (long)m_Width, (long)m_Height }; 424 | vih2->rcTarget = vih2->rcSource; 425 | vih2->AvgTimePerFrame = m_AvgTimePerFrame; 426 | vih2->bmiHeader.biSize = sizeof(vih2->bmiHeader); 427 | vih2->bmiHeader.biWidth = m_PitchBuff / m_Format.Packsize; 428 | vih2->bmiHeader.biHeight = (m_Format.fourcc == BI_RGB) ? -(long)m_Height : m_Height; 429 | vih2->bmiHeader.biPlanes = 1; 430 | vih2->bmiHeader.biBitCount = m_Format.bitCount; 431 | vih2->bmiHeader.biCompression = m_Format.fourcc; 432 | vih2->bmiHeader.biSizeImage = m_BufferSize; 433 | 434 | vih2->dwControlFlags = m_ColorInfo; 435 | 436 | if (m_Sar.num > 0 && m_Sar.den > 0 && m_Sar.num < INT16_MAX && m_Sar.den < INT16_MAX) { 437 | auto parX = m_Sar.num * m_Width; 438 | auto parY = m_Sar.den * m_Height; 439 | const auto gcd = std::gcd(parX, parY); 440 | parX /= gcd; 441 | parY /= gcd; 442 | vih2->dwPictAspectRatioX = parX; 443 | vih2->dwPictAspectRatioY = parY; 444 | } 445 | } 446 | 447 | HRESULT CAviSynthVideoStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) 448 | { 449 | //CAutoLock cAutoLock(m_pFilter->pStateLock()); 450 | 451 | ASSERT(pAlloc); 452 | ASSERT(pProperties); 453 | 454 | HRESULT hr = NOERROR; 455 | 456 | pProperties->cBuffers = 1; 457 | pProperties->cbBuffer = m_BufferSize; 458 | 459 | ALLOCATOR_PROPERTIES Actual; 460 | if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { 461 | return hr; 462 | } 463 | 464 | if (Actual.cbBuffer < pProperties->cbBuffer) { 465 | return E_FAIL; 466 | } 467 | ASSERT(Actual.cBuffers == pProperties->cBuffers); 468 | 469 | return NOERROR; 470 | } 471 | 472 | HRESULT CAviSynthVideoStream::FillBuffer(IMediaSample* pSample) 473 | { 474 | { 475 | CAutoLock cAutoLockShared(&m_cSharedState); 476 | 477 | if (m_CurrentFrame >= m_NumFrames) { 478 | return S_FALSE; 479 | } 480 | 481 | AM_MEDIA_TYPE* pmt; 482 | if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { 483 | CMediaType mt(*pmt); 484 | SetMediaType(&mt); 485 | DeleteMediaType(pmt); 486 | } 487 | 488 | if (m_mt.formattype != FORMAT_VideoInfo2) { 489 | return S_FALSE; 490 | } 491 | 492 | BYTE* dst_data = nullptr; 493 | HRESULT hr = pSample->GetPointer(&dst_data); 494 | if (FAILED(hr) || !dst_data) { 495 | return S_FALSE; 496 | } 497 | 498 | long buffSize = pSample->GetSize(); 499 | if (buffSize < (long)m_BufferSize) { 500 | return S_FALSE; 501 | } 502 | 503 | UINT DataLength = 0; 504 | 505 | if (m_BitmapError) { 506 | DataLength = m_PitchBuff * m_Height; 507 | 508 | const BYTE* src_data = m_BitmapError.get(); 509 | if (m_Pitch == m_PitchBuff) { 510 | memcpy(dst_data, src_data, DataLength); 511 | } 512 | else { 513 | UINT linesize = std::min(m_Pitch, m_PitchBuff); 514 | for (UINT y = 0; y < m_Height; y++) { 515 | memcpy(dst_data, src_data, linesize); 516 | src_data += m_Pitch; 517 | dst_data += m_PitchBuff; 518 | } 519 | } 520 | } 521 | else { 522 | auto Clip = m_pAviSynthFile->m_AVSValue.AsClip(); 523 | auto VFrame = Clip->GetFrame(m_CurrentFrame, m_pAviSynthFile->m_ScriptEnvironment); 524 | 525 | const int num_planes = m_Format.planes; 526 | for (int i = 0; i < num_planes; i++) { 527 | const int plane = m_Planes[i]; 528 | const BYTE* src_data = VFrame->GetReadPtr(plane); 529 | int src_pitch = VFrame->GetPitch(plane); 530 | const UINT height = VFrame->GetHeight(plane); 531 | UINT dst_pitch = m_PitchBuff; 532 | if (i > 0 && (m_Format.ASformat&VideoInfo::CS_Sub_Width_Mask) == VideoInfo::CS_Sub_Width_2) { 533 | dst_pitch /= 2; 534 | } 535 | 536 | if (m_Format.fourcc == BI_RGB) { 537 | src_data += src_pitch * (height - 1); 538 | src_pitch = -src_pitch; 539 | } 540 | 541 | if (src_pitch == dst_pitch) { 542 | memcpy(dst_data, src_data, dst_pitch * height); 543 | dst_data += dst_pitch * height; 544 | } 545 | else { 546 | UINT linesize = std::min((UINT)abs(src_pitch), dst_pitch); 547 | for (UINT y = 0; y < height; y++) { 548 | memcpy(dst_data, src_data, linesize); 549 | src_data += src_pitch; 550 | dst_data += dst_pitch; 551 | } 552 | } 553 | DataLength += dst_pitch * height; 554 | } 555 | } 556 | 557 | pSample->SetActualDataLength(DataLength); 558 | 559 | // Sample time 560 | REFERENCE_TIME rtStart = llMulDiv(UNITS * m_FrameCounter, m_fpsDen, m_fpsNum, 0); 561 | REFERENCE_TIME rtStop = llMulDiv(UNITS * (m_FrameCounter+1), m_fpsDen, m_fpsNum, 0); 562 | // The sample times are modified by the current rate. 563 | if (m_dRateSeeking != 1.0) { 564 | rtStart = static_cast(rtStart / m_dRateSeeking); 565 | rtStop = static_cast(rtStop / m_dRateSeeking); 566 | } 567 | pSample->SetTime(&rtStart, &rtStop); 568 | 569 | m_FrameCounter++; 570 | m_CurrentFrame++; 571 | } 572 | 573 | pSample->SetSyncPoint(TRUE); 574 | 575 | if (m_bDiscontinuity) { 576 | pSample->SetDiscontinuity(TRUE); 577 | m_bDiscontinuity = FALSE; 578 | } 579 | 580 | return S_OK; 581 | } 582 | 583 | HRESULT CAviSynthVideoStream::CheckMediaType(const CMediaType* pmt) 584 | { 585 | if (pmt->majortype == MEDIATYPE_Video 586 | && pmt->subtype == m_Format.subtype 587 | && pmt->formattype == FORMAT_VideoInfo2) { 588 | 589 | VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)pmt->Format(); 590 | if (vih2->bmiHeader.biWidth >= (long)m_Width && abs(vih2->bmiHeader.biHeight) == (long)m_Height) { 591 | return S_OK; 592 | } 593 | } 594 | 595 | return E_INVALIDARG; 596 | } 597 | 598 | HRESULT CAviSynthVideoStream::SetMediaType(const CMediaType* pMediaType) 599 | { 600 | HRESULT hr = __super::SetMediaType(pMediaType); 601 | 602 | if (SUCCEEDED(hr)) { 603 | VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)pMediaType->Format(); 604 | m_PitchBuff = m_Format.Packsize * vih2->bmiHeader.biWidth; 605 | ASSERT(m_PitchBuff >= m_Pitch); 606 | m_BufferSize = m_PitchBuff * abs(vih2->bmiHeader.biHeight) * m_Format.buffCoeff / 2; 607 | 608 | DLog(L"SetMediaType with subtype {}", GUIDtoWString(m_mt.subtype)); 609 | } 610 | 611 | return hr; 612 | } 613 | 614 | HRESULT CAviSynthVideoStream::GetMediaType(int iPosition, CMediaType* pmt) 615 | { 616 | CAutoLock cAutoLock(m_pFilter->pStateLock()); 617 | 618 | if (iPosition < 0) { 619 | return E_INVALIDARG; 620 | } 621 | if (iPosition >= 1) { 622 | return VFW_S_NO_MORE_ITEMS; 623 | } 624 | 625 | *pmt = m_mt; 626 | 627 | return S_OK; 628 | } 629 | 630 | // 631 | // CAviSynthAudioStream 632 | // 633 | 634 | CAviSynthAudioStream::CAviSynthAudioStream(CAviSynthFile* pAviSynthFile, CSource* pParent, HRESULT* phr) 635 | : CSourceStream(L"Audio", phr, pParent, L"Audio") 636 | , CSourceSeeking(L"Audio", (IPin*)this, phr, &m_cSharedState) 637 | , m_pAviSynthFile(pAviSynthFile) 638 | { 639 | CAutoLock cAutoLock(&m_cSharedState); 640 | 641 | HRESULT hr; 642 | std::wstring error; 643 | 644 | try { 645 | auto Clip = m_pAviSynthFile->m_AVSValue.AsClip(); 646 | auto VInfo = Clip->GetVideoInfo(); 647 | 648 | if (VInfo.HasAudio()) { 649 | m_Channels = VInfo.AudioChannels(); 650 | m_SampleRate = VInfo.SamplesPerSecond(); 651 | m_BytesPerSample = VInfo.BytesPerAudioSample(); 652 | m_BitDepth = m_BytesPerSample * 8 / m_Channels; 653 | m_SampleType = (AvsSampleType)VInfo.SampleType(); 654 | m_NumSamples = VInfo.num_audio_samples; 655 | 656 | WORD wFormatTag; 657 | if (m_SampleType == SAMPLE_FLOAT) { 658 | wFormatTag = WAVE_FORMAT_IEEE_FLOAT; 659 | m_Subtype = MEDIASUBTYPE_IEEE_FLOAT; 660 | } else { 661 | wFormatTag = WAVE_FORMAT_PCM; 662 | m_Subtype = MEDIASUBTYPE_PCM; 663 | } 664 | 665 | m_BufferSamples = m_SampleRate / 5; // 5 for 200 ms; 20 for 50 ms 666 | 667 | m_rtDuration = m_rtStop = llMulDiv(m_NumSamples, UNITS, m_SampleRate, 0); 668 | 669 | m_mt.InitMediaType(); 670 | m_mt.SetType(&MEDIATYPE_Audio); 671 | m_mt.SetSubtype(&m_Subtype); 672 | m_mt.SetFormatType(&FORMAT_WaveFormatEx); 673 | m_mt.SetTemporalCompression(FALSE); 674 | m_mt.SetSampleSize(m_BytesPerSample); 675 | 676 | bool has_at_least_v10 = true; 677 | try { 678 | m_pAviSynthFile->m_ScriptEnvironment->CheckVersion(10); 679 | } 680 | catch (const AvisynthError&) { 681 | has_at_least_v10 = false; 682 | } 683 | 684 | UINT channelLayout = has_at_least_v10 ? VInfo.GetChannelMask() : 0; 685 | 686 | if (channelLayout) { 687 | WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)m_mt.AllocFormatBuffer(sizeof(WAVEFORMATEXTENSIBLE)); 688 | wfex->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 689 | wfex->Format.nChannels = m_Channels; 690 | wfex->Format.nSamplesPerSec = m_SampleRate; 691 | wfex->Format.nAvgBytesPerSec = m_BytesPerSample * m_SampleRate; 692 | wfex->Format.nBlockAlign = m_BytesPerSample; 693 | wfex->Format.wBitsPerSample = m_BitDepth; 694 | wfex->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); // 22 695 | wfex->Samples.wValidBitsPerSample = m_BitDepth; 696 | wfex->dwChannelMask = channelLayout; 697 | wfex->SubFormat = m_Subtype; 698 | } 699 | else { 700 | WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.AllocFormatBuffer(sizeof(WAVEFORMATEX)); 701 | wfe->wFormatTag = wFormatTag; 702 | wfe->nChannels = m_Channels; 703 | wfe->nSamplesPerSec = m_SampleRate; 704 | wfe->nAvgBytesPerSec = m_BytesPerSample * m_SampleRate; 705 | wfe->nBlockAlign = m_BytesPerSample; 706 | wfe->wBitsPerSample = m_BitDepth; 707 | wfe->cbSize = 0; 708 | } 709 | 710 | m_StreamInfo = std::format(L"Audio stream: {} channels, {} Hz, ", m_Channels, m_SampleRate); 711 | switch (m_SampleType) { 712 | case SAMPLE_INT8: m_StreamInfo.append(L"int8"); break; 713 | case SAMPLE_INT16: m_StreamInfo.append(L"int16"); break; 714 | case SAMPLE_INT24: m_StreamInfo.append(L"int24"); break; 715 | case SAMPLE_INT32: m_StreamInfo.append(L"int32"); break; 716 | case SAMPLE_FLOAT: m_StreamInfo.append(L"float32"); break; 717 | } 718 | DLog(m_StreamInfo); 719 | 720 | hr = S_OK; 721 | } 722 | } 723 | catch ([[maybe_unused]] const std::exception& e) { 724 | DLog(L"{}\n{}", A2WStr(e.what()), error); 725 | 726 | hr = E_FAIL; 727 | } 728 | 729 | *phr = hr; 730 | } 731 | 732 | CAviSynthAudioStream::~CAviSynthAudioStream() 733 | { 734 | } 735 | 736 | STDMETHODIMP CAviSynthAudioStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) 737 | { 738 | CheckPointer(ppv, E_POINTER); 739 | 740 | return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) 741 | : CSourceStream::NonDelegatingQueryInterface(riid, ppv); 742 | } 743 | 744 | HRESULT CAviSynthAudioStream::OnThreadCreate() 745 | { 746 | CAutoLock cAutoLockShared(&m_cSharedState); 747 | 748 | m_SampleCounter = 0; 749 | m_CurrentSample = (int)llMulDiv(m_rtStart, m_SampleRate, UNITS, 0); // round down 750 | 751 | return CSourceStream::OnThreadCreate(); 752 | } 753 | 754 | HRESULT CAviSynthAudioStream::OnThreadStartPlay() 755 | { 756 | m_bDiscontinuity = TRUE; 757 | return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); 758 | } 759 | 760 | void CAviSynthAudioStream::UpdateFromSeek() 761 | { 762 | if (ThreadExists()) { 763 | // next time around the loop, the worker thread will 764 | // pick up the position change. 765 | // We need to flush all the existing data - we must do that here 766 | // as our thread will probably be blocked in GetBuffer otherwise 767 | 768 | m_bFlushing = TRUE; 769 | 770 | DeliverBeginFlush(); 771 | // make sure we have stopped pushing 772 | Stop(); 773 | // complete the flush 774 | DeliverEndFlush(); 775 | 776 | m_bFlushing = FALSE; 777 | 778 | // restart 779 | Run(); 780 | } 781 | } 782 | 783 | HRESULT CAviSynthAudioStream::SetRate(double dRate) 784 | { 785 | if (dRate <= 0) { 786 | return E_INVALIDARG; 787 | } 788 | 789 | { 790 | CAutoLock lock(CSourceSeeking::m_pLock); 791 | m_dRateSeeking = dRate; 792 | } 793 | 794 | UpdateFromSeek(); 795 | 796 | return S_OK; 797 | } 798 | 799 | HRESULT CAviSynthAudioStream::ChangeStart() 800 | { 801 | { 802 | CAutoLock lock(CSourceSeeking::m_pLock); 803 | m_SampleCounter = 0; 804 | m_CurrentSample = (int)llMulDiv(m_rtStart, m_SampleRate, UNITS, 0); // round down 805 | } 806 | 807 | UpdateFromSeek(); 808 | 809 | return S_OK; 810 | } 811 | 812 | HRESULT CAviSynthAudioStream::ChangeStop() 813 | { 814 | { 815 | CAutoLock lock(CSourceSeeking::m_pLock); 816 | if (m_CurrentSample < m_NumSamples) { 817 | return S_OK; 818 | } 819 | } 820 | 821 | // We're already past the new stop time -- better flush the graph. 822 | UpdateFromSeek(); 823 | 824 | return S_OK; 825 | } 826 | 827 | HRESULT CAviSynthAudioStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) 828 | { 829 | //CAutoLock cAutoLock(m_pFilter->pStateLock()); 830 | 831 | ASSERT(pAlloc); 832 | ASSERT(pProperties); 833 | 834 | HRESULT hr = NOERROR; 835 | 836 | pProperties->cBuffers = 1; 837 | pProperties->cbBuffer = m_BufferSamples * m_BytesPerSample; 838 | 839 | ALLOCATOR_PROPERTIES Actual; 840 | if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { 841 | return hr; 842 | } 843 | 844 | if (Actual.cbBuffer < pProperties->cbBuffer) { 845 | return E_FAIL; 846 | } 847 | ASSERT(Actual.cBuffers == pProperties->cBuffers); 848 | 849 | return NOERROR; 850 | } 851 | 852 | HRESULT CAviSynthAudioStream::FillBuffer(IMediaSample* pSample) 853 | { 854 | { 855 | CAutoLock cAutoLockShared(&m_cSharedState); 856 | 857 | if (m_CurrentSample >= m_NumSamples) { 858 | return S_FALSE; 859 | } 860 | 861 | AM_MEDIA_TYPE* pmt; 862 | if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { 863 | CMediaType mt(*pmt); 864 | SetMediaType(&mt); 865 | DeleteMediaType(pmt); 866 | } 867 | 868 | if (m_mt.formattype != FORMAT_WaveFormatEx) { 869 | return S_FALSE; 870 | } 871 | 872 | BYTE* dst_data = nullptr; 873 | HRESULT hr = pSample->GetPointer(&dst_data); 874 | if (FAILED(hr) || !dst_data) { 875 | return S_FALSE; 876 | } 877 | 878 | long buffSize = pSample->GetSize(); 879 | if (buffSize < (long)(m_BufferSamples * m_BytesPerSample)) { 880 | return S_FALSE; 881 | } 882 | 883 | auto Clip = m_pAviSynthFile->m_AVSValue.AsClip(); 884 | int64_t count = std::min(m_BufferSamples, m_NumSamples - m_CurrentSample); 885 | Clip->GetAudio(dst_data, m_CurrentSample, count, m_pAviSynthFile->m_ScriptEnvironment); 886 | 887 | pSample->SetActualDataLength(count * m_BytesPerSample); 888 | 889 | // Sample time 890 | REFERENCE_TIME rtStart = llMulDiv(m_SampleCounter, UNITS, m_SampleRate, 0); 891 | REFERENCE_TIME rtStop = llMulDiv(m_SampleCounter + count, UNITS, m_SampleRate, 0); 892 | // The sample times are modified by the current rate. 893 | if (m_dRateSeeking != 1.0) { 894 | rtStart = static_cast(rtStart / m_dRateSeeking); 895 | rtStop = static_cast(rtStop / m_dRateSeeking); 896 | } 897 | pSample->SetTime(&rtStart, &rtStop); 898 | 899 | m_SampleCounter += count; 900 | m_CurrentSample += count; 901 | } 902 | 903 | pSample->SetSyncPoint(TRUE); 904 | 905 | if (m_bDiscontinuity) { 906 | pSample->SetDiscontinuity(TRUE); 907 | m_bDiscontinuity = FALSE; 908 | } 909 | 910 | return S_OK; 911 | } 912 | 913 | HRESULT CAviSynthAudioStream::CheckMediaType(const CMediaType* pmt) 914 | { 915 | if (pmt->majortype == MEDIATYPE_Audio 916 | && pmt->subtype == m_Subtype 917 | && pmt->formattype == FORMAT_WaveFormatEx) { 918 | 919 | WAVEFORMATEX* wfe = (WAVEFORMATEX*)pmt->Format(); 920 | if ((int)wfe->nChannels >= m_Channels 921 | && (int)wfe->nSamplesPerSec == m_SampleRate 922 | && (int)wfe->nBlockAlign == m_BytesPerSample 923 | && (int)wfe->wBitsPerSample == m_BitDepth) { 924 | return S_OK; 925 | } 926 | } 927 | 928 | return E_INVALIDARG; 929 | } 930 | 931 | HRESULT CAviSynthAudioStream::SetMediaType(const CMediaType* pMediaType) 932 | { 933 | HRESULT hr = __super::SetMediaType(pMediaType); 934 | 935 | if (SUCCEEDED(hr)) { 936 | DLog(L"SetMediaType with subtype {}", GUIDtoWString(m_mt.subtype)); 937 | } 938 | 939 | return hr; 940 | } 941 | 942 | HRESULT CAviSynthAudioStream::GetMediaType(int iPosition, CMediaType* pmt) 943 | { 944 | CAutoLock cAutoLock(m_pFilter->pStateLock()); 945 | 946 | if (iPosition < 0) { 947 | return E_INVALIDARG; 948 | } 949 | if (iPosition >= 1) { 950 | return VFW_S_NO_MORE_ITEMS; 951 | } 952 | 953 | *pmt = m_mt; 954 | 955 | return S_OK; 956 | } 957 | -------------------------------------------------------------------------------- /Source/AviSynthStream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifndef __AVISYNTH_7_H__ 10 | #include "../Include/avisynth.h" 11 | #endif 12 | #include "Helper.h" 13 | 14 | // 15 | // CAviSynthFile 16 | // 17 | 18 | class CAviSynthFile 19 | { 20 | friend class CAviSynthVideoStream; 21 | friend class CAviSynthAudioStream; 22 | 23 | HMODULE m_hAviSynthDll = nullptr; 24 | 25 | IScriptEnvironment* m_ScriptEnvironment = nullptr; 26 | AVSValue m_AVSValue; 27 | const AVS_Linkage* m_Linkage = nullptr; 28 | 29 | std::wstring m_FileInfo; 30 | 31 | public: 32 | CAviSynthFile(const WCHAR* filepath, CSource* pParent, HRESULT* phr); 33 | ~CAviSynthFile(); 34 | 35 | std::wstring_view GetInfo() { return m_FileInfo; } 36 | }; 37 | 38 | // 39 | // CAviSynthVideoStream 40 | // 41 | 42 | class CAviSynthVideoStream 43 | : public CSourceStream 44 | , public CSourceSeeking 45 | { 46 | private: 47 | CCritSec m_cSharedState; 48 | 49 | const CAviSynthFile* m_pAviSynthFile; 50 | 51 | BOOL m_bDiscontinuity = FALSE; 52 | BOOL m_bFlushing = FALSE; 53 | 54 | PVideoFrame m_Frame; 55 | int m_Planes[4] = {}; 56 | 57 | std::unique_ptr m_BitmapError; 58 | 59 | REFERENCE_TIME m_AvgTimePerFrame = 0; 60 | int m_FrameCounter = 0; 61 | int m_CurrentFrame = 0; 62 | 63 | FmtParams_t m_Format = {}; 64 | UINT m_Width = 0; 65 | UINT m_Height = 0; 66 | UINT m_Pitch = 0; 67 | UINT m_PitchBuff = 0; 68 | UINT m_BufferSize = 0; 69 | 70 | UINT m_ColorInfo = 0; 71 | struct { 72 | int64_t num = 0; 73 | int64_t den = 0; 74 | } m_Sar; 75 | 76 | int m_NumFrames = 0; 77 | unsigned m_fpsNum = 1; 78 | unsigned m_fpsDen = 1; 79 | 80 | std::wstring m_StreamInfo; 81 | 82 | public: 83 | CAviSynthVideoStream(CAviSynthFile* pAviSynthFile, CSource* pParent, HRESULT* phr); 84 | CAviSynthVideoStream(std::wstring_view error_str, CSource* pParent, HRESULT* phr); 85 | virtual ~CAviSynthVideoStream(); 86 | 87 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override; 88 | 89 | std::wstring_view GetInfo() { return m_StreamInfo; } 90 | 91 | private: 92 | HRESULT OnThreadCreate() override; 93 | HRESULT OnThreadStartPlay() override; 94 | 95 | void UpdateFromSeek(); 96 | 97 | // IMediaSeeking 98 | STDMETHODIMP SetRate(double dRate) override; 99 | 100 | HRESULT ChangeStart() override; 101 | HRESULT ChangeStop() override; 102 | HRESULT ChangeRate() override { return S_OK; } 103 | 104 | void InitVideoMediaType(); 105 | 106 | public: 107 | HRESULT DecideBufferSize(IMemAllocator* pIMemAlloc, ALLOCATOR_PROPERTIES* pProperties) override; 108 | HRESULT FillBuffer(IMediaSample* pSample) override; 109 | HRESULT CheckMediaType(const CMediaType* pMediaType) override; 110 | HRESULT SetMediaType(const CMediaType* pMediaType) override; 111 | HRESULT GetMediaType(int iPosition, CMediaType* pmt) override; 112 | 113 | // IQualityControl 114 | STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) override { return E_NOTIMPL; } 115 | }; 116 | 117 | // 118 | // CAviSynthAudioStream 119 | // 120 | 121 | class CAviSynthAudioStream 122 | : public CSourceStream 123 | , public CSourceSeeking 124 | { 125 | private: 126 | CCritSec m_cSharedState; 127 | 128 | const CAviSynthFile* m_pAviSynthFile; 129 | 130 | BOOL m_bDiscontinuity = FALSE; 131 | BOOL m_bFlushing = FALSE; 132 | 133 | GUID m_Subtype = {}; 134 | int m_Channels = 0; 135 | int m_SampleRate = 0; 136 | int m_BytesPerSample = 0; // for all audio channels 137 | int m_BitDepth = 0; 138 | AvsSampleType m_SampleType = (AvsSampleType)0; 139 | 140 | int m_BufferSamples = 0; 141 | 142 | int64_t m_SampleCounter = 0; 143 | int64_t m_CurrentSample = 0; 144 | int64_t m_NumSamples = 0; 145 | 146 | std::wstring m_StreamInfo; 147 | 148 | public: 149 | CAviSynthAudioStream(CAviSynthFile* pAviSynthFile, CSource* pParent, HRESULT* phr); 150 | virtual ~CAviSynthAudioStream(); 151 | 152 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override; 153 | 154 | std::wstring_view GetInfo() { return m_StreamInfo; } 155 | 156 | private: 157 | HRESULT OnThreadCreate() override; 158 | HRESULT OnThreadStartPlay() override; 159 | void UpdateFromSeek(); 160 | 161 | // IMediaSeeking 162 | STDMETHODIMP SetRate(double dRate) override; 163 | 164 | HRESULT ChangeStart() override; 165 | HRESULT ChangeStop() override; 166 | HRESULT ChangeRate() override { return S_OK; } 167 | 168 | public: 169 | HRESULT DecideBufferSize(IMemAllocator* pIMemAlloc, ALLOCATOR_PROPERTIES* pProperties) override; 170 | HRESULT FillBuffer(IMediaSample* pSample) override; 171 | HRESULT CheckMediaType(const CMediaType* pMediaType) override; 172 | HRESULT SetMediaType(const CMediaType* pMediaType) override; 173 | HRESULT GetMediaType(int iPosition, CMediaType* pmt) override; 174 | 175 | // IQualityControl 176 | STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) override { return E_NOTIMPL; } 177 | }; 178 | -------------------------------------------------------------------------------- /Source/Helper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #include "stdafx.h" 8 | #include "../Include/Version.h" 9 | 10 | #ifndef __AVISYNTH_7_H__ 11 | #include "../Include/avisynth.h" 12 | #endif 13 | 14 | #ifndef VSSCRIPT_H 15 | #include "../Include/VSScript4.h" 16 | #endif 17 | 18 | #include "Helper.h" 19 | 20 | 21 | std::wstring GetVersionStr() 22 | { 23 | std::wstring version = _CRT_WIDE(VERSION_STR); 24 | #if VER_RELEASE != 1 25 | version += std::format(L" (git-{}-{})", 26 | _CRT_WIDE(_CRT_STRINGIZE(REV_DATE)), 27 | _CRT_WIDE(_CRT_STRINGIZE(REV_HASH)) 28 | ); 29 | #endif 30 | #ifdef _WIN64 31 | version.append(L" x64"); 32 | #endif 33 | #ifdef _DEBUG 34 | version.append(L" DEBUG"); 35 | #endif 36 | return version; 37 | } 38 | 39 | LPCWSTR GetNameAndVersion() 40 | { 41 | static std::wstring version = L"MPC Script Source " + GetVersionStr(); 42 | 43 | return version.c_str(); 44 | } 45 | 46 | static const FmtParams_t s_FormatTable[] = { 47 | // fourcc | subtype | ASformat | VSformat | str |Packsize|buffCoeff|CDepth|planes|bitCount 48 | {DWORD(-1), GUID_NULL, 0, 0, nullptr, 0, 0, 0, 0, 0}, 49 | // YUV packed 50 | {FCC('YUY2'), MEDIASUBTYPE_YUY2, VideoInfo::CS_YUY2, 0, L"YUY2", 2, 2, 8, 1, 16}, 51 | // YUV planar 52 | {FCC('YV12'), MEDIASUBTYPE_YV12, VideoInfo::CS_I420, 0, L"I420", 1, 3, 8, 3, 12}, 53 | {FCC('YV12'), MEDIASUBTYPE_YV12, VideoInfo::CS_YV12, pfYUV420P8, L"YV12", 1, 3, 8, 3, 12}, 54 | {MAKEFOURCC('Y','3',11,10), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV420P10, pfYUV420P10, L"YUV420P10", 2, 3, 10, 3, 24}, 55 | {MAKEFOURCC('Y','3',11,12), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV420P12, pfYUV420P12, L"YUV420P12", 2, 3, 12, 3, 24}, 56 | {MAKEFOURCC('Y','3',11,14), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV420P14, pfYUV420P14, L"YUV420P14", 2, 3, 14, 3, 24}, 57 | {MAKEFOURCC('Y','3',11,16), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV420P16, pfYUV420P16, L"YUV420P16", 2, 3, 16, 3, 24}, 58 | {FCC('YV16'), MEDIASUBTYPE_YV16, VideoInfo::CS_YV16, pfYUV422P8, L"YV16", 1, 4, 8, 3, 16}, 59 | {MAKEFOURCC('Y','3',10,10), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV422P10, pfYUV422P10, L"YUV422P10", 2, 4, 10, 3, 32}, 60 | {MAKEFOURCC('Y','3',10,12), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV422P12, pfYUV422P12, L"YUV422P12", 2, 4, 12, 3, 32}, 61 | {MAKEFOURCC('Y','3',10,14), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV422P14, pfYUV422P14, L"YUV422P14", 2, 4, 14, 3, 32}, 62 | {MAKEFOURCC('Y','3',10,16), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV422P16, pfYUV422P16, L"YUV422P16", 2, 4, 16, 3, 32}, 63 | {FCC('YV24'), MEDIASUBTYPE_YV24, VideoInfo::CS_YV24, pfYUV444P8, L"YV24", 1, 6, 8, 3, 24}, 64 | {MAKEFOURCC('Y','3',0,10), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV444P10, pfYUV444P10, L"YUV444P10", 2, 6, 10, 3, 48}, 65 | {MAKEFOURCC('Y','3',0,12), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV444P12, pfYUV444P12, L"YUV444P12", 2, 6, 12, 3, 48}, 66 | {MAKEFOURCC('Y','3',0,14), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV444P14, pfYUV444P14, L"YUV444P14", 2, 6, 14, 3, 48}, 67 | {MAKEFOURCC('Y','3',0,16), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUV444P16, pfYUV444P16, L"YUV444P16", 2, 6, 16, 3, 48}, 68 | // YUV planar whith alpha 69 | {MAKEFOURCC('Y','4',0,8), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUVA444, 0, L"YUVA444P8", 1, 8, 8, 4, 32}, 70 | {MAKEFOURCC('Y','4',0,10), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUVA444P10, 0, L"YUVA444P10", 2, 8, 10, 4, 64}, 71 | {MAKEFOURCC('Y','4',0,16), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_YUVA444P16, 0, L"YUVA444P16", 2, 8, 16, 4, 64}, 72 | // RGB packed 73 | {BI_RGB, MEDIASUBTYPE_RGB24, VideoInfo::CS_BGR24, 0, L"RGB24", 3, 2, 8, 1, 24}, 74 | {BI_RGB, MEDIASUBTYPE_RGB32, 0, 0, L"RGB32", 4, 2, 8, 1, 32}, 75 | {BI_RGB, MEDIASUBTYPE_ARGB32, VideoInfo::CS_BGR32, 0, L"ARGB32", 4, 2, 8, 1, 32}, 76 | {MAKEFOURCC('B','G','R',48), MEDIASUBTYPE_BGR48, VideoInfo::CS_BGR48, 0, L"BGR48", 6, 2, 16, 1, 48}, 77 | {MAKEFOURCC('B','R','A',64), MEDIASUBTYPE_BGRA64, VideoInfo::CS_BGR64, 0, L"BGRA64", 8, 2, 16, 1, 64}, 78 | // RGB planar 79 | {MAKEFOURCC('G','3',0,8), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_RGBP, pfRGB24, L"RGBP8", 1, 6, 8, 3, 24}, 80 | {MAKEFOURCC('G','3',0,10), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_RGBP10, pfRGB30, L"RGBP10", 2, 6, 10, 3, 48}, 81 | {MAKEFOURCC('G','3',0,16), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_RGBP16, pfRGB48, L"RGBP16", 2, 6, 16, 3, 48}, 82 | // RGB planar whith alpha 83 | {MAKEFOURCC('G','4',0,8), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_RGBAP, 0, L"RGBAP8", 1, 8, 8, 4, 32}, 84 | {MAKEFOURCC('G','4',0,10), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_RGBAP10, 0, L"RGBAP10", 2, 8, 10, 4, 64}, 85 | {MAKEFOURCC('G','4',0,16), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_RGBAP16, 0, L"RGBAP16", 2, 8, 16, 4, 64}, 86 | // grayscale 87 | {FCC('Y800'), MEDIASUBTYPE_Y800, VideoInfo::CS_Y8, pfGray8, L"Y8", 1, 2, 8, 1, 8}, 88 | {MAKEFOURCC('Y','1',0,10), MEDIASUBTYPE_LAV_RAWVIDEO, VideoInfo::CS_Y10, pfGray10, L"Y10", 2, 2, 10, 1, 16}, 89 | {MAKEFOURCC('Y','1',0,16), MEDIASUBTYPE_Y16, VideoInfo::CS_Y16, pfGray16, L"Y16", 2, 2, 16, 1, 16}, 90 | }; 91 | 92 | const FmtParams_t& GetFormatParamsAviSynth(const int asFormat) 93 | { 94 | for (const auto& f : s_FormatTable) { 95 | if (f.ASformat == asFormat) { 96 | return f; 97 | } 98 | } 99 | return s_FormatTable[0]; 100 | } 101 | 102 | const FmtParams_t& GetFormatParamsVapourSynth(const int vsVideoFormat) 103 | { 104 | for (const auto& f : s_FormatTable) { 105 | if (f.VSformat == vsVideoFormat) { 106 | return f; 107 | } 108 | } 109 | return s_FormatTable[0]; 110 | } 111 | 112 | std::unique_ptr GetBitmapWithText(const std::wstring& text, const long width, const long height) 113 | { 114 | HFONT hFont = CreateFontW(-14, 0, 0, 0, FW_NORMAL, FALSE, 115 | FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, 116 | CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, 117 | FIXED_PITCH, L"Consolas"); 118 | if (!hFont) { 119 | return nullptr; 120 | } 121 | 122 | BOOL ret = 0; 123 | HDC hDC = CreateCompatibleDC(nullptr); 124 | SetMapMode(hDC, MM_TEXT); 125 | 126 | HFONT hFontOld = (HFONT)SelectObject(hDC, hFont); 127 | 128 | SIZE size; 129 | ret = GetTextExtentPoint32W(hDC, L"_", 1, &size); 130 | 131 | // Prepare to create a bitmap 132 | BITMAPINFO bmi = {}; 133 | bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 134 | bmi.bmiHeader.biWidth = width; 135 | bmi.bmiHeader.biHeight = -height; 136 | bmi.bmiHeader.biPlanes = 1; 137 | bmi.bmiHeader.biCompression = BI_RGB; 138 | bmi.bmiHeader.biBitCount = 32; 139 | 140 | HGDIOBJ hBitmapOld = nullptr; 141 | void* pBitmapBits = nullptr; 142 | HBITMAP hBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &pBitmapBits, nullptr, 0); 143 | if (pBitmapBits) { 144 | HGDIOBJ hBitmapOld = SelectObject(hDC, hBitmap); 145 | 146 | SetTextColor(hDC, RGB(255, 255, 255)); 147 | SetBkColor(hDC, RGB(64, 64, 64)); 148 | RECT rect = {0, 0, width, height}; 149 | HBRUSH hBrush = CreateSolidBrush(RGB(64, 64, 64)); 150 | FillRect(hDC, &rect, hBrush); 151 | DrawTextW(hDC, text.c_str(), text.size(), &rect, DT_LEFT|DT_WORDBREAK); 152 | 153 | GdiFlush(); 154 | DeleteObject(hBrush); 155 | 156 | const long len = width * height * 4; 157 | std::unique_ptr bitmapData(new(std::nothrow) BYTE[len]); 158 | 159 | if (bitmapData) { 160 | memcpy(bitmapData.get(), pBitmapBits, len); 161 | } 162 | 163 | SelectObject(hDC, hBitmapOld); 164 | DeleteObject(hBitmap); 165 | 166 | SelectObject(hDC, hFontOld); 167 | DeleteObject(hFont); 168 | DeleteDC(hDC); 169 | 170 | return bitmapData; 171 | } 172 | 173 | SelectObject(hDC, hFontOld); 174 | DeleteObject(hFont); 175 | DeleteDC(hDC); 176 | 177 | return nullptr; 178 | } 179 | -------------------------------------------------------------------------------- /Source/Helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "Utils/Util.h" 10 | #include "Utils/StringUtil.h" 11 | 12 | LPCWSTR GetNameAndVersion(); 13 | 14 | struct FmtParams_t { 15 | DWORD fourcc; 16 | GUID subtype; 17 | int ASformat; 18 | int VSformat; 19 | const wchar_t* str; 20 | int Packsize; 21 | int buffCoeff; 22 | int CDepth; 23 | int planes; 24 | int bitCount; 25 | }; 26 | 27 | const FmtParams_t& GetFormatParamsAviSynth(const int asFormat); 28 | const FmtParams_t& GetFormatParamsVapourSynth(const int vsVideoFormat); 29 | 30 | std::unique_ptr GetBitmapWithText(const std::wstring& text, const long width, const long height); 31 | -------------------------------------------------------------------------------- /Source/IScriptSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #pragma once 8 | 9 | interface __declspec(uuid("1B3DA9DF-63CA-46ED-8572-1615AA187662")) 10 | IScriptSource : public IUnknown { 11 | STDMETHOD_(bool, GetActive()) PURE; 12 | STDMETHOD(GetScriptInfo) (std::wstring& str) PURE; 13 | }; 14 | -------------------------------------------------------------------------------- /Source/MpcScriptSource.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DllCanUnloadNow PRIVATE 3 | DllGetClassObject PRIVATE 4 | DllRegisterServer PRIVATE 5 | DllUnregisterServer PRIVATE 6 | -------------------------------------------------------------------------------- /Source/MpcScriptSource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v0lt/ScriptSourceFilter/37546f0cfd188d08fb1dc888dbaf0c7e2b7e379f/Source/MpcScriptSource.rc -------------------------------------------------------------------------------- /Source/MpcScriptSource.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {DAF59106-BC83-478F-95D9-4516C2A52970} 23 | MpcScriptSource 24 | Win32Proj 25 | MpcScriptSource 26 | 27 | 28 | 29 | 30 | DynamicLibrary 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | .ax 43 | 44 | 45 | $(ProjectName)64 46 | 47 | 48 | 49 | MpcScriptSource.def 50 | false 51 | 52 | 53 | ..\update_revision.cmd 54 | 55 | 56 | $(ProjectDir) 57 | Use 58 | stdafx.h 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Create 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Source/MpcScriptSource.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {9788c006-0809-4532-aa20-b51ed992525a} 6 | cpp;c;cxx;def;odl;idl;hpj;bat;asm 7 | 8 | 9 | {4d561854-929b-492e-9fba-c2cebb7cc3d4} 10 | h;hpp;hxx;hm;inl;inc 11 | 12 | 13 | {addff0d6-0d94-4e4c-b5ea-b7d5b330fd45} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe 15 | 16 | 17 | {a01ce4a8-f1ae-4465-8aea-4c4d569b5f63} 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Utils 47 | 48 | 49 | Utils 50 | 51 | 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Resource Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Utils 82 | 83 | 84 | Utils 85 | 86 | 87 | 88 | 89 | Resource Files 90 | 91 | 92 | 93 | 94 | Resource Files 95 | 96 | 97 | -------------------------------------------------------------------------------- /Source/PropPage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #include "stdafx.h" 8 | #include "resource.h" 9 | #include "Helper.h" 10 | #include "PropPage.h" 11 | 12 | void SetCursor(HWND hWnd, LPCWSTR lpCursorName) 13 | { 14 | SetClassLongPtrW(hWnd, GCLP_HCURSOR, (LONG_PTR)::LoadCursorW(nullptr, lpCursorName)); 15 | } 16 | 17 | void SetCursor(HWND hWnd, UINT nID, LPCWSTR lpCursorName) 18 | { 19 | SetCursor(::GetDlgItem(hWnd, nID), lpCursorName); 20 | } 21 | 22 | inline void ComboBox_AddStringData(HWND hWnd, int nIDComboBox, LPCWSTR str, LONG_PTR data) 23 | { 24 | LRESULT lValue = SendDlgItemMessageW(hWnd, nIDComboBox, CB_ADDSTRING, 0, (LPARAM)str); 25 | if (lValue != CB_ERR) { 26 | SendDlgItemMessageW(hWnd, nIDComboBox, CB_SETITEMDATA, lValue, data); 27 | } 28 | } 29 | 30 | inline LONG_PTR ComboBox_GetCurItemData(HWND hWnd, int nIDComboBox) 31 | { 32 | LRESULT lValue = SendDlgItemMessageW(hWnd, nIDComboBox, CB_GETCURSEL, 0, 0); 33 | if (lValue != CB_ERR) { 34 | lValue = SendDlgItemMessageW(hWnd, nIDComboBox, CB_GETITEMDATA, lValue, 0); 35 | } 36 | return lValue; 37 | } 38 | 39 | void ComboBox_SelectByItemData(HWND hWnd, int nIDComboBox, LONG_PTR data) 40 | { 41 | LRESULT lCount = SendDlgItemMessageW(hWnd, nIDComboBox, CB_GETCOUNT, 0, 0); 42 | if (lCount != CB_ERR) { 43 | for (LRESULT idx = 0; idx < lCount; idx++) { 44 | const LRESULT lValue = SendDlgItemMessageW(hWnd, nIDComboBox, CB_GETITEMDATA, idx, 0); 45 | if (data == lValue) { 46 | SendDlgItemMessageW(hWnd, nIDComboBox, CB_SETCURSEL, idx, 0); 47 | break; 48 | } 49 | } 50 | } 51 | } 52 | 53 | 54 | // CSSInfoPPage 55 | 56 | // https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd375010(v=vs.85).aspx 57 | 58 | CSSInfoPPage::CSSInfoPPage(LPUNKNOWN lpunk, HRESULT* phr) : 59 | CBasePropertyPage(L"InfoProp", lpunk, IDD_INFOPROPPAGE, IDS_INFOPROPPAGE_TITLE) 60 | { 61 | DLog(L"CSSInfoPPage()"); 62 | } 63 | 64 | CSSInfoPPage::~CSSInfoPPage() 65 | { 66 | DLog(L"~CSSInfoPPage()"); 67 | 68 | if (m_hMonoFont) { 69 | DeleteObject(m_hMonoFont); 70 | m_hMonoFont = 0; 71 | } 72 | } 73 | 74 | void CSSInfoPPage::SetControls() 75 | { 76 | std::wstring strInfo; 77 | m_pScriptSource->GetScriptInfo(strInfo); 78 | str_replace(strInfo, L"\n", L"\r\n"); 79 | SetDlgItemTextW(IDC_EDIT1, strInfo.c_str()); 80 | } 81 | 82 | HRESULT CSSInfoPPage::OnConnect(IUnknown *pUnk) 83 | { 84 | if (pUnk == nullptr) return E_POINTER; 85 | 86 | m_pScriptSource = pUnk; 87 | if (!m_pScriptSource) { 88 | return E_NOINTERFACE; 89 | } 90 | 91 | return S_OK; 92 | } 93 | 94 | HRESULT CSSInfoPPage::OnDisconnect() 95 | { 96 | if (m_pScriptSource == nullptr) { 97 | return E_UNEXPECTED; 98 | } 99 | 100 | m_pScriptSource.Release(); 101 | 102 | return S_OK; 103 | } 104 | 105 | HRESULT CSSInfoPPage::OnActivate() 106 | { 107 | // set m_hWnd for CWindow 108 | m_hWnd = m_hwnd; 109 | 110 | // init monospace font 111 | LOGFONTW lf = {}; 112 | HDC hdc = GetWindowDC(); 113 | lf.lfHeight = -MulDiv(9, GetDeviceCaps(hdc, LOGPIXELSY), 72); 114 | ReleaseDC(hdc); 115 | lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN; 116 | wcscpy_s(lf.lfFaceName, L"Consolas"); 117 | m_hMonoFont = CreateFontIndirectW(&lf); 118 | 119 | GetDlgItem(IDC_EDIT1).SetFont(m_hMonoFont); 120 | 121 | SetControls(); 122 | 123 | SetDlgItemTextW(IDC_EDIT3, GetNameAndVersion()); 124 | 125 | SetCursor(m_hWnd, IDC_ARROW); 126 | 127 | return S_OK; 128 | } 129 | 130 | INT_PTR CSSInfoPPage::OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 131 | { 132 | if (uMsg == WM_CLOSE) { 133 | // fixed Esc handling when EDITTEXT control has ES_MULTILINE property and is in focus 134 | return (LRESULT)1; 135 | } 136 | 137 | // Let the parent class handle the message. 138 | return CBasePropertyPage::OnReceiveMessage(hwnd, uMsg, wParam, lParam); 139 | } 140 | 141 | HRESULT CSSInfoPPage::OnApplyChanges() 142 | { 143 | return S_OK; 144 | } 145 | -------------------------------------------------------------------------------- /Source/PropPage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "IScriptSource.h" 10 | 11 | // CSSInfoPPage 12 | 13 | class __declspec(uuid("D36E542D-8645-4F2C-A758-55C6FDF67E50")) 14 | CSSInfoPPage : public CBasePropertyPage, public CWindow 15 | { 16 | HFONT m_hMonoFont = nullptr; 17 | CComQIPtr m_pScriptSource; 18 | 19 | public: 20 | CSSInfoPPage(LPUNKNOWN lpunk, HRESULT* phr); 21 | ~CSSInfoPPage(); 22 | 23 | private: 24 | void SetControls(); 25 | 26 | HRESULT OnConnect(IUnknown* pUnknown) override; 27 | HRESULT OnDisconnect() override; 28 | HRESULT OnActivate() override; 29 | void SetDirty() 30 | { 31 | m_bDirty = TRUE; 32 | if (m_pPageSite) { 33 | m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY); 34 | } 35 | } 36 | INT_PTR OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override; 37 | HRESULT OnApplyChanges() override; 38 | }; 39 | -------------------------------------------------------------------------------- /Source/ScriptSource.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #include "stdafx.h" 8 | 9 | #include "../Include/Version.h" 10 | #include "PropPage.h" 11 | 12 | #include "ScriptSource.h" 13 | 14 | #define OPT_REGKEY_ScriptSource L"Software\\MPC-BE Filters\\MPC Script Source" 15 | 16 | // 17 | // CScriptSource 18 | // 19 | 20 | CScriptSource::CScriptSource(LPUNKNOWN lpunk, HRESULT* phr) 21 | : CSource(L"MPC Script Source", lpunk, __uuidof(this)) 22 | { 23 | #ifdef _DEBUG 24 | DbgSetModuleLevel(LOG_TRACE, DWORD_MAX); 25 | DbgSetModuleLevel(LOG_ERROR, DWORD_MAX); 26 | #endif 27 | 28 | DLog(L"Windows {}", GetWindowsVersion()); 29 | DLog(GetNameAndVersion()); 30 | 31 | HRESULT hr = S_OK; 32 | 33 | if (phr) { 34 | *phr = hr; 35 | } 36 | 37 | return; 38 | } 39 | 40 | CScriptSource::~CScriptSource() 41 | { 42 | DLog(L"~CScriptSource()"); 43 | } 44 | 45 | STDMETHODIMP CScriptSource::NonDelegatingQueryInterface(REFIID riid, void** ppv) 46 | { 47 | CheckPointer(ppv, E_POINTER); 48 | 49 | return 50 | QI(IFileSourceFilter) 51 | QI(IAMFilterMiscFlags) 52 | QI(ISpecifyPropertyPages) 53 | QI(IScriptSource) 54 | QI(IExFilterConfig) 55 | __super::NonDelegatingQueryInterface(riid, ppv); 56 | } 57 | 58 | // IFileSourceFilter 59 | 60 | STDMETHODIMP CScriptSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) 61 | { 62 | // TODO: destroy any already existing pins and create new, now we are just going die nicely instead of doing it :) 63 | if (GetPinCount() > 0) { 64 | return VFW_E_ALREADY_CONNECTED; 65 | } 66 | 67 | std::wstring fn = pszFileName; 68 | std::wstring ext = fn.substr(fn.find_last_of('.')); 69 | str_tolower(ext); 70 | 71 | HRESULT hr = S_OK; 72 | if (ext == L".avs") { 73 | m_pAviSynthFile.reset(new(std::nothrow) CAviSynthFile(pszFileName, this, &hr)); 74 | } 75 | else if (ext == L".vpy") { 76 | m_pVapourSynthFile.reset(new(std::nothrow) CVapourSynthFile(pszFileName, this, &hr)); 77 | } 78 | else { 79 | return E_INVALIDARG; 80 | } 81 | 82 | if (FAILED(hr)) { 83 | return hr; 84 | } 85 | 86 | m_fn = std::move(fn); 87 | 88 | return S_OK; 89 | } 90 | 91 | STDMETHODIMP CScriptSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) 92 | { 93 | CheckPointer(ppszFileName, E_POINTER); 94 | 95 | size_t nCount = m_fn.size() + 1; 96 | *ppszFileName = (LPOLESTR)CoTaskMemAlloc(nCount * sizeof(WCHAR)); 97 | if (!(*ppszFileName)) { 98 | return E_OUTOFMEMORY; 99 | } 100 | 101 | wcscpy_s(*ppszFileName, nCount, m_fn.c_str()); 102 | 103 | return S_OK; 104 | } 105 | 106 | // IAMFilterMiscFlags 107 | 108 | STDMETHODIMP_(ULONG) CScriptSource::GetMiscFlags() 109 | { 110 | return AM_FILTER_MISC_FLAGS_IS_SOURCE; 111 | } 112 | 113 | // ISpecifyPropertyPages 114 | STDMETHODIMP CScriptSource::GetPages(CAUUID* pPages) 115 | { 116 | CheckPointer(pPages, E_POINTER); 117 | 118 | pPages->cElems = 1; 119 | pPages->pElems = reinterpret_cast(CoTaskMemAlloc(sizeof(GUID) * pPages->cElems)); 120 | if (pPages->pElems == nullptr) { 121 | return E_OUTOFMEMORY; 122 | } 123 | 124 | pPages->pElems[0] = __uuidof(CSSInfoPPage); 125 | 126 | return S_OK; 127 | } 128 | 129 | // IScriptSource 130 | 131 | STDMETHODIMP_(bool) CScriptSource::GetActive() 132 | { 133 | return (GetPinCount() > 0); 134 | } 135 | 136 | STDMETHODIMP CScriptSource::GetScriptInfo(std::wstring& str) 137 | { 138 | if (GetActive()) { 139 | if (m_pAviSynthFile) { 140 | str.assign(m_pAviSynthFile->GetInfo()); 141 | } 142 | else if (m_pVapourSynthFile) { 143 | str.assign(m_pVapourSynthFile->GetInfo()); 144 | } 145 | return S_OK; 146 | } else { 147 | str.assign(L"filter is not active"); 148 | return S_FALSE; 149 | } 150 | } 151 | 152 | // IExFilterConfig 153 | 154 | STDMETHODIMP CScriptSource::Flt_GetInt64(LPCSTR field, __int64 *value) 155 | { 156 | CheckPointer(value, E_POINTER); 157 | 158 | if (!strcmp(field, "version")) { 159 | *value = ((uint64_t)VER_MAJOR << 48) 160 | | ((uint64_t)VER_MINOR << 32) 161 | | ((uint64_t)VER_BUILD << 16) 162 | | ((uint64_t)REV_NUM); 163 | return S_OK; 164 | } 165 | 166 | return E_INVALIDARG; 167 | } 168 | -------------------------------------------------------------------------------- /Source/ScriptSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include "Helper.h" 12 | #include "IScriptSource.h" 13 | #include "../Include/FilterInterfacesImpl.h" 14 | 15 | #include "AviSynthStream.h" 16 | #include "VapourSynthStream.h" 17 | 18 | #define STR_CLSID_ScriptSource "{7D3BBD5A-880D-4A30-A2D1-7B8C2741AFEF}" 19 | 20 | class __declspec(uuid(STR_CLSID_ScriptSource)) 21 | CScriptSource 22 | : public CSource 23 | , public IFileSourceFilter 24 | , public IAMFilterMiscFlags 25 | , public ISpecifyPropertyPages 26 | , public IScriptSource 27 | , public CExFilterConfigImpl 28 | { 29 | private: 30 | friend class CAviSynthStream; 31 | friend class CVapourSynthStream; 32 | 33 | std::wstring m_fn; 34 | 35 | std::unique_ptr m_pAviSynthFile; 36 | std::unique_ptr m_pVapourSynthFile; 37 | 38 | public: 39 | CScriptSource(LPUNKNOWN lpunk, HRESULT* phr); 40 | ~CScriptSource(); 41 | 42 | DECLARE_IUNKNOWN 43 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); 44 | 45 | // IFileSourceFilter 46 | STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); 47 | STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); 48 | 49 | // IAMFilterMiscFlags 50 | STDMETHODIMP_(ULONG) GetMiscFlags(); 51 | 52 | // ISpecifyPropertyPages 53 | STDMETHODIMP GetPages(CAUUID* pPages); 54 | 55 | // IScriptSource 56 | STDMETHODIMP_(bool) GetActive(); 57 | STDMETHODIMP GetScriptInfo(std::wstring& str); 58 | 59 | // IExFilterConfig 60 | STDMETHODIMP Flt_GetInt64(LPCSTR field, __int64* value) override; 61 | }; 62 | -------------------------------------------------------------------------------- /Source/Utils/StringUtil.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 v0lt, Aleksoid 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include "stdafx.h" 22 | #include 23 | #include "StringUtil.h" 24 | 25 | void str_split(const std::string& str, std::vector& tokens, char delim) 26 | { 27 | std::istringstream iss(str); 28 | std::string tmp; 29 | while (std::getline(iss, tmp, delim)) { 30 | if (tmp.size()) { 31 | tokens.push_back(tmp); 32 | } 33 | } 34 | } 35 | 36 | void str_split(const std::wstring& wstr, std::vector& tokens, wchar_t delim) 37 | { 38 | std::wistringstream iss(wstr); 39 | std::wstring tmp; 40 | while (std::getline(iss, tmp, delim)) { 41 | if (tmp.size()) { 42 | tokens.push_back(tmp); 43 | } 44 | } 45 | } 46 | 47 | void str_replace(std::string& s, const std::string_view from, const std::string_view to) 48 | { 49 | std::string str; 50 | size_t pos = 0; 51 | size_t pf = 0; 52 | while ((pf = s.find(from, pos)) < s.size()) { 53 | str.append(s, pos, pf - pos); 54 | str.append(to); 55 | pos = pf + from.size(); 56 | } 57 | if (str.size()) { 58 | str.append(s, pos); 59 | s = str; 60 | } 61 | } 62 | 63 | void str_replace(std::wstring& s, const std::wstring_view from, const std::wstring_view to) 64 | { 65 | std::wstring str; 66 | size_t pos = 0; 67 | size_t pf = 0; 68 | while ((pf = s.find(from, pos)) < s.size()) { 69 | str.append(s, pos, pf - pos); 70 | str.append(to); 71 | pos = pf + from.size(); 72 | } 73 | if (str.size()) { 74 | str.append(s, pos); 75 | s = str; 76 | } 77 | } 78 | 79 | // 80 | // converting strings of different formats 81 | // 82 | 83 | std::wstring ConvertAnsiToWide(const std::string_view sv) 84 | { 85 | int count = MultiByteToWideChar(CP_ACP, 0, sv.data(), (int)sv.length(), nullptr, 0); 86 | std::wstring wstr(count, 0); 87 | MultiByteToWideChar(CP_ACP, 0, sv.data(), (int)sv.length(), &wstr[0], count); 88 | return wstr; 89 | } 90 | 91 | std::wstring ConvertUtf8ToWide(const std::string_view sv) 92 | { 93 | int count = MultiByteToWideChar(CP_UTF8, 0, sv.data(), (int)sv.length(), nullptr, 0); 94 | std::wstring wstr(count, 0); 95 | MultiByteToWideChar(CP_UTF8, 0, sv.data(), (int)sv.length(), &wstr[0], count); 96 | return wstr; 97 | } 98 | 99 | std::string ConvertWideToANSI(const std::wstring_view wsv) 100 | { 101 | int count = WideCharToMultiByte(CP_ACP, 0, wsv.data(), (int)wsv.length(), nullptr, 0, nullptr, nullptr); 102 | std::string str(count, 0); 103 | WideCharToMultiByte(CP_ACP, 0, wsv.data(), -1, &str[0], count, nullptr, nullptr); 104 | return str; 105 | } 106 | 107 | std::string ConvertWideToUtf8(const std::wstring_view wsv) 108 | { 109 | int count = WideCharToMultiByte(CP_UTF8, 0, wsv.data(), (int)wsv.length(), nullptr, 0, nullptr, nullptr); 110 | std::string str(count, 0); 111 | WideCharToMultiByte(CP_UTF8, 0, wsv.data(), -1, &str[0], count, nullptr, nullptr); 112 | return str; 113 | } 114 | -------------------------------------------------------------------------------- /Source/Utils/StringUtil.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 v0lt, Aleksoid 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | // 27 | // convert string to lower or upper case 28 | // 29 | 30 | inline void str_tolower(std::string& s) 31 | { 32 | std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::tolower(c); } ); 33 | // char for std::tolower should be converted to unsigned char 34 | } 35 | 36 | inline void str_toupper(std::string& s) 37 | { 38 | std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::toupper(c); } ); 39 | // char for std::toupper should be converted to unsigned char 40 | } 41 | 42 | inline void str_tolower(std::wstring& s) 43 | { 44 | std::transform(s.begin(), s.end(), s.begin(), ::tolower); 45 | } 46 | 47 | inline void str_toupper(std::wstring& s) 48 | { 49 | std::transform(s.begin(), s.end(), s.begin(), ::toupper); 50 | } 51 | 52 | inline void str_tolower_all(std::wstring& s) 53 | { 54 | const std::ctype& f = std::use_facet>(std::locale()); 55 | std::ignore = f.tolower(&s[0], &s[0] + s.size()); 56 | } 57 | 58 | inline void str_toupper_all(std::wstring& s) 59 | { 60 | const std::ctype& f = std::use_facet>(std::locale()); 61 | std::ignore = f.toupper(&s[0], &s[0] + s.size()); 62 | } 63 | 64 | // 65 | // split a string using char delimiter 66 | // 67 | 68 | void str_split(const std::string& str, std::vector& tokens, char delim); 69 | 70 | void str_split(const std::wstring& wstr, std::vector& tokens, wchar_t delim); 71 | 72 | // 73 | // trimming whitespace 74 | // 75 | 76 | inline std::string str_trim(const std::string_view sv) 77 | { 78 | auto sfront = std::find_if_not(sv.begin(), sv.end(), [](int c) {return isspace(c); }); 79 | auto sback = std::find_if_not(sv.rbegin(), sv.rend(), [](int c) {return isspace(c); }).base(); 80 | return (sback <= sfront ? std::string() : std::string(sfront, sback)); 81 | } 82 | 83 | inline std::wstring str_trim(const std::wstring_view sv) 84 | { 85 | auto sfront = std::find_if_not(sv.begin(), sv.end(), [](int c) {return iswspace(c); }); 86 | auto sback = std::find_if_not(sv.rbegin(), sv.rend(), [](int c) {return iswspace(c); }).base(); 87 | return (sback <= sfront ? std::wstring() : std::wstring(sfront, sback)); 88 | } 89 | 90 | // 91 | // trimming a character at the end 92 | // 93 | 94 | inline void str_trim_end(std::string& s, const char ch) 95 | { 96 | s.erase(s.find_last_not_of(ch) + 1); 97 | } 98 | 99 | inline void str_trim_end(std::wstring& s, const wchar_t ch) 100 | { 101 | s.erase(s.find_last_not_of(ch) + 1); 102 | } 103 | 104 | // 105 | // truncate after a null character 106 | // 107 | 108 | inline void str_truncate_after_null(std::string& s) 109 | { 110 | s.erase(std::find(s.begin(), s.end(), '\0'), s.end()); 111 | } 112 | 113 | inline void str_truncate_after_null(std::wstring& s) 114 | { 115 | s.erase(std::find(s.begin(), s.end(), '\0'), s.end()); 116 | } 117 | 118 | // 119 | // replace substring 120 | // 121 | 122 | void str_replace(std::string& s, const std::string_view from, const std::string_view to); 123 | void str_replace(std::wstring& s, const std::wstring_view from, const std::wstring_view to); 124 | 125 | // 126 | // simple convert ANSI string to wide character string 127 | // 128 | 129 | inline std::wstring A2WStr(const std::string_view sv) 130 | { 131 | return std::wstring(sv.begin(), sv.end()); 132 | } 133 | 134 | // 135 | // converting strings of different formats 136 | // 137 | 138 | std::wstring ConvertAnsiToWide(const std::string_view sv); 139 | 140 | std::wstring ConvertUtf8ToWide(const std::string_view sv); 141 | 142 | std::string ConvertWideToANSI(const std::wstring_view wsv); 143 | 144 | std::string ConvertWideToUtf8(const std::wstring_view wsv); 145 | -------------------------------------------------------------------------------- /Source/Utils/Util.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 v0lt, Aleksoid 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include "stdafx.h" 22 | #include "Util.h" 23 | 24 | static bool IsWindows11OrGreater(DWORD dwBuildNumber) 25 | { 26 | OSVERSIONINFOEXW osvi = { 27 | .dwOSVersionInfoSize = sizeof(osvi), 28 | .dwMajorVersion = HIBYTE(_WIN32_WINNT_WIN10), 29 | .dwMinorVersion = LOBYTE(_WIN32_WINNT_WIN10), 30 | .dwBuildNumber = dwBuildNumber, }; 31 | DWORDLONG const dwlConditionMask = VerSetConditionMask( 32 | VerSetConditionMask( 33 | VerSetConditionMask( 34 | 0, VER_MAJORVERSION, VER_GREATER_EQUAL), 35 | VER_MINORVERSION, VER_GREATER_EQUAL), 36 | VER_BUILDNUMBER, VER_GREATER_EQUAL); 37 | 38 | return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, dwlConditionMask) != FALSE; 39 | } 40 | 41 | static LPCWSTR GetWinVer() 42 | { 43 | // https://learn.microsoft.com/en-us/windows/release-health/release-information#windows-10-release-history 44 | // https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information#windows-11-release-history 45 | const struct { 46 | const DWORD buildNumber; 47 | LPCWSTR version; 48 | } 49 | win10versions[] = { 50 | { 26100, L"11 24H2" }, 51 | { 22631, L"11 23H2" }, 52 | { 22621, L"11 22H2" }, 53 | { 22000, L"11 21H2" }, 54 | { 19045, L"10 22H2" }, 55 | { 19044, L"10 21H2" }, 56 | { 19043, L"10 21H1" }, 57 | { 19042, L"10 20H2" }, 58 | { 19041, L"10 2004" }, 59 | { 18363, L"10 1909" }, 60 | { 18362, L"10 1903" }, 61 | { 17763, L"10 1809" }, 62 | { 17134, L"10 1803" }, 63 | { 16299, L"10 1709" }, 64 | { 15063, L"10 1703" }, 65 | { 14393, L"10 1607" }, 66 | { 10586, L"10 1511" }, 67 | { 10240, L"10 1507" }, 68 | }; 69 | 70 | OSVERSIONINFOEXW osvi = { 71 | .dwOSVersionInfoSize = sizeof(osvi), 72 | .dwMajorVersion = HIBYTE(_WIN32_WINNT_WIN10), 73 | .dwMinorVersion = LOBYTE(_WIN32_WINNT_WIN10), }; 74 | DWORDLONG const dwlConditionMask = VerSetConditionMask( 75 | VerSetConditionMask( 76 | VerSetConditionMask( 77 | 0, VER_MAJORVERSION, VER_GREATER_EQUAL), 78 | VER_MINORVERSION, VER_GREATER_EQUAL), 79 | VER_BUILDNUMBER, VER_GREATER_EQUAL); 80 | 81 | for (const auto& win10ver : win10versions) { 82 | osvi.dwBuildNumber = win10ver.buildNumber; 83 | if (VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, dwlConditionMask) != FALSE) { 84 | return win10ver.version; 85 | } 86 | } 87 | 88 | if (IsWindows8Point1OrGreater()) { 89 | return L"8.1"; 90 | } 91 | if (IsWindows8OrGreater()) { 92 | return L"8"; 93 | } 94 | if (IsWindows7SP1OrGreater()) { 95 | return L"7 SP1"; 96 | } 97 | if (IsWindows7OrGreater()) { 98 | return L"7"; 99 | } 100 | return L"Vista or older"; 101 | } 102 | 103 | bool IsWindows11_24H2OrGreater() 104 | { 105 | static auto ret = IsWindows11OrGreater(26100); 106 | return ret; 107 | } 108 | 109 | LPCWSTR GetWindowsVersion() 110 | { 111 | static LPCWSTR winver = GetWinVer(); 112 | return winver; 113 | } 114 | 115 | std::wstring HR2Str(const HRESULT hr) 116 | { 117 | std::wstring str; 118 | #define UNPACK_VALUE(VALUE) case VALUE: str = L#VALUE; break; 119 | #define UNPACK_HR_WIN32(VALUE) case (((VALUE) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000): str = L#VALUE; break; 120 | switch (hr) { 121 | // Common HRESULT Values https://learn.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values 122 | UNPACK_VALUE(S_OK); 123 | #ifdef _WINERROR_ 124 | UNPACK_VALUE(S_FALSE); 125 | UNPACK_VALUE(E_NOTIMPL); 126 | UNPACK_VALUE(E_NOINTERFACE); 127 | UNPACK_VALUE(E_POINTER); 128 | UNPACK_VALUE(E_ABORT); 129 | UNPACK_VALUE(E_FAIL); 130 | UNPACK_VALUE(E_UNEXPECTED); 131 | UNPACK_VALUE(E_ACCESSDENIED); 132 | UNPACK_VALUE(E_HANDLE); 133 | UNPACK_VALUE(E_OUTOFMEMORY); 134 | UNPACK_VALUE(E_INVALIDARG); 135 | // some COM Error Codes (Generic) https://learn.microsoft.com/en-us/windows/win32/com/com-error-codes-1 136 | UNPACK_VALUE(REGDB_E_CLASSNOTREG); 137 | // some COM Error Codes (UI, Audio, DirectX, Codec) https://learn.microsoft.com/en-us/windows/win32/com/com-error-codes-10 138 | UNPACK_VALUE(DXGI_STATUS_OCCLUDED); 139 | UNPACK_VALUE(DXGI_STATUS_MODE_CHANGED); 140 | UNPACK_VALUE(DXGI_ERROR_INVALID_CALL); 141 | UNPACK_VALUE(DXGI_ERROR_DEVICE_REMOVED); 142 | UNPACK_VALUE(DXGI_ERROR_DEVICE_RESET); 143 | UNPACK_VALUE(DXGI_ERROR_SDK_COMPONENT_MISSING); 144 | UNPACK_VALUE(WINCODEC_ERR_COMPONENTNOTFOUND); 145 | UNPACK_VALUE(WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT); 146 | UNPACK_VALUE(WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE); 147 | // some System Error Codes https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes 148 | UNPACK_HR_WIN32(ERROR_GEN_FAILURE); 149 | UNPACK_HR_WIN32(ERROR_NOT_SUPPORTED); 150 | UNPACK_HR_WIN32(ERROR_INSUFFICIENT_BUFFER); 151 | UNPACK_HR_WIN32(ERROR_MOD_NOT_FOUND); 152 | UNPACK_HR_WIN32(ERROR_INVALID_WINDOW_HANDLE); 153 | UNPACK_HR_WIN32(ERROR_CLASS_ALREADY_EXISTS); 154 | #endif 155 | #ifdef _MFERROR_H 156 | UNPACK_VALUE(MF_E_INVALIDMEDIATYPE); 157 | UNPACK_VALUE(MF_E_INVALID_FORMAT); 158 | #endif 159 | #ifdef _D3D9_H_ 160 | // some D3DERR values https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3derr 161 | UNPACK_VALUE(S_PRESENT_OCCLUDED); 162 | UNPACK_VALUE(S_PRESENT_MODE_CHANGED); 163 | UNPACK_VALUE(D3DERR_DEVICEHUNG); 164 | UNPACK_VALUE(D3DERR_DEVICELOST); 165 | UNPACK_VALUE(D3DERR_DEVICENOTRESET); 166 | UNPACK_VALUE(D3DERR_DEVICEREMOVED); 167 | UNPACK_VALUE(D3DERR_DRIVERINTERNALERROR); 168 | UNPACK_VALUE(D3DERR_INVALIDCALL); 169 | UNPACK_VALUE(D3DERR_OUTOFVIDEOMEMORY); 170 | UNPACK_VALUE(D3DERR_WASSTILLDRAWING); 171 | UNPACK_VALUE(D3DERR_NOTAVAILABLE); 172 | #endif 173 | default: 174 | str = std::format(L"{:#010x}", (uint32_t)hr); 175 | }; 176 | #undef UNPACK_VALUE 177 | #undef UNPACK_HR_WIN32 178 | return str; 179 | } 180 | 181 | HRESULT GetDataFromResource(LPVOID& data, DWORD& size, UINT resid) 182 | { 183 | static const HMODULE hModule = (HMODULE)&__ImageBase; 184 | 185 | HRSRC hrsrc = FindResourceW(hModule, MAKEINTRESOURCEW(resid), L"FILE"); 186 | if (!hrsrc) { 187 | return E_INVALIDARG; 188 | } 189 | HGLOBAL hGlobal = LoadResource(hModule, hrsrc); 190 | if (!hGlobal) { 191 | return E_FAIL; 192 | } 193 | size = SizeofResource(hModule, hrsrc); 194 | if (!size) { 195 | return E_FAIL; 196 | } 197 | data = LockResource(hGlobal); 198 | if (!data) { 199 | return E_FAIL; 200 | } 201 | 202 | return S_OK; 203 | } 204 | 205 | // https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code 206 | // 207 | // Usage: SetThreadName ((DWORD)-1, "MainThread"); 208 | // 209 | const DWORD MS_VC_EXCEPTION = 0x406D1388; 210 | #pragma pack(push,8) 211 | typedef struct tagTHREADNAME_INFO 212 | { 213 | DWORD dwType; // Must be 0x1000. 214 | LPCSTR szName; // Pointer to name (in user addr space). 215 | DWORD dwThreadID; // Thread ID (-1=caller thread). 216 | DWORD dwFlags; // Reserved for future use, must be zero. 217 | } THREADNAME_INFO; 218 | #pragma pack(pop) 219 | void SetThreadName(DWORD dwThreadID, const char* threadName) { 220 | THREADNAME_INFO info; 221 | info.dwType = 0x1000; 222 | info.szName = threadName; 223 | info.dwThreadID = dwThreadID; 224 | info.dwFlags = 0; 225 | #pragma warning(push) 226 | #pragma warning(disable: 6320 6322) 227 | __try { 228 | RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); 229 | } 230 | __except (EXCEPTION_EXECUTE_HANDLER) { 231 | } 232 | #pragma warning(pop) 233 | } 234 | -------------------------------------------------------------------------------- /Source/Utils/Util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 v0lt, Aleksoid 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #pragma once 22 | 23 | #ifndef FCC 24 | #define FCC(ch4) ((((DWORD)(ch4) & 0xFF) << 24) | \ 25 | (((DWORD)(ch4) & 0xFF00) << 8) | \ 26 | (((DWORD)(ch4) & 0xFF0000) >> 8) | \ 27 | (((DWORD)(ch4) & 0xFF000000) >> 24)) 28 | #endif 29 | 30 | #ifndef DEFINE_MEDIATYPE_GUID 31 | #define DEFINE_MEDIATYPE_GUID(name, format) \ 32 | DEFINE_GUID(name, \ 33 | format, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); 34 | #endif 35 | 36 | template 37 | inline void DebugLogFmt(std::wstring_view format, Args&& ...args) 38 | { 39 | DbgLogInfo(LOG_TRACE, 3, std::vformat(format, std::make_wformat_args(args...)).c_str()); 40 | } 41 | 42 | #ifdef _DEBUG 43 | #define DLog(...) DebugLogFmt(__VA_ARGS__) 44 | #define DLogIf(f,...) {if (f) DebugLogFmt(__VA_ARGS__);} 45 | #else 46 | #define DLog(...) __noop 47 | #define DLogIf(f,...) __noop 48 | #endif 49 | 50 | #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } } 51 | #define SAFE_CLOSE_HANDLE(p) { if (p) { if ((p) != INVALID_HANDLE_VALUE) ASSERT(CloseHandle(p)); (p) = nullptr; } } 52 | #define SAFE_DELETE(p) { if (p) { delete (p); (p) = nullptr; } } 53 | 54 | #define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : 55 | #define IFQIRETURN(i) if (riid == __uuidof(i)) { return GetInterface((i*)this, ppv); } 56 | 57 | #define ALIGN(x, a) __ALIGN_MASK(x,(decltype(x))(a)-1) 58 | #define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) 59 | 60 | // Media subtypes 61 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Y8, 0x20203859); 62 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Y800, 0x30303859); 63 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Y16, 0x10003159); // Y1[0][16] 64 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_YV16, 0x36315659); 65 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_YV24, 0x34325659); 66 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_I420, 0x30323449); // from "wmcodecdsp.h" 67 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Y42B, 0x42323459); 68 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_444P, 0x50343434); 69 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Y210, 0x30313259); 70 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Y216, 0x36313259); 71 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Y410, 0x30313459); 72 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_Y416, 0x36313459); 73 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_YUV444P16, 0x10003359); // Y3[0][16] 74 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_RGB48, 0x30424752); // RGB[48] (RGB0) 75 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_BGR48, 0x30524742); // BGR[48] (BGR0) 76 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_BGRA64, 0x40415242); // BRA[64] (BRA@) 77 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_b48r, 0x72383462); 78 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_b64a, 0x61343662); 79 | DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_r210, 0x30313272); 80 | DEFINE_GUID(MEDIASUBTYPE_LAV_RAWVIDEO, 0xd80fa03c, 0x35c1, 0x4fa1, 0x8c, 0x8e, 0x37, 0x5c, 0x86, 0x67, 0x16, 0x6e); 81 | 82 | // non-standard values for Transfer Matrix 83 | #define VIDEOTRANSFERMATRIX_FCC 6 84 | #define VIDEOTRANSFERMATRIX_YCgCo 7 85 | 86 | template 87 | // If the specified value is out of range, set to default values. 88 | inline T discard(T const& val, T const& def, T const& lo, T const& hi) 89 | { 90 | return (val > hi || val < lo) ? def : val; 91 | } 92 | 93 | template 94 | inline T round_pow2(T number, T pow2) 95 | { 96 | ASSERT(pow2 > 0); 97 | ASSERT(!(pow2 & (pow2 - 1))); 98 | --pow2; 99 | if (number < 0) { 100 | return (number - pow2) & ~pow2; 101 | } else { 102 | return (number + pow2) & ~pow2; 103 | } 104 | } 105 | 106 | [[nodiscard]] bool IsWindows11_24H2OrGreater(); 107 | LPCWSTR GetWindowsVersion(); 108 | 109 | inline std::wstring GUIDtoWString(const GUID& guid) 110 | { 111 | std::wstring str(39, 0); 112 | int ret = StringFromGUID2(guid, &str[0], 39); 113 | if (ret) { 114 | str.resize(ret - 1); 115 | } else { 116 | str.clear(); 117 | } 118 | return str; 119 | } 120 | 121 | std::wstring HR2Str(const HRESULT hr); 122 | 123 | HRESULT GetDataFromResource(LPVOID& data, DWORD& size, UINT resid); 124 | 125 | // Usage: SetThreadName ((DWORD)-1, "MainThread"); 126 | void SetThreadName(DWORD dwThreadID, const char* threadName); 127 | -------------------------------------------------------------------------------- /Source/VUIOptions.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #include "stdafx.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "Helper.h" 13 | #include "VUIOptions.h" 14 | 15 | // Rec. ITU-T H.264 16 | // https://www.itu.int/itu-t/recommendations/rec.aspx?rec=14659 17 | 18 | bool SetColorInfoFromFrameFrops(UINT& extFmtValue, const char* keyName, int64_t value) 19 | { 20 | DXVA2_ExtendedFormat exFmt; 21 | exFmt.value = extFmtValue; 22 | 23 | if (strcmp(keyName, "_ChromaLocation") == 0) { 24 | // 0=left, 1=center, 2=topleft, 3=top, 4=bottomleft, 5=bottom. 25 | switch (value) { 26 | case 0: exFmt.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_MPEG2; break; 27 | case 1: exFmt.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_MPEG1; break; 28 | case 2: exFmt.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_Cosited; break; 29 | } 30 | } 31 | else if (strcmp(keyName, "_ColorRange") == 0) { 32 | // 0=full range, 1=limited range 33 | switch (value) { 34 | case 0: exFmt.NominalRange = DXVA2_NominalRange_0_255; break; 35 | case 1: exFmt.NominalRange = DXVA2_NominalRange_16_235; break; 36 | } 37 | } 38 | else if (strcmp(keyName, "_Primaries") == 0) { 39 | switch (value) { 40 | case 1: exFmt.VideoPrimaries = DXVA2_VideoPrimaries_BT709; break; 41 | case 4: exFmt.VideoPrimaries = DXVA2_VideoPrimaries_BT470_2_SysM; break; 42 | case 5: exFmt.VideoPrimaries = DXVA2_VideoPrimaries_BT470_2_SysBG; break; 43 | case 6: exFmt.VideoPrimaries = DXVA2_VideoPrimaries_SMPTE170M; break; 44 | case 7: exFmt.VideoPrimaries = DXVA2_VideoPrimaries_SMPTE240M; break; 45 | case 9: exFmt.VideoPrimaries = MFVideoPrimaries_BT2020; break; 46 | case 10: exFmt.VideoPrimaries = MFVideoPrimaries_XYZ; break; 47 | case 11: exFmt.VideoPrimaries = MFVideoPrimaries_DCI_P3; break; 48 | } 49 | } 50 | else if (strcmp(keyName, "_Matrix") == 0) { 51 | switch (value) { 52 | case 1: exFmt.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT709; break; 53 | case 4: exFmt.VideoTransferMatrix = VIDEOTRANSFERMATRIX_FCC; break; 54 | case 5: 55 | case 6: exFmt.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT601; break; 56 | case 7: exFmt.VideoTransferMatrix = DXVA2_VideoTransferMatrix_SMPTE240M; break; 57 | case 8: exFmt.VideoTransferMatrix = VIDEOTRANSFERMATRIX_YCgCo; break; 58 | case 10: 59 | case 11: exFmt.VideoTransferMatrix = MFVideoTransferMatrix_BT2020_10; break; 60 | } 61 | } 62 | else if (strcmp(keyName, "_Transfer") == 0) { 63 | switch (value) { 64 | case 1: 65 | case 6: 66 | case 14: 67 | case 15: exFmt.VideoTransferFunction = DXVA2_VideoTransFunc_709; break; 68 | case 4: exFmt.VideoTransferFunction = DXVA2_VideoTransFunc_22; break; 69 | case 5: exFmt.VideoTransferFunction = DXVA2_VideoTransFunc_28; break; 70 | case 7: exFmt.VideoTransferFunction = DXVA2_VideoTransFunc_240M; break; 71 | case 8: exFmt.VideoTransferFunction = DXVA2_VideoTransFunc_10; break; 72 | case 9: exFmt.VideoTransferFunction = MFVideoTransFunc_Log_100; break; 73 | case 10: exFmt.VideoTransferFunction = MFVideoTransFunc_Log_316; break; 74 | case 16: exFmt.VideoTransferFunction = MFVideoTransFunc_2084; break; 75 | case 18: exFmt.VideoTransferFunction = MFVideoTransFunc_HLG; break; 76 | } 77 | } 78 | 79 | if (exFmt.value != extFmtValue) { 80 | extFmtValue = exFmt.value; 81 | return true; 82 | } 83 | else { 84 | return false; 85 | } 86 | } 87 | 88 | /* 89 | "Video Usability Info" https://code.videolan.org/videolan/x264/-/blob/master/x264.c 90 | 91 | --range Specify color range 92 | auto, tv, pc 93 | 94 | --colorprim Specify color primaries 95 | undef, bt709, bt470m, bt470bg, smpte170m, 96 | smpte240m, film, bt2020, smpte428, 97 | smpte431, smpte432 98 | 99 | --transfer Specify transfer characteristics 100 | undef, bt709, bt470m, bt470bg, smpte170m, 101 | smpte240m, linear, log100, log316, 102 | iec61966-2-4, bt1361e, iec61966-2-1, 103 | bt2020-10, bt2020-12, smpte2084, smpte428, 104 | arib-std-b67 105 | 106 | --colormatrix Specify color matrix setting 107 | undef, bt709, fcc, bt470bg, smpte170m, 108 | smpte240m, GBR, YCgCo, bt2020nc, bt2020c, 109 | smpte2085, chroma-derived-nc, 110 | chroma-derived-c, ICtCp 111 | 112 | --chromaloc Specify chroma sample location (0 to 5) 113 | 0 - Left(MPEG-2) 114 | 1 - Center(MPEG-1) 115 | 2 - TopLeft(Co-sited) 116 | */ 117 | 118 | struct str_value { 119 | LPCSTR str; 120 | UINT value; 121 | }; 122 | 123 | static const str_value vui_range[] { 124 | { "tv", DXVA2_NominalRange_16_235 }, 125 | { "pc", DXVA2_NominalRange_0_255 }, 126 | }; 127 | 128 | static const str_value vui_colorprim[] { 129 | { "bt709", DXVA2_VideoPrimaries_BT709 }, 130 | { "bt470m", DXVA2_VideoPrimaries_BT470_2_SysM }, 131 | { "bt470bg", DXVA2_VideoPrimaries_BT470_2_SysBG }, 132 | { "smpte170m", DXVA2_VideoPrimaries_SMPTE170M }, 133 | { "smpte240m", DXVA2_VideoPrimaries_SMPTE240M }, 134 | { "bt2020", MFVideoPrimaries_BT2020 }, 135 | }; 136 | 137 | static const str_value vui_transfer[] { 138 | { "bt709", DXVA2_VideoTransFunc_709 }, 139 | { "bt470m", DXVA2_VideoTransFunc_22 }, 140 | { "bt470bg", DXVA2_VideoTransFunc_28 }, 141 | { "smpte170m", DXVA2_VideoTransFunc_709 }, 142 | { "smpte240m", DXVA2_VideoTransFunc_240M }, 143 | { "linear", DXVA2_VideoTransFunc_10 }, 144 | { "log100", MFVideoTransFunc_Log_100 }, 145 | { "log316", MFVideoTransFunc_Log_316 }, 146 | { "smpte2084", MFVideoTransFunc_2084 }, 147 | { "arib-std-b67", MFVideoTransFunc_HLG }, 148 | }; 149 | 150 | static const str_value vui_colormatrix[] { 151 | { "bt709", DXVA2_VideoTransferMatrix_BT709 }, 152 | { "fcc", VIDEOTRANSFERMATRIX_FCC }, 153 | { "bt470bg", DXVA2_VideoTransferMatrix_BT601 }, 154 | { "smpte240m", DXVA2_VideoTransferMatrix_SMPTE240M }, 155 | { "YCgCo", VIDEOTRANSFERMATRIX_YCgCo }, 156 | { "bt2020nc", MFVideoTransferMatrix_BT2020_10 }, 157 | { "bt2020c", MFVideoTransferMatrix_BT2020_10 }, 158 | }; 159 | 160 | static const str_value vui_chromaloc[] { 161 | { "0", DXVA2_VideoChromaSubsampling_MPEG2 }, 162 | { "1", DXVA2_VideoChromaSubsampling_MPEG1 }, 163 | { "2", DXVA2_VideoChromaSubsampling_Cosited }, 164 | }; 165 | 166 | bool SetColorInfoFromVUIOptions(UINT& extFmtValue, LPCWSTR scriptfile) 167 | { 168 | DXVA2_ExtendedFormat exFmt; 169 | exFmt.value = extFmtValue; 170 | 171 | std::string vui_options; 172 | std::ifstream scrypt(scriptfile); 173 | 174 | if (scrypt.is_open()) { 175 | const std::string vui_prefix("# $VUI:"); 176 | std::string line; 177 | while (std::getline(scrypt, line)) { 178 | // looking for the last line of VUI options 179 | if (line.compare(0, vui_prefix.size(), vui_prefix) == 0) { 180 | vui_options = line.substr(vui_prefix.size()); 181 | } 182 | } 183 | scrypt.close(); 184 | } 185 | 186 | std::vector tokens; 187 | str_split(vui_options, tokens, ' '); 188 | 189 | if (tokens.size() >= 2) { 190 | unsigned i = 0; 191 | while (i+1 < tokens.size()) { 192 | const auto& param = tokens[i]; 193 | const auto& value = tokens[i+1]; 194 | if (param == "--range") { 195 | for (const auto& item : vui_range) { 196 | if (value == item.str) { 197 | exFmt.NominalRange = item.value; 198 | i++; 199 | break; 200 | } 201 | } 202 | } 203 | else if (param == "--colorprim") { 204 | for (const auto& item : vui_colorprim) { 205 | if (value == item.str) { 206 | exFmt.VideoPrimaries = item.value; 207 | i++; 208 | break; 209 | } 210 | } 211 | } 212 | else if (param == "--transfer") { 213 | for (const auto& item : vui_transfer) { 214 | if (value == item.str) { 215 | exFmt.VideoTransferFunction = item.value; 216 | i++; 217 | break; 218 | } 219 | } 220 | } 221 | else if (param == "--colormatrix") { 222 | for (const auto& item : vui_colormatrix) { 223 | if (value == item.str) { 224 | exFmt.VideoTransferMatrix = item.value; 225 | i++; 226 | break; 227 | } 228 | } 229 | } 230 | else if (param == "--chromaloc") { 231 | for (const auto& item : vui_chromaloc) { 232 | if (value == item.str) { 233 | exFmt.VideoChromaSubsampling = item.value; 234 | i++; 235 | break; 236 | } 237 | } 238 | } 239 | i++; 240 | } 241 | } 242 | 243 | if (exFmt.value != extFmtValue) { 244 | extFmtValue = exFmt.value; 245 | return true; 246 | } 247 | else { 248 | return false; 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /Source/VUIOptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #pragma once 8 | 9 | bool SetColorInfoFromFrameFrops(UINT& extFmtValue, const char* keyName, int64_t value); 10 | 11 | bool SetColorInfoFromVUIOptions(UINT& extFmtValue, LPCWSTR scriptfile); 12 | -------------------------------------------------------------------------------- /Source/VapourSynthStream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifndef VSSCRIPT_H 10 | #include "../Include/VSScript4.h" 11 | #endif 12 | #include "Helper.h" 13 | 14 | // 15 | // CVapourSynthFile 16 | // 17 | 18 | class CVapourSynthFile 19 | { 20 | friend class CVapourSynthVideoStream; 21 | friend class CVapourSynthAudioStream; 22 | 23 | HMODULE m_hVSScriptDll = nullptr; 24 | 25 | const VSAPI* m_vsAPI = nullptr; 26 | const VSSCRIPTAPI* m_vsScriptAPI = nullptr; 27 | VSScript* m_vsScript = nullptr; 28 | VSNode* m_vsNodeVideo = nullptr; 29 | VSNode* m_vsNodeAudio = nullptr; 30 | 31 | std::wstring m_FileInfo; 32 | 33 | void SetVSNodes(); 34 | 35 | public: 36 | CVapourSynthFile(const WCHAR* filepath, CSource* pParent, HRESULT* phr); 37 | ~CVapourSynthFile(); 38 | 39 | std::wstring_view GetInfo() { return m_FileInfo; } 40 | }; 41 | 42 | // 43 | // CVapourSynthVideoStream 44 | // 45 | 46 | class CVapourSynthVideoStream 47 | : public CSourceStream 48 | , public CSourceSeeking 49 | { 50 | private: 51 | CCritSec m_cSharedState; 52 | 53 | const CVapourSynthFile* m_pVapourSynthFile; 54 | 55 | const VSVideoInfo* m_vsVideoInfo = nullptr; 56 | int m_Planes[4] = { 0, 1, 2, 3 }; 57 | 58 | std::unique_ptr m_BitmapError; 59 | 60 | REFERENCE_TIME m_AvgTimePerFrame = 0; 61 | int m_FrameCounter = 0; 62 | int m_CurrentFrame = 0; 63 | 64 | BOOL m_bDiscontinuity = FALSE; 65 | BOOL m_bFlushing = FALSE; 66 | 67 | FmtParams_t m_Format = {}; 68 | UINT m_Width = 0; 69 | UINT m_Height = 0; 70 | UINT m_Pitch = 0; 71 | UINT m_PitchBuff = 0; 72 | UINT m_BufferSize = 0; 73 | 74 | UINT m_ColorInfo = 0; 75 | struct { 76 | int64_t num = 0; 77 | int64_t den = 0; 78 | } m_Sar; 79 | 80 | int m_NumFrames = 0; 81 | int64_t m_fpsNum = 1; 82 | int64_t m_fpsDen = 1; 83 | 84 | char m_vsErrorMessage[1024] = {}; 85 | std::wstring m_StreamInfo; 86 | 87 | public: 88 | CVapourSynthVideoStream(CVapourSynthFile* pVapourSynthFile, CSource* pParent, HRESULT* phr); 89 | virtual ~CVapourSynthVideoStream(); 90 | 91 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override; 92 | 93 | std::wstring_view GetInfo() { return m_StreamInfo; } 94 | 95 | private: 96 | HRESULT OnThreadCreate() override; 97 | HRESULT OnThreadStartPlay() override; 98 | 99 | void UpdateFromSeek(); 100 | 101 | // IMediaSeeking 102 | STDMETHODIMP SetRate(double dRate) override; 103 | 104 | HRESULT ChangeStart() override; 105 | HRESULT ChangeStop() override; 106 | HRESULT ChangeRate() override { return S_OK; } 107 | 108 | void InitVideoMediaType(); 109 | 110 | public: 111 | HRESULT DecideBufferSize(IMemAllocator* pIMemAlloc, ALLOCATOR_PROPERTIES* pProperties) override; 112 | HRESULT FillBuffer(IMediaSample* pSample) override; 113 | HRESULT CheckMediaType(const CMediaType* pMediaType) override; 114 | HRESULT SetMediaType(const CMediaType* pMediaType) override; 115 | HRESULT GetMediaType(int iPosition, CMediaType* pmt) override; 116 | 117 | // IQualityControl 118 | STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) override { return E_NOTIMPL; } 119 | }; 120 | 121 | // 122 | // CVapourSynthAudioStream 123 | // 124 | 125 | class CVapourSynthAudioStream 126 | : public CSourceStream 127 | , public CSourceSeeking 128 | { 129 | private: 130 | CCritSec m_cSharedState; 131 | 132 | const CVapourSynthFile* m_pVapourSynthFile; 133 | 134 | const VSAudioInfo* m_vsAudioInfo = nullptr; 135 | 136 | BOOL m_bDiscontinuity = FALSE; 137 | BOOL m_bFlushing = FALSE; 138 | 139 | GUID m_Subtype = {}; 140 | int m_Channels = 0; 141 | int m_SampleRate = 0; 142 | int m_BytesPerSample = 0; // for all audio channels 143 | int m_BitDepth = 0; 144 | VSSampleType m_SampleType = {}; 145 | 146 | int m_FrameSamples = 0; 147 | int m_NumFrames = 0; 148 | int64_t m_NumSamples = 0; 149 | 150 | int m_FrameCounter = 0; 151 | int m_CurrentFrame = 0; 152 | 153 | char m_vsErrorMessage[1024] = {}; 154 | std::wstring m_StreamInfo; 155 | 156 | public: 157 | CVapourSynthAudioStream(CVapourSynthFile* pVapourSynthFile, CSource* pParent, HRESULT* phr); 158 | virtual ~CVapourSynthAudioStream(); 159 | 160 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override; 161 | 162 | std::wstring_view GetInfo() { return m_StreamInfo; } 163 | 164 | private: 165 | HRESULT OnThreadCreate() override; 166 | HRESULT OnThreadStartPlay() override; 167 | void UpdateFromSeek(); 168 | 169 | // IMediaSeeking 170 | STDMETHODIMP SetRate(double dRate) override; 171 | 172 | HRESULT ChangeStart() override; 173 | HRESULT ChangeStop() override; 174 | HRESULT ChangeRate() override { return S_OK; } 175 | 176 | public: 177 | HRESULT DecideBufferSize(IMemAllocator* pIMemAlloc, ALLOCATOR_PROPERTIES* pProperties) override; 178 | HRESULT FillBuffer(IMediaSample* pSample) override; 179 | HRESULT CheckMediaType(const CMediaType* pMediaType) override; 180 | HRESULT SetMediaType(const CMediaType* pMediaType) override; 181 | HRESULT GetMediaType(int iPosition, CMediaType* pmt) override; 182 | 183 | // IQualityControl 184 | STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) override { return E_NOTIMPL; } 185 | }; 186 | -------------------------------------------------------------------------------- /Source/dllmain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #include "stdafx.h" 8 | #include 9 | #include "ScriptSource.h" 10 | #include "PropPage.h" 11 | 12 | template 13 | static CUnknown* WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT* phr) 14 | { 15 | *phr = S_OK; 16 | CUnknown* punk = new(std::nothrow) T(lpunk, phr); 17 | if (punk == nullptr) { 18 | *phr = E_OUTOFMEMORY; 19 | } 20 | return punk; 21 | } 22 | 23 | const AMOVIESETUP_PIN sudpPins[] = { 24 | {(LPWSTR)L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, 0, nullptr}, 25 | }; 26 | 27 | const AMOVIESETUP_FILTER sudFilter[] = { 28 | {&__uuidof(CScriptSource), L"MPC Script Source", MERIT_NORMAL, (UINT)std::size(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, 29 | }; 30 | 31 | CFactoryTemplate g_Templates[] = { 32 | {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, 33 | {L"InfoProp", &__uuidof(CSSInfoPPage), CreateInstance, nullptr, nullptr}, 34 | }; 35 | 36 | int g_cTemplates = (int)std::size(g_Templates); 37 | 38 | STDAPI DllRegisterServer() 39 | { 40 | return AMovieDllRegisterServer2(TRUE); 41 | } 42 | 43 | STDAPI DllUnregisterServer() 44 | { 45 | LPCWSTR strGuid = _CRT_WIDE(STR_CLSID_ScriptSource); 46 | DWORD type; 47 | WCHAR data[40]; 48 | DWORD cbData; 49 | 50 | HKEY hKey; 51 | LONG ec = ::RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Media Type\\Extensions\\.avs", 0, KEY_ALL_ACCESS, &hKey); 52 | if (ec == ERROR_SUCCESS) { 53 | ec = RegQueryValueExW(hKey, L"Source Filter", nullptr, &type, (LPBYTE)data, &cbData); 54 | if (ec == ERROR_SUCCESS && type == REG_SZ && _wcsicmp(strGuid, data) == 0) { 55 | RegDeleteValueW(hKey, L"Source Filter"); 56 | } 57 | ::RegCloseKey(hKey); 58 | } 59 | 60 | ec = ::RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Media Type\\Extensions\\.vpy", 0, KEY_ALL_ACCESS, &hKey); 61 | if (ec == ERROR_SUCCESS) { 62 | ec = RegQueryValueExW(hKey, L"Source Filter", nullptr, &type, (LPBYTE)data, &cbData); 63 | if (ec == ERROR_SUCCESS && type == REG_SZ && _wcsicmp(strGuid, data) == 0) { 64 | RegDeleteValueW(hKey, L"Source Filter"); 65 | } 66 | ::RegCloseKey(hKey); 67 | } 68 | 69 | return AMovieDllRegisterServer2(FALSE); 70 | } 71 | 72 | extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); 73 | 74 | BOOL WINAPI DllMain(HINSTANCE hDllHandle, DWORD dwReason, LPVOID pReserved) 75 | { 76 | return DllEntryPoint(hDllHandle, dwReason, pReserved); 77 | } 78 | -------------------------------------------------------------------------------- /Source/res/MpcScriptSource.rc2: -------------------------------------------------------------------------------- 1 | // 2 | // MpcScriptSource.rc2 - resources Microsoft Visual C++ does not edit directly 3 | // 4 | 5 | #ifdef APSTUDIO_INVOKED 6 | #error this file is not editable by Microsoft Visual C++ 7 | #endif //APSTUDIO_INVOKED 8 | 9 | 10 | ///////////////////////////////////////////////////////////////////////////// 11 | // Add manually edited resources here... 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | 15 | #include "../../Include/Version.h" 16 | 17 | 18 | ///////////////////////////////////////////////////////////////////////////// 19 | // 20 | // FILE 21 | // 22 | 23 | 24 | ///////////////////////////////////////////////////////////////////////////// 25 | // 26 | // Version 27 | // 28 | 29 | VS_VERSION_INFO VERSIONINFO 30 | FILEVERSION VERSION_NUM 31 | PRODUCTVERSION VERSION_NUM 32 | FILEFLAGSMASK 0x17L 33 | #ifdef _DEBUG 34 | FILEFLAGS 0x1L 35 | #else 36 | FILEFLAGS 0x0L 37 | #endif 38 | FILEOS 0x4L 39 | FILETYPE 0x2L 40 | FILESUBTYPE 0x0L 41 | BEGIN 42 | BLOCK "StringFileInfo" 43 | BEGIN 44 | BLOCK "040904b0" 45 | BEGIN 46 | VALUE "CompanyName", "MPC-BE Team" 47 | VALUE "FileDescription", "MPC Script Source" 48 | VALUE "FileVersion", VERSION_STR 49 | VALUE "InternalName", "ScriptSource" 50 | VALUE "LegalCopyright", "Copyright 2020-2024" 51 | #ifdef _WIN64 52 | 53 | VALUE "OriginalFilename", "MpcScriptSource64.ax" 54 | #else 55 | VALUE "OriginalFilename", "MpcScriptSource.ax" 56 | #endif 57 | VALUE "ProductName", "MPC Script Source" 58 | VALUE "ProductVersion", VERSION_STR 59 | END 60 | END 61 | BLOCK "VarFileInfo" 62 | BEGIN 63 | VALUE "Translation", 0x409, 1200 64 | END 65 | END 66 | -------------------------------------------------------------------------------- /Source/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by MpcScriptSource.rc 4 | // 5 | #define IDD_MAINPROPPAGE 102 6 | #define IDD_INFOPROPPAGE 103 7 | #define IDS_MAINPROPPAGE_TITLE 104 8 | #define IDS_INFOPROPPAGE_TITLE 105 9 | #define IDC_STATIC1 1001 10 | #define IDC_STATIC2 1002 11 | #define IDC_STATIC3 1003 12 | #define IDC_CHECK1 1004 13 | #define IDC_CHECK2 1005 14 | #define IDC_CHECK3 1006 15 | #define IDC_CHECK4 1007 16 | #define IDC_CHECK5 1008 17 | #define IDC_CHECK6 1009 18 | #define IDC_CHECK7 1010 19 | #define IDC_CHECK8 1011 20 | #define IDC_CHECK9 1012 21 | #define IDC_CHECK10 1013 22 | #define IDC_CHECK11 1014 23 | #define IDC_CHECK12 1015 24 | #define IDC_COMBO1 1016 25 | #define IDC_COMBO2 1017 26 | #define IDC_COMBO3 1018 27 | #define IDC_COMBO4 1019 28 | #define IDC_COMBO5 1020 29 | #define IDC_EDIT1 1021 30 | #define IDC_EDIT2 1022 31 | #define IDC_EDIT3 1023 32 | #define IDC_BUTTON1 1024 33 | #define IDC_SLIDER1 1025 34 | #define IDC_SLIDER2 1026 35 | 36 | // Next default values for new objects 37 | // 38 | #ifdef APSTUDIO_INVOKED 39 | #ifndef APSTUDIO_READONLY_SYMBOLS 40 | #define _APS_NEXT_RESOURCE_VALUE 104 41 | #define _APS_NEXT_COMMAND_VALUE 40001 42 | #define _APS_NEXT_CONTROL_VALUE 1026 43 | #define _APS_NEXT_SYMED_VALUE 101 44 | #endif 45 | #endif 46 | -------------------------------------------------------------------------------- /Source/stdafx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #include "stdafx.h" 8 | 9 | #pragma comment(lib, "winmm.lib") 10 | -------------------------------------------------------------------------------- /Source/stdafx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2024 v0lt 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 10 | #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "../external/BaseClasses/streams.h" 27 | -------------------------------------------------------------------------------- /build_scriptsource.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | REM Copyright (C) 2020-2024 v0lt 3 | REM 4 | REM SPDX-License-Identifier: LGPL-2.1-only 5 | 6 | SETLOCAL ENABLEDELAYEDEXPANSION 7 | CD /D %~dp0 8 | 9 | SET "TITLE=MPC Script Source" 10 | SET "PROJECT=MpcScriptSource" 11 | 12 | SET "MSBUILD_SWITCHES=/nologo /consoleloggerparameters:Verbosity=minimal /maxcpucount /nodeReuse:true" 13 | SET "BUILDTYPE=Build" 14 | SET "BUILDCFG=Release" 15 | SET "SUFFIX=" 16 | SET "SIGN=False" 17 | 18 | FOR %%A IN (%*) DO ( 19 | IF /I "%%A" == "Debug" ( 20 | SET "BUILDCFG=Debug" 21 | SET "SUFFIX=_Debug" 22 | ) 23 | IF /I "%%A" == "Sign" ( 24 | SET "SIGN=True" 25 | ) 26 | IF /I "%%A" == "VS2019" ( 27 | SET "COMPILER=VS2019" 28 | ) 29 | IF /I "%%A" == "VS2022" ( 30 | SET "COMPILER=VS2022" 31 | ) 32 | ) 33 | 34 | IF /I "%SIGN%" == "True" ( 35 | IF NOT EXIST "%~dp0signinfo.txt" ( 36 | CALL :SubMsg "WARNING" "signinfo.txt not found." 37 | SET "SIGN=False" 38 | ) 39 | ) 40 | 41 | CALL :SubVSPath 42 | SET "TOOLSET=%VS_PATH%\Common7\Tools\vsdevcmd" 43 | 44 | SET "LOG_DIR=_bin\logs" 45 | IF NOT EXIST "%LOG_DIR%" MD "%LOG_DIR%" 46 | 47 | CALL "%TOOLSET%" -arch=x86 48 | REM again set the source directory (fix possible bug in VS2017) 49 | CD /D %~dp0 50 | CALL :SubCompiling x86 51 | 52 | CALL "%TOOLSET%" -arch=amd64 53 | REM again set the source directory (fix possible bug in VS2017) 54 | CD /D %~dp0 55 | CALL :SubCompiling x64 56 | 57 | IF /I "%SIGN%" == "True" ( 58 | SET FILES="%~dp0_bin\Filter_x86%SUFFIX%\%PROJECT%.ax" "%~dp0_bin\Filter_x64%SUFFIX%\%PROJECT%64.ax" 59 | CALL "%~dp0\sign.cmd" %%FILES%% 60 | IF %ERRORLEVEL% NEQ 0 ( 61 | CALL :SubMsg "ERROR" "Problem signing files." 62 | ) ELSE ( 63 | CALL :SubMsg "INFO" "Files signed successfully." 64 | ) 65 | ) 66 | 67 | FOR /F "tokens=3,4 delims= " %%A IN ( 68 | 'FINDSTR /I /L /C:"define VER_MAJOR" "Include\Version.h"') DO (SET "VERMAJOR=%%A") 69 | FOR /F "tokens=3,4 delims= " %%A IN ( 70 | 'FINDSTR /I /L /C:"define VER_MINOR" "Include\Version.h"') DO (SET "VERMINOR=%%A") 71 | FOR /F "tokens=3,4 delims= " %%A IN ( 72 | 'FINDSTR /I /L /C:"define VER_BUILD" "Include\Version.h"') DO (SET "VERBUILD=%%A") 73 | FOR /F "tokens=3,4 delims= " %%A IN ( 74 | 'FINDSTR /I /L /C:"define VER_RELEASE" "Include\Version.h"') DO (SET "VERRELEASE=%%A") 75 | FOR /F "tokens=3,4 delims= " %%A IN ( 76 | 'FINDSTR /I /L /C:"define REV_DATE" "revision.h"') DO (SET "REVDATE=%%A") 77 | FOR /F "tokens=3,4 delims= " %%A IN ( 78 | 'FINDSTR /I /L /C:"define REV_HASH" "revision.h"') DO (SET "REVHASH=%%A") 79 | FOR /F "tokens=3,4 delims= " %%A IN ( 80 | 'FINDSTR /I /L /C:"define REV_NUM" "revision.h"') DO (SET "REVNUM=%%A") 81 | FOR /F "tokens=3,4 delims= " %%A IN ( 82 | 'FINDSTR /I /L /C:"define REV_BRANCH" "revision.h"') DO (SET "REVBRANCH=%%A") 83 | 84 | IF /I "%VERRELEASE%" == "1" ( 85 | SET "PCKG_NAME=%PROJECT%-%VERMAJOR%.%VERMINOR%.%VERBUILD%.%REVNUM%%SUFFIX%" 86 | ) ELSE ( 87 | IF /I "%REVBRANCH%" == "master" ( 88 | SET "PCKG_NAME=%PROJECT%-%VERMAJOR%.%VERMINOR%.%VERBUILD%.%REVNUM%_git%REVDATE%-%REVHASH%%SUFFIX%" 89 | ) ELSE ( 90 | SET "PCKG_NAME=%PROJECT%-%VERMAJOR%.%VERMINOR%.%VERBUILD%.%REVNUM%.%REVBRANCH%_git%REVDATE%-%REVHASH%%SUFFIX%" 91 | ) 92 | ) 93 | 94 | CALL :SubDetectSevenzipPath 95 | IF DEFINED SEVENZIP ( 96 | IF EXIST "_bin\%PCKG_NAME%.zip" DEL "_bin\%PCKG_NAME%.zip" 97 | 98 | TITLE Creating archive %PCKG_NAME%.zip... 99 | START "7z" /B /WAIT "%SEVENZIP%" a -tzip -mx9 "_bin\%PCKG_NAME%.zip" ^ 100 | .\_bin\Filter_x86%SUFFIX%\%PROJECT%.ax ^ 101 | .\_bin\Filter_x64%SUFFIX%\%PROJECT%64.ax ^ 102 | .\distrib\Install_MpcScriptSource_32.cmd ^ 103 | .\distrib\Install_MpcScriptSource_64.cmd ^ 104 | .\distrib\Uninstall_MpcScriptSource_32.cmd ^ 105 | .\distrib\Uninstall_MpcScriptSource_64.cmd ^ 106 | .\distrib\Reset_Settings.cmd ^ 107 | .\Readme.md ^ 108 | .\history.txt ^ 109 | .\LICENSE.txt 110 | IF %ERRORLEVEL% NEQ 0 CALL :SubMsg "ERROR" "Unable to create %PCKG_NAME%.zip!" 111 | CALL :SubMsg "INFO" "%PCKG_NAME%.zip successfully created" 112 | ) 113 | 114 | TITLE Compiling %TITLE% [FINISHED] 115 | TIMEOUT /T 3 116 | ENDLOCAL 117 | EXIT 118 | 119 | :SubVSPath 120 | SET "PARAMS=-property installationPath -requires Microsoft.Component.MSBuild" 121 | IF /I "%COMPILER%" == "VS2019" ( 122 | SET "PARAMS=%PARAMS% -version [16.0,17.0)" 123 | ) ELSE IF /I "%COMPILER%" == "VS2022" ( 124 | SET "PARAMS=%PARAMS% -version [17.0,18.0)" 125 | ) ELSE ( 126 | SET "PARAMS=%PARAMS% -latest" 127 | ) 128 | SET "VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" %PARAMS%" 129 | FOR /f "delims=" %%A IN ('!VSWHERE!') DO SET VS_PATH=%%A 130 | EXIT /B 131 | 132 | :SubDetectSevenzipPath 133 | FOR %%G IN (7z.exe) DO (SET "SEVENZIP_PATH=%%~$PATH:G") 134 | IF EXIST "%SEVENZIP_PATH%" (SET "SEVENZIP=%SEVENZIP_PATH%" & EXIT /B) 135 | 136 | FOR %%G IN (7za.exe) DO (SET "SEVENZIP_PATH=%%~$PATH:G") 137 | IF EXIST "%SEVENZIP_PATH%" (SET "SEVENZIP=%SEVENZIP_PATH%" & EXIT /B) 138 | 139 | FOR /F "tokens=2*" %%A IN ( 140 | 'REG QUERY "HKLM\SOFTWARE\7-Zip" /v "Path" 2^>NUL ^| FIND "REG_SZ" ^|^| 141 | REG QUERY "HKLM\SOFTWARE\Wow6432Node\7-Zip" /v "Path" 2^>NUL ^| FIND "REG_SZ"') DO SET "SEVENZIP=%%B\7z.exe" 142 | EXIT /B 143 | 144 | :SubCompiling 145 | TITLE Compiling %TITLE% - %BUILDCFG%^|%1... 146 | MSBuild.exe %PROJECT%.sln %MSBUILD_SWITCHES%^ 147 | /target:%BUILDTYPE% /p:Configuration="%BUILDCFG%" /p:Platform=%1^ 148 | /flp1:LogFile=%LOG_DIR%\errors_%BUILDCFG%_%1.log;errorsonly;Verbosity=diagnostic^ 149 | /flp2:LogFile=%LOG_DIR%\warnings_%BUILDCFG%_%1.log;warningsonly;Verbosity=diagnostic 150 | IF %ERRORLEVEL% NEQ 0 ( 151 | CALL :SubMsg "ERROR" "%PROJECT%.sln %BUILDCFG% %1 - Compilation failed!" 152 | ) ELSE ( 153 | CALL :SubMsg "INFO" "%PROJECT%.sln %BUILDCFG% %1 compiled successfully" 154 | ) 155 | EXIT /B 156 | 157 | :SubMsg 158 | ECHO. & ECHO ------------------------------ 159 | IF /I "%~1" == "ERROR" ( 160 | CALL :SubColorText "0C" "[%~1]" & ECHO %~2 161 | ) ELSE IF /I "%~1" == "INFO" ( 162 | CALL :SubColorText "0A" "[%~1]" & ECHO %~2 163 | ) ELSE IF /I "%~1" == "WARNING" ( 164 | CALL :SubColorText "0E" "[%~1]" & ECHO %~2 165 | ) 166 | ECHO ------------------------------ & ECHO. 167 | IF /I "%~1" == "ERROR" ( 168 | ECHO Press any key to close this window... 169 | PAUSE >NUL 170 | ENDLOCAL 171 | EXIT 172 | ) ELSE ( 173 | EXIT /B 174 | ) 175 | 176 | :SubColorText 177 | FOR /F "tokens=1,2 delims=#" %%A IN ( 178 | '"PROMPT #$H#$E# & ECHO ON & FOR %%B IN (1) DO REM"') DO ( 179 | SET "DEL=%%A") 180 | "%~2" 181 | FINDSTR /v /a:%1 /R ".18" "%~2" NUL 182 | DEL "%~2" > NUL 2>&1 183 | EXIT /B -------------------------------------------------------------------------------- /common.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(SolutionDir)_bin\obj\$(Configuration)_$(PlatformShortName)\$(ProjectName)\ 5 | $(SolutionDir)_bin\lib\$(Configuration)_$(PlatformShortName)\ 6 | $(SolutionDir)_bin\Filter_$(PlatformShortName)_Debug\ 7 | $(SolutionDir)_bin\Filter_$(PlatformShortName)\ 8 | true 9 | false 10 | 11 | 12 | 13 | /Zo /Zc:throwingNew /Zc:rvalueCast %(AdditionalOptions) 14 | true 15 | 4244; 4838; 26451 16 | 4267;%(DisableSpecificWarnings) 17 | Sync 18 | true 19 | stdcpp20 20 | true 21 | NOMINMAX;_WINDOWS;WINDOWS;WINVER=0x0601;_WIN32_WINNT=0x0601;_USRDLL;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) 22 | WIN32;%(PreprocessorDefinitions) 23 | _WIN64;WIN64;%(PreprocessorDefinitions) 24 | Level3 25 | 26 | 27 | MachineX86 28 | MachineX64 29 | 30 | 31 | true 32 | Debug 33 | true 34 | Windows 35 | MachineX86 36 | MachineX64 37 | 38 | 39 | 0x0409 40 | WIN32;%(PreprocessorDefinitions) 41 | _WIN64;%(PreprocessorDefinitions) 42 | 43 | 44 | 45 | 46 | EnableFastChecks 47 | EditAndContinue 48 | ProgramDatabase 49 | Disabled 50 | MultiThreadedDebug 51 | 52 | 53 | _DEBUG;%(PreprocessorDefinitions) 54 | 55 | 56 | false 57 | DebugFastLink 58 | 59 | 60 | 61 | 62 | /Zc:inline %(AdditionalOptions) 63 | ProgramDatabase 64 | AnySuitable 65 | true 66 | Speed 67 | false 68 | MaxSpeed 69 | _CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) 70 | MultiThreaded 71 | true 72 | true 73 | 74 | 75 | true 76 | 77 | 78 | true 79 | true 80 | UseFastLinkTimeCodeGeneration 81 | .rdata=.text 82 | true 83 | true 84 | 85 | 86 | NDEBUG;%(PreprocessorDefinitions) 87 | 88 | 89 | -------------------------------------------------------------------------------- /distrib/Install_MpcScriptSource_32.cmd: -------------------------------------------------------------------------------- 1 | @cd /d "%~dp0" 2 | @regsvr32.exe MpcScriptSource.ax /s 3 | @if %errorlevel% NEQ 0 goto error 4 | :success 5 | @echo. 6 | @echo. 7 | @echo Installation succeeded. 8 | @echo. 9 | @echo Please do not delete the MpcScriptSource.ax file. 10 | @echo The installer has not copied the files anywhere. 11 | @echo. 12 | @goto done 13 | :error 14 | @echo. 15 | @echo. 16 | @echo Installation failed. 17 | @echo. 18 | @echo You need to right click "Install_MPCScriptSource_32.cmd" and choose "run as admin". 19 | @echo. 20 | :done 21 | @pause >NUL 22 | -------------------------------------------------------------------------------- /distrib/Install_MpcScriptSource_64.cmd: -------------------------------------------------------------------------------- 1 | @cd /d "%~dp0" 2 | @regsvr32.exe MpcScriptSource64.ax /s 3 | @if %errorlevel% NEQ 0 goto error 4 | :success 5 | @echo. 6 | @echo. 7 | @echo Installation succeeded. 8 | @echo. 9 | @echo Please do not delete the MpcScriptSource64.ax file. 10 | @echo The installer has not copied the files anywhere. 11 | @echo. 12 | @goto done 13 | :error 14 | @echo. 15 | @echo. 16 | @echo Installation failed. 17 | @echo. 18 | @echo You need to right click "Install_MpcScriptSource_64.cmd" and choose "run as admin". 19 | @echo. 20 | :done 21 | @pause >NUL 22 | -------------------------------------------------------------------------------- /distrib/Reset_Settings.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo. 3 | echo. 4 | title Restore MPC Script Source default settings... 5 | start /min reg delete "HKEY_CURRENT_USER\Software\MPC-BE Filters\MPC Script Source" /f 6 | echo settings were reset to default 7 | echo. 8 | pause >NUL 9 | -------------------------------------------------------------------------------- /distrib/Uninstall_MpcScriptSource_32.cmd: -------------------------------------------------------------------------------- 1 | @cd /d "%~dp0" 2 | @regsvr32.exe MpcScriptSource.ax /u /s 3 | @if %errorlevel% NEQ 0 goto error 4 | :success 5 | @echo. 6 | @echo. 7 | @echo Uninstallation succeeded. 8 | @echo. 9 | @goto done 10 | :error 11 | @echo. 12 | @echo. 13 | @echo Uninstallation failed. 14 | @echo. 15 | @echo You need to right click "Uninstall_MpcScriptSource_32.cmd" and choose "run as admin". 16 | @echo. 17 | :done 18 | @pause >NUL 19 | -------------------------------------------------------------------------------- /distrib/Uninstall_MpcScriptSource_64.cmd: -------------------------------------------------------------------------------- 1 | @cd /d "%~dp0" 2 | @regsvr32.exe MpcScriptSource64.ax /u /s 3 | @if %errorlevel% NEQ 0 goto error 4 | :success 5 | @echo. 6 | @echo. 7 | @echo Uninstallation succeeded. 8 | @echo. 9 | @goto done 10 | :error 11 | @echo. 12 | @echo. 13 | @echo Uninstallation failed. 14 | @echo. 15 | @echo You need to right click "Uninstall_MpcScriptSource_64.cmd" and choose "run as admin". 16 | @echo. 17 | :done 18 | @pause >NUL 19 | -------------------------------------------------------------------------------- /external/BaseClasses.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA} 23 | BaseClasses 24 | Win32Proj 25 | BaseClasses 26 | 27 | 28 | 29 | 30 | StaticLibrary 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | _LIB;%(PreprocessorDefinitions) 43 | Use 44 | streams.h 45 | 46 | 47 | strmiids.lib 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Create 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /external/BaseClasses.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Header Files 16 | 17 | 18 | Header Files 19 | 20 | 21 | Header Files 22 | 23 | 24 | Header Files 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files 109 | 110 | 111 | Header Files 112 | 113 | 114 | Header Files 115 | 116 | 117 | Header Files 118 | 119 | 120 | Header Files 121 | 122 | 123 | Header Files 124 | 125 | 126 | Header Files 127 | 128 | 129 | 130 | 131 | Source Files 132 | 133 | 134 | Source Files 135 | 136 | 137 | Source Files 138 | 139 | 140 | Source Files 141 | 142 | 143 | Source Files 144 | 145 | 146 | Source Files 147 | 148 | 149 | Source Files 150 | 151 | 152 | Source Files 153 | 154 | 155 | Source Files 156 | 157 | 158 | Source Files 159 | 160 | 161 | Source Files 162 | 163 | 164 | Source Files 165 | 166 | 167 | Source Files 168 | 169 | 170 | Source Files 171 | 172 | 173 | Source Files 174 | 175 | 176 | Source Files 177 | 178 | 179 | Source Files 180 | 181 | 182 | Source Files 183 | 184 | 185 | Source Files 186 | 187 | 188 | Source Files 189 | 190 | 191 | Source Files 192 | 193 | 194 | Source Files 195 | 196 | 197 | Source Files 198 | 199 | 200 | Source Files 201 | 202 | 203 | Source Files 204 | 205 | 206 | Source Files 207 | 208 | 209 | Source Files 210 | 211 | 212 | Source Files 213 | 214 | 215 | Source Files 216 | 217 | 218 | Source Files 219 | 220 | 221 | Source Files 222 | 223 | 224 | Source Files 225 | 226 | 227 | Source Files 228 | 229 | 230 | -------------------------------------------------------------------------------- /history.txt: -------------------------------------------------------------------------------- 1 | 0.2.7.192 - 2024-04-03 2 | ----------------------- 3 | Fixed registration of a filter from a folder with Unicode characters. 4 | 5 | 0.2.5.183 - 2024-12-13 6 | ----------------------- 7 | Fixed support for YV12, YV16, YV24 formats for AviSynth+. 8 | 9 | 0.2.3.174 - 2024-11-05 10 | ----------------------- 11 | Fixed display of video frame with error in AviSynth script. 12 | Fixed opening VapourSynth scripts without sound. 13 | Added support for Y10 (Gray10) format. 14 | 15 | 0.2.1.165 - 2024-08-18 16 | ----------------------- 17 | The license has been changed to LGPL-2.1. 18 | Added audio support for AviSynth+ and VapourSynth scripts. 19 | ScriptSourceFilter will not show a video with an error if it cannot connect to AviSynth+ or VapourSynth. This will allow the player to try other filters. 20 | Now uses VapourSynth API 4. 21 | Recommended versions are AviSynth+ 3.7.3 or later, VapourSynth R63 or later. 22 | 23 | 0.1.4.128 - 2022-09-21 24 | ----------------------- 25 | Added Frame Properties support for AviSynth+ and VapourSynth R59. 26 | Recommended versions are AviSynth+ 3.7.2 or later, VapourSynth R59 or later. 27 | 28 | 0.1.2.106 - 2022-01-05 29 | ----------------------- 30 | Removed filter registration for .avs and .vpy extensions. This preserves the ability to open scripts using the "AVI/WAV File Source" system filter. Better solution is to add ScriptSourceFilter as an external filter in MPC-BE, MPC-HC and other players, set the priority as preferred and enable the filter when needed. 31 | 32 | 0.1.0.76 - 2020-06-16 33 | ---------------------- 34 | The first official release. -------------------------------------------------------------------------------- /platform.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 10.0.17763.0 5 | v141 6 | 7 | 8 | 10.0 9 | v142 10 | 11 | 12 | 10.0 13 | v143 14 | 15 | -------------------------------------------------------------------------------- /sign.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | REM (C) 2015-2019 see Authors.txt 3 | REM 4 | REM This file is part of MPC-BE. 5 | REM 6 | REM MPC-BE is free software; you can redistribute it and/or modify 7 | REM it under the terms of the GNU General Public License as published by 8 | REM the Free Software Foundation; either version 3 of the License, or 9 | REM (at your option) any later version. 10 | REM 11 | REM MPC-BE is distributed in the hope that it will be useful, 12 | REM but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | REM GNU General Public License for more details. 15 | REM 16 | REM You should have received a copy of the GNU General Public License 17 | REM along with this program. If not, see . 18 | 19 | SETLOCAL 20 | 21 | IF "%~1" == "" ( 22 | ECHO %~nx0: No input file specified! 23 | GOTO END 24 | ) 25 | 26 | IF NOT EXIST "%~dp0signinfo.txt" ( 27 | ECHO %~nx0: %~dp0signinfo.txt is not present! 28 | GOTO END 29 | ) 30 | 31 | IF NOT DEFINED VCVARS ( 32 | FOR /f "delims=" %%A IN ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -property installationPath -requires Microsoft.Component.MSBuild Microsoft.VisualStudio.Component.VC.ATLMFC Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -latest') DO SET "VCVARS=%%A\Common7\Tools\vsdevcmd.bat" 33 | ) 34 | 35 | IF NOT EXIST "%VCVARS%" ( 36 | ECHO ERROR: "Visual Studio environment variable(s) is missing - possible it's not installed on your PC" 37 | GOTO END 38 | ) 39 | 40 | CALL "%VCVARS%" -no_logo -arch=x86 41 | 42 | TITLE Signing "%*"... 43 | ECHO. & ECHO Signing "%*"... 44 | 45 | FOR /F "delims=" %%A IN (%~dp0signinfo.txt) DO (SET "SIGN_CMD=%%A" && CALL :SIGN %*) 46 | 47 | :END 48 | ENDLOCAL 49 | EXIT /B %ERRORLEVEL% 50 | 51 | :SIGN 52 | FOR /L %%i IN (1,1,5) DO ( 53 | IF %%i GTR 1 ECHO %%i attempt 54 | signtool.exe sign %SIGN_CMD% %* 55 | IF %ERRORLEVEL% EQU 0 EXIT /B %ERRORLEVEL% 56 | ) 57 | -------------------------------------------------------------------------------- /update_revision.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | SETLOCAL 3 | CD /D %~dp0 4 | 5 | ECHO #pragma once > revision.h 6 | 7 | SET gitexe="git.exe" 8 | %gitexe% --version 9 | IF /I %ERRORLEVEL%==0 GOTO :GitOK 10 | 11 | SET gitexe="c:\Program Files\Git\cmd\git.exe" 12 | IF NOT EXIST %gitexe% set gitexe="c:\Program Files\Git\bin\git.exe" 13 | IF NOT EXIST %gitexe% GOTO :END 14 | 15 | :GitOK 16 | 17 | %gitexe% log -1 --date=format:%%Y.%%m.%%d --pretty=format:"#define REV_DATE %%ad%%n" >> revision.h 18 | %gitexe% log -1 --pretty=format:"#define REV_HASH %%h%%n" >> revision.h 19 | 20 | > revision.h 21 | %gitexe% symbolic-ref --short HEAD >> revision.h 22 | IF %ERRORLEVEL% NEQ 0 ( 23 | ECHO LOCAL >> revision.h 24 | ) 25 | 26 | > revision.h 27 | %gitexe% rev-list --count HEAD >> revision.h 28 | IF %ERRORLEVEL% NEQ 0 ( 29 | ECHO 0 >> revision.h 30 | ) 31 | 32 | :END 33 | ENDLOCAL 34 | EXIT /B 35 | --------------------------------------------------------------------------------