├── src ├── assrender.def ├── timecodes.h ├── sub.h ├── ASSRender.rc ├── CMakeLists.txt ├── timecodes.c ├── assrender.h ├── include │ ├── avs │ │ ├── types.h │ │ ├── capi.h │ │ └── config.h │ ├── VapourSynth.h │ └── avisynth_c.h ├── render.h ├── sub.c ├── csriapi.c ├── csri.h ├── assrender.c └── render.c ├── lib ├── x86-32 │ └── readme.txt └── x86-64 │ └── readme.txt ├── CMakeLists.txt ├── cmake_uninstall.cmake.in ├── .gitmodules ├── .gitignore ├── .github └── workflows │ ├── c-cpp.yml │ └── build.yml └── README.md /src/assrender.def: -------------------------------------------------------------------------------- 1 | LIBRARY assrender 2 | EXPORTS 3 | VapourSynthPluginInit -------------------------------------------------------------------------------- /lib/x86-32/readme.txt: -------------------------------------------------------------------------------- 1 | placeholder for 32 bit avisynth.lib from Avisynth C API SDK files -------------------------------------------------------------------------------- /lib/x86-64/readme.txt: -------------------------------------------------------------------------------- 1 | placeholder for 64 bit avisynth.lib from Avisynth C API SDK files -------------------------------------------------------------------------------- /src/timecodes.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIMECODE_H_ 2 | #define _TIMECODE_H_ 3 | 4 | #include "assrender.h" 5 | 6 | int parse_timecodesv1(FILE* f, int total, udata* ud); 7 | 8 | int parse_timecodesv2(FILE* f, int total, udata* ud); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/sub.h: -------------------------------------------------------------------------------- 1 | #ifndef _SUB_H_ 2 | #define _SUB_H_ 3 | 4 | // #include 5 | #include "assrender.h" 6 | 7 | void ass_read_matrix(FILE* fh, char* csp); 8 | 9 | ASS_Track* parse_srt(FILE* fh, udata* ud, const char* srt_font); 10 | 11 | int init_ass(int w, int h, double scale, double line_spacing, ASS_Hinting hinting, 12 | int frame_width, int frame_height, double dar, double sar, int set_default_storage_size, 13 | int top, int bottom, int left, int right, int verbosity, 14 | const char* fontdir, udata* ud); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(assrender) 3 | 4 | include(GNUInstallDirs) 5 | 6 | if(MINGW) 7 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc -Wl,--add-stdcall-alias") 8 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wpedantic") 9 | set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-s") 10 | endif() 11 | 12 | add_subdirectory(src) 13 | 14 | # uninstall target 15 | configure_file( 16 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" 17 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 18 | IMMEDIATE @ONLY) 19 | 20 | add_custom_target(uninstall 21 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 22 | -------------------------------------------------------------------------------- /cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 3 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | 5 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 6 | string(REGEX REPLACE "\n" ";" files "${files}") 7 | foreach(file ${files}) 8 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 9 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 10 | exec_program( 11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out 13 | RETURN_VALUE rm_retval 14 | ) 15 | if(NOT "${rm_retval}" STREQUAL 0) 16 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 17 | endif(NOT "${rm_retval}" STREQUAL 0) 18 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 19 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 20 | endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 21 | endforeach(file) 22 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SMP/libass"] 2 | path = SMP/libass 3 | url = https://github.com/ShiftMediaProject/libass.git 4 | [submodule "SMP/libiconv"] 5 | path = SMP/libiconv 6 | url = https://github.com/ShiftMediaProject/libiconv.git 7 | [submodule "SMP/harfbuzz"] 8 | path = SMP/harfbuzz 9 | url = https://github.com/ShiftMediaProject/harfbuzz.git 10 | [submodule "SMP/fontconfig"] 11 | path = SMP/fontconfig 12 | url = https://github.com/ShiftMediaProject/fontconfig.git 13 | [submodule "SMP/freetype2"] 14 | path = SMP/freetype2 15 | url = https://github.com/ShiftMediaProject/freetype2.git 16 | [submodule "SMP/libxml2"] 17 | path = SMP/libxml2 18 | url = https://github.com/ShiftMediaProject/libxml2.git 19 | [submodule "fribidi"] 20 | path = fribidi 21 | url = https://github.com/ShiftMediaProject/fribidi.git 22 | [submodule "SMP/fribidi"] 23 | path = SMP/fribidi 24 | url = https://github.com/ShiftMediaProject/fribidi.git 25 | [submodule "SMP/liblzma"] 26 | path = SMP/liblzma 27 | url = https://github.com/ShiftMediaProject/liblzma.git 28 | [submodule "SMP/zlib"] 29 | path = SMP/zlib 30 | url = https://github.com/ShiftMediaProject/zlib.git 31 | -------------------------------------------------------------------------------- /src/ASSRender.rc: -------------------------------------------------------------------------------- 1 | #include 2 | #pragma code_page(65001) 3 | VS_VERSION_INFO VERSIONINFO 4 | FILEVERSION 0, 38, 3, 0 5 | PRODUCTVERSION 0, 38, 3, 0 6 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 7 | FILEFLAGS 0 8 | FILEOS VOS_NT_WINDOWS32 9 | #ifdef OPENOBEX_EXPORTS 10 | FILETYPE VFT_DLL 11 | #else 12 | FILETYPE VFT_STATIC_LIB 13 | #endif 14 | FILESUBTYPE VFT2_UNKNOWN 15 | BEGIN 16 | BLOCK "StringFileInfo" 17 | BEGIN 18 | BLOCK "040904B0" 19 | BEGIN 20 | VALUE "CompanyName", "" 21 | VALUE "FileDescription", "a plugin for VapourSynth to rend ASS/SSA subtitles using libass" 22 | VALUE "FileVersion", "0.38.3.0" 23 | VALUE "InternalName", "ASSRENDER.DLL" 24 | VALUE "LegalCopyright", "" 25 | VALUE "OriginalFilename", "LIBASSRENDER.DLL" 26 | VALUE "ProductName", "ASSRender plugin for VapourSynth" 27 | VALUE "ProductVersion", "0.38.3.0" 28 | END 29 | END 30 | BLOCK "VarFileInfo" 31 | BEGIN 32 | VALUE "Translation", 0x0409, 0x04B0 /* U.S. English (Unicode) */ 33 | END 34 | END 35 | 36 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(PluginName "assrender") 2 | 3 | if (NOT WIN32) 4 | string(TOLOWER "${PluginName}" PluginName) 5 | endif() 6 | 7 | set(ProjectName "${PluginName}") 8 | project(${ProjectName} LANGUAGES C) 9 | 10 | file(GLOB ASSRender_SRC *.c) 11 | 12 | if(WIN32) 13 | list(APPEND ASSRender_SRC "ASSRender.rc") 14 | if(NOT MINGW) 15 | list(APPEND ASSRender_SRC "assrender.def") 16 | endif() 17 | endif() 18 | 19 | add_library(${PluginName} SHARED ${ASSRender_SRC}) 20 | 21 | set_target_properties(${PluginName} PROPERTIES "OUTPUT_NAME" "${PluginName}") 22 | if (MINGW) 23 | set_target_properties(${PluginName} PROPERTIES PREFIX "") 24 | set_target_properties(${PluginName} PROPERTIES IMPORT_PREFIX "") 25 | endif() 26 | 27 | #dedicated include dir for VapourSynth.h 28 | target_include_directories(${ProjectName} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) 29 | 30 | find_package(PkgConfig REQUIRED) 31 | PKG_CHECK_MODULES(LIBASS REQUIRED libass>=0.12.0) 32 | target_include_directories(${PluginName} PRIVATE ${LIBASS_INCLUDE_DIRS}) 33 | target_link_libraries(${ProjectName} ${LIBASS_LINK_LIBRARIES}) 34 | 35 | include(GNUInstallDirs) 36 | 37 | install(TARGETS ${ProjectName} LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/vapoursynth") 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib/*/avisynth.lib 2 | 3 | CMakeCache.txt 4 | CMakeFiles/* 5 | cmake.db 6 | 7 | *.aps 8 | *.db 9 | *.opendb 10 | *.opensdf 11 | *.sdf 12 | *.suo 13 | *.user 14 | #cmake generated files 15 | cmake_install.cmake 16 | cmake_uninstall.cmake 17 | generate.stamp 18 | generate.stamp.depend 19 | makefile 20 | 21 | #make 22 | install_manifest.txt 23 | 24 | SMP/ 25 | 26 | #*/build/.vs 27 | build/* 28 | */build/Win32 29 | */build/x64 30 | Test 31 | 32 | # Build results 33 | [Dd]ebug/ 34 | [Dd]ebugPublic/ 35 | [Rr]elease/ 36 | [Rr]eleases/ 37 | [Rr]elWithDebInfo/ 38 | x64/ 39 | x86/ 40 | bld/ 41 | [Bb]in/ 42 | [Oo]bj/ 43 | [Ll]og/ 44 | /msvc 45 | # Visual C++ cache files 46 | ipch/ 47 | *.aps 48 | *.ncb 49 | *.opendb 50 | *.opensdf 51 | *.sdf 52 | *.cachefile 53 | *.VC.db 54 | *.VC.VC.opendb 55 | *.VC.db-shm 56 | *.VC.db-wal 57 | 58 | # Visual Studio profiler 59 | *.psess 60 | *.vsp 61 | *.vspx 62 | *.sap 63 | 64 | # Visual Studio 2015 cache/options directory 65 | .vs/ 66 | # Uncomment if you have tasks that create the project's static files in wwwroot 67 | #wwwroot/ 68 | 69 | # MSTest test Results 70 | [Tt]est[Rr]esult*/ 71 | [Bb]uild[Ll]og.* 72 | 73 | # NUNIT 74 | *.VisualState.xml 75 | TestResult.xml 76 | 77 | # Build Results of an ATL Project 78 | [Dd]ebugPS/ 79 | [Rr]eleasePS/ 80 | dlldata.c 81 | -------------------------------------------------------------------------------- /src/timecodes.c: -------------------------------------------------------------------------------- 1 | #include "timecodes.h" 2 | 3 | int parse_timecodesv1(FILE* f, int total, udata* ud) 4 | { 5 | int start, end, n = 0; 6 | double t = 0.0, basefps = 0.0, fps; 7 | char l[BUFSIZ]; 8 | int64_t* ts = calloc(total, sizeof(int64_t)); 9 | 10 | if (!ts) 11 | return 0; 12 | 13 | while ((fgets(l, BUFSIZ - 1, f) != NULL) && n < total) { 14 | if (l[0] == 0 || l[0] == '\n' || l[0] == '\r' || l[0] == '#') 15 | continue; 16 | 17 | if (sscanf(l, "Assume %lf", &basefps) == 1) 18 | continue; 19 | 20 | if (!(sscanf(l, "%d,%d,%lf", &start, &end, &fps) == 3)) 21 | continue; 22 | 23 | if (basefps == 0.0) 24 | continue; 25 | 26 | while (n < start && n < total) { 27 | ts[n++] = (int64_t)(t + 0.5); 28 | t += 1000.0 / basefps; 29 | } 30 | 31 | while (n <= end && n < total) { 32 | ts[n++] = (int64_t)(t + 0.5); 33 | t += 1000.0 / fps; 34 | } 35 | } 36 | 37 | if (basefps == 0.0) { 38 | free(ts); 39 | return 0; 40 | } 41 | 42 | while (n < total) { 43 | ts[n++] = (int64_t)(t + 0.5); 44 | t += 1000.0 / basefps; 45 | } 46 | 47 | ud->timestamp = ts; 48 | 49 | return 1; 50 | } 51 | 52 | int parse_timecodesv2(FILE* f, int total, udata* ud) 53 | { 54 | int n = 0; 55 | int64_t* ts = calloc(total, sizeof(int64_t)); 56 | char l[BUFSIZ]; 57 | 58 | if (!ts) { 59 | return 0; 60 | } 61 | 62 | while ((fgets(l, BUFSIZ - 1, f) != NULL) && n < total) { 63 | if (l[0] == 0 || l[0] == '\n' || l[0] == '\r' || l[0] == '#') 64 | continue; 65 | 66 | ts[n++] = atoll(l); 67 | } 68 | 69 | if (n < total) { 70 | free(ts); 71 | return 0; 72 | } 73 | 74 | ud->timestamp = ts; 75 | 76 | return 1; 77 | } 78 | -------------------------------------------------------------------------------- /src/assrender.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASSRENDER_H_ 2 | #define _ASSRENDER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "VapourSynth.h" 13 | 14 | #if defined(_MSC_VER) 15 | #define __NO_ISOCEXT 16 | #define __NO_INLINE__ 17 | 18 | #define strcasecmp _stricmp 19 | #define atoll _atoi64 20 | #endif 21 | 22 | typedef struct { 23 | // premultiplied coefficients for integer scaled arithmetics 24 | int y_r, y_g, y_b; 25 | int u_r, u_g, u_b; 26 | int v_r, v_g, v_b; 27 | int offset_y; 28 | bool valid; 29 | } ConversionMatrix; 30 | 31 | typedef enum { 32 | MATRIX_NONE = 0, 33 | MATRIX_BT601, 34 | MATRIX_PC601, 35 | MATRIX_BT709, 36 | MATRIX_PC709, 37 | MATRIX_PC2020, 38 | MATRIX_BT2020, 39 | MATRIX_TVFCC, 40 | MATRIX_PCFCC, 41 | MATRIX_TV240M, 42 | MATRIX_PC240M 43 | } matrix_type; 44 | 45 | typedef void (* fPixel)(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 46 | typedef void (* fMakeSubImg)(ASS_Image* img, uint8_t** sub_img, uint32_t width, int bits_per_pixel, int rgb, ConversionMatrix* m); 47 | 48 | void col2yuv(uint32_t* c, uint8_t* y, uint8_t* u, uint8_t* v, ConversionMatrix* m); 49 | void col2rgb(uint32_t* c, uint8_t* r, uint8_t* g, uint8_t* b); 50 | 51 | typedef struct { 52 | uint8_t* sub_img[4]; 53 | uint32_t isvfr; 54 | ASS_Track* ass; 55 | ASS_Library* ass_library; 56 | ASS_Renderer* ass_renderer; 57 | int64_t* timestamp; 58 | ConversionMatrix mx; 59 | fPixel apply; 60 | fMakeSubImg f_make_sub_img; 61 | int bits_per_pixel; 62 | int pixelsize; 63 | int rgb_fullscale; 64 | int greyscale; 65 | } udata; 66 | typedef struct { 67 | VSNodeRef* node; 68 | const VSVideoInfo* vi; 69 | char* prop; 70 | void* user_data; 71 | } VS_FilterInfo; 72 | 73 | #define ASSRENDER_VERSION "0.38.3" 74 | #endif 75 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | # build-linux: 7 | # runs-on: ubuntu-20.04 8 | # steps: 9 | # - uses: actions/checkout@v2 10 | # - name: install deps 11 | # run: | 12 | # sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential g++ gcc libass-dev pkg-config 13 | # - name: build 14 | # run: | 15 | # cmake -B build -S . 16 | # cmake --build build --clean-first 17 | 18 | build-macos: 19 | runs-on: macos-13 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: install deps 23 | run: | 24 | brew install cmake libass 25 | - name: build 26 | run: | 27 | cmake -B build -S . 28 | cmake --build build --clean-first 29 | 30 | # build-mingw: 31 | # runs-on: windows-2019 32 | # defaults: 33 | # run: 34 | # shell: msys2 {0} 35 | # steps: 36 | # - uses: actions/checkout@v2 37 | # - uses: msys2/setup-msys2@v2 38 | # with: 39 | # update: true 40 | # install: base-devel git mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-libass 41 | # msystem: MINGW64 42 | # path-type: inherit 43 | # - name: build 44 | # run: | 45 | # cmake -G "MSYS Makefiles" -B build -S . 46 | # cmake --build build --clean-first 47 | 48 | # build-win: 49 | # runs-on: windows-2019 50 | # strategy: 51 | # matrix: 52 | # include: 53 | # - target: 'x86' 54 | # platform: 'Win32' 55 | # - target: 'x64' 56 | # platform: 'x64' 57 | # steps: 58 | # - uses: actions/checkout@v2 59 | # - name: install submodules and nasm 60 | # shell: cmd 61 | # run: | 62 | # git submodule update --init --recursive --remote 63 | # git clone https://github.com/ShiftMediaProject/VSNASM.git --branch 0.9 64 | # .\VSNASM\install_script.bat 65 | # - name: force /MT build 66 | # shell: bash 67 | # run: | 68 | # sed -i -e 's||&MultiThreaded|g' SMP/*/SMP/*.vcxproj 69 | # sed -i -e 's||&MultiThreaded|g' assrender.vcxproj 70 | # - name: add msbuild to PATH 71 | # uses: microsoft/setup-msbuild@v1 72 | # - name: build 73 | # run: MSBuild.exe /t:Rebuild /p:WindowsTargetPlatformVersion=10.0.19041.0 /p:PlatformToolset=v142 /m /p:Configuration=Release /p:Platform=${{matrix.target}} 74 | # - name: copy 75 | # run: cmake -E copy "bin\Release_${{matrix.platform}}\assrender.dll" dist\${{matrix.target}}\assrender.dll 76 | # - name: upload 77 | # uses: actions/upload-artifact@v2 78 | # with: 79 | # name: assrender_bin 80 | # path: dist 81 | -------------------------------------------------------------------------------- /src/render.h: -------------------------------------------------------------------------------- 1 | #ifndef _RENDER_H_ 2 | #define _RENDER_H_ 3 | 4 | #include "assrender.h" 5 | 6 | #define _r(c) (( (c) >> 24)) 7 | #define _g(c) ((((c) >> 16) & 0xFF)) 8 | #define _b(c) ((((c) >> 8) & 0xFF)) 9 | #define _a(c) (( (c) & 0xFF)) 10 | 11 | #define div256(x) (((x + 128) >> 8)) 12 | #define div65536(x) (((x + 32768) >> 16)) 13 | #define div255(x) ((div256(x + div256(x)))) 14 | #define div65535(x) ((div65536(x + div65536(x)))) 15 | 16 | #define blend(srcA, srcC, dstC) \ 17 | ((div255(srcA * srcC + (255 - srcA) * dstC))) 18 | #define blend2(src1A, src1C, src2A, src2C, dstC) \ 19 | ((div255(((src1A * src1C + src2A * src2C + (510 - src1A - src2A) * dstC + 1) >> 1)))) 20 | #define blend4(src1A, src1C, src2A, src2C, src3A, src3C, src4A, src4C, dstC) \ 21 | ((div255(((src1A * src1C + src2A * src2C + src3A * src3C + src4A * src4C + (1020 - src1A - src2A - src3A - src4A) * dstC + 2) >> 2)))) 22 | #define scale(srcA, srcC, dstC) \ 23 | ((srcA * srcC + (255 - srcA) * dstC)) 24 | #define dblend(srcA, srcC, dstA, dstC, outA) \ 25 | (((srcA * srcC * 255 + dstA * dstC * (255 - srcA) + (outA >> 1)) / outA)) 26 | 27 | void FillMatrix(ConversionMatrix* matrix, matrix_type mt); 28 | 29 | void make_sub_img(ASS_Image* img, uint8_t** sub_img, uint32_t width, int bits_per_pixel, int rgb, ConversionMatrix *mx); 30 | void make_sub_img16(ASS_Image* img, uint8_t** sub_img, uint32_t width, int bits_per_pixel, int rgb, ConversionMatrix* mx); 31 | 32 | void apply_rgba(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 33 | void apply_rgb(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 34 | void apply_rgb48(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 35 | void apply_rgb64(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 36 | void apply_yuy2(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 37 | void apply_yv12(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 38 | void apply_yv16(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 39 | void apply_yv24(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 40 | void apply_y8(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 41 | void apply_yuv420(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 42 | void apply_yuv422(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 43 | void apply_yuv444(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 44 | void apply_y(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 45 | void apply_yv411(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height); 46 | 47 | const VSFrameRef* VS_CC assrender_get_frame_vs(int n, int activationReason, void** instanceData, void** frameData, VSFrameContext* frameCtx, VSCore* core, const VSAPI* vsapi); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/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 | # define AVSC_EXPORT __declspec(dllexport) 98 | # define AVSC_API(ret, name) EXTERN_C AVSC_EXPORT ret AVSC_CC name 99 | #else 100 | # define AVSC_EXPORT EXTERN_C 101 | # define AVSC_API(ret, name) EXTERN_C ret AVSC_CC name 102 | #endif 103 | #else 104 | # define AVSC_EXPORT EXTERN_C __declspec(dllexport) 105 | # ifndef AVSC_NO_DECLSPEC 106 | # define AVSC_API(ret, name) EXTERN_C __declspec(dllimport) ret AVSC_CC name 107 | # else 108 | # define AVSC_API(ret, name) typedef ret (AVSC_CC *name##_func) 109 | # endif 110 | #endif 111 | 112 | #endif //AVS_CAPI_H 113 | -------------------------------------------------------------------------------- /src/sub.c: -------------------------------------------------------------------------------- 1 | #include "sub.h" 2 | 3 | void ass_read_matrix(FILE* fh, char* csp) { 4 | if (!fh) 5 | return; 6 | 7 | char buf[BUFSIZ]; 8 | 9 | while (fgets(buf, BUFSIZ - 1, fh) != NULL) { 10 | if (buf[0] == 0 || buf[0] == '\n' || buf[0] == '\r') 11 | continue; 12 | 13 | if (sscanf(buf, "YCbCr Matrix: %s", csp) == 1) 14 | break; 15 | 16 | if (sscanf(buf, "Video Colorspace: %s", csp) == 1) 17 | break; 18 | 19 | if (!strcmp(buf, "[Events]")) 20 | break; 21 | } 22 | 23 | fclose(fh); 24 | } 25 | 26 | ASS_Track* parse_srt(FILE* fh, udata* ud, const char* srt_font) 27 | { 28 | if (!fh) 29 | return NULL; 30 | 31 | char l[BUFSIZ], buf[BUFSIZ]; 32 | int start[4], end[4], isn; 33 | ASS_Track* ass = ass_new_track(ud->ass_library); 34 | 35 | sprintf(buf, "[V4+ Styles]\nStyle: Default,%s,20,&H1EFFFFFF,&H00FFFFFF," 36 | "&H29000000,&H3C000000,0,0,0,0,100,100,0,0,1,1,1.2,2,10,10," 37 | "12,1\n\n[Events]\n", 38 | srt_font); 39 | 40 | ass_process_data(ass, buf, BUFSIZ - 1); 41 | 42 | while (fgets(l, BUFSIZ - 1, fh) != NULL) { 43 | if (l[0] == 0 || l[0] == '\n' || l[0] == '\r') 44 | continue; 45 | 46 | if (sscanf(l, "%d:%d:%d,%d --> %d:%d:%d,%d", &start[0], &start[1], 47 | &start[2], &start[3], &end[0], &end[1], &end[2], 48 | &end[3]) == 8) { 49 | sprintf(buf, "Dialogue: 0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d," 50 | "Default,,0,0,0,,{\\blur0.7}", 51 | start[0], start[1], start[2], 52 | (int)((double)start[3] / 10.0 + 0.5), end[0], end[1], 53 | end[2], (int)((double)end[3] / 10.0 + 0.5)); 54 | isn = 0; 55 | 56 | while (fgets(l, BUFSIZ - 1, fh) != NULL) { 57 | if (l[0] == 0 || l[0] == '\n' || l[0] == '\r') 58 | break; 59 | 60 | if (l[strlen(l) - 1] == '\n' || l[strlen(l) - 1] == '\r') 61 | l[strlen(l) - 1] = 0; 62 | 63 | if (isn) { 64 | strcat(buf, "\\N"); 65 | } 66 | 67 | strncat(buf, l, BUFSIZ - 1); 68 | isn = 1; 69 | } 70 | 71 | ass_process_data(ass, buf, BUFSIZ - 1); 72 | } 73 | } 74 | 75 | fclose(fh); 76 | 77 | return ass; 78 | } 79 | 80 | void msg_callback(int level, const char* fmt, va_list va, void* data) 81 | { 82 | if (level > (intptr_t)data) 83 | return; 84 | 85 | fprintf(stderr, "libass: "); 86 | vfprintf(stderr, fmt, va); 87 | fprintf(stderr, "\n"); 88 | } 89 | 90 | int init_ass(int w, int h, double scale, double line_spacing, ASS_Hinting hinting, 91 | int frame_width, int frame_height, double dar, double sar, int set_default_storage_size, 92 | int top, int bottom, int left, int right, int verbosity, 93 | const char* fontdir, udata* ud) 94 | { 95 | ASS_Renderer* ass_renderer; 96 | ASS_Library* ass_library = ass_library_init(); 97 | 98 | if (!ass_library) 99 | return 0; 100 | 101 | ass_set_message_cb(ass_library, msg_callback, (void*)(intptr_t)verbosity); 102 | ass_set_extract_fonts(ass_library, 0); 103 | ass_set_style_overrides(ass_library, 0); 104 | 105 | ass_renderer = ass_renderer_init(ass_library); 106 | 107 | if (!ass_renderer) 108 | return 0; 109 | 110 | ass_set_font_scale(ass_renderer, scale); 111 | ass_set_hinting(ass_renderer, hinting); 112 | ass_set_margins(ass_renderer, top, bottom, left, right); 113 | ass_set_use_margins(ass_renderer, 1); 114 | 115 | if (line_spacing) 116 | ass_set_line_spacing(ass_renderer, line_spacing); 117 | 118 | if (frame_width && frame_height) { 119 | ass_set_frame_size(ass_renderer, frame_width, frame_height); 120 | ass_set_storage_size(ass_renderer, w, h); 121 | } 122 | else if (dar && sar) { 123 | ass_set_frame_size(ass_renderer, w, h); 124 | ass_set_pixel_aspect(ass_renderer, dar / sar); 125 | } 126 | else { 127 | ass_set_frame_size(ass_renderer, w, h); 128 | if (set_default_storage_size) { 129 | ass_set_storage_size(ass_renderer, w, h); 130 | } 131 | } 132 | 133 | if (strcmp(fontdir, "")) 134 | ass_set_fonts_dir(ass_library, fontdir); 135 | 136 | ass_set_fonts(ass_renderer, NULL, NULL, 1, NULL, 1); 137 | ud->ass_library = ass_library; 138 | ud->ass_renderer = ass_renderer; 139 | 140 | return 1; 141 | } 142 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push] 4 | 5 | env: 6 | fc_ver: 2.17.1 7 | ft_ver: 2-13-3 8 | hb_ver: 11.4.3 9 | fb_ver: 1.0.16 10 | ass_ver: 0.17.4 11 | 12 | jobs: 13 | build: 14 | strategy: 15 | matrix: 16 | env: 17 | - os: windows-latest 18 | identifier: win 19 | # - os: macos-latest 20 | # identifier: osx 21 | - os: ubuntu-latest 22 | identifier: linux 23 | arch: ['x64'] # 'arm64' 24 | 25 | name: build-${{ matrix.env.os }}-${{ matrix.arch }} 26 | runs-on: ${{ matrix.env.os }} 27 | 28 | steps: 29 | - uses: actions/checkout@v4 30 | 31 | - name: install deps (ubuntu) 32 | if: matrix.env.os == 'ubuntu-latest' 33 | run: | 34 | sudo apt-get update && sudo apt-get install -y ninja-build nasm 35 | sudo python3 -m pip install --upgrade meson 36 | git clone https://gitlab.freedesktop.org/fontconfig/fontconfig.git -b ${{ env.fc_ver }} --depth=1 fontconfig-${{ env.fc_ver }} 37 | git clone --recurse-submodules https://github.com/freetype/freetype.git -b VER-${{ env.ft_ver }} --depth=1 freetype-${{ env.ft_ver }} 38 | git clone --recurse-submodules https://github.com/harfbuzz/harfbuzz.git -b ${{ env.hb_ver }} --depth=1 harfbuzz-${{ env.hb_ver }} 39 | git clone https://github.com/fribidi/fribidi.git -b v${{ env.fb_ver }} --depth=1 fribidi-${{ env.fb_ver }} 40 | git clone https://github.com/libass/libass.git -b ${{ env.ass_ver }} --depth=1 libass-${{ env.ass_ver }} 41 | 42 | - name: set msbuild (windows) 43 | if: matrix.env.os == 'windows-latest' 44 | uses: ilammy/msvc-dev-cmd@v1 45 | 46 | - name: install deps and set env (windows) 47 | if: matrix.env.os == 'windows-latest' 48 | run: | 49 | choco install ninja nasm pkgconfiglite 50 | python -m pip install --upgrade pip 51 | pip install meson 52 | $env:PKG_CONFIG_PATH = "C:/lib/pkgconfig" 53 | Add-Content -Path $env:GITHUB_ENV -Value "PKG_CONFIG_PATH=$env:PKG_CONFIG_PATH" 54 | # Get-ChildItem env: 55 | git clone https://github.com/libass/libass.git -b ${{ env.ass_ver }} --depth=1 libass-${{ env.ass_ver }} 56 | 57 | - name: build freetype (ubuntu) 58 | if: matrix.env.os == 'ubuntu-latest' 59 | run: | 60 | cd freetype-${{ env.ft_ver }} 61 | meson --default-library=static -Dharfbuzz=disabled -Dbrotli=disabled -Dpng=disabled -Dzlib=disabled build 62 | meson compile -C build 63 | sudo meson install -C build 64 | 65 | - name: build fontconfig (ubuntu) 66 | if: matrix.env.os == 'ubuntu-latest' 67 | run: | 68 | cd fontconfig-${{ env.fc_ver }} 69 | meson --default-library=static -Ddoc=disabled -Dtests=disabled -Dcache-build=disabled build 70 | ninja -C build 71 | sudo ninja -C build install 72 | 73 | - name: build harbuzz (ubuntu) 74 | if: matrix.env.os == 'ubuntu-latest' 75 | run: | 76 | cd harfbuzz-${{ env.hb_ver }} 77 | meson --default-library=static -Dtests=disabled -Dintrospection=disabled -Ddocs=disabled build 78 | meson compile -C build 79 | sudo meson install -C build 80 | 81 | - name: build fribidi (ubuntu) 82 | if: matrix.env.os == 'ubuntu-latest' 83 | run: | 84 | cd fribidi-${{ env.fb_ver }} 85 | meson --default-library=static -Ddocs=false -Dtests=false --backend=ninja build 86 | ninja -C build 87 | sudo ninja -C build install 88 | 89 | - name: build libass (ubuntu) 90 | if: matrix.env.os == 'ubuntu-latest' 91 | run: | 92 | cd ./libass-${{ env.ass_ver }} 93 | ./autogen.sh 94 | CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --disable-shared 95 | make -j2 96 | sudo make install 97 | 98 | - name: build libass (windows) 99 | if: matrix.env.os == 'windows-latest' 100 | run: | 101 | cd ./libass-${{ env.ass_ver }} 102 | meson wrap update-db 103 | meson wrap install fribidi 104 | # meson wrap install fontconfig 105 | meson wrap install freetype2 106 | meson wrap install expat 107 | meson wrap install harfbuzz 108 | meson wrap install libpng 109 | meson wrap install zlib 110 | 111 | meson -Ddefault_library=static -Dbuildtype=release -Dasm=enabled -Db_vscrt=static_from_buildtype -Dc_std=c11 -Dcpp_std=c++17 build 112 | meson compile -C build 113 | meson install -C build 114 | 115 | - name: build (ubuntu) 116 | if: matrix.env.os == 'ubuntu-latest' 117 | run: | 118 | cmake -B build -S . 119 | cmake --build build --clean-first 120 | 121 | - name: build (windows) 122 | if: matrix.env.os == 'windows-latest' 123 | run: | 124 | cmake -B build -S . -D CMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded 125 | cd build 126 | msbuild /t:Rebuild /m /p:Configuration=Release /p:Platform=${{ matrix.arch }} .\assrender.sln 127 | 128 | - name: set short version 129 | shell: bash 130 | run: | 131 | ver_short=`git rev-parse --short HEAD` 132 | echo "VERSION=$ver_short" >> $GITHUB_ENV 133 | 134 | - name: upload 135 | uses: actions/upload-artifact@v4 136 | with: 137 | name: assrender_${{ matrix.env.identifier }}-${{ matrix.arch }}_${{ env.VERSION }} 138 | path: | 139 | build/src/libassrender.so 140 | build/src/Release/assrender.dll -------------------------------------------------------------------------------- /src/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 | #else 61 | # error Unsupported CPU architecture. 62 | #endif 63 | 64 | // VC++ LLVM-Clang-cl MinGW-Gnu 65 | // MSVC x x 66 | // MSVC_PURE x 67 | // CLANG x 68 | // GCC x 69 | 70 | #if defined(__clang__) 71 | // Check clang first. clang-cl also defines __MSC_VER 72 | // We set MSVC because they are mostly compatible 73 | # define CLANG 74 | #if defined(_MSC_VER) 75 | # define MSVC 76 | # define AVS_FORCEINLINE __attribute__((always_inline)) 77 | #else 78 | # define AVS_FORCEINLINE __attribute__((always_inline)) inline 79 | #endif 80 | #elif defined(_MSC_VER) 81 | # define MSVC 82 | # define MSVC_PURE 83 | # define AVS_FORCEINLINE __forceinline 84 | #elif defined(__GNUC__) 85 | # define GCC 86 | # define AVS_FORCEINLINE __attribute__((always_inline)) inline 87 | #else 88 | # error Unsupported compiler. 89 | # define AVS_FORCEINLINE inline 90 | # undef __forceinline 91 | # define __forceinline inline 92 | #endif 93 | 94 | #if defined(_WIN32) 95 | # define AVS_WINDOWS 96 | #elif defined(__linux__) 97 | # define AVS_LINUX 98 | # define AVS_POSIX 99 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 100 | # define AVS_BSD 101 | # define AVS_POSIX 102 | #elif defined(__APPLE__) 103 | # define AVS_MACOS 104 | # define AVS_POSIX 105 | #elif defined(__HAIKU__) 106 | # define AVS_HAIKU 107 | # define AVS_POSIX 108 | #else 109 | # error Operating system unsupported. 110 | #endif 111 | 112 | // useful warnings disabler macros for supported compilers 113 | 114 | #if defined(_MSC_VER) 115 | #define DISABLE_WARNING_PUSH __pragma(warning( push )) 116 | #define DISABLE_WARNING_POP __pragma(warning( pop )) 117 | #define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber )) 118 | 119 | #define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE DISABLE_WARNING(4101) 120 | #define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(4505) 121 | // other warnings you want to deactivate... 122 | 123 | #elif defined(__GNUC__) || defined(__clang__) 124 | #define DO_PRAGMA(X) _Pragma(#X) 125 | #define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push) 126 | #define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop) 127 | #define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName) 128 | 129 | #define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE DISABLE_WARNING(-Wunused-variable) 130 | #define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(-Wunused-function) 131 | // other warnings you want to deactivate... 132 | 133 | #else 134 | #define DISABLE_WARNING_PUSH 135 | #define DISABLE_WARNING_POP 136 | #define DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE 137 | #define DISABLE_WARNING_UNREFERENCED_FUNCTION 138 | // other warnings you want to deactivate... 139 | 140 | #endif 141 | 142 | #if defined(AVS_POSIX) 143 | #define NEW_AVSVALUE 144 | #else 145 | #define NEW_AVSVALUE 146 | #endif 147 | 148 | #if defined(AVS_WINDOWS) 149 | // Windows XP does not have proper initialization for 150 | // thread local variables. 151 | // Use workaround instead __declspec(thread) 152 | #define XP_TLS 153 | #endif 154 | 155 | #endif //AVS_CONFIG_H 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AssRender-Vapoursynth 2 | 3 | AssRender-Vapoursynth is a Vapoursynth api3 plugin that renders ASS / SSA and SRT (without the HTML-like markup) subtitles, based on the source of pinterf’s fork. It uses libass to render the subtitles, which makes it the fastest, lower memory usage and most correct ASS renderer for Vapoursynth. Now (version >= 0.37.1) it also provides csri interface, you can use it with some support softwares, such as Aegisub. 4 | 5 | This also means that it is much more picky about script syntax than VSFilter and friends, so keep that in mind before blaming the filter. Yes, people have reported a lot of errors that were actually the script author’s fault. 6 | 7 | ## Vapoursynth Usage 8 | 9 | Supported video formats: 10 | - 8-, 10-, 12-, 14- and 16-bit integer 11 | - YUV, RGB, GRAY 12 | 13 | ### TextSub 14 | 15 | `assrender.TextSub(clip clip, string file, [string vfr, int hinting=0, float scale=1.0, float line_spacing=1.0, float dar, float sar, bool set_default_storage_size=True, int top=0, int bottom=0, int left=0, int right=0, string charset, int debuglevel, string fontdir="", string srt_font="sans-serif", string colorspace])` 16 | 17 | Like `sub.TextFile`, `xyvsf.TextSub` 18 | 19 | - `clip`: Input video clip. 20 | 21 | - `file`: Your subtitle file. May be ASS, SSA or SRT (without the HTML-like markup). 22 | 23 | - `vfr`: Specify timecodes v1 or v2 file when working with VFRaC. 24 | 25 | - `hinting`: Font hinting mode. Choose between none (0, default), light (1), normal (2) and Freetype native (3) autohinting. 26 | 27 | - `scale`: Font scale. Defaults to 1.0. 28 | 29 | - `line_spacing`: Line spacing in pixels. Defaults to 1.0 and won’t be scaled with frame size. 30 | 31 | - `frame_width`, `frame_height`: Actual displayed size, provide more information than `dar`&`sar`. Of course you need to set both parameters. 32 | 33 | - `dar`, `sar`: Aspect ratio, less priority than `frame_width`&`frame_height`. You need to set both parameters, too. 34 | 35 | - `set_default_storage_size`: Whether to render ASS according to storage size, default is True. It’s behavior is consistent with the latest libass, but it maybe show some incorrect display effects, you can see *[Fix rendering with libass to match xy-VSFilter](https://github.com/wangqr/Aegisub/pull/134)* for details. 36 | 37 | - `top`, `bottom`, `left`, `right`: Margins. They will be added to the frame size and may be negative. 38 | 39 | - `charset`: Character set to use, in GNU iconv or enca format. Defaults to detect the BOM and fallback to UTF-8 if BOM not found. Example enca format: `enca:pl:cp1250` (guess the encoding for Polish, fall back on `cp1250`) 40 | 41 | - `debuglevel`: How much crap assrender is supposed to spam to stderr. 42 | 43 | - `fontdir`: Additional font directory. Useful if you are lazy but want to keep your system fonts clean. Default value: `""` 44 | 45 | - `srt_font`: Font to use for SRT subtitles. Defaults to whatever Fontconfig chooses for “sans-serif”. 46 | 47 | - `colorspace`: The color space of your (YUV) video. Possible values: 48 | - Rec2020, BT.2020 49 | - Rec709, BT.709 50 | - Rec601, BT.601 51 | - PC.709 52 | - PC.601 53 | - TV.fcc, PC.fcc 54 | - TV.240m, PC.240m 55 | - none, guess 56 | 57 | Default is to use the ASS script’s `YCbCr Matrix` or `Video Colorspace` property. 58 | 59 | Recognized .ASS properties: `TV.601`, `TV.709`, `PC.601`, `PC.709`, `TV.240m`, `PC.240m` `TV.fcc`, `PC.fcc` and `none`. 60 | 61 | `none` and `guess` decides upon on video resolution: width > 1280 or height > 576 → `BT.709`, else → `BT.601`. 62 | When no hint found in ASS script and `colorspace` parameter is empty then the default is `BT.601`. 63 | 64 | ### Subtitle 65 | 66 | `assrender.Subtitle(clip clip, string[] text, [string style="sans-serif,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,0,7,10,10,10,1", int[] start, int[] end, string vfr, int hinting=0, float scale=1.0, float line_spacing=1.0, float dar, float sar, bool set_default_storage_size=True, int top=0, int bottom=0, int left=0, int right=0, string charset, int debuglevel, string fontdir="", string srt_font="sans-serif", string colorspace])` 67 | 68 | Like `sub.Subtitle`, it can render single line or multiline subtile string instead of a subtitle file. 69 | 70 | - `clip`: Input video clip. 71 | 72 | - `text`: String to be rendered, it will rendering multiline string if input a list. These can include ASS Tags. 73 | 74 | - `style`: `text` used ASS style 75 | 76 | - `start`, `end`: Subtitle display time, start frame number and end frame’s next frame number, it will trim like `[start:end]`, default is all frames of clip. 77 | - If you input list, each pair of `start` and `end` matches a `text`, and the missing `start` and `end` will be filled with the last one. 78 | - You must specify both the value of `start` and `end` if use these, otherwise it will be discarded. 79 | - If you dont’t render multiline subtitles, `std.Loop` maybe faster. 80 | 81 | Other parameters are same as `assrender.TextSub`, but not necessarily useful, such as `srt_font`. 82 | 83 | ### FrameProp 84 | 85 | `assrender.FrameProp(clip clip, [string prop="ass", string style="sans-serif,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,0,7,10,10,10,1", string vfr, int hinting=0, float scale=1.0, float line_spacing=1.0, float dar, float sar, bool set_default_storage_size=True, int top=0, int bottom=0, int left=0, int right=0, string charset, int debuglevel, string fontdir="", string srt_font="sans-serif", string colorspace])` 86 | 87 | `FrameProp` behaves like `Subtitle`, except that the ASS event for a frame comes from the given frame property `prop`, which defaults to `"ass"`. As each frame specifies its own event, there is no need to provide explicit `start`/`end` times like `Subtitle`. 88 | 89 | For example, the following code shows the current frame number at the top left corner of each frame for clip c: 90 | ```python 91 | c.akarin.Text("FrameNum {N}", prop="ass").assrender.FrameProp() 92 | ``` 93 | 94 | ## Csri 95 | 96 | It have two csri render names: `assrender_textsub` and `assrender_ob_textsub`. `ob` means old behavior, their differences can be referred to description of `set_default_storage_size` in vapoursynth usage. 97 | 98 | ## Build instructions 99 | 100 | see `.github/workflows/build.yml` 101 | 102 | ## Licenses 103 | For all modules: see msvc/licenses 104 | 105 | ## Links 106 | * Doom9 forum: https://forum.doom9.org/showthread.php?t=148926 107 | * Avisynth wiki: http://avisynth.nl/index.php/AssRender 108 | * libass original: https://github.com/libass/libass 109 | 110 | ## Change log 111 | See https://github.com/AmusementClub/assrender/releases 112 | -------------------------------------------------------------------------------- /src/csriapi.c: -------------------------------------------------------------------------------- 1 | #include "assrender.h" 2 | #include "render.h" 3 | #include "sub.h" 4 | 5 | #if defined(_WIN32) 6 | # define CSRIAPI __declspec(dllexport) 7 | #elif defined(__GNUC__) && __GNUC__ >= 4 8 | # define CSRIAPI __attribute__((visibility("default"))) 9 | #else 10 | # define CSRIAPI 11 | #endif 12 | #define CSRI_OWN_HANDLES 13 | typedef enum { 14 | assrender, 15 | assrender_ob 16 | } csri_rend; 17 | typedef struct { 18 | udata *ud; 19 | int64_t width, height; 20 | bool frame_requested; 21 | bool set_default_storage_size; 22 | } csri_inst; 23 | 24 | #include "csri.h" 25 | 26 | static csri_rend csri_assrender = assrender; 27 | static csri_rend csri_assrender_ob = assrender_ob; 28 | 29 | CSRIAPI csri_inst *csri_open_file(csri_rend *renderer, const char *filename, struct csri_openflag *flags) 30 | { 31 | csri_inst *inst = malloc(sizeof(csri_inst)); 32 | memset(inst, 0, sizeof(csri_inst)); 33 | inst->ud = malloc(sizeof(udata)); 34 | memset(inst->ud, 0, sizeof(udata)); 35 | 36 | inst->set_default_storage_size = *renderer != csri_assrender_ob; 37 | 38 | if (init_ass(0, 0, 1.0, 0, ASS_HINTING_NONE, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, "", inst->ud)) { 39 | ASS_Track *ass = ass_read_file(inst->ud->ass_library, (char *)filename, (char *)"utf-8"); 40 | if (ass) { 41 | inst->ud->ass = ass; 42 | 43 | inst->ud->f_make_sub_img = make_sub_img; 44 | 45 | return inst; 46 | } 47 | } 48 | csri_close(inst); 49 | return NULL; 50 | } 51 | 52 | 53 | CSRIAPI csri_inst *csri_open_mem(csri_rend *renderer, const void *data, size_t length, struct csri_openflag *flags) 54 | { 55 | csri_inst *inst = malloc(sizeof(csri_inst)); 56 | memset(inst, 0, sizeof(csri_inst)); 57 | inst->ud = malloc(sizeof(udata)); 58 | memset(inst->ud, 0, sizeof(udata)); 59 | 60 | inst->set_default_storage_size = *renderer != csri_assrender_ob; 61 | 62 | if (init_ass(0, 0, 1.0, 0, ASS_HINTING_NONE, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, "", inst->ud)) { 63 | ASS_Track *ass = ass_read_memory(inst->ud->ass_library, (char *)data, length, (char *)"utf-8"); 64 | if (ass) { 65 | inst->ud->ass = ass; 66 | 67 | inst->ud->f_make_sub_img = make_sub_img; 68 | 69 | return inst; 70 | } 71 | } 72 | csri_close(inst); 73 | return NULL; 74 | } 75 | 76 | 77 | CSRIAPI void csri_close(csri_inst *inst) 78 | { 79 | if (!inst) return; 80 | 81 | udata *ud = inst->ud; 82 | 83 | ass_renderer_done(ud->ass_renderer); 84 | ass_library_done(ud->ass_library); 85 | ass_free_track(ud->ass); 86 | 87 | if (inst->frame_requested) { 88 | for (int i = 0; i < 4; ++i) { 89 | free(ud->sub_img[i]); 90 | } 91 | } 92 | 93 | if (ud->isvfr) 94 | free(ud->timestamp); 95 | 96 | free(ud); 97 | free(inst); 98 | } 99 | 100 | 101 | CSRIAPI int csri_request_fmt(csri_inst *inst, const struct csri_fmt *fmt) 102 | { 103 | if (!inst) return -1; 104 | 105 | if (!fmt->width || !fmt->height) 106 | return -1; 107 | 108 | switch (fmt->pixfmt) { 109 | case CSRI_F_BGR_: 110 | inst->ud->apply = apply_rgba; 111 | break; 112 | default: 113 | return -1; 114 | } 115 | 116 | if (inst->frame_requested && (inst->width != fmt->width || inst->height != fmt->height)) { 117 | for (int i = 0; i < 4; ++i) { 118 | free(inst->ud->sub_img[i]); 119 | } 120 | inst->frame_requested = false; 121 | } 122 | 123 | inst->width = fmt->width; 124 | inst->height = fmt->height; 125 | 126 | FillMatrix(&inst->ud->mx, MATRIX_NONE); 127 | 128 | ass_set_frame_size(inst->ud->ass_renderer, inst->width, inst->height); 129 | if (inst->set_default_storage_size) 130 | ass_set_storage_size(inst->ud->ass_renderer, inst->width, inst->height); 131 | 132 | const int bits_per_pixel = 8; 133 | const int pixelsize = 32; 134 | const int rgb_fullscale = false; 135 | const int greyscale = false; 136 | 137 | const int buffersize = inst->width * inst->height * pixelsize; 138 | 139 | if (!inst->frame_requested) { 140 | for (int i = 0; i < 4; ++i) { 141 | inst->ud->sub_img[i] = malloc(buffersize); 142 | } 143 | inst->frame_requested = true; 144 | } 145 | 146 | inst->ud->bits_per_pixel = bits_per_pixel; 147 | inst->ud->pixelsize = pixelsize; 148 | inst->ud->rgb_fullscale = rgb_fullscale; 149 | inst->ud->greyscale = greyscale; 150 | 151 | return 0; 152 | } 153 | 154 | 155 | CSRIAPI void csri_render(csri_inst *inst, struct csri_frame *frame, double time) 156 | { 157 | int changed; 158 | long long ts = time * 1000; 159 | ASS_Image *img = ass_render_frame(inst->ud->ass_renderer, inst->ud->ass, ts, &changed); 160 | 161 | if (img) { 162 | uint32_t height, width, pitch[2]; 163 | uint8_t *data[3]; 164 | 165 | switch (frame->pixfmt) { 166 | case CSRI_F_BGR_: 167 | data[0] = frame->planes[0]; 168 | pitch[0] = frame->strides[0]; 169 | break; 170 | default: 171 | return; 172 | } 173 | 174 | height = inst->height; 175 | width = inst->width; 176 | 177 | if (changed) { 178 | memset(inst->ud->sub_img[0], 0x00, height * width * inst->ud->pixelsize); 179 | inst->ud->f_make_sub_img(img, inst->ud->sub_img, width, inst->ud->bits_per_pixel, inst->ud->rgb_fullscale, &inst->ud->mx); 180 | } 181 | 182 | inst->ud->apply(inst->ud->sub_img, data, pitch, width, height); 183 | } 184 | } 185 | 186 | 187 | // No extensions supported 188 | CSRIAPI void *csri_query_ext(csri_rend *rend, csri_ext_id extname) 189 | { 190 | return 0; 191 | } 192 | 193 | // Get info for renderer 194 | static struct csri_info csri_assrender_info = { 195 | #ifdef _DEBUG 196 | .name = "assrender_textsub_debug", // name 197 | .specific = ASSRENDER_VERSION, // version (assumed version number, svn revision, patchlevel) 198 | #else 199 | .name = "assrender_textsub", // name 200 | .specific = ASSRENDER_VERSION, // version (assumed version number, svn revision, patchlevel) 201 | #endif 202 | .longname = "assrender/TextSub (pingplug & pinterf & Masaiki)", // longname 203 | .author = "pingplug", // author 204 | .copyright = "Copyright (c) 2012-2015 by pingplug, 2021 by pinterf, 2021-2022 by Masaiki" // copyright 205 | }; 206 | static struct csri_info csri_assrender_ob_info = { 207 | #ifdef _DEBUG 208 | .name = "assrender_ob_textsub_debug", // name 209 | .specific = ASSRENDER_VERSION, // version (assumed version number, svn revision, patchlevel) 210 | #else 211 | .name = "assrender_ob_textsub", // name 212 | .specific = ASSRENDER_VERSION, // version (assumed version number, svn revision, patchlevel) 213 | #endif 214 | .longname = "assrender/TextSub (pingplug & pinterf & Masaiki)", // longname 215 | .author = "pingplug", // author 216 | .copyright = "Copyright (c) 2012-2015 by pingplug, 2021 by pinterf, 2021-2022 by Masaiki" // copyright 217 | }; 218 | CSRIAPI struct csri_info *csri_renderer_info(csri_rend *rend) 219 | { 220 | switch (*rend) 221 | { 222 | case assrender: 223 | return &csri_assrender_info; 224 | case assrender_ob: 225 | return &csri_assrender_ob_info; 226 | default: 227 | return NULL; 228 | } 229 | } 230 | CSRIAPI csri_rend *csri_renderer_byname(const char *name, const char *specific) 231 | { 232 | if (strcmp(name, csri_assrender_info.name) == 0 && (!specific || strcmp(specific, csri_assrender_info.specific) == 0)) 233 | return &csri_assrender; 234 | if (strcmp(name, csri_assrender_ob_info.name) == 0 && (!specific || strcmp(specific, csri_assrender_ob_info.specific) == 0)) 235 | return &csri_assrender_ob; 236 | return NULL; 237 | } 238 | CSRIAPI csri_rend *csri_renderer_default() 239 | { 240 | return &csri_assrender; 241 | } 242 | CSRIAPI csri_rend *csri_renderer_next(csri_rend *prev) 243 | { 244 | if (*prev == csri_assrender) { 245 | return &csri_assrender_ob; 246 | } 247 | return NULL; 248 | } 249 | 250 | -------------------------------------------------------------------------------- /src/csri.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * csri: common subtitle renderer interface 3 | ***************************************************************************** 4 | * Copyright (C) 2007 David Lamparter 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * - The name of the author may not be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 29 | ****************************************************************************/ 30 | 31 | /** \file csri.h - main CSRI (common subtitle renderer interface) include. 32 | * $Id: csri.h 45 2007-06-20 01:00:40Z equinox $ */ 33 | 34 | #ifndef _CSRI_H 35 | /** \cond */ 36 | #define _CSRI_H 20070119 37 | /** \endcond */ 38 | 39 | #include /* ptrdiff_t */ 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | #ifndef CSRIAPI 46 | /** CSRI API attributes. 47 | * defaults to \c extern. 48 | */ 49 | #define CSRIAPI extern 50 | #endif 51 | 52 | /** \defgroup base CSRI base API. */ 53 | /*@{*/ 54 | 55 | /** pixel format specification for frames */ 56 | enum csri_pixfmt { 57 | CSRI_F_RGBA = 0, 58 | CSRI_F_ARGB, 59 | CSRI_F_BGRA, 60 | CSRI_F_ABGR, 61 | 62 | CSRI_F_RGB_ = 0x100, 63 | CSRI_F__RGB, 64 | CSRI_F_BGR_, /**< Windows "RGB32" */ 65 | CSRI_F__BGR, 66 | 67 | CSRI_F_RGB = 0x200, 68 | CSRI_F_BGR, /**< Windows "RGB24" */ 69 | 70 | CSRI_F_AYUV = 0x1000, 71 | CSRI_F_YUVA, 72 | CSRI_F_YVUA, 73 | 74 | CSRI_F_YUY2 = 0x1100, 75 | 76 | CSRI_F_YV12A = 0x2011, /**< planar YUV 2x2 + alpha plane */ 77 | CSRI_F_YV12 = 0x2111 /**< planar YUV 2x2 */ 78 | }; 79 | 80 | #define csri_is_rgb(x) ((x) < 0x1000) 81 | #define csri_is_yuv(x) ((x) >= 0x1000) 82 | #define csri_is_yuv_planar(x) ((x) >= 0x2000) 83 | #define csri_get_yuv_planar_xred(x) (0xf & (x)) 84 | #define csri_get_yuv_planar_yred(x) (0xf & ((x) >> 4)) 85 | #define csri_is_yuv_packed(x) ((x) >= 0x1000 && (x) < 0x2000) 86 | #define csri_has_alpha(x) (((x) & 0xfff) < 0x100) 87 | 88 | /** frame/image format specification pre-fed to the renderer */ 89 | struct csri_fmt { 90 | /** format to be used */ 91 | enum csri_pixfmt pixfmt; 92 | /** image width, full frame. 93 | * 94 | * This should specify the full size of the frame. 95 | * Specifying the video sub-size (in case of added black 96 | * borders) is left to an extension. 97 | */ 98 | unsigned width; 99 | /** image height */ 100 | unsigned height; 101 | }; 102 | 103 | /** single frame to be fed to the renderer. */ 104 | struct csri_frame { 105 | /** frame format. 106 | * It is an application bug if this differs from the one 107 | * passed in struct #csri_fmt to csri_query_fmt() 108 | */ 109 | enum csri_pixfmt pixfmt; 110 | /** the frame's data. 111 | * Packed formats only use planes[0]; planar formats 112 | * have the data ordered as Y, U, V[, A]. 113 | * 114 | * Also note that the topmost line always comes first. 115 | * The Windows biHeight strange-ity is \a NOT duplicated. 116 | */ 117 | unsigned char *planes[4]; 118 | /** strides for the individual planes. 119 | * Stride means full byte offset, i.e. do \a not add 120 | * frame width 121 | */ 122 | ptrdiff_t strides[4]; 123 | }; 124 | 125 | #ifndef CSRI_OWN_HANDLES 126 | /** opaque renderer data */ 127 | typedef void csri_rend; 128 | /** opaque instance data */ 129 | typedef void csri_inst; 130 | #endif 131 | 132 | #ifdef DOXYGEN 133 | /** disable the emission of the csri_rend and csri_inst typedefs. 134 | * define this if you are in a renderer and are typedef'ing 135 | * csri_rend and csri_inst to your own structs. 136 | */ 137 | #define CSRI_OWN_HANDLES 138 | #endif 139 | 140 | /** renderer description. 141 | * \ingroup loader 142 | */ 143 | struct csri_info { 144 | /** an identifier for the renderer. 145 | * - MUST match the regular expression 146 | * \code ^[a-zA-Z]([a-zA-Z0-9_]*[a-zA-Z0-9])? \endcode 147 | * i.e. consists only of letters, numbers and underscores; 148 | * must start with a letter and doesnt have an underscore 149 | * as the last character. 150 | */ 151 | const char *name; 152 | /** an identifier to the exact version of the renderer. 153 | * most likely a version number or revision identifier. 154 | * 155 | * The helper library does a strcmp over this field in order 156 | * to order multiple instances of the same renderer. Use 157 | * higher-byte-value strings for newer renderers. 158 | */ 159 | const char *specific; 160 | 161 | /** a nice name to be presented to the user */ 162 | const char *longname; 163 | /** the renderer's author */ 164 | const char *author; 165 | /** a copyright string. Copyright (c) 2042 by Mr. Nice Guy */ 166 | const char *copyright; 167 | }; 168 | 169 | /** data of extension-dependent type. 170 | * The field to be used MUST be specified in the extension where it is used. 171 | */ 172 | union csri_vardata { 173 | long lval; 174 | double dval; 175 | const char *utf8val; 176 | void *otherval; 177 | }; 178 | 179 | /** extension identifier. 180 | * This follows reverse DNS syntax, i.e.: 181 | * \code root.branch.leaf \endcode 182 | * you can either reverse a registered domain name, e.g. 183 | * \code com.microsoft.csri.usegdiplus \endcode 184 | * or ask the CSRI maintainers to assign a namespace to you. 185 | * 186 | * currently registered namespaces are: 187 | * 188 | * \code 189 | * csri.* - official extensions 190 | * asa.* - custom extensions of the asa renderer 191 | * \endcode 192 | */ 193 | typedef const char *csri_ext_id; 194 | 195 | /** script loading parameters. 196 | * each flag MUST have an associated extension, which can be queried 197 | * with csri_query_ext(). If the open flag constitutes an extension on its 198 | * sole own, csri_query_ext() can return a meaningless non-NULL value for 199 | * it. 200 | * 201 | * The data field used must be specified. 202 | * 203 | * An extension can have multiple flags. In that case, the flags should have 204 | * the extension name as common prefix, separated with a dot. 205 | * 206 | * A renderer MUST ignore unknown open flags. It MUST NOT return an error 207 | * just because it does not support a particular flag. 208 | */ 209 | struct csri_openflag { 210 | /** flag name */ 211 | csri_ext_id name; 212 | /** flag data argument */ 213 | union csri_vardata data; 214 | /** link to next flag */ 215 | struct csri_openflag *next; 216 | }; 217 | 218 | /** load a script from a file. 219 | * \param renderer the handle to the renderer 220 | * \param filename the path to the file to be loaded. \n 221 | * The filename should be encoded as UTF-8. Windows renderers are 222 | * expected to convert it to UTF-16 and use the Unicode Windows API 223 | * functions. 224 | * \param flags a linked list of open flags. \n 225 | * The caller manages memory allocation, i.e. static allocation is OK. 226 | * \return the renderer instance handle, or NULL on error. 227 | */ 228 | CSRIAPI csri_inst *csri_open_file(csri_rend *renderer, 229 | const char *filename, struct csri_openflag *flags); 230 | 231 | /** load a script from memory. 232 | * \param renderer the handle to the renderer 233 | * \param data pointer to the first data byte. \n 234 | * The caller manages memory allocation and should free the data after 235 | * calling csri_open_mem(). If the renderer needs to keep the data, it 236 | * must copy it. \n 237 | * The renderer is not allowed to write to the data. 238 | * \param length length, in bytes, of the data 239 | * \param flags see csri_open_file() 240 | * \return the render instance handle, or NULL on error. 241 | */ 242 | 243 | CSRIAPI csri_inst *csri_open_mem(csri_rend *renderer, 244 | const void *data, size_t length, struct csri_openflag *flags); 245 | 246 | /** close a renderer instance. 247 | * \param inst the instance handle. 248 | */ 249 | CSRIAPI void csri_close(csri_inst *inst); 250 | 251 | 252 | /** query / set the image format and size. 253 | * \param inst the renderer instance handle 254 | * \param fmt the format and image size to be used 255 | * \return 0 if the format was successfully set, 256 | * any other value in case of error. 257 | */ 258 | CSRIAPI int csri_request_fmt(csri_inst *inst, const struct csri_fmt *fmt); 259 | 260 | /** render a single frame 261 | * \param inst the renderer instance handle 262 | * \param frame frame data to render to 263 | * \param time associated timestamp of the frame 264 | */ 265 | CSRIAPI void csri_render(csri_inst *inst, struct csri_frame *frame, 266 | double time); 267 | 268 | 269 | /** query for an extension. 270 | * \param rend the renderer handle 271 | * \param extname the extension's identifier 272 | * \return NULL if the extension is not supported, 273 | * a pointer to extension-specific data otherwise 274 | * 275 | * The data pointed to by the return value does not neccessarily need to 276 | * have any meaning; An extension that does not need to return data 277 | * can return a pointer to whatever it wants, as long as that pointer is 278 | * not NULL. 279 | * 280 | * In the usual case, the pointer is supposed to point to a struct with 281 | * function pointers and other information as needed. 282 | */ 283 | CSRIAPI void *csri_query_ext(csri_rend *rend, csri_ext_id extname); 284 | 285 | /*@}*/ 286 | 287 | /** \defgroup loader CSRI loader API. 288 | * 289 | * These functions locate renderers based on given parameters. 290 | * 291 | * Renderers must implement these functions as well. 292 | * 293 | * They are used by the library to grab renderer information 294 | * from a shared object; and also this way a single renderer 295 | * can be linked directly into an appliaction. 296 | */ 297 | /*@{*/ 298 | 299 | /** get renderer information 300 | * \param rend the renderer handle 301 | * \return information about the renderer, or NULL in case the renderer 302 | * encountered an internal error. 303 | */ 304 | CSRIAPI struct csri_info *csri_renderer_info(csri_rend *rend); 305 | 306 | /** try to load a given renderer 307 | * \param name the name of the renderer, as in csri_info.name 308 | * \param specific the specific version of the renderer, 309 | * as in csri_info.specific;\n 310 | * alternatively NULL if any version of the renderer is ok. 311 | * \return a handle to the renderer if it was successfully loaded, 312 | * NULL otherwise. 313 | */ 314 | CSRIAPI csri_rend *csri_renderer_byname(const char *name, 315 | const char *specific); 316 | 317 | /** try to find an implementation of the given extensions. 318 | * \param next number of extensions pointed to by ext 319 | * \param ext array of extensions to search for 320 | * \return a handle to a renderer supporting ALL of the 321 | * extensions, NULL if none was found. 322 | */ 323 | CSRIAPI csri_rend *csri_renderer_byext(unsigned n_ext, csri_ext_id *ext); 324 | 325 | /** get the default (highest priority) renderer 326 | * \return a handle to the default renderer, or NULL if 327 | * no renderer is installed. 328 | * 329 | * Together with csri_renderer_next(), this can be used 330 | * to enumerate all installed renderers. 331 | */ 332 | CSRIAPI csri_rend *csri_renderer_default(); 333 | 334 | /** get the next lower priority renderer 335 | * \param prev the current renderer 336 | * \return the renderer with the next lower priority than 337 | * the one named in prev, or NULL if prev is the last 338 | * renderer installed. 339 | */ 340 | CSRIAPI csri_rend *csri_renderer_next(csri_rend *prev); 341 | 342 | /*@}*/ 343 | 344 | #ifdef __cplusplus 345 | } 346 | #endif 347 | 348 | #endif /* _CSRI_H */ 349 | -------------------------------------------------------------------------------- /src/include/VapourSynth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2017 Fredrik Mellbin 3 | * 4 | * This file is part of VapourSynth. 5 | * 6 | * VapourSynth is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * VapourSynth is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with VapourSynth; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef VAPOURSYNTH_H 22 | #define VAPOURSYNTH_H 23 | 24 | #include 25 | 26 | #define VAPOURSYNTH_API_MAJOR 3 27 | #define VAPOURSYNTH_API_MINOR 6 28 | #define VAPOURSYNTH_API_VERSION ((VAPOURSYNTH_API_MAJOR << 16) | (VAPOURSYNTH_API_MINOR)) 29 | 30 | /* Convenience for C++ users. */ 31 | #ifdef __cplusplus 32 | # define VS_EXTERN_C extern "C" 33 | # if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) 34 | # define VS_NOEXCEPT noexcept 35 | # else 36 | # define VS_NOEXCEPT 37 | # endif 38 | #else 39 | # define VS_EXTERN_C 40 | # define VS_NOEXCEPT 41 | #endif 42 | 43 | #if defined(_WIN32) && !defined(_WIN64) 44 | # define VS_CC __stdcall 45 | #else 46 | # define VS_CC 47 | #endif 48 | 49 | /* And now for some symbol hide-and-seek... */ 50 | #if defined(_WIN32) /* Windows being special */ 51 | # define VS_EXTERNAL_API(ret) VS_EXTERN_C __declspec(dllexport) ret VS_CC 52 | #elif defined(__GNUC__) && __GNUC__ >= 4 53 | # define VS_EXTERNAL_API(ret) VS_EXTERN_C __attribute__((visibility("default"))) ret VS_CC 54 | #else 55 | # define VS_EXTERNAL_API(ret) VS_EXTERN_C ret VS_CC 56 | #endif 57 | 58 | #if !defined(VS_CORE_EXPORTS) && defined(_WIN32) 59 | # define VS_API(ret) VS_EXTERN_C __declspec(dllimport) ret VS_CC 60 | #else 61 | # define VS_API(ret) VS_EXTERNAL_API(ret) 62 | #endif 63 | 64 | typedef struct VSFrameRef VSFrameRef; 65 | typedef struct VSNodeRef VSNodeRef; 66 | typedef struct VSCore VSCore; 67 | typedef struct VSPlugin VSPlugin; 68 | typedef struct VSNode VSNode; 69 | typedef struct VSFuncRef VSFuncRef; 70 | typedef struct VSMap VSMap; 71 | typedef struct VSAPI VSAPI; 72 | typedef struct VSFrameContext VSFrameContext; 73 | 74 | typedef enum VSColorFamily { 75 | /* all planar formats */ 76 | cmGray = 1000000, 77 | cmRGB = 2000000, 78 | cmYUV = 3000000, 79 | cmYCoCg = 4000000, 80 | /* special for compatibility */ 81 | cmCompat = 9000000 82 | } VSColorFamily; 83 | 84 | typedef enum VSSampleType { 85 | stInteger = 0, 86 | stFloat = 1 87 | } VSSampleType; 88 | 89 | /* The +10 is so people won't be using the constants interchangably "by accident" */ 90 | typedef enum VSPresetFormat { 91 | pfNone = 0, 92 | 93 | pfGray8 = cmGray + 10, 94 | pfGray16, 95 | 96 | pfGrayH, 97 | pfGrayS, 98 | 99 | pfYUV420P8 = cmYUV + 10, 100 | pfYUV422P8, 101 | pfYUV444P8, 102 | pfYUV410P8, 103 | pfYUV411P8, 104 | pfYUV440P8, 105 | 106 | pfYUV420P9, 107 | pfYUV422P9, 108 | pfYUV444P9, 109 | 110 | pfYUV420P10, 111 | pfYUV422P10, 112 | pfYUV444P10, 113 | 114 | pfYUV420P16, 115 | pfYUV422P16, 116 | pfYUV444P16, 117 | 118 | pfYUV444PH, 119 | pfYUV444PS, 120 | 121 | pfYUV420P12, 122 | pfYUV422P12, 123 | pfYUV444P12, 124 | 125 | pfYUV420P14, 126 | pfYUV422P14, 127 | pfYUV444P14, 128 | 129 | pfRGB24 = cmRGB + 10, 130 | pfRGB27, 131 | pfRGB30, 132 | pfRGB48, 133 | 134 | pfRGBH, 135 | pfRGBS, 136 | 137 | /* special for compatibility, if you implement these in any filter I'll personally kill you */ 138 | /* I'll also change their ids around to break your stuff regularly */ 139 | pfCompatBGR32 = cmCompat + 10, 140 | pfCompatYUY2 141 | } VSPresetFormat; 142 | 143 | typedef enum VSFilterMode { 144 | fmParallel = 100, /* completely parallel execution */ 145 | fmParallelRequests = 200, /* for filters that are serial in nature but can request one or more frames they need in advance */ 146 | fmUnordered = 300, /* for filters that modify their internal state every request */ 147 | fmSerial = 400 /* for source filters and compatibility with other filtering architectures */ 148 | } VSFilterMode; 149 | 150 | typedef struct VSFormat { 151 | char name[32]; 152 | int id; 153 | int colorFamily; /* see VSColorFamily */ 154 | int sampleType; /* see VSSampleType */ 155 | int bitsPerSample; /* number of significant bits */ 156 | int bytesPerSample; /* actual storage is always in a power of 2 and the smallest possible that can fit the number of bits used per sample */ 157 | 158 | int subSamplingW; /* log2 subsampling factor, applied to second and third plane */ 159 | int subSamplingH; 160 | 161 | int numPlanes; /* implicit from colorFamily */ 162 | } VSFormat; 163 | 164 | typedef enum VSNodeFlags { 165 | nfNoCache = 1, 166 | nfIsCache = 2, 167 | nfMakeLinear = 4 /* api 3.3 */ 168 | } VSNodeFlags; 169 | 170 | typedef enum VSPropTypes { 171 | ptUnset = 'u', 172 | ptInt = 'i', 173 | ptFloat = 'f', 174 | ptData = 's', 175 | ptNode = 'c', 176 | ptFrame = 'v', 177 | ptFunction = 'm' 178 | } VSPropTypes; 179 | 180 | typedef enum VSGetPropErrors { 181 | peUnset = 1, 182 | peType = 2, 183 | peIndex = 4 184 | } VSGetPropErrors; 185 | 186 | typedef enum VSPropAppendMode { 187 | paReplace = 0, 188 | paAppend = 1, 189 | paTouch = 2 190 | } VSPropAppendMode; 191 | 192 | typedef struct VSCoreInfo { 193 | const char *versionString; 194 | int core; 195 | int api; 196 | int numThreads; 197 | int64_t maxFramebufferSize; 198 | int64_t usedFramebufferSize; 199 | } VSCoreInfo; 200 | 201 | typedef struct VSVideoInfo { 202 | const VSFormat *format; 203 | int64_t fpsNum; 204 | int64_t fpsDen; 205 | int width; 206 | int height; 207 | int numFrames; /* api 3.2 - no longer allowed to be 0 */ 208 | int flags; 209 | } VSVideoInfo; 210 | 211 | typedef enum VSActivationReason { 212 | arInitial = 0, 213 | arFrameReady = 1, 214 | arAllFramesReady = 2, 215 | arError = -1 216 | } VSActivationReason; 217 | 218 | typedef enum VSMessageType { 219 | mtDebug = 0, 220 | mtWarning = 1, 221 | mtCritical = 2, 222 | mtFatal = 3 223 | } VSMessageType; 224 | 225 | /* core entry point */ 226 | typedef const VSAPI *(VS_CC *VSGetVapourSynthAPI)(int version); 227 | 228 | /* plugin function and filter typedefs */ 229 | typedef void (VS_CC *VSPublicFunction)(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi); 230 | typedef void (VS_CC *VSRegisterFunction)(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin); 231 | typedef void (VS_CC *VSConfigPlugin)(const char *identifier, const char *defaultNamespace, const char *name, int apiVersion, int readonly, VSPlugin *plugin); 232 | typedef void (VS_CC *VSInitPlugin)(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin); 233 | typedef void (VS_CC *VSFreeFuncData)(void *userData); 234 | typedef void (VS_CC *VSFilterInit)(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi); 235 | typedef const VSFrameRef *(VS_CC *VSFilterGetFrame)(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi); 236 | typedef void (VS_CC *VSFilterFree)(void *instanceData, VSCore *core, const VSAPI *vsapi); 237 | 238 | /* other */ 239 | typedef void (VS_CC *VSFrameDoneCallback)(void *userData, const VSFrameRef *f, int n, VSNodeRef *, const char *errorMsg); 240 | typedef void (VS_CC *VSMessageHandler)(int msgType, const char *msg, void *userData); 241 | typedef void (VS_CC *VSMessageHandlerFree)(void *userData); 242 | 243 | struct VSAPI { 244 | VSCore *(VS_CC *createCore)(int threads) VS_NOEXCEPT; 245 | void (VS_CC *freeCore)(VSCore *core) VS_NOEXCEPT; 246 | const VSCoreInfo *(VS_CC *getCoreInfo)(VSCore *core) VS_NOEXCEPT; /* deprecated as of api 3.6, use getCoreInfo2 instead */ 247 | 248 | const VSFrameRef *(VS_CC *cloneFrameRef)(const VSFrameRef *f) VS_NOEXCEPT; 249 | VSNodeRef *(VS_CC *cloneNodeRef)(VSNodeRef *node) VS_NOEXCEPT; 250 | VSFuncRef *(VS_CC *cloneFuncRef)(VSFuncRef *f) VS_NOEXCEPT; 251 | 252 | void (VS_CC *freeFrame)(const VSFrameRef *f) VS_NOEXCEPT; 253 | void (VS_CC *freeNode)(VSNodeRef *node) VS_NOEXCEPT; 254 | void (VS_CC *freeFunc)(VSFuncRef *f) VS_NOEXCEPT; 255 | 256 | VSFrameRef *(VS_CC *newVideoFrame)(const VSFormat *format, int width, int height, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT; 257 | VSFrameRef *(VS_CC *copyFrame)(const VSFrameRef *f, VSCore *core) VS_NOEXCEPT; 258 | void (VS_CC *copyFrameProps)(const VSFrameRef *src, VSFrameRef *dst, VSCore *core) VS_NOEXCEPT; 259 | 260 | void (VS_CC *registerFunction)(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT; 261 | VSPlugin *(VS_CC *getPluginById)(const char *identifier, VSCore *core) VS_NOEXCEPT; 262 | VSPlugin *(VS_CC *getPluginByNs)(const char *ns, VSCore *core) VS_NOEXCEPT; 263 | VSMap *(VS_CC *getPlugins)(VSCore *core) VS_NOEXCEPT; 264 | VSMap *(VS_CC *getFunctions)(VSPlugin *plugin) VS_NOEXCEPT; 265 | void (VS_CC *createFilter)(const VSMap *in, VSMap *out, const char *name, VSFilterInit init, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, int flags, void *instanceData, VSCore *core) VS_NOEXCEPT; 266 | void (VS_CC *setError)(VSMap *map, const char *errorMessage) VS_NOEXCEPT; /* use to signal errors outside filter getframe functions */ 267 | const char *(VS_CC *getError)(const VSMap *map) VS_NOEXCEPT; /* use to query errors, returns 0 if no error */ 268 | void (VS_CC *setFilterError)(const char *errorMessage, VSFrameContext *frameCtx) VS_NOEXCEPT; /* use to signal errors in the filter getframe function */ 269 | VSMap *(VS_CC *invoke)(VSPlugin *plugin, const char *name, const VSMap *args) VS_NOEXCEPT; 270 | 271 | const VSFormat *(VS_CC *getFormatPreset)(int id, VSCore *core) VS_NOEXCEPT; 272 | const VSFormat *(VS_CC *registerFormat)(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT; 273 | 274 | const VSFrameRef *(VS_CC *getFrame)(int n, VSNodeRef *node, char *errorMsg, int bufSize) VS_NOEXCEPT; /* do never use inside a filter's getframe function, for external applications using the core as a library or for requesting frames in a filter constructor */ 275 | void (VS_CC *getFrameAsync)(int n, VSNodeRef *node, VSFrameDoneCallback callback, void *userData) VS_NOEXCEPT; /* do never use inside a filter's getframe function, for external applications using the core as a library or for requesting frames in a filter constructor */ 276 | const VSFrameRef *(VS_CC *getFrameFilter)(int n, VSNodeRef *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ 277 | void (VS_CC *requestFrameFilter)(int n, VSNodeRef *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ 278 | void (VS_CC *queryCompletedFrame)(VSNodeRef **node, int *n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ 279 | void (VS_CC *releaseFrameEarly)(VSNodeRef *node, int n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ 280 | 281 | int (VS_CC *getStride)(const VSFrameRef *f, int plane) VS_NOEXCEPT; 282 | const uint8_t *(VS_CC *getReadPtr)(const VSFrameRef *f, int plane) VS_NOEXCEPT; 283 | uint8_t *(VS_CC *getWritePtr)(VSFrameRef *f, int plane) VS_NOEXCEPT; 284 | 285 | VSFuncRef *(VS_CC *createFunc)(VSPublicFunction func, void *userData, VSFreeFuncData free, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT; 286 | void (VS_CC *callFunc)(VSFuncRef *func, const VSMap *in, VSMap *out, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT; /* core and vsapi arguments are completely ignored, they only remain to preserve ABI */ 287 | 288 | /* property access functions */ 289 | VSMap *(VS_CC *createMap)(void) VS_NOEXCEPT; 290 | void (VS_CC *freeMap)(VSMap *map) VS_NOEXCEPT; 291 | void (VS_CC *clearMap)(VSMap *map) VS_NOEXCEPT; 292 | 293 | const VSVideoInfo *(VS_CC *getVideoInfo)(VSNodeRef *node) VS_NOEXCEPT; 294 | void (VS_CC *setVideoInfo)(const VSVideoInfo *vi, int numOutputs, VSNode *node) VS_NOEXCEPT; 295 | const VSFormat *(VS_CC *getFrameFormat)(const VSFrameRef *f) VS_NOEXCEPT; 296 | int (VS_CC *getFrameWidth)(const VSFrameRef *f, int plane) VS_NOEXCEPT; 297 | int (VS_CC *getFrameHeight)(const VSFrameRef *f, int plane) VS_NOEXCEPT; 298 | const VSMap *(VS_CC *getFramePropsRO)(const VSFrameRef *f) VS_NOEXCEPT; 299 | VSMap *(VS_CC *getFramePropsRW)(VSFrameRef *f) VS_NOEXCEPT; 300 | 301 | int (VS_CC *propNumKeys)(const VSMap *map) VS_NOEXCEPT; 302 | const char *(VS_CC *propGetKey)(const VSMap *map, int index) VS_NOEXCEPT; 303 | int (VS_CC *propNumElements)(const VSMap *map, const char *key) VS_NOEXCEPT; 304 | char (VS_CC *propGetType)(const VSMap *map, const char *key) VS_NOEXCEPT; 305 | 306 | int64_t(VS_CC *propGetInt)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 307 | double(VS_CC *propGetFloat)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 308 | const char *(VS_CC *propGetData)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 309 | int (VS_CC *propGetDataSize)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 310 | VSNodeRef *(VS_CC *propGetNode)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 311 | const VSFrameRef *(VS_CC *propGetFrame)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 312 | VSFuncRef *(VS_CC *propGetFunc)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; 313 | 314 | int (VS_CC *propDeleteKey)(VSMap *map, const char *key) VS_NOEXCEPT; 315 | int (VS_CC *propSetInt)(VSMap *map, const char *key, int64_t i, int append) VS_NOEXCEPT; 316 | int (VS_CC *propSetFloat)(VSMap *map, const char *key, double d, int append) VS_NOEXCEPT; 317 | int (VS_CC *propSetData)(VSMap *map, const char *key, const char *data, int size, int append) VS_NOEXCEPT; 318 | int (VS_CC *propSetNode)(VSMap *map, const char *key, VSNodeRef *node, int append) VS_NOEXCEPT; 319 | int (VS_CC *propSetFrame)(VSMap *map, const char *key, const VSFrameRef *f, int append) VS_NOEXCEPT; 320 | int (VS_CC *propSetFunc)(VSMap *map, const char *key, VSFuncRef *func, int append) VS_NOEXCEPT; 321 | 322 | int64_t (VS_CC *setMaxCacheSize)(int64_t bytes, VSCore *core) VS_NOEXCEPT; 323 | int (VS_CC *getOutputIndex)(VSFrameContext *frameCtx) VS_NOEXCEPT; 324 | VSFrameRef *(VS_CC *newVideoFrame2)(const VSFormat *format, int width, int height, const VSFrameRef **planeSrc, const int *planes, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT; 325 | void (VS_CC *setMessageHandler)(VSMessageHandler handler, void *userData) VS_NOEXCEPT; /* deprecated as of api 3.6, use addMessageHandler and removeMessageHandler instead */ 326 | int (VS_CC *setThreadCount)(int threads, VSCore *core) VS_NOEXCEPT; 327 | 328 | const char *(VS_CC *getPluginPath)(const VSPlugin *plugin) VS_NOEXCEPT; 329 | 330 | /* api 3.1 */ 331 | const int64_t *(VS_CC *propGetIntArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT; 332 | const double *(VS_CC *propGetFloatArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT; 333 | 334 | int (VS_CC *propSetIntArray)(VSMap *map, const char *key, const int64_t *i, int size) VS_NOEXCEPT; 335 | int (VS_CC *propSetFloatArray)(VSMap *map, const char *key, const double *d, int size) VS_NOEXCEPT; 336 | 337 | /* api 3.4 */ 338 | void (VS_CC *logMessage)(int msgType, const char *msg) VS_NOEXCEPT; 339 | 340 | /* api 3.6 */ 341 | int (VS_CC *addMessageHandler)(VSMessageHandler handler, VSMessageHandlerFree free, void *userData) VS_NOEXCEPT; 342 | int (VS_CC *removeMessageHandler)(int id) VS_NOEXCEPT; 343 | void (VS_CC *getCoreInfo2)(VSCore *core, VSCoreInfo *info) VS_NOEXCEPT; 344 | }; 345 | 346 | VS_API(const VSAPI *) getVapourSynthAPI(int version) VS_NOEXCEPT; 347 | 348 | #endif /* VAPOURSYNTH_H */ 349 | -------------------------------------------------------------------------------- /src/assrender.c: -------------------------------------------------------------------------------- 1 | #include "assrender.h" 2 | #include "render.h" 3 | #include "sub.h" 4 | #include "timecodes.h" 5 | 6 | static char* read_file_bytes(FILE* fp, size_t* bufsize) 7 | { 8 | int res; 9 | long sz; 10 | long bytes_read; 11 | char* buf; 12 | res = fseek(fp, 0, SEEK_END); 13 | if (res == -1) { 14 | fclose(fp); 15 | return 0; 16 | } 17 | 18 | sz = ftell(fp); 19 | rewind(fp); 20 | 21 | buf = sz < SIZE_MAX ? malloc(sz + 1) : NULL; 22 | if (!buf) { 23 | fclose(fp); 24 | return NULL; 25 | } 26 | bytes_read = 0; 27 | do { 28 | res = fread(buf + bytes_read, 1, sz - bytes_read, fp); 29 | if (res <= 0) { 30 | fclose(fp); 31 | free(buf); 32 | return 0; 33 | } 34 | bytes_read += res; 35 | } while (sz - bytes_read > 0); 36 | buf[sz] = '\0'; 37 | fclose(fp); 38 | 39 | if (bufsize) 40 | *bufsize = sz; 41 | return buf; 42 | } 43 | 44 | static const char* detect_bom(const char* buf, const size_t bufsize) { 45 | if (bufsize >= 4) { 46 | if (!strncmp(buf, "\xef\xbb\xbf", 3)) 47 | return "UTF-8"; 48 | if (!strncmp(buf, "\x00\x00\xfe\xff", 4)) 49 | return "UTF-32BE"; 50 | if (!strncmp(buf, "\xff\xfe\x00\x00", 4)) 51 | return "UTF-32LE"; 52 | if (!strncmp(buf, "\xfe\xff", 2)) 53 | return "UTF-16BE"; 54 | if (!strncmp(buf, "\xff\xfe", 2)) 55 | return "UTF-16LE"; 56 | } 57 | return "UTF-8"; 58 | } 59 | 60 | #ifdef _WIN32 61 | #define WIN32_LEAN_AND_MEAN 62 | #include 63 | #else 64 | #include 65 | #endif 66 | 67 | #ifdef _WIN32 68 | static wchar_t *utf8_to_utf16le(const char *data) { 69 | const int out_size = MultiByteToWideChar(CP_UTF8, 0, data, -1, NULL, 0); 70 | wchar_t *out = malloc(out_size * sizeof(wchar_t)); 71 | MultiByteToWideChar(CP_UTF8, 0, data, -1, out, out_size); 72 | return out; 73 | } 74 | #endif 75 | 76 | bool file_exists(const char *path) { 77 | #ifdef _WIN32 78 | wchar_t *path_utf16le = utf8_to_utf16le(path); 79 | DWORD dwAttrib = GetFileAttributesW(path_utf16le); 80 | free(path_utf16le); 81 | return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); 82 | #else 83 | struct stat path_stat; 84 | if (stat(path, &path_stat) != 0) { 85 | return false; 86 | } 87 | return S_ISREG(path_stat.st_mode); 88 | #endif 89 | } 90 | 91 | static FILE* open_utf8_filename(const char* f, const char* m) 92 | { 93 | if (!file_exists(f)) return NULL; 94 | #ifdef _WIN32 95 | wchar_t* file_name = utf8_to_utf16le(f); 96 | wchar_t* mode = utf8_to_utf16le(m); 97 | FILE* fp = _wfopen(file_name, mode); 98 | free(file_name); 99 | free(mode); 100 | return fp; 101 | #else 102 | return fopen(f, m); 103 | #endif 104 | } 105 | 106 | static char* strrepl(const char* in, const char* str, const char* repl) 107 | { 108 | size_t siz; 109 | char* res, * outptr; 110 | const char* inptr; 111 | int count = 0; 112 | 113 | inptr = in; 114 | 115 | while ((inptr = strstr(inptr, str))) { 116 | count++; 117 | inptr++; 118 | } 119 | 120 | if (count == 0) { 121 | size_t in_len = strlen(in); 122 | res = malloc(in_len + 1); 123 | memcpy(res, in, in_len + 1); 124 | return res; 125 | } 126 | 127 | siz = (strlen(in) - strlen(str) * count + strlen(repl) * count) * 128 | sizeof(char) + 1; 129 | 130 | #define VSMAX(a,b) ((a) > (b) ? (a) : (b)) 131 | res = malloc(VSMAX(siz, strlen(in) * sizeof(char) + 1)); 132 | #undef VSMAX 133 | 134 | strcpy(res, in); 135 | 136 | outptr = res; 137 | inptr = in; 138 | 139 | while ((outptr = strstr(outptr, str)) && (inptr = strstr(inptr, str))) { 140 | outptr[0] = '\0'; 141 | strcat(outptr, repl); 142 | strcat(outptr, (inptr + strlen(str))); 143 | 144 | outptr++; 145 | inptr++; 146 | } 147 | 148 | return res; 149 | } 150 | static bool frameToTime(int frame, int64_t fpsNum, int64_t fpsDen, char* str, size_t str_size) 151 | { 152 | int64_t timeint, time_ms; 153 | time_t time_secs; 154 | struct tm* ti; 155 | if (frame != 0 && (INT64_MAX / fpsDen) < ((int64_t)frame * 100)) { 156 | //Overflow would occur 157 | return false; 158 | } 159 | else { 160 | timeint = (int64_t)frame * 100 * fpsDen / fpsNum; 161 | } 162 | time_secs = timeint / 100; 163 | time_ms = timeint % 100; 164 | ti = gmtime(&time_secs); 165 | snprintf(str, str_size, "%d:%02d:%02d.%02" PRIu64, ti->tm_hour, ti->tm_min, ti->tm_sec, time_ms); 166 | 167 | return true; 168 | } 169 | 170 | void VS_CC assrender_destroy_vs(void* instanceData, VSCore* core, const VSAPI* vsapi) { 171 | VS_FilterInfo* d = instanceData; 172 | udata* ud = d->user_data; 173 | 174 | ass_renderer_done(((udata*)ud)->ass_renderer); 175 | ass_library_done(((udata*)ud)->ass_library); 176 | ass_free_track(((udata*)ud)->ass); 177 | 178 | free(((udata*)ud)->sub_img[0]); 179 | free(((udata*)ud)->sub_img[1]); 180 | free(((udata*)ud)->sub_img[2]); 181 | free(((udata*)ud)->sub_img[3]); 182 | 183 | if (((udata*)ud)->isvfr) 184 | free(((udata*)ud)->timestamp); 185 | 186 | free(ud); 187 | free(d->prop); 188 | 189 | vsapi->freeNode(d->node); 190 | free(d); 191 | 192 | } 193 | void VS_CC assrender_init_vs(VSMap* in, VSMap* out, void** instanceData, VSNode* node, VSCore* core, const VSAPI* vsapi) { 194 | const VS_FilterInfo* d = *instanceData; 195 | vsapi->setVideoInfo(d->vi, 1, node); 196 | } 197 | void VS_CC assrender_create_vs(const VSMap* in, VSMap* out, void* userData, VSCore* core, const VSAPI* vsapi) { 198 | VS_FilterInfo* fi = malloc(sizeof(VS_FilterInfo)); 199 | fi->node = vsapi->propGetNode(in, "clip", 0, NULL); 200 | fi->vi = vsapi->getVideoInfo(fi->node); 201 | fi->prop = NULL; 202 | char e[256] = {0}; 203 | int err = 0; 204 | 205 | const char* vfr = vsapi->propGetData(in, "vfr", 0, &err); 206 | int h = vsapi->propGetInt(in, "hinting", 0, &err); 207 | double scale = vsapi->propGetFloat(in, "scale", 0, &err); 208 | if (err) scale = 1.0; 209 | double line_spacing = vsapi->propGetFloat(in, "line_spacing", 0, &err); 210 | int frame_width = vsapi->propGetInt(in, "frame_width", 0, &err); 211 | int frame_height = vsapi->propGetInt(in, "frame_height", 0, &err); 212 | double dar = vsapi->propGetFloat(in, "dar", 0, &err); 213 | double sar = vsapi->propGetFloat(in, "sar", 0, &err); 214 | int set_default_storage_size = vsapi->propGetInt(in, "set_default_storage_size", 0, &err); 215 | if (err) set_default_storage_size = 1; 216 | int top = vsapi->propGetInt(in, "top", 0, &err); 217 | int bottom = vsapi->propGetInt(in, "bottom", 0, &err); 218 | int left = vsapi->propGetInt(in, "left", 0, &err); 219 | int right = vsapi->propGetInt(in, "right", 0, &err); 220 | const char* cs = vsapi->propGetData(in, "charset", 0, &err); 221 | if (err) cs = NULL; 222 | int debuglevel = vsapi->propGetInt(in, "debuglevel", 0, &err); 223 | const char* fontdir = vsapi->propGetData(in, "fontdir", 0, &err); 224 | if (err) fontdir = ""; 225 | const char* srt_font = vsapi->propGetData(in, "srt_font", 0, &err); 226 | if (err) srt_font = "sans-serif"; 227 | const char* colorspace = vsapi->propGetData(in, "colorspace", 0, &err); 228 | if (err) colorspace = ""; 229 | 230 | char* tmpcsp = calloc(1, BUFSIZ); 231 | strncpy(tmpcsp, colorspace, BUFSIZ - 1); 232 | 233 | ASS_Hinting hinting; 234 | udata* data; 235 | ASS_Track* ass; 236 | 237 | /* 238 | no unsupported colorspace left, bitness is checked at other place 239 | if (0 == 1) { 240 | v = avs_new_value_error( 241 | "AssRender: unsupported colorspace"); 242 | avs_release_clip(c); 243 | return v; 244 | } 245 | */ 246 | 247 | switch (h) { 248 | case 0: 249 | hinting = ASS_HINTING_NONE; 250 | break; 251 | case 1: 252 | hinting = ASS_HINTING_LIGHT; 253 | break; 254 | case 2: 255 | hinting = ASS_HINTING_NORMAL; 256 | break; 257 | case 3: 258 | hinting = ASS_HINTING_NATIVE; 259 | break; 260 | default: 261 | vsapi->setError(out, "AssRender: invalid hinting mode"); 262 | return; 263 | } 264 | 265 | data = malloc(sizeof(udata)); 266 | 267 | if (!init_ass( 268 | fi->vi->width, fi->vi->height, scale, line_spacing, hinting, 269 | frame_width, frame_height, dar, sar, set_default_storage_size, 270 | top, bottom, left, right, debuglevel, 271 | fontdir, data) 272 | ) { 273 | vsapi->setError(out, "AssRender: failed to initialize"); 274 | return; 275 | } 276 | 277 | if (!strcmp(userData, "TextSub")) { 278 | const char* f = vsapi->propGetData(in, "file", 0, &err); 279 | if (!f) { 280 | vsapi->setError(out, "AssRender: no input file specified"); 281 | return; 282 | } 283 | if (!strcasecmp(strrchr(f, '.'), ".srt")) { 284 | FILE* fp = open_utf8_filename(f, "r"); 285 | if (!fp) { 286 | vsapi->setError(out, "AssRender: input file does not exist or is not a regular file"); 287 | return; 288 | } 289 | ass = parse_srt(fp, data, srt_font); 290 | } 291 | else { 292 | FILE* fp = open_utf8_filename(f, "rb"); 293 | if (!fp) { 294 | vsapi->setError(out, "AssRender: input file does not exist or is not a regular file"); 295 | return; 296 | } 297 | size_t bufsize; 298 | char* buf = read_file_bytes(fp, &bufsize); 299 | if (cs == NULL) cs = detect_bom(buf, bufsize); 300 | ass = ass_read_memory(data->ass_library, buf, bufsize, (char*)cs); 301 | fp = open_utf8_filename(f, "r"); 302 | ass_read_matrix(fp, tmpcsp); 303 | } 304 | } 305 | else if (!strcmp(userData, "Subtitle")){ 306 | #define BUFFER_SIZE 16 307 | int ntext = vsapi->propNumElements(in, "text"); 308 | if (ntext < 1) { 309 | vsapi->setError(out, "AssRender: No text to be rendered"); 310 | return; 311 | } 312 | 313 | char const ** const texts = malloc(ntext * sizeof(char *)); 314 | int *text_lengths = malloc(ntext * sizeof(int)); 315 | for (int i = 0; i < ntext; i++) { 316 | texts[i] = vsapi->propGetData(in, "text", i, &err); 317 | if (err) texts[i] = ""; 318 | texts[i] = strrepl(texts[i], "\n", "\\N"); 319 | text_lengths[i] = strlen(texts[i]); 320 | } 321 | 322 | const char *style = vsapi->propGetData(in, "style", 0, &err); 323 | if (err) style = "sans-serif,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,0,7,10,10,10,1"; 324 | 325 | int *startframes = malloc(ntext * sizeof(int)); 326 | int *endframes = malloc(ntext * sizeof(int)); 327 | int nstart = vsapi->propNumElements(in, "start"); 328 | int nend = vsapi->propNumElements(in, "end"); 329 | int nspan = nstart < nend ? nstart : nend; 330 | if (nspan < 1) { 331 | for (int i = 0; i < ntext; i++) 332 | startframes[i] = 0, endframes[i] = fi->vi->numFrames; 333 | } 334 | else { 335 | for (int i = 0; i < nspan; i++) { 336 | startframes[i] = vsapi->propGetInt(in, "start", i, &err); 337 | if (err) startframes[i] = 0; 338 | endframes[i] = vsapi->propGetInt(in, "end", i, &err); 339 | if (err) endframes[i] = fi->vi->numFrames; 340 | } 341 | for (int i = nspan; i < ntext; ++i) { 342 | startframes[i] = startframes[nspan - 1]; 343 | endframes[i] = endframes[nspan - 1]; 344 | } 345 | } 346 | 347 | int full_dialogues_length = 0; 348 | for (int i = 0; i < ntext; i++) { 349 | char start[BUFFER_SIZE] = { 0 }, end[BUFFER_SIZE] = { 0 }; 350 | if (!frameToTime(startframes[i], fi->vi->fpsNum, fi->vi->fpsDen, start, BUFFER_SIZE) || 351 | !frameToTime(endframes[i], fi->vi->fpsNum, fi->vi->fpsDen, end, BUFFER_SIZE)) { 352 | snprintf(e, 256, "AssRender: Unable to calculate %s time", start[0] ? "end" : "start"); 353 | goto clean; 354 | } 355 | int dialogue_space = 32 + strlen(start) + strlen(end) + text_lengths[i]; 356 | char *tmp = malloc(dialogue_space); 357 | snprintf(tmp, dialogue_space, "Dialogue: 0,%s,%s,Default,,0,0,0,,%s\n", start, end, texts[i]); 358 | free((void *)texts[i]); 359 | texts[i] = tmp; 360 | text_lengths[i] = dialogue_space - 1; 361 | full_dialogues_length += text_lengths[i]; 362 | } 363 | 364 | char x[BUFFER_SIZE], y[BUFFER_SIZE]; 365 | const char *fmt = "[Script Info]\n" 366 | "ScriptType: v4.00+\n" 367 | "PlayResX: %s\n" 368 | "PlayResY: %s\n" 369 | "[V4+ Styles]\n" 370 | "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n" 371 | "Style: Default,%s\n" 372 | "[Events]\n" 373 | "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n"; 374 | 375 | snprintf(x, BUFFER_SIZE, "%d", fi->vi->width); 376 | snprintf(y, BUFFER_SIZE, "%d", fi->vi->height); 377 | 378 | size_t siz = (412 + strlen(x) + strlen(y) + strlen(style) + full_dialogues_length) * sizeof(char); 379 | 380 | char *final_text = malloc(siz); 381 | snprintf(final_text, siz, fmt, x, y, style); 382 | 383 | int pos = strlen(final_text); 384 | for (int i = 0; i < ntext; i++) { 385 | memcpy(final_text + pos, texts[i], text_lengths[i]); 386 | pos += text_lengths[i]; 387 | } 388 | final_text[pos] = 0; 389 | 390 | ass = ass_read_memory(data->ass_library, final_text, pos, "UTF-8"); 391 | 392 | free(final_text); 393 | 394 | clean: 395 | free(startframes); 396 | free(endframes); 397 | free(text_lengths); 398 | for (int i = 0; i < ntext; i++) 399 | free((void *)texts[i]); 400 | free((void *)texts); 401 | 402 | if (*e) 403 | vsapi->setError(out, e); 404 | 405 | } else { // if (!strcmp(userData, "FrameProp")){ 406 | const char *prop = vsapi->propGetData(in, "prop", 0, &err); 407 | if (!prop) prop = "ass"; 408 | fi->prop = strdup(prop); 409 | 410 | const char *style = vsapi->propGetData(in, "style", 0, &err); 411 | if (err) style = "sans-serif,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,0,7,10,10,10,1"; 412 | 413 | char x[BUFFER_SIZE], y[BUFFER_SIZE]; 414 | const char *fmt = "[Script Info]\n" 415 | "ScriptType: v4.00+\n" 416 | "PlayResX: %s\n" 417 | "PlayResY: %s\n" 418 | "[V4+ Styles]\n" 419 | "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n" 420 | "Style: Default,%s\n" 421 | "[Events]\n" 422 | "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n"; 423 | 424 | snprintf(x, BUFFER_SIZE, "%d", fi->vi->width); 425 | snprintf(y, BUFFER_SIZE, "%d", fi->vi->height); 426 | 427 | size_t siz = (strlen(fmt) + strlen(x) + strlen(y) + strlen(style) + 1) * sizeof(char); 428 | 429 | char *final_text = malloc(siz); 430 | snprintf(final_text, siz, fmt, x, y, style); 431 | 432 | ass = ass_read_memory(data->ass_library, final_text, strlen(final_text), "UTF-8"); 433 | 434 | free(final_text); 435 | 436 | if (*e) 437 | vsapi->setError(out, e); 438 | 439 | #undef BUFFER_SIZE 440 | } 441 | 442 | if (!ass) { 443 | vsapi->setError(out, "AssRender: unable to parse ass text"); 444 | return; 445 | } 446 | 447 | data->ass = ass; 448 | 449 | if (vfr) { 450 | int ver; 451 | FILE* fh = open_utf8_filename(vfr, "r"); 452 | 453 | if (!fh) { 454 | snprintf(e, 256, "AssRender: could not read timecodes file '%s'", vfr); 455 | vsapi->setError(out, e); 456 | return; 457 | } 458 | 459 | data->isvfr = 1; 460 | 461 | if (fscanf(fh, "# timecode format v%d", &ver) != 1) { 462 | snprintf(e, 256, "AssRender: invalid timecodes file '%s'", vfr); 463 | vsapi->setError(out, e); 464 | return; 465 | } 466 | 467 | switch (ver) { 468 | case 1: 469 | 470 | if (!parse_timecodesv1(fh, fi->vi->numFrames, data)) { 471 | vsapi->setError(out, "AssRender: error parsing timecodes file"); 472 | return; 473 | } 474 | 475 | break; 476 | case 2: 477 | 478 | if (!parse_timecodesv2(fh, fi->vi->numFrames, data)) { 479 | vsapi->setError(out, "AssRender: timecodes file had less frames than expected"); 480 | return; 481 | } 482 | 483 | break; 484 | } 485 | 486 | fclose(fh); 487 | } 488 | else { 489 | data->isvfr = 0; 490 | } 491 | 492 | matrix_type color_mt; 493 | 494 | if (fi->vi->format->colorFamily == cmRGB) { 495 | color_mt = MATRIX_NONE; // no RGB->YUV conversion 496 | } 497 | else { 498 | // .ASS "YCbCr Matrix" valid values are 499 | // "none" "tv.601" "pc.601" "tv.709" "pc.709" "tv.240m" "pc.240m" "tv.fcc" "pc.fcc" 500 | if (!strcasecmp(tmpcsp, "bt.709") || !strcasecmp(tmpcsp, "rec709") || !strcasecmp(tmpcsp, "tv.709")) { 501 | color_mt = MATRIX_BT709; 502 | } 503 | else if (!strcasecmp(tmpcsp, "pc.709")) { 504 | color_mt = MATRIX_PC709; 505 | } 506 | else if (!strcasecmp(tmpcsp, "bt.601") || !strcasecmp(tmpcsp, "rec601") || !strcasecmp(tmpcsp, "tv.601")) { 507 | color_mt = MATRIX_BT601; 508 | } 509 | else if (!strcasecmp(tmpcsp, "pc.601")) { 510 | color_mt = MATRIX_PC601; 511 | } 512 | else if (!strcasecmp(tmpcsp, "tv.fcc")) { 513 | color_mt = MATRIX_TVFCC; 514 | } 515 | else if (!strcasecmp(tmpcsp, "pc.fcc")) { 516 | color_mt = MATRIX_PCFCC; 517 | } 518 | else if (!strcasecmp(tmpcsp, "tv.240m")) { 519 | color_mt = MATRIX_TV240M; 520 | } 521 | else if (!strcasecmp(tmpcsp, "pc.240m")) { 522 | color_mt = MATRIX_PC240M; 523 | } 524 | else if (!strcasecmp(tmpcsp, "bt.2020") || !strcasecmp(tmpcsp, "rec2020")) { 525 | color_mt = MATRIX_BT2020; 526 | } 527 | else if (!strcasecmp(tmpcsp, "none") || !strcasecmp(tmpcsp, "guess")) { 528 | /* not yet 529 | * Theoretically only for 10 and 12 bits: 530 | if (fi->vi.width > 1920 || fi->vi.height > 1080) 531 | color_mt = MATRIX_BT2020; 532 | else 533 | */ 534 | if (fi->vi->width > 1280 || fi->vi->height > 576) 535 | color_mt = MATRIX_PC709; 536 | else 537 | color_mt = MATRIX_PC601; 538 | } 539 | else { 540 | color_mt = MATRIX_BT601; 541 | } 542 | } 543 | 544 | FillMatrix(&data->mx, color_mt); 545 | 546 | const int bits_per_pixel = fi->vi->format->bitsPerSample; 547 | const int pixelsize = fi->vi->format->bytesPerSample; 548 | const int greyscale = fi->vi->format->colorFamily == cmGray; 549 | 550 | if (bits_per_pixel == 8) 551 | data->f_make_sub_img = make_sub_img; 552 | else if (bits_per_pixel <= 16) 553 | data->f_make_sub_img = make_sub_img16; 554 | else { 555 | vsapi->setError(out, "AssRender: unsupported bit depth: 32"); 556 | return; 557 | } 558 | 559 | 560 | switch (fi->vi->format->id) 561 | { 562 | case pfYUV420P8: 563 | data->apply = apply_yv12; 564 | break; 565 | case pfYUV420P10: 566 | case pfYUV420P12: 567 | case pfYUV420P14: 568 | case pfYUV420P16: 569 | data->apply = apply_yuv420; 570 | break; 571 | case pfYUV422P8: 572 | data->apply = apply_yv16; 573 | break; 574 | case pfYUV422P10: 575 | case pfYUV422P12: 576 | case pfYUV422P14: 577 | case pfYUV422P16: 578 | data->apply = apply_yuv422; 579 | break; 580 | case pfYUV444P8: 581 | case pfRGB24: 582 | data->apply = apply_yv24; 583 | break; 584 | case pfYUV444P10: 585 | case pfYUV444P12: 586 | case pfYUV444P14: 587 | case pfYUV444P16: 588 | case pfRGB48: 589 | data->apply = apply_yuv444; 590 | break; 591 | case pfGray8: 592 | data->apply = apply_y8; 593 | break; 594 | case pfGray16: 595 | data->apply = apply_y; 596 | break; 597 | default: 598 | vsapi->setError(out, "AssRender: unsupported pixel type"); 599 | return; 600 | } 601 | 602 | free(tmpcsp); 603 | 604 | const int buffersize = fi->vi->width * fi->vi->height * pixelsize; 605 | 606 | data->sub_img[0] = malloc(buffersize); 607 | data->sub_img[1] = malloc(buffersize); 608 | data->sub_img[2] = malloc(buffersize); 609 | data->sub_img[3] = malloc(buffersize); 610 | 611 | data->bits_per_pixel = bits_per_pixel; 612 | data->pixelsize = pixelsize; 613 | data->rgb_fullscale = fi->vi->format->colorFamily == cmRGB; 614 | data->greyscale = greyscale; 615 | 616 | fi->user_data = data; 617 | 618 | vsapi->createFilter(in, out, userData, assrender_init_vs, assrender_get_frame_vs, assrender_destroy_vs, fmParallelRequests, 0, fi, core); 619 | 620 | return; 621 | } 622 | #define COMMON_PARAMS \ 623 | "vfr:data:opt;" \ 624 | "hinting:int:opt;" \ 625 | "scale:float:opt;" \ 626 | "line_spacing:float:opt;" \ 627 | "frame_width:int:opt;" \ 628 | "frame_height:int:opt;" \ 629 | "dar:float:opt;" \ 630 | "sar:float:opt;" \ 631 | "set_default_storage_size:int:opt;" \ 632 | "top:int:opt;" \ 633 | "bottom:int:opt;" \ 634 | "left:int:opt;" \ 635 | "right:int:opt;" \ 636 | "charset:data:opt;" \ 637 | "debuglevel:int:opt;" \ 638 | "fontdir:data:opt;" \ 639 | "srt_font:data:opt;" \ 640 | "colorspace:data:opt;", 641 | void VS_CC VapourSynthPluginInit(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin* plugin) { 642 | configFunc("com.pinterf.assrender", "assrender", "AssRender", VAPOURSYNTH_API_VERSION, 1, plugin); 643 | registerFunc("TextSub", 644 | "clip:clip;" 645 | "file:data;" 646 | COMMON_PARAMS 647 | assrender_create_vs, "TextSub", plugin); 648 | registerFunc("Subtitle", 649 | "clip:clip;" 650 | "text:data[];" 651 | "style:data:opt;" 652 | "start:int[]:opt;" 653 | "end:int[]:opt;" 654 | COMMON_PARAMS 655 | assrender_create_vs, "Subtitle", plugin); 656 | registerFunc("FrameProp", 657 | "clip:clip;" 658 | "prop:data:opt;" 659 | "style:data:opt;" 660 | COMMON_PARAMS 661 | assrender_create_vs, "FrameProp", plugin); 662 | } -------------------------------------------------------------------------------- /src/render.c: -------------------------------------------------------------------------------- 1 | #include "render.h" 2 | 3 | // Kg is not parameter, calculated from Kr and Kb 4 | static void BuildMatrix(ConversionMatrix* matrix, double Kr, double Kb, int shift, int full_scale, int bits_per_pixel) 5 | { 6 | int Sy, Suv, Oy; 7 | 8 | // for 8-16 bits 9 | Oy = full_scale ? 0 : (16 << (bits_per_pixel - 8)); 10 | 11 | const int ymin = (full_scale ? 0 : 16) << (bits_per_pixel - 8); 12 | const int max_pixel_value = (1 << bits_per_pixel) - 1; 13 | const int ymax = full_scale ? max_pixel_value : (235 << (bits_per_pixel - 8)); 14 | Sy = ymax - ymin; 15 | 16 | const int cmin = full_scale ? 0 : (16 << (bits_per_pixel - 8)); 17 | const int cmax = full_scale ? max_pixel_value : (240 << (bits_per_pixel - 8)); 18 | Suv = (cmax - cmin) / 2; 19 | 20 | const double mulfac = (double)(1ULL << shift); // integer aritmetic precision scale 21 | 22 | const double Kg = 1. - Kr - Kb; 23 | 24 | const int Srgb = (1 << bits_per_pixel) - 1; 25 | matrix->y_b = (int)(Sy * Kb * mulfac / Srgb + 0.5); //B 26 | matrix->y_g = (int)(Sy * Kg * mulfac / Srgb + 0.5); //G 27 | matrix->y_r = (int)(Sy * Kr * mulfac / Srgb + 0.5); //R 28 | matrix->u_b = (int)(Suv * mulfac / Srgb + 0.5); 29 | matrix->u_g = (int)(Suv * Kg / (Kb - 1) * mulfac / Srgb + 0.5); 30 | matrix->u_r = (int)(Suv * Kr / (Kb - 1) * mulfac / Srgb + 0.5); 31 | matrix->v_b = (int)(Suv * Kb / (Kr - 1) * mulfac / Srgb + 0.5); 32 | matrix->v_g = (int)(Suv * Kg / (Kr - 1) * mulfac / Srgb + 0.5); 33 | matrix->v_r = (int)(Suv * mulfac / Srgb + 0.5); 34 | matrix->offset_y = Oy; 35 | matrix->valid = true; 36 | } 37 | 38 | void FillMatrix(ConversionMatrix* matrix, matrix_type mt) 39 | { 40 | const int bits_per_pixel = 8; 41 | const int bitshift = 16; // for integer arithmetic 42 | matrix->valid = true; 43 | 44 | switch (mt) { 45 | case MATRIX_NONE: 46 | matrix->valid = false; 47 | break; 48 | case MATRIX_BT601: 49 | BuildMatrix(matrix, 0.299, /* 0.587 */ 0.114, bitshift, false, bits_per_pixel); // false: limited range 50 | break; 51 | case MATRIX_PC601: 52 | BuildMatrix(matrix, 0.299, /* 0.587 */ 0.114, bitshift, true, bits_per_pixel); // true: full scale 53 | break; 54 | case MATRIX_BT709: 55 | BuildMatrix(matrix, 0.2126, /* 0.7152 */ 0.0722, bitshift, false, bits_per_pixel); // false: limited range 56 | break; 57 | case MATRIX_PC709: 58 | BuildMatrix(matrix, 0.2126, /* 0.7152 */ 0.0722, bitshift, true, bits_per_pixel); // true: full scale 59 | break; 60 | case MATRIX_BT2020: 61 | BuildMatrix(matrix, 0.2627, /* 0.6780 */ 0.0593, bitshift, false, bits_per_pixel); // false: limited range 62 | break; 63 | case MATRIX_PC2020: 64 | BuildMatrix(matrix, 0.2627, /* 0.6780 */ 0.0593, bitshift, true, bits_per_pixel); // true: full scale 65 | break; 66 | case MATRIX_TVFCC: 67 | BuildMatrix(matrix, 0.300, /* 0.590 */ 0.110, bitshift, false, bits_per_pixel); // false: limited range 68 | break; 69 | case MATRIX_PCFCC: 70 | BuildMatrix(matrix, 0.300, /* 0.590 */ 0.110, bitshift, true, bits_per_pixel); // true: full scale 71 | break; 72 | case MATRIX_TV240M: 73 | BuildMatrix(matrix, 0.212, /* 0.701 */ 0.087, bitshift, false, bits_per_pixel); // false: limited range 74 | break; 75 | case MATRIX_PC240M: 76 | BuildMatrix(matrix, 0.212, /* 0.701 */ 0.087, bitshift, true, bits_per_pixel); // true: full scale 77 | break; 78 | default: 79 | matrix->valid = false; 80 | } 81 | } 82 | 83 | inline void col2rgb(uint32_t* c, uint8_t* r, uint8_t* g, uint8_t* b) 84 | { 85 | *r = _r(*c); 86 | *g = _g(*c); 87 | *b = _b(*c); 88 | } 89 | 90 | inline void col2yuv(uint32_t* c, uint8_t* y, uint8_t* u, uint8_t* v, ConversionMatrix* m) 91 | { 92 | *y = div65536(m->y_r * _r(*c) + m->y_g * _g(*c) + m->y_b * _b(*c)) + m->offset_y; 93 | *u = div65536(m->u_r * _r(*c) + m->u_g * _g(*c) + m->u_b * _b(*c)) + 128; 94 | *v = div65536(m->v_r * _r(*c) + m->v_g * _g(*c) + m->v_b * _b(*c)) + 128; 95 | } 96 | 97 | void make_sub_img(ASS_Image* img, uint8_t** sub_img, uint32_t width, int bits_per_pixel, int rgb, ConversionMatrix* mx) 98 | { 99 | uint8_t c1, c2, c3, a, a1; 100 | uint8_t* src; 101 | uint8_t* dstC1, * dstC2, * dstC3, * dstA; 102 | uint32_t dsta; 103 | 104 | while (img) { 105 | if (img->w == 0 || img->h == 0) { 106 | // nothing to render 107 | img = img->next; 108 | continue; 109 | } 110 | 111 | // color comes always in 8 bits 112 | if(mx->valid) 113 | col2yuv(&img->color, &c1, &c2, &c3, mx); 114 | else 115 | col2rgb(&img->color, &c1, &c2, &c3); 116 | a1 = 255 - _a(img->color); // transparency 117 | 118 | src = img->bitmap; 119 | dstC1 = sub_img[1] + img->dst_y * width + img->dst_x; 120 | dstC2 = sub_img[2] + img->dst_y * width + img->dst_x; 121 | dstC3 = sub_img[3] + img->dst_y * width + img->dst_x; 122 | dstA = sub_img[0] + img->dst_y * width + img->dst_x; 123 | 124 | for (int i = 0; i < img->h; i++) { 125 | for (int j = 0; j < img->w; j++) { 126 | a = div255(src[j] * a1); 127 | if (a) { 128 | if (dstA[j]) { 129 | dsta = scale(a, 255, dstA[j]); 130 | dstC1[j] = dblend(a, c1, dstA[j], dstC1[j], dsta); 131 | dstC2[j] = dblend(a, c2, dstA[j], dstC2[j], dsta); 132 | dstC3[j] = dblend(a, c3, dstA[j], dstC3[j], dsta); 133 | dstA[j] = div255(dsta); 134 | } else { 135 | dstC1[j] = c1; 136 | dstC2[j] = c2; 137 | dstC3[j] = c3; 138 | dstA[j] = a; 139 | } 140 | } 141 | } 142 | 143 | src += img->stride; 144 | dstC1 += width; 145 | dstC2 += width; 146 | dstC3 += width; 147 | dstA += width; 148 | } 149 | 150 | img = img->next; 151 | } 152 | } 153 | 154 | void make_sub_img16(ASS_Image* img, uint8_t** sub_img0, uint32_t width, int bits_per_pixel, int rgb, ConversionMatrix *mx) 155 | { 156 | uint16_t** sub_img = (uint16_t**)sub_img0; 157 | 158 | uint8_t c1_8, c2_8, c3_8; 159 | 160 | int c1, c2, c3; 161 | int a1, a; 162 | 163 | uint8_t* src; 164 | uint16_t* dstC1, * dstC2, * dstC3, * dstA; 165 | uint32_t dsta; 166 | 167 | while (img) { 168 | if (img->w == 0 || img->h == 0) { 169 | // nothing to render 170 | img = img->next; 171 | continue; 172 | } 173 | 174 | // color comes always in 8 bits 175 | if (mx->valid) 176 | col2yuv(&img->color, &c1_8, &c2_8, &c3_8, mx); 177 | else 178 | col2rgb(&img->color, &c1_8, &c2_8, &c3_8); 179 | a1 = 255 - _a(img->color); // transparency, always 0..255 180 | if (rgb) { 181 | const int max_pixel_value = (1 << bits_per_pixel) - 1; 182 | // rgb needs full scale stretch 8->N bits 183 | c1 = (int)(c1_8 * max_pixel_value / 255.0f + 0.5f); 184 | c2 = (int)(c2_8 * max_pixel_value / 255.0f + 0.5f); 185 | c3 = (int)(c3_8 * max_pixel_value / 255.0f + 0.5f); 186 | } 187 | else { 188 | // YUV: bit shift 189 | c1 = c1_8 << (bits_per_pixel - 8); 190 | c2 = c2_8 << (bits_per_pixel - 8); 191 | c3 = c3_8 << (bits_per_pixel - 8); 192 | } 193 | 194 | src = img->bitmap; // always 8 bits 195 | // dst 1..3 is real bit depth 0 (alpha) is 8 bits 196 | dstC1 = sub_img[1] + img->dst_y * width + img->dst_x; 197 | dstC2 = sub_img[2] + img->dst_y * width + img->dst_x; 198 | dstC3 = sub_img[3] + img->dst_y * width + img->dst_x; 199 | dstA = sub_img[0] + img->dst_y * width + img->dst_x; 200 | 201 | for (int i = 0; i < img->h; i++) { 202 | for (int j = 0; j < img->w; j++) { 203 | a = div255(src[j] * a1); 204 | if (a) { 205 | if (dstA[j]) { 206 | // combine with existing dst transparency 207 | dsta = scale(a, 255, dstA[j]); 208 | dstC1[j] = dblend(a, c1, dstA[j], dstC1[j], dsta); 209 | dstC2[j] = dblend(a, c2, dstA[j], dstC2[j], dsta); 210 | dstC3[j] = dblend(a, c3, dstA[j], dstC3[j], dsta); 211 | dstA[j] = div255(dsta); // always 0..255 212 | } 213 | else { 214 | dstC1[j] = c1; 215 | dstC2[j] = c2; 216 | dstC3[j] = c3; 217 | dstA[j] = a; // always 0..255 218 | } 219 | } 220 | } 221 | 222 | src += img->stride; 223 | dstC1 += width; 224 | dstC2 += width; 225 | dstC3 += width; 226 | dstA += width; 227 | } 228 | 229 | img = img->next; 230 | } 231 | } 232 | 233 | void apply_rgba(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height) 234 | { 235 | uint8_t *srcA, *srcR, *srcG, *srcB, *dstA, *dstR, *dstG, *dstB; 236 | uint32_t i, j, k, dsta; 237 | 238 | srcR = sub_img[1]; 239 | srcG = sub_img[2]; 240 | srcB = sub_img[3]; 241 | srcA = sub_img[0]; 242 | 243 | dstB = data[0]; 244 | dstG = dstB + 1; 245 | dstR = dstB + 2; 246 | dstA = dstB + 3; 247 | 248 | for (i = 0; i < height; i++) { 249 | for (j = 0; j < width; j++) { 250 | if (srcA[j]) { 251 | k = j * 4; 252 | dsta = scale(srcA[j], 255, dstA[k]); 253 | dstR[k] = dblend(srcA[j], srcR[j], dstA[k], dstR[k], dsta); 254 | dstG[k] = dblend(srcA[j], srcG[j], dstA[k], dstG[k], dsta); 255 | dstB[k] = dblend(srcA[j], srcB[j], dstA[k], dstB[k], dsta); 256 | dstA[k] = div255(dsta); 257 | } 258 | } 259 | 260 | srcR += width; 261 | srcG += width; 262 | srcB += width; 263 | srcA += width; 264 | dstR += pitch[0]; 265 | dstG += pitch[0]; 266 | dstB += pitch[0]; 267 | dstA += pitch[0]; 268 | } 269 | } 270 | 271 | void apply_rgb(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height) 272 | { 273 | uint8_t *srcR, *srcG, *srcB, *srcA, *dstR, *dstG, *dstB; 274 | uint32_t i, j, k; 275 | 276 | srcR = sub_img[1]; 277 | srcG = sub_img[2]; 278 | srcB = sub_img[3]; 279 | srcA = sub_img[0]; 280 | 281 | dstB = data[0]; 282 | dstG = dstB + 1; 283 | dstR = dstB + 2; 284 | 285 | for (i = 0; i < height; i++) { 286 | for (j = 0; j < width; j++) { 287 | if (srcA[j]) { 288 | k = j * 3; 289 | dstR[k] = blend(srcA[j], srcR[j], dstR[k]); 290 | dstG[k] = blend(srcA[j], srcG[j], dstG[k]); 291 | dstB[k] = blend(srcA[j], srcB[j], dstB[k]); 292 | } 293 | } 294 | 295 | srcR += width; 296 | srcG += width; 297 | srcB += width; 298 | srcA += width; 299 | dstR += pitch[0]; 300 | dstG += pitch[0]; 301 | dstB += pitch[0]; 302 | } 303 | } 304 | 305 | void apply_rgb64(uint8_t** sub_img_8, uint8_t** data_8, int32_t* pitch, uint32_t width, uint32_t height) 306 | { 307 | uint16_t* srcA, * srcR, * srcG, * srcB, * dstA, * dstR, * dstG, * dstB; 308 | uint32_t i, j, k, dsta; 309 | uint16_t** sub_img = (uint16_t**)sub_img_8; 310 | uint16_t** data = (uint16_t**)data_8; 311 | 312 | srcR = sub_img[1]; 313 | srcG = sub_img[2]; 314 | srcB = sub_img[3]; 315 | srcA = sub_img[0]; // 0..255 always 316 | 317 | const int pitch0 = pitch[0] / sizeof(uint16_t); 318 | 319 | dstB = data[0]; 320 | // fixme pf: don't use 4 pointers, maybe they are not recognized to optimize out 321 | dstG = dstB + 1; 322 | dstR = dstB + 2; 323 | dstA = dstB + 3; 324 | 325 | for (i = 0; i < height; i++) { 326 | for (j = 0; j < width; j++) { 327 | if (srcA[j]) { 328 | k = j * 4; 329 | dsta = scale(srcA[j], 255, dstA[k]); 330 | dstR[k] = dblend(srcA[j], srcR[j], dstA[k], dstR[k], dsta); 331 | dstG[k] = dblend(srcA[j], srcG[j], dstA[k], dstG[k], dsta); 332 | dstB[k] = dblend(srcA[j], srcB[j], dstA[k], dstB[k], dsta); 333 | dstA[k] = div255(dsta); 334 | } 335 | } 336 | 337 | srcR += width; 338 | srcG += width; 339 | srcB += width; 340 | srcA += width; 341 | dstR += pitch0; 342 | dstG += pitch0; 343 | dstB += pitch0; 344 | dstA += pitch0; 345 | } 346 | } 347 | 348 | void apply_rgb48(uint8_t** sub_img_8, uint8_t** data_8, int32_t* pitch, uint32_t width, uint32_t height) 349 | { 350 | uint16_t* srcR, * srcG, * srcB, * srcA, * dstR, * dstG, * dstB; 351 | uint32_t i, j, k; 352 | uint16_t** sub_img = (uint16_t**)sub_img_8; 353 | uint16_t** data = (uint16_t**)data_8; 354 | 355 | srcR = sub_img[1]; 356 | srcG = sub_img[2]; 357 | srcB = sub_img[3]; 358 | srcA = sub_img[0]; // 0..255 always 359 | 360 | const int pitch0 = pitch[0] / sizeof(uint16_t); 361 | 362 | dstB = data[0]; 363 | // fixme pf: don't use 3 pointers, maybe they are not recognized to optimize out 364 | dstG = dstB + 1; 365 | dstR = dstB + 2; 366 | 367 | for (i = 0; i < height; i++) { 368 | for (j = 0; j < width; j++) { 369 | if (srcA[j]) { 370 | k = j * 3; 371 | dstR[k] = blend(srcA[j], srcR[j], dstR[k]); 372 | dstG[k] = blend(srcA[j], srcG[j], dstG[k]); 373 | dstB[k] = blend(srcA[j], srcB[j], dstB[k]); 374 | } 375 | } 376 | 377 | srcR += width; 378 | srcG += width; 379 | srcB += width; 380 | srcA += width; 381 | dstR += pitch0; 382 | dstG += pitch0; 383 | dstB += pitch0; 384 | } 385 | } 386 | 387 | void apply_yuy2(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height) 388 | { 389 | uint8_t *srcY0, *srcY1, *srcU0, *srcU1, *srcV0, *srcV1, *srcA0, *srcA1; 390 | uint8_t *dstY0, *dstU, *dstY1, *dstV; 391 | uint32_t i, j, k; 392 | 393 | srcY0 = sub_img[1]; 394 | srcY1 = sub_img[1] + 1; 395 | srcU0 = sub_img[2]; 396 | srcU1 = sub_img[2] + 1; 397 | srcV0 = sub_img[3]; 398 | srcV1 = sub_img[3] + 1; 399 | srcA0 = sub_img[0]; 400 | srcA1 = sub_img[0] + 1; 401 | 402 | // YUYV 403 | dstY0 = data[0]; 404 | dstU = data[0] + 1; 405 | dstY1 = data[0] + 2; 406 | dstV = data[0] + 3; 407 | 408 | for (i = 0; i < height; i++) { 409 | for (j = 0; j < width; j += 2) { 410 | if (srcA0[j] + srcA1[j]) { 411 | k = j * 2; 412 | dstY0[k] = blend(srcA0[j], srcY0[j], dstY0[k]); 413 | dstY1[k] = blend(srcA1[j], srcY1[j], dstY1[k]); 414 | dstU[k] = blend2(srcA0[j], srcU0[j], 415 | srcA1[j], srcU1[j], dstU[k]); 416 | dstV[k] = blend2(srcA0[j], srcV0[j], 417 | srcA1[j], srcV1[j], dstV[k]); 418 | } 419 | } 420 | 421 | srcY0 += width; 422 | srcY1 += width; 423 | srcU0 += width; 424 | srcU1 += width; 425 | srcV0 += width; 426 | srcV1 += width; 427 | srcA0 += width; 428 | srcA1 += width; 429 | dstY0 += pitch[0]; 430 | dstU += pitch[0]; 431 | dstY1 += pitch[0]; 432 | dstV += pitch[0]; 433 | } 434 | } 435 | 436 | void apply_yv12(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height) 437 | { 438 | uint8_t *srcY00, *srcU00, *srcV00, *srcA00; 439 | uint8_t *srcY01, *srcU01, *srcV01, *srcA01; 440 | uint8_t *srcY10, *srcU10, *srcV10, *srcA10; 441 | uint8_t *srcY11, *srcU11, *srcV11, *srcA11; 442 | uint8_t *dstY00, *dstY01, *dstY10, *dstY11, *dstU, *dstV; 443 | uint32_t i, j, k; 444 | 445 | srcY00 = sub_img[1]; 446 | srcY01 = sub_img[1] + 1; 447 | srcY10 = sub_img[1] + width; 448 | srcY11 = sub_img[1] + width + 1; 449 | srcU00 = sub_img[2]; 450 | srcU01 = sub_img[2] + 1; 451 | srcU10 = sub_img[2] + width; 452 | srcU11 = sub_img[2] + width + 1; 453 | srcV00 = sub_img[3]; 454 | srcV01 = sub_img[3] + 1; 455 | srcV10 = sub_img[3] + width; 456 | srcV11 = sub_img[3] + width + 1; 457 | srcA00 = sub_img[0]; 458 | srcA01 = sub_img[0] + 1; 459 | srcA10 = sub_img[0] + width; 460 | srcA11 = sub_img[0] + width + 1; 461 | 462 | dstY00 = data[0]; 463 | dstY01 = data[0] + 1; 464 | dstY10 = data[0] + pitch[0]; 465 | dstY11 = data[0] + pitch[0] + 1; 466 | dstU = data[1]; 467 | dstV = data[2]; 468 | 469 | for (i = 0; i < height; i += 2) { 470 | for (j = 0; j < width; j += 2) { 471 | k = j >> 1; 472 | if (srcA00[j] + srcA01[j] + srcA10[j] + srcA11[j]) { 473 | dstY00[j] = blend(srcA00[j], srcY00[j], dstY00[j]); 474 | dstY01[j] = blend(srcA01[j], srcY01[j], dstY01[j]); 475 | dstY10[j] = blend(srcA10[j], srcY10[j], dstY10[j]); 476 | dstY11[j] = blend(srcA11[j], srcY11[j], dstY11[j]); 477 | dstU[k] = blend4(srcA00[j], srcU00[j], 478 | srcA01[j], srcU01[j], 479 | srcA10[j], srcU10[j], 480 | srcA11[j], srcU11[j], dstU[k]); 481 | dstV[k] = blend4(srcA00[j], srcV00[j], 482 | srcA01[j], srcV01[j], 483 | srcA10[j], srcV10[j], 484 | srcA11[j], srcV11[j], dstV[k]); 485 | } 486 | } 487 | 488 | srcY00 += width * 2; 489 | srcY01 += width * 2; 490 | srcY10 += width * 2; 491 | srcY11 += width * 2; 492 | srcU00 += width * 2; 493 | srcU01 += width * 2; 494 | srcU10 += width * 2; 495 | srcU11 += width * 2; 496 | srcV00 += width * 2; 497 | srcV01 += width * 2; 498 | srcV10 += width * 2; 499 | srcV11 += width * 2; 500 | srcA00 += width * 2; 501 | srcA01 += width * 2; 502 | srcA10 += width * 2; 503 | srcA11 += width * 2; 504 | dstY00 += pitch[0] * 2; 505 | dstY01 += pitch[0] * 2; 506 | dstY10 += pitch[0] * 2; 507 | dstY11 += pitch[0] * 2; 508 | dstU += pitch[1]; 509 | dstV += pitch[1]; 510 | } 511 | } 512 | 513 | void apply_yuv420(uint8_t** sub_img_8, uint8_t** data_8, int32_t* pitch, uint32_t width, uint32_t height) 514 | { 515 | uint16_t* srcY00, * srcU00, * srcV00, * srcA00; 516 | uint16_t* srcY01, * srcU01, * srcV01, * srcA01; 517 | uint16_t* srcY10, * srcU10, * srcV10, * srcA10; 518 | uint16_t* srcY11, * srcU11, * srcV11, * srcA11; 519 | uint16_t* dstY00, * dstY01, * dstY10, * dstY11, * dstU, * dstV; 520 | uint32_t i, j, k; 521 | 522 | uint16_t** sub_img = (uint16_t**)sub_img_8; 523 | uint16_t** data = (uint16_t**)data_8; 524 | 525 | // sub_img[0] is 0..255 always 526 | 527 | const int pitch0 = pitch[0] / sizeof(uint16_t); 528 | const int pitchUV = pitch[1] / sizeof(uint16_t); 529 | 530 | srcY00 = sub_img[1]; 531 | srcY01 = sub_img[1] + 1; 532 | srcY10 = sub_img[1] + width; 533 | srcY11 = sub_img[1] + width + 1; 534 | srcU00 = sub_img[2]; 535 | srcU01 = sub_img[2] + 1; 536 | srcU10 = sub_img[2] + width; 537 | srcU11 = sub_img[2] + width + 1; 538 | srcV00 = sub_img[3]; 539 | srcV01 = sub_img[3] + 1; 540 | srcV10 = sub_img[3] + width; 541 | srcV11 = sub_img[3] + width + 1; 542 | srcA00 = sub_img[0]; 543 | srcA01 = sub_img[0] + 1; 544 | srcA10 = sub_img[0] + width; 545 | srcA11 = sub_img[0] + width + 1; 546 | 547 | dstY00 = data[0]; 548 | dstY01 = data[0] + 1; 549 | dstY10 = data[0] + pitch0; 550 | dstY11 = data[0] + pitch0 + 1; 551 | dstU = data[1]; 552 | dstV = data[2]; 553 | 554 | //4:2:0 : 2x2 Y for each chroma 555 | for (i = 0; i < height; i += 2) { 556 | for (j = 0; j < width; j += 2) { 557 | k = j >> 1; 558 | if (srcA00[j] + srcA01[j] + srcA10[j] + srcA11[j]) { 559 | dstY00[j] = blend(srcA00[j], srcY00[j], dstY00[j]); 560 | dstY01[j] = blend(srcA01[j], srcY01[j], dstY01[j]); 561 | dstY10[j] = blend(srcA10[j], srcY10[j], dstY10[j]); 562 | dstY11[j] = blend(srcA11[j], srcY11[j], dstY11[j]); 563 | dstU[k] = blend4(srcA00[j], srcU00[j], 564 | srcA01[j], srcU01[j], 565 | srcA10[j], srcU10[j], 566 | srcA11[j], srcU11[j], dstU[k]); 567 | dstV[k] = blend4(srcA00[j], srcV00[j], 568 | srcA01[j], srcV01[j], 569 | srcA10[j], srcV10[j], 570 | srcA11[j], srcV11[j], dstV[k]); 571 | } 572 | } 573 | 574 | srcY00 += width * 2; 575 | srcY01 += width * 2; 576 | srcY10 += width * 2; 577 | srcY11 += width * 2; 578 | srcU00 += width * 2; 579 | srcU01 += width * 2; 580 | srcU10 += width * 2; 581 | srcU11 += width * 2; 582 | srcV00 += width * 2; 583 | srcV01 += width * 2; 584 | srcV10 += width * 2; 585 | srcV11 += width * 2; 586 | srcA00 += width * 2; 587 | srcA01 += width * 2; 588 | srcA10 += width * 2; 589 | srcA11 += width * 2; 590 | dstY00 += pitch0 * 2; 591 | dstY01 += pitch0 * 2; 592 | dstY10 += pitch0 * 2; 593 | dstY11 += pitch0 * 2; 594 | dstU += pitchUV; 595 | dstV += pitchUV; 596 | } 597 | } 598 | 599 | void apply_yv411(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height) 600 | { 601 | uint8_t* srcY, * srcU, * srcV, * srcA; 602 | uint8_t* dstY0, * dstV, *dstU; 603 | 604 | srcY = sub_img[1]; 605 | srcU = sub_img[2]; 606 | srcV = sub_img[3]; 607 | srcA = sub_img[0]; 608 | 609 | dstY0 = data[0]; 610 | dstU = data[1]; 611 | dstV = data[2]; 612 | 613 | for (unsigned int i = 0; i < height; i++) { 614 | for (unsigned int j = 0; j < width / 4; j++) { 615 | int jy = j * 4; 616 | if (srcA[jy] + srcA[jy + 1] + srcA[jy + 2] + srcA[jy + 3]) { 617 | dstY0[jy + 0] = blend(srcA[jy + 0], srcY[jy + 0], dstY0[jy + 0]); 618 | dstY0[jy + 1] = blend(srcA[jy + 1], srcY[jy + 1], dstY0[jy + 1]); 619 | dstY0[jy + 2] = blend(srcA[jy + 2], srcY[jy + 2], dstY0[jy + 2]); 620 | dstY0[jy + 3] = blend(srcA[jy + 3], srcY[jy + 3], dstY0[jy + 3]); 621 | dstU[j] = blend4(srcA[jy + 0], srcU[jy + 0], 622 | srcA[jy + 1], srcU[jy + 1], 623 | srcA[jy + 2], srcU[jy + 2], 624 | srcA[jy + 3], srcU[jy + 3], 625 | dstU[j]); 626 | dstV[j] = blend4(srcA[jy + 0], srcV[jy + 0], 627 | srcA[jy + 1], srcV[jy + 1], 628 | srcA[jy + 2], srcV[jy + 2], 629 | srcA[jy + 3], srcV[jy + 3], 630 | dstV[j]); 631 | } 632 | } 633 | 634 | srcY += width; 635 | srcU += width; 636 | srcV += width; 637 | srcA += width; 638 | dstY0 += pitch[0]; 639 | dstU += pitch[1]; 640 | dstV += pitch[1]; 641 | } 642 | } 643 | 644 | void apply_yv16(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height) 645 | { 646 | uint8_t *srcY0, *srcY1, *srcU0, *srcU1, *srcV0, *srcV1, *srcA0, *srcA1; 647 | uint8_t *dstY0, *dstU, *dstY1, *dstV; 648 | uint32_t i, j, k; 649 | 650 | srcY0 = sub_img[1]; 651 | srcY1 = sub_img[1] + 1; 652 | srcU0 = sub_img[2]; 653 | srcU1 = sub_img[2] + 1; 654 | srcV0 = sub_img[3]; 655 | srcV1 = sub_img[3] + 1; 656 | srcA0 = sub_img[0]; 657 | srcA1 = sub_img[0] + 1; 658 | 659 | dstY0 = data[0]; 660 | dstU = data[1]; 661 | dstY1 = data[0] + 1; 662 | dstV = data[2]; 663 | 664 | for (i = 0; i < height; i++) { 665 | for (j = 0; j < width; j += 2) { 666 | k = j >> 1; 667 | if (srcA0[j] + srcA1[j]) { 668 | dstY0[j] = blend(srcA0[j], srcY0[j], dstY0[j]); 669 | dstY1[j] = blend(srcA1[j], srcY1[j], dstY1[j]); 670 | dstU[k] = blend2(srcA0[j], srcU0[j], 671 | srcA1[j], srcU1[j], dstU[k]); 672 | dstV[k] = blend2(srcA0[j], srcV0[j], 673 | srcA1[j], srcV1[j], dstV[k]); 674 | } 675 | } 676 | 677 | srcY0 += width; 678 | srcY1 += width; 679 | srcU0 += width; 680 | srcU1 += width; 681 | srcV0 += width; 682 | srcV1 += width; 683 | srcA0 += width; 684 | srcA1 += width; 685 | dstY0 += pitch[0]; 686 | dstY1 += pitch[0]; 687 | dstU += pitch[1]; 688 | dstV += pitch[1]; 689 | } 690 | } 691 | 692 | void apply_yuv422(uint8_t** sub_img_8, uint8_t** data_8, int32_t* pitch, uint32_t width, uint32_t height) 693 | { 694 | uint16_t* srcY0, * srcY1, * srcU0, * srcU1, * srcV0, * srcV1, * srcA0, * srcA1; 695 | uint16_t* dstY0, * dstU, * dstY1, * dstV; 696 | uint32_t i, j, k; 697 | 698 | uint16_t** sub_img = (uint16_t**)sub_img_8; 699 | uint16_t** data = (uint16_t**)data_8; 700 | 701 | // sub_img[0] is 0..255 always 702 | 703 | const int pitch0 = pitch[0] / sizeof(uint16_t); 704 | const int pitchUV = pitch[1] / sizeof(uint16_t); 705 | 706 | srcY0 = sub_img[1]; 707 | srcY1 = sub_img[1] + 1; 708 | srcU0 = sub_img[2]; 709 | srcU1 = sub_img[2] + 1; 710 | srcV0 = sub_img[3]; 711 | srcV1 = sub_img[3] + 1; 712 | srcA0 = sub_img[0]; 713 | srcA1 = sub_img[0] + 1; 714 | 715 | dstY0 = data[0]; 716 | dstU = data[1]; 717 | dstY1 = data[0] + 1; 718 | dstV = data[2]; 719 | 720 | for (i = 0; i < height; i++) { 721 | for (j = 0; j < width; j += 2) { 722 | k = j >> 1; 723 | if (srcA0[j] + srcA1[j]) { 724 | dstY0[j] = blend(srcA0[j], srcY0[j], dstY0[j]); 725 | dstY1[j] = blend(srcA1[j], srcY1[j], dstY1[j]); 726 | dstU[k] = blend2(srcA0[j], srcU0[j], 727 | srcA1[j], srcU1[j], dstU[k]); 728 | dstV[k] = blend2(srcA0[j], srcV0[j], 729 | srcA1[j], srcV1[j], dstV[k]); 730 | } 731 | } 732 | 733 | srcY0 += width; 734 | srcY1 += width; 735 | srcU0 += width; 736 | srcU1 += width; 737 | srcV0 += width; 738 | srcV1 += width; 739 | srcA0 += width; 740 | srcA1 += width; 741 | dstY0 += pitch0; 742 | dstY1 += pitch0; 743 | dstU += pitchUV; 744 | dstV += pitchUV; 745 | } 746 | } 747 | 748 | void apply_yv24(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height) 749 | { 750 | uint8_t *srcY, *srcU, *srcV, *srcA, *dstY, *dstU, *dstV; 751 | uint32_t i, j; 752 | 753 | srcY = sub_img[1]; 754 | srcU = sub_img[2]; 755 | srcV = sub_img[3]; 756 | srcA = sub_img[0]; 757 | 758 | dstY = data[0]; 759 | dstU = data[1]; 760 | dstV = data[2]; 761 | 762 | for (i = 0; i < height; i++) { 763 | for (j = 0; j < width; j++) { 764 | if (srcA[j]) { 765 | dstY[j] = blend(srcA[j], srcY[j], dstY[j]); 766 | dstU[j] = blend(srcA[j], srcU[j], dstU[j]); 767 | dstV[j] = blend(srcA[j], srcV[j], dstV[j]); 768 | } 769 | } 770 | 771 | srcY += width; 772 | srcU += width; 773 | srcV += width; 774 | srcA += width; 775 | dstY += pitch[0]; 776 | dstU += pitch[0]; 777 | dstV += pitch[0]; 778 | } 779 | } 780 | 781 | void apply_yuv444(uint8_t** sub_img_8, uint8_t** data_8, int32_t* pitch, uint32_t width, uint32_t height) 782 | { 783 | // planar RGB as well 784 | uint16_t* srcY, * srcU, * srcV, * srcA, * dstY, * dstU, * dstV; 785 | uint32_t i, j; 786 | 787 | uint16_t** sub_img = (uint16_t**)sub_img_8; 788 | uint16_t** data = (uint16_t**)data_8; 789 | 790 | // sub_img[0] is 0..255 always 791 | 792 | const int pitch0 = pitch[0] / sizeof(uint16_t); 793 | 794 | srcY = sub_img[1]; 795 | srcU = sub_img[2]; 796 | srcV = sub_img[3]; 797 | srcA = sub_img[0]; 798 | 799 | dstY = data[0]; 800 | dstU = data[1]; 801 | dstV = data[2]; 802 | 803 | for (i = 0; i < height; i++) { 804 | for (j = 0; j < width; j++) { 805 | if (srcA[j]) { 806 | dstY[j] = blend(srcA[j], srcY[j], dstY[j]); 807 | dstU[j] = blend(srcA[j], srcU[j], dstU[j]); 808 | dstV[j] = blend(srcA[j], srcV[j], dstV[j]); 809 | } 810 | } 811 | 812 | srcY += width; 813 | srcU += width; 814 | srcV += width; 815 | srcA += width; 816 | dstY += pitch0; 817 | dstU += pitch0; 818 | dstV += pitch0; 819 | } 820 | } 821 | 822 | void apply_y8(uint8_t** sub_img, uint8_t** data, int32_t* pitch, uint32_t width, uint32_t height) 823 | { 824 | uint8_t *srcY, *srcA, *dstY; 825 | uint32_t i, j; 826 | 827 | srcY = sub_img[1]; 828 | srcA = sub_img[0]; 829 | 830 | dstY = data[0]; 831 | 832 | for (i = 0; i < height; i++) { 833 | for (j = 0; j < width; j++) { 834 | if (srcA[j]) { 835 | dstY[j] = blend(srcA[j], srcY[j], dstY[j]); 836 | } 837 | } 838 | 839 | srcY += width; 840 | srcA += width; 841 | dstY += pitch[0]; 842 | } 843 | } 844 | 845 | void apply_y(uint8_t** sub_img_8, uint8_t** data_8, int32_t* pitch, uint32_t width, uint32_t height) 846 | { 847 | uint16_t* srcY, * srcA, * dstY; 848 | uint32_t i, j; 849 | 850 | uint16_t** sub_img = (uint16_t**)sub_img_8; 851 | uint16_t** data = (uint16_t**)data_8; 852 | 853 | // sub_img[0] is 0..255 always 854 | 855 | const int pitch0 = pitch[0] / sizeof(uint16_t); 856 | 857 | srcY = sub_img[1]; 858 | srcA = sub_img[0]; 859 | 860 | dstY = data[0]; 861 | 862 | for (i = 0; i < height; i++) { 863 | for (j = 0; j < width; j++) { 864 | if (srcA[j]) { 865 | dstY[j] = blend(srcA[j], srcY[j], dstY[j]); 866 | } 867 | } 868 | 869 | srcY += width; 870 | srcA += width; 871 | dstY += pitch0; 872 | } 873 | } 874 | 875 | const VSFrameRef* VS_CC assrender_get_frame_vs(int n, int activationReason, void** instanceData, void** frameData, VSFrameContext* frameCtx, VSCore* core, const VSAPI* vsapi) { 876 | const VS_FilterInfo* p = *instanceData; 877 | if (activationReason == arInitial) { 878 | vsapi->requestFrameFilter(n, p->node, frameCtx); 879 | } 880 | else if (activationReason == arAllFramesReady) { 881 | udata* ud = (udata*)p->user_data; 882 | ASS_Image* img; 883 | 884 | int64_t ts; 885 | int changed; 886 | 887 | const VSFrameRef* src = vsapi->getFrameFilter(n, p->node, frameCtx); 888 | 889 | if (p->prop) { 890 | const VSMap *map = vsapi->getFramePropsRO(src); 891 | int err; 892 | const char *text = vsapi->propGetData(map, p->prop, 0, &err); 893 | if (text) { 894 | // ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text 895 | const char *fmt = "%d,0,Default,,0,0,0,,%s\n"; 896 | int event_space = strlen(fmt) + strlen(text) + 16 + 1; 897 | char *tmp = malloc(event_space); 898 | snprintf(tmp, event_space, fmt, n, text); 899 | int64_t ts, duration; 900 | if (!ud->isvfr) { 901 | ts = (int64_t)n * (int64_t)1000 * (int64_t)p->vi->fpsDen / (int64_t)p->vi->fpsNum; 902 | duration = 1000 * (int64_t)p->vi->fpsDen / p->vi->fpsNum; 903 | } else { 904 | ts = ud->timestamp[n]; 905 | if (n == p->vi->numFrames - 1) 906 | duration = 30; // arbitrary 907 | else 908 | duration = ud->timestamp[n+1] - ud->timestamp[n]; 909 | } 910 | ass_process_chunk(ud->ass, tmp, strlen(tmp), ts, duration); 911 | free(tmp); 912 | } 913 | } 914 | 915 | VSFrameRef *dst = vsapi->copyFrame(src, core); 916 | vsapi->freeFrame(src); 917 | 918 | if (!ud->isvfr) { 919 | // it’s a casting party! 920 | ts = (int64_t)n * (int64_t)1000 * (int64_t)p->vi->fpsDen / (int64_t)p->vi->fpsNum; 921 | } 922 | else { 923 | ts = ud->timestamp[n]; 924 | } 925 | 926 | img = ass_render_frame(ud->ass_renderer, ud->ass, ts, &changed); 927 | 928 | if (img) { 929 | uint32_t height, width, pitch[2]; 930 | uint8_t* data[3]; 931 | 932 | if (p->vi->format->colorFamily != cmCompat && !ud->greyscale) { 933 | if (p->vi->format->colorFamily == cmRGB) { 934 | // planar RGB as 444 935 | data[0] = vsapi->getWritePtr(dst, 0); 936 | data[1] = vsapi->getWritePtr(dst, 1); 937 | data[2] = vsapi->getWritePtr(dst, 2); 938 | pitch[0] = vsapi->getStride(dst, 0); 939 | } 940 | else { 941 | data[0] = vsapi->getWritePtr(dst, 0); 942 | data[1] = vsapi->getWritePtr(dst, 1); 943 | data[2] = vsapi->getWritePtr(dst, 2); 944 | pitch[0] = vsapi->getStride(dst, 0); 945 | pitch[1] = vsapi->getStride(dst, 1); 946 | } 947 | } 948 | else { 949 | data[0] = vsapi->getWritePtr(dst, 0); 950 | pitch[0] = vsapi->getStride(dst, 0); 951 | } 952 | 953 | height = p->vi->height; 954 | width = p->vi->width; 955 | 956 | if (changed) { 957 | memset(ud->sub_img[0], 0x00, height * width * ud->pixelsize); 958 | ud->f_make_sub_img(img, ud->sub_img, width, ud->bits_per_pixel, ud->rgb_fullscale, &ud->mx); 959 | } 960 | 961 | ud->apply(ud->sub_img, data, pitch, width, height); 962 | } 963 | 964 | return dst; 965 | } 966 | return NULL; 967 | } -------------------------------------------------------------------------------- /src/include/avisynth_c.h: -------------------------------------------------------------------------------- 1 | // Avisynth C Interface Version 0.20 2 | // Copyright 2003 Kevin Atkinson 3 | 4 | // Copyright 2020 AviSynth+ project 5 | 6 | // This program 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 2 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program 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, write to the Free Software 18 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | // MA 02110-1301 USA, or visit 20 | // http://www.gnu.org/copyleft/gpl.html . 21 | // 22 | // As a special exception, I give you permission to link to the 23 | // Avisynth C interface with independent modules that communicate with 24 | // the Avisynth C interface solely through the interfaces defined in 25 | // avisynth_c.h, regardless of the license terms of these independent 26 | // modules, and to copy and distribute the resulting combined work 27 | // under terms of your choice, provided that every copy of the 28 | // combined work is accompanied by a complete copy of the source code 29 | // of the Avisynth C interface and Avisynth itself (with the version 30 | // used to produce the combined work), being distributed under the 31 | // terms of the GNU General Public License plus this exception. An 32 | // independent module is a module which is not derived from or based 33 | // on Avisynth C Interface, such as 3rd-party filters, import and 34 | // export plugins, or graphical user interfaces. 35 | 36 | // NOTE: this is a partial update of the Avisynth C interface to recognize 37 | // new color spaces and interface elements added in Avisynth 2.60 and AviSynth+. 38 | // This interface is not 100% Avisynth+ CPP interface equivalent. 39 | 40 | // 170103: added new CPU constants (FMA4, AVX512xx) 41 | // 171102: define SIZETMOD. do not use yet, experimental. Offsets are size_t instead of int. Affects x64. 42 | // 171106: avs_get_row_size calls into avs_get_row_size_p, instead of direct field access 43 | // 171106: avs_get_height calls into avs_get_row_size_p, instead of direct field access 44 | // 180524: AVSC_EXPORT to dllexport in capi.h for avisynth_c_plugin_init 45 | // 180524: avs_is_same_colorspace VideoInfo parameters to const 46 | // 181230: Readability: functions regrouped to mix less AVSC_API and AVSC_INLINE, put together Avisynth+ specific stuff 47 | // 181230: use #ifndef AVSC_NO_DECLSPEC for AVSC_INLINE functions which are calling API functions 48 | // 181230: comments on avs_load_library (helper for loading API entries dynamically into a struct using AVSC_NO_DECLSPEC define) 49 | // 181230: define alias AVS_FRAME_ALIGN as FRAME_ALIGN 50 | // 181230: remove unused form of avs_get_rowsize and avs_get_height (kept earlier for reference) 51 | // 190104: avs_load_library: smart fallback mechanism for Avisynth+ specific functions: 52 | // if they are not loadable, they will work in a classic Avisynth compatible mode 53 | // Example#1: e.g. avs_is_444 will call the existing avs_is_yv24 instead 54 | // Example#2: avs_bits_per_component will return 8 for all colorspaces (Classic Avisynth supports only 8 bits/pixel) 55 | // Thus the Avisynth+ specific API functions are safely callable even when connected to classic Avisynth DLL 56 | // 202002xx non-Windows friendly additions 57 | // 20200305 avs_vsprintf parameter type change: (void *) to va_list 58 | // 20200330: (remove test SIZETMOD define for clarity) 59 | // 20200513: user must use explicite #define AVS26_FALLBACK_SIMULATION for having fallback helpers in dynamic loaded library section 60 | // 20200513: Follow AviSynth+ V8 interface additions 61 | // AVS_VideoFrame struct extended with placeholder for frame property pointer 62 | // avs_subframe_planar_a 63 | // avs_copy_frame_props 64 | // avs_get_frame_props_ro, avs_get_frame_props_rw 65 | // avs_prop_num_keys, avs_prop_get_key, avs_prop_num_elements, avs_prop_get_type, avs_prop_get_data_size 66 | // avs_prop_get_int, avs_prop_get_float, avs_prop_get_data, avs_prop_get_clip, avs_prop_get_frame, avs_prop_get_int_array, avs_prop_get_float_array 67 | // avs_prop_set_int, avs_prop_set_float, avs_prop_set_data, avs_prop_set_clip, avs_prop_set_frame, avs_prop_set_int_array, avs_prop_set_float_array 68 | // avs_prop_delete_key, avs_clear_map 69 | // avs_new_video_frame_p, avs_new_video_frame_p_a 70 | // avs_get_env_property (internal system properties), AVS_AEP_xxx (AvsEnvProperty) enums 71 | // avs_get_var_try, avs_get_var_bool, avs_get_var_int, avs_get_var_double, avs_get_var_string, avs_get_var_long 72 | // avs_pool_allocate, avs_pool_free 73 | 74 | 75 | #ifndef __AVISYNTH_C__ 76 | #define __AVISYNTH_C__ 77 | 78 | #include "avs/config.h" 79 | #include "avs/capi.h" 80 | #include "avs/types.h" 81 | 82 | #define AVS_FRAME_ALIGN FRAME_ALIGN 83 | ///////////////////////////////////////////////////////////////////// 84 | // 85 | // Constants 86 | // 87 | 88 | #ifndef __AVISYNTH_8_H__ 89 | enum { 90 | AVISYNTH_INTERFACE_CLASSIC_VERSION = 6, 91 | AVISYNTH_INTERFACE_VERSION = 8 92 | }; 93 | #endif 94 | 95 | enum {AVS_SAMPLE_INT8 = 1<<0, 96 | AVS_SAMPLE_INT16 = 1<<1, 97 | AVS_SAMPLE_INT24 = 1<<2, 98 | AVS_SAMPLE_INT32 = 1<<3, 99 | AVS_SAMPLE_FLOAT = 1<<4}; 100 | 101 | enum {AVS_PLANAR_Y=1<<0, 102 | AVS_PLANAR_U=1<<1, 103 | AVS_PLANAR_V=1<<2, 104 | AVS_PLANAR_ALIGNED=1<<3, 105 | AVS_PLANAR_Y_ALIGNED=AVS_PLANAR_Y|AVS_PLANAR_ALIGNED, 106 | AVS_PLANAR_U_ALIGNED=AVS_PLANAR_U|AVS_PLANAR_ALIGNED, 107 | AVS_PLANAR_V_ALIGNED=AVS_PLANAR_V|AVS_PLANAR_ALIGNED, 108 | AVS_PLANAR_A=1<<4, 109 | AVS_PLANAR_R=1<<5, 110 | AVS_PLANAR_G=1<<6, 111 | AVS_PLANAR_B=1<<7, 112 | AVS_PLANAR_A_ALIGNED=AVS_PLANAR_A|AVS_PLANAR_ALIGNED, 113 | AVS_PLANAR_R_ALIGNED=AVS_PLANAR_R|AVS_PLANAR_ALIGNED, 114 | AVS_PLANAR_G_ALIGNED=AVS_PLANAR_G|AVS_PLANAR_ALIGNED, 115 | AVS_PLANAR_B_ALIGNED=AVS_PLANAR_B|AVS_PLANAR_ALIGNED}; 116 | 117 | // Colorspace properties. 118 | enum { 119 | AVS_CS_YUVA = 1 << 27, 120 | AVS_CS_BGR = 1 << 28, 121 | AVS_CS_YUV = 1 << 29, 122 | AVS_CS_INTERLEAVED = 1 << 30, 123 | AVS_CS_PLANAR = 1 << 31, 124 | 125 | AVS_CS_SHIFT_SUB_WIDTH = 0, 126 | AVS_CS_SHIFT_SUB_HEIGHT = 8, 127 | AVS_CS_SHIFT_SAMPLE_BITS = 16, 128 | 129 | AVS_CS_SUB_WIDTH_MASK = 7 << AVS_CS_SHIFT_SUB_WIDTH, 130 | AVS_CS_SUB_WIDTH_1 = 3 << AVS_CS_SHIFT_SUB_WIDTH, // YV24 131 | AVS_CS_SUB_WIDTH_2 = 0 << AVS_CS_SHIFT_SUB_WIDTH, // YV12, I420, YV16 132 | AVS_CS_SUB_WIDTH_4 = 1 << AVS_CS_SHIFT_SUB_WIDTH, // YUV9, YV411 133 | 134 | AVS_CS_VPLANEFIRST = 1 << 3, // YV12, YV16, YV24, YV411, YUV9 135 | AVS_CS_UPLANEFIRST = 1 << 4, // I420 136 | 137 | AVS_CS_SUB_HEIGHT_MASK = 7 << AVS_CS_SHIFT_SUB_HEIGHT, 138 | AVS_CS_SUB_HEIGHT_1 = 3 << AVS_CS_SHIFT_SUB_HEIGHT, // YV16, YV24, YV411 139 | AVS_CS_SUB_HEIGHT_2 = 0 << AVS_CS_SHIFT_SUB_HEIGHT, // YV12, I420 140 | AVS_CS_SUB_HEIGHT_4 = 1 << AVS_CS_SHIFT_SUB_HEIGHT, // YUV9 141 | 142 | AVS_CS_SAMPLE_BITS_MASK = 7 << AVS_CS_SHIFT_SAMPLE_BITS, 143 | AVS_CS_SAMPLE_BITS_8 = 0 << AVS_CS_SHIFT_SAMPLE_BITS, 144 | AVS_CS_SAMPLE_BITS_10 = 5 << AVS_CS_SHIFT_SAMPLE_BITS, 145 | AVS_CS_SAMPLE_BITS_12 = 6 << AVS_CS_SHIFT_SAMPLE_BITS, 146 | AVS_CS_SAMPLE_BITS_14 = 7 << AVS_CS_SHIFT_SAMPLE_BITS, 147 | AVS_CS_SAMPLE_BITS_16 = 1 << AVS_CS_SHIFT_SAMPLE_BITS, 148 | AVS_CS_SAMPLE_BITS_32 = 2 << AVS_CS_SHIFT_SAMPLE_BITS, 149 | 150 | AVS_CS_PLANAR_MASK = AVS_CS_PLANAR | AVS_CS_INTERLEAVED | AVS_CS_YUV | AVS_CS_BGR | AVS_CS_YUVA | AVS_CS_SAMPLE_BITS_MASK | AVS_CS_SUB_HEIGHT_MASK | AVS_CS_SUB_WIDTH_MASK, 151 | AVS_CS_PLANAR_FILTER = ~(AVS_CS_VPLANEFIRST | AVS_CS_UPLANEFIRST), 152 | 153 | AVS_CS_RGB_TYPE = 1 << 0, 154 | AVS_CS_RGBA_TYPE = 1 << 1, 155 | 156 | AVS_CS_GENERIC_YUV420 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_2 | AVS_CS_SUB_WIDTH_2, // 4:2:0 planar 157 | AVS_CS_GENERIC_YUV422 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_2, // 4:2:2 planar 158 | AVS_CS_GENERIC_YUV444 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_1, // 4:4:4 planar 159 | AVS_CS_GENERIC_Y = AVS_CS_PLANAR | AVS_CS_INTERLEAVED | AVS_CS_YUV, // Y only (4:0:0) 160 | AVS_CS_GENERIC_RGBP = AVS_CS_PLANAR | AVS_CS_BGR | AVS_CS_RGB_TYPE, // planar RGB 161 | AVS_CS_GENERIC_RGBAP = AVS_CS_PLANAR | AVS_CS_BGR | AVS_CS_RGBA_TYPE, // planar RGBA 162 | AVS_CS_GENERIC_YUVA420 = AVS_CS_PLANAR | AVS_CS_YUVA | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_2 | AVS_CS_SUB_WIDTH_2, // 4:2:0:A planar 163 | AVS_CS_GENERIC_YUVA422 = AVS_CS_PLANAR | AVS_CS_YUVA | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_2, // 4:2:2:A planar 164 | AVS_CS_GENERIC_YUVA444 = AVS_CS_PLANAR | AVS_CS_YUVA | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_1 }; // 4:4:4:A planar 165 | 166 | 167 | // Specific color formats 168 | enum { 169 | AVS_CS_UNKNOWN = 0, 170 | AVS_CS_BGR24 = AVS_CS_RGB_TYPE | AVS_CS_BGR | AVS_CS_INTERLEAVED, 171 | AVS_CS_BGR32 = AVS_CS_RGBA_TYPE | AVS_CS_BGR | AVS_CS_INTERLEAVED, 172 | AVS_CS_YUY2 = 1<<2 | AVS_CS_YUV | AVS_CS_INTERLEAVED, 173 | // AVS_CS_YV12 = 1<<3 Reserved 174 | // AVS_CS_I420 = 1<<4 Reserved 175 | AVS_CS_RAW32 = 1<<5 | AVS_CS_INTERLEAVED, 176 | 177 | AVS_CS_YV24 = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_8, // YUV 4:4:4 planar 178 | AVS_CS_YV16 = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_8, // YUV 4:2:2 planar 179 | AVS_CS_YV12 = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_8, // YUV 4:2:0 planar 180 | AVS_CS_I420 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_UPLANEFIRST | AVS_CS_SUB_HEIGHT_2 | AVS_CS_SUB_WIDTH_2, // YUV 4:2:0 planar 181 | AVS_CS_IYUV = AVS_CS_I420, 182 | AVS_CS_YV411 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_4, // YUV 4:1:1 planar 183 | AVS_CS_YUV9 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_4 | AVS_CS_SUB_WIDTH_4, // YUV 4:1:0 planar 184 | AVS_CS_Y8 = AVS_CS_GENERIC_Y | AVS_CS_SAMPLE_BITS_8, // Y 4:0:0 planar 185 | 186 | //------------------------- 187 | // AVS16: new planar constants go live! Experimental PF 160613 188 | // 10-12-14-16 bit + planar RGB + BGR48/64 160725 189 | AVS_CS_YUV444P10 = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_10, // YUV 4:4:4 10bit samples 190 | AVS_CS_YUV422P10 = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_10, // YUV 4:2:2 10bit samples 191 | AVS_CS_YUV420P10 = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_10, // YUV 4:2:0 10bit samples 192 | AVS_CS_Y10 = AVS_CS_GENERIC_Y | AVS_CS_SAMPLE_BITS_10, // Y 4:0:0 10bit samples 193 | 194 | AVS_CS_YUV444P12 = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_12, // YUV 4:4:4 12bit samples 195 | AVS_CS_YUV422P12 = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_12, // YUV 4:2:2 12bit samples 196 | AVS_CS_YUV420P12 = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_12, // YUV 4:2:0 12bit samples 197 | AVS_CS_Y12 = AVS_CS_GENERIC_Y | AVS_CS_SAMPLE_BITS_12, // Y 4:0:0 12bit samples 198 | 199 | AVS_CS_YUV444P14 = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_14, // YUV 4:4:4 14bit samples 200 | AVS_CS_YUV422P14 = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_14, // YUV 4:2:2 14bit samples 201 | AVS_CS_YUV420P14 = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_14, // YUV 4:2:0 14bit samples 202 | AVS_CS_Y14 = AVS_CS_GENERIC_Y | AVS_CS_SAMPLE_BITS_14, // Y 4:0:0 14bit samples 203 | 204 | AVS_CS_YUV444P16 = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_16, // YUV 4:4:4 16bit samples 205 | AVS_CS_YUV422P16 = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_16, // YUV 4:2:2 16bit samples 206 | AVS_CS_YUV420P16 = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_16, // YUV 4:2:0 16bit samples 207 | AVS_CS_Y16 = AVS_CS_GENERIC_Y | AVS_CS_SAMPLE_BITS_16, // Y 4:0:0 16bit samples 208 | 209 | // 32 bit samples (float) 210 | AVS_CS_YUV444PS = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_32, // YUV 4:4:4 32bit samples 211 | AVS_CS_YUV422PS = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_32, // YUV 4:2:2 32bit samples 212 | AVS_CS_YUV420PS = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_32, // YUV 4:2:0 32bit samples 213 | AVS_CS_Y32 = AVS_CS_GENERIC_Y | AVS_CS_SAMPLE_BITS_32, // Y 4:0:0 32bit samples 214 | 215 | // RGB packed 216 | AVS_CS_BGR48 = AVS_CS_RGB_TYPE | AVS_CS_BGR | AVS_CS_INTERLEAVED | AVS_CS_SAMPLE_BITS_16, // BGR 3x16 bit 217 | AVS_CS_BGR64 = AVS_CS_RGBA_TYPE | AVS_CS_BGR | AVS_CS_INTERLEAVED | AVS_CS_SAMPLE_BITS_16, // BGR 4x16 bit 218 | // no packed 32 bit (float) support for these legacy types 219 | 220 | // RGB planar 221 | AVS_CS_RGBP = AVS_CS_GENERIC_RGBP | AVS_CS_SAMPLE_BITS_8, // Planar RGB 8 bit samples 222 | AVS_CS_RGBP10 = AVS_CS_GENERIC_RGBP | AVS_CS_SAMPLE_BITS_10, // Planar RGB 10bit samples 223 | AVS_CS_RGBP12 = AVS_CS_GENERIC_RGBP | AVS_CS_SAMPLE_BITS_12, // Planar RGB 12bit samples 224 | AVS_CS_RGBP14 = AVS_CS_GENERIC_RGBP | AVS_CS_SAMPLE_BITS_14, // Planar RGB 14bit samples 225 | AVS_CS_RGBP16 = AVS_CS_GENERIC_RGBP | AVS_CS_SAMPLE_BITS_16, // Planar RGB 16bit samples 226 | AVS_CS_RGBPS = AVS_CS_GENERIC_RGBP | AVS_CS_SAMPLE_BITS_32, // Planar RGB 32bit samples 227 | 228 | // RGBA planar 229 | AVS_CS_RGBAP = AVS_CS_GENERIC_RGBAP | AVS_CS_SAMPLE_BITS_8, // Planar RGBA 8 bit samples 230 | AVS_CS_RGBAP10 = AVS_CS_GENERIC_RGBAP | AVS_CS_SAMPLE_BITS_10, // Planar RGBA 10bit samples 231 | AVS_CS_RGBAP12 = AVS_CS_GENERIC_RGBAP | AVS_CS_SAMPLE_BITS_12, // Planar RGBA 12bit samples 232 | AVS_CS_RGBAP14 = AVS_CS_GENERIC_RGBAP | AVS_CS_SAMPLE_BITS_14, // Planar RGBA 14bit samples 233 | AVS_CS_RGBAP16 = AVS_CS_GENERIC_RGBAP | AVS_CS_SAMPLE_BITS_16, // Planar RGBA 16bit samples 234 | AVS_CS_RGBAPS = AVS_CS_GENERIC_RGBAP | AVS_CS_SAMPLE_BITS_32, // Planar RGBA 32bit samples 235 | 236 | // Planar YUVA 237 | AVS_CS_YUVA444 = AVS_CS_GENERIC_YUVA444 | AVS_CS_SAMPLE_BITS_8, // YUVA 4:4:4 8bit samples 238 | AVS_CS_YUVA422 = AVS_CS_GENERIC_YUVA422 | AVS_CS_SAMPLE_BITS_8, // YUVA 4:2:2 8bit samples 239 | AVS_CS_YUVA420 = AVS_CS_GENERIC_YUVA420 | AVS_CS_SAMPLE_BITS_8, // YUVA 4:2:0 8bit samples 240 | 241 | AVS_CS_YUVA444P10 = AVS_CS_GENERIC_YUVA444 | AVS_CS_SAMPLE_BITS_10, // YUVA 4:4:4 10bit samples 242 | AVS_CS_YUVA422P10 = AVS_CS_GENERIC_YUVA422 | AVS_CS_SAMPLE_BITS_10, // YUVA 4:2:2 10bit samples 243 | AVS_CS_YUVA420P10 = AVS_CS_GENERIC_YUVA420 | AVS_CS_SAMPLE_BITS_10, // YUVA 4:2:0 10bit samples 244 | 245 | AVS_CS_YUVA444P12 = AVS_CS_GENERIC_YUVA444 | AVS_CS_SAMPLE_BITS_12, // YUVA 4:4:4 12bit samples 246 | AVS_CS_YUVA422P12 = AVS_CS_GENERIC_YUVA422 | AVS_CS_SAMPLE_BITS_12, // YUVA 4:2:2 12bit samples 247 | AVS_CS_YUVA420P12 = AVS_CS_GENERIC_YUVA420 | AVS_CS_SAMPLE_BITS_12, // YUVA 4:2:0 12bit samples 248 | 249 | AVS_CS_YUVA444P14 = AVS_CS_GENERIC_YUVA444 | AVS_CS_SAMPLE_BITS_14, // YUVA 4:4:4 14bit samples 250 | AVS_CS_YUVA422P14 = AVS_CS_GENERIC_YUVA422 | AVS_CS_SAMPLE_BITS_14, // YUVA 4:2:2 14bit samples 251 | AVS_CS_YUVA420P14 = AVS_CS_GENERIC_YUVA420 | AVS_CS_SAMPLE_BITS_14, // YUVA 4:2:0 14bit samples 252 | 253 | AVS_CS_YUVA444P16 = AVS_CS_GENERIC_YUVA444 | AVS_CS_SAMPLE_BITS_16, // YUVA 4:4:4 16bit samples 254 | AVS_CS_YUVA422P16 = AVS_CS_GENERIC_YUVA422 | AVS_CS_SAMPLE_BITS_16, // YUVA 4:2:2 16bit samples 255 | AVS_CS_YUVA420P16 = AVS_CS_GENERIC_YUVA420 | AVS_CS_SAMPLE_BITS_16, // YUVA 4:2:0 16bit samples 256 | 257 | AVS_CS_YUVA444PS = AVS_CS_GENERIC_YUVA444 | AVS_CS_SAMPLE_BITS_32, // YUVA 4:4:4 32bit samples 258 | AVS_CS_YUVA422PS = AVS_CS_GENERIC_YUVA422 | AVS_CS_SAMPLE_BITS_32, // YUVA 4:2:2 32bit samples 259 | AVS_CS_YUVA420PS = AVS_CS_GENERIC_YUVA420 | AVS_CS_SAMPLE_BITS_32, // YUVA 4:2:0 32bit samples 260 | 261 | }; 262 | 263 | enum { 264 | AVS_IT_BFF = 1<<0, 265 | AVS_IT_TFF = 1<<1, 266 | AVS_IT_FIELDBASED = 1<<2}; 267 | 268 | enum { 269 | AVS_FILTER_TYPE=1, 270 | AVS_FILTER_INPUT_COLORSPACE=2, 271 | AVS_FILTER_OUTPUT_TYPE=9, 272 | AVS_FILTER_NAME=4, 273 | AVS_FILTER_AUTHOR=5, 274 | AVS_FILTER_VERSION=6, 275 | AVS_FILTER_ARGS=7, 276 | AVS_FILTER_ARGS_INFO=8, 277 | AVS_FILTER_ARGS_DESCRIPTION=10, 278 | AVS_FILTER_DESCRIPTION=11}; 279 | 280 | enum { //SUBTYPES 281 | AVS_FILTER_TYPE_AUDIO=1, 282 | AVS_FILTER_TYPE_VIDEO=2, 283 | AVS_FILTER_OUTPUT_TYPE_SAME=3, 284 | AVS_FILTER_OUTPUT_TYPE_DIFFERENT=4}; 285 | 286 | enum { 287 | // New 2.6 explicitly defined cache hints. 288 | AVS_CACHE_NOTHING = 10, // Do not cache video. 289 | AVS_CACHE_WINDOW = 11, // Hard protect up to X frames within a range of X from the current frame N. 290 | AVS_CACHE_GENERIC = 12, // LRU cache up to X frames. 291 | AVS_CACHE_FORCE_GENERIC = 13, // LRU cache up to X frames, override any previous CACHE_WINDOW. 292 | 293 | AVS_CACHE_GET_POLICY = 30, // Get the current policy. 294 | AVS_CACHE_GET_WINDOW = 31, // Get the current window h_span. 295 | AVS_CACHE_GET_RANGE = 32, // Get the current generic frame range. 296 | 297 | AVS_CACHE_AUDIO = 50, // Explicitly do cache audio, X byte cache. 298 | AVS_CACHE_AUDIO_NOTHING = 51, // Explicitly do not cache audio. 299 | AVS_CACHE_AUDIO_NONE = 52, // Audio cache off (auto mode), X byte initial cache. 300 | AVS_CACHE_AUDIO_AUTO = 53, // Audio cache on (auto mode), X byte initial cache. 301 | 302 | AVS_CACHE_GET_AUDIO_POLICY = 70, // Get the current audio policy. 303 | AVS_CACHE_GET_AUDIO_SIZE = 71, // Get the current audio cache size. 304 | 305 | AVS_CACHE_PREFETCH_FRAME = 100, // Queue request to prefetch frame N. 306 | AVS_CACHE_PREFETCH_GO = 101, // Action video prefetches. 307 | 308 | AVS_CACHE_PREFETCH_AUDIO_BEGIN = 120, // Begin queue request transaction to prefetch audio (take critical section). 309 | AVS_CACHE_PREFETCH_AUDIO_STARTLO = 121, // Set low 32 bits of start. 310 | AVS_CACHE_PREFETCH_AUDIO_STARTHI = 122, // Set high 32 bits of start. 311 | AVS_CACHE_PREFETCH_AUDIO_COUNT = 123, // Set low 32 bits of length. 312 | AVS_CACHE_PREFETCH_AUDIO_COMMIT = 124, // Enqueue request transaction to prefetch audio (release critical section). 313 | AVS_CACHE_PREFETCH_AUDIO_GO = 125, // Action audio prefetches. 314 | 315 | AVS_CACHE_GETCHILD_CACHE_MODE = 200, // Cache ask Child for desired video cache mode. 316 | AVS_CACHE_GETCHILD_CACHE_SIZE = 201, // Cache ask Child for desired video cache size. 317 | AVS_CACHE_GETCHILD_AUDIO_MODE = 202, // Cache ask Child for desired audio cache mode. 318 | AVS_CACHE_GETCHILD_AUDIO_SIZE = 203, // Cache ask Child for desired audio cache size. 319 | 320 | AVS_CACHE_GETCHILD_COST = 220, // Cache ask Child for estimated processing cost. 321 | AVS_CACHE_COST_ZERO = 221, // Child response of zero cost (ptr arithmetic only). 322 | AVS_CACHE_COST_UNIT = 222, // Child response of unit cost (less than or equal 1 full frame blit). 323 | AVS_CACHE_COST_LOW = 223, // Child response of light cost. (Fast) 324 | AVS_CACHE_COST_MED = 224, // Child response of medium cost. (Real time) 325 | AVS_CACHE_COST_HI = 225, // Child response of heavy cost. (Slow) 326 | 327 | AVS_CACHE_GETCHILD_THREAD_MODE = 240, // Cache ask Child for thread safety. 328 | AVS_CACHE_THREAD_UNSAFE = 241, // Only 1 thread allowed for all instances. 2.5 filters default! 329 | AVS_CACHE_THREAD_CLASS = 242, // Only 1 thread allowed for each instance. 2.6 filters default! 330 | AVS_CACHE_THREAD_SAFE = 243, // Allow all threads in any instance. 331 | AVS_CACHE_THREAD_OWN = 244, // Safe but limit to 1 thread, internally threaded. 332 | 333 | AVS_CACHE_GETCHILD_ACCESS_COST = 260, // Cache ask Child for preferred access pattern. 334 | AVS_CACHE_ACCESS_RAND = 261, // Filter is access order agnostic. 335 | AVS_CACHE_ACCESS_SEQ0 = 262, // Filter prefers sequential access (low cost) 336 | AVS_CACHE_ACCESS_SEQ1 = 263, // Filter needs sequential access (high cost) 337 | 338 | AVS_CACHE_AVSPLUS_CONSTANTS = 500, // Smaller values are reserved for classic Avisynth 339 | 340 | AVS_CACHE_DONT_CACHE_ME = 501, // Filters that don't need caching (eg. trim, cache etc.) should return 1 to this request 341 | AVS_CACHE_SET_MIN_CAPACITY = 502, 342 | AVS_CACHE_SET_MAX_CAPACITY = 503, 343 | AVS_CACHE_GET_MIN_CAPACITY = 504, 344 | AVS_CACHE_GET_MAX_CAPACITY = 505, 345 | AVS_CACHE_GET_SIZE = 506, 346 | AVS_CACHE_GET_REQUESTED_CAP = 507, 347 | AVS_CACHE_GET_CAPACITY = 508, 348 | AVS_CACHE_GET_MTMODE = 509, 349 | 350 | AVS_CACHE_IS_CACHE_REQ = 510, 351 | AVS_CACHE_IS_CACHE_ANS = 511, 352 | AVS_CACHE_IS_MTGUARD_REQ = 512, 353 | AVS_CACHE_IS_MTGUARD_ANS = 513, 354 | 355 | AVS_CACHE_AVSPLUS_CUDA_CONSTANTS = 600, 356 | 357 | AVS_CACHE_GET_DEV_TYPE = 601, // Device types a filter can return 358 | AVS_CACHE_GET_CHILD_DEV_TYPE = 602, // Device types a fitler can receive 359 | 360 | AVS_CACHE_USER_CONSTANTS = 1000 // Smaller values are reserved for the core 361 | 362 | }; 363 | 364 | 365 | 366 | // enums for frame property functions 367 | // AVSPropTypes 368 | enum { 369 | AVS_PROPTYPE_UNSET = 'u', 370 | AVS_PROPTYPE_INT = 'i', 371 | AVS_PROPTYPE_FLOAT = 'f', 372 | AVS_PROPTYPE_DATA = 's', 373 | AVS_PROPTYPE_CLIP = 'c', 374 | AVS_PROPTYPE_FRAME = 'v' 375 | }; 376 | 377 | // AVSGetPropErrors for avs_prop_get_... 378 | enum { 379 | AVS_GETPROPERROR_UNSET = 1, 380 | AVS_GETPROPERROR_TYPE = 2, 381 | AVS_GETPROPERROR_INDEX = 4 382 | }; 383 | 384 | // AVSPropAppendMode for avs_prop_set_... 385 | enum { 386 | AVS_PROPAPPENDMODE_REPLACE = 0, 387 | AVS_PROPAPPENDMODE_APPEND = 1, 388 | AVS_PROPAPPENDMODE_TOUCH = 2 389 | }; 390 | 391 | // AvsEnvProperty for avs_get_env_property 392 | enum 393 | { 394 | AVS_AEP_PHYSICAL_CPUS = 1, 395 | AVS_AEP_LOGICAL_CPUS = 2, 396 | AVS_AEP_THREADPOOL_THREADS = 3, 397 | AVS_AEP_FILTERCHAIN_THREADS = 4, 398 | AVS_AEP_THREAD_ID = 5, 399 | AVS_AEP_VERSION = 6, 400 | 401 | // Neo additionals 402 | AVS_AEP_NUM_DEVICES = 901, 403 | AVS_AEP_FRAME_ALIGN = 902, 404 | AVS_AEP_PLANE_ALIGN = 903, 405 | 406 | AVS_AEP_SUPPRESS_THREAD = 921, 407 | AVS_AEP_GETFRAME_RECURSIVE = 922 408 | }; 409 | 410 | // enum AvsAllocType for avs_allocate 411 | enum { 412 | AVS_ALLOCTYPE_NORMAL_ALLOC = 1, 413 | AVS_ALLOCTYPE_POOLED_ALLOC = 2 414 | }; 415 | 416 | #ifdef BUILDING_AVSCORE 417 | AVSValue create_c_video_filter(AVSValue args, void * user_data, IScriptEnvironment * e0); 418 | 419 | struct AVS_ScriptEnvironment { 420 | IScriptEnvironment * env; 421 | const char * error; 422 | AVS_ScriptEnvironment(IScriptEnvironment * e = 0) 423 | : env(e), error(0) {} 424 | }; 425 | #endif 426 | 427 | typedef struct AVS_Clip AVS_Clip; 428 | typedef struct AVS_ScriptEnvironment AVS_ScriptEnvironment; 429 | 430 | ///////////////////////////////////////////////////////////////////// 431 | // 432 | // AVS_VideoInfo 433 | // 434 | 435 | // AVS_VideoInfo is laid out identically to VideoInfo 436 | typedef struct AVS_VideoInfo { 437 | int width, height; // width=0 means no video 438 | unsigned fps_numerator, fps_denominator; 439 | int num_frames; 440 | 441 | int pixel_type; 442 | 443 | int audio_samples_per_second; // 0 means no audio 444 | int sample_type; 445 | int64_t num_audio_samples; 446 | int nchannels; 447 | 448 | // Image type properties 449 | 450 | int image_type; 451 | } AVS_VideoInfo; 452 | 453 | // useful functions of the above 454 | AVSC_INLINE int avs_has_video(const AVS_VideoInfo * p) 455 | { return (p->width!=0); } 456 | 457 | AVSC_INLINE int avs_has_audio(const AVS_VideoInfo * p) 458 | { return (p->audio_samples_per_second!=0); } 459 | 460 | AVSC_INLINE int avs_is_rgb(const AVS_VideoInfo * p) 461 | { return !!(p->pixel_type&AVS_CS_BGR); } 462 | 463 | AVSC_INLINE int avs_is_rgb24(const AVS_VideoInfo * p) 464 | { return ((p->pixel_type&AVS_CS_BGR24)==AVS_CS_BGR24) && ((p->pixel_type & AVS_CS_SAMPLE_BITS_MASK) == AVS_CS_SAMPLE_BITS_8); } 465 | 466 | AVSC_INLINE int avs_is_rgb32(const AVS_VideoInfo * p) 467 | { return ((p->pixel_type&AVS_CS_BGR32)==AVS_CS_BGR32) && ((p->pixel_type & AVS_CS_SAMPLE_BITS_MASK) == AVS_CS_SAMPLE_BITS_8); } 468 | 469 | AVSC_INLINE int avs_is_yuv(const AVS_VideoInfo * p) 470 | { return !!(p->pixel_type&AVS_CS_YUV ); } 471 | 472 | AVSC_INLINE int avs_is_yuy2(const AVS_VideoInfo * p) 473 | { return (p->pixel_type & AVS_CS_YUY2) == AVS_CS_YUY2; } 474 | 475 | AVSC_API(int, avs_is_yv24)(const AVS_VideoInfo * p); // avs+: for generic 444 check, use avs_is_yuv444 476 | 477 | AVSC_API(int, avs_is_yv16)(const AVS_VideoInfo * p); // avs+: for generic 422 check, use avs_is_yuv422 478 | 479 | AVSC_API(int, avs_is_yv12)(const AVS_VideoInfo * p) ; // avs+: for generic 420 check, use avs_is_yuv420 480 | 481 | AVSC_API(int, avs_is_yv411)(const AVS_VideoInfo * p); 482 | 483 | AVSC_API(int, avs_is_y8)(const AVS_VideoInfo * p); // avs+: for generic grayscale, use avs_is_y 484 | 485 | AVSC_API(int, avs_get_plane_width_subsampling)(const AVS_VideoInfo * p, int plane); 486 | 487 | AVSC_API(int, avs_get_plane_height_subsampling)(const AVS_VideoInfo * p, int plane); 488 | 489 | AVSC_API(int, avs_bits_per_pixel)(const AVS_VideoInfo * p); 490 | 491 | AVSC_API(int, avs_bytes_from_pixels)(const AVS_VideoInfo * p, int pixels); 492 | 493 | AVSC_API(int, avs_row_size)(const AVS_VideoInfo * p, int plane); 494 | 495 | AVSC_API(int, avs_bmp_size)(const AVS_VideoInfo * vi); 496 | 497 | AVSC_API(int, avs_is_color_space)(const AVS_VideoInfo * p, int c_space); 498 | 499 | // no API for these, inline helper functions 500 | AVSC_INLINE int avs_is_property(const AVS_VideoInfo * p, int property) 501 | { 502 | return ((p->image_type & property) == property); 503 | } 504 | 505 | AVSC_INLINE int avs_is_planar(const AVS_VideoInfo * p) 506 | { 507 | return !!(p->pixel_type & AVS_CS_PLANAR); 508 | } 509 | 510 | AVSC_INLINE int avs_is_field_based(const AVS_VideoInfo * p) 511 | { 512 | return !!(p->image_type & AVS_IT_FIELDBASED); 513 | } 514 | 515 | AVSC_INLINE int avs_is_parity_known(const AVS_VideoInfo * p) 516 | { 517 | return ((p->image_type & AVS_IT_FIELDBASED) && (p->image_type & (AVS_IT_BFF | AVS_IT_TFF))); 518 | } 519 | 520 | AVSC_INLINE int avs_is_bff(const AVS_VideoInfo * p) 521 | { 522 | return !!(p->image_type & AVS_IT_BFF); 523 | } 524 | 525 | AVSC_INLINE int avs_is_tff(const AVS_VideoInfo * p) 526 | { 527 | return !!(p->image_type & AVS_IT_TFF); 528 | } 529 | 530 | AVSC_INLINE int avs_samples_per_second(const AVS_VideoInfo * p) 531 | { return p->audio_samples_per_second; } 532 | 533 | AVSC_INLINE int avs_bytes_per_channel_sample(const AVS_VideoInfo * p) 534 | { 535 | switch (p->sample_type) { 536 | case AVS_SAMPLE_INT8: return sizeof(signed char); 537 | case AVS_SAMPLE_INT16: return sizeof(signed short); 538 | case AVS_SAMPLE_INT24: return 3; 539 | case AVS_SAMPLE_INT32: return sizeof(signed int); 540 | case AVS_SAMPLE_FLOAT: return sizeof(float); 541 | default: return 0; 542 | } 543 | } 544 | 545 | AVSC_INLINE int avs_bytes_per_audio_sample(const AVS_VideoInfo * p) 546 | { return p->nchannels*avs_bytes_per_channel_sample(p);} 547 | 548 | AVSC_INLINE int64_t avs_audio_samples_from_frames(const AVS_VideoInfo * p, int64_t frames) 549 | { return ((int64_t)(frames) * p->audio_samples_per_second * p->fps_denominator / p->fps_numerator); } 550 | 551 | AVSC_INLINE int avs_frames_from_audio_samples(const AVS_VideoInfo * p, int64_t samples) 552 | { return (int)(samples * (int64_t)p->fps_numerator / (int64_t)p->fps_denominator / (int64_t)p->audio_samples_per_second); } 553 | 554 | AVSC_INLINE int64_t avs_audio_samples_from_bytes(const AVS_VideoInfo * p, int64_t bytes) 555 | { return bytes / avs_bytes_per_audio_sample(p); } 556 | 557 | AVSC_INLINE int64_t avs_bytes_from_audio_samples(const AVS_VideoInfo * p, int64_t samples) 558 | { return samples * avs_bytes_per_audio_sample(p); } 559 | 560 | AVSC_INLINE int avs_audio_channels(const AVS_VideoInfo * p) 561 | { return p->nchannels; } 562 | 563 | AVSC_INLINE int avs_sample_type(const AVS_VideoInfo * p) 564 | { return p->sample_type;} 565 | 566 | // useful mutator 567 | // Note: these are video format properties, neither frame properties, nor system properties 568 | AVSC_INLINE void avs_set_property(AVS_VideoInfo * p, int property) 569 | { p->image_type|=property; } 570 | 571 | AVSC_INLINE void avs_clear_property(AVS_VideoInfo * p, int property) 572 | { p->image_type&=~property; } 573 | 574 | AVSC_INLINE void avs_set_field_based(AVS_VideoInfo * p, int isfieldbased) 575 | { if (isfieldbased) p->image_type|=AVS_IT_FIELDBASED; else p->image_type&=~AVS_IT_FIELDBASED; } 576 | 577 | AVSC_INLINE void avs_set_fps(AVS_VideoInfo * p, unsigned numerator, unsigned denominator) 578 | { 579 | unsigned x=numerator, y=denominator; 580 | while (y) { // find gcd 581 | unsigned t = x%y; x = y; y = t; 582 | } 583 | p->fps_numerator = numerator/x; 584 | p->fps_denominator = denominator/x; 585 | } 586 | 587 | #ifndef AVSC_NO_DECLSPEC 588 | // this inline function is calling an API function 589 | AVSC_INLINE int avs_is_same_colorspace(const AVS_VideoInfo * x, const AVS_VideoInfo * y) 590 | { 591 | return (x->pixel_type == y->pixel_type) 592 | || (avs_is_yv12(x) && avs_is_yv12(y)); 593 | } 594 | #endif 595 | 596 | // AviSynth+ extensions 597 | AVSC_API(int, avs_is_rgb48)(const AVS_VideoInfo * p); 598 | 599 | AVSC_API(int, avs_is_rgb64)(const AVS_VideoInfo * p); 600 | 601 | AVSC_API(int, avs_is_yuv444p16)(const AVS_VideoInfo * p); // deprecated, use avs_is_yuv444 602 | AVSC_API(int, avs_is_yuv422p16)(const AVS_VideoInfo * p); // deprecated, use avs_is_yuv422 603 | AVSC_API(int, avs_is_yuv420p16)(const AVS_VideoInfo * p); // deprecated, use avs_is_yuv420 604 | AVSC_API(int, avs_is_y16)(const AVS_VideoInfo * p); // deprecated, use avs_is_y 605 | AVSC_API(int, avs_is_yuv444ps)(const AVS_VideoInfo * p); // deprecated, use avs_is_yuv444 606 | AVSC_API(int, avs_is_yuv422ps)(const AVS_VideoInfo * p); // deprecated, use avs_is_yuv422 607 | AVSC_API(int, avs_is_yuv420ps)(const AVS_VideoInfo * p); // deprecated, use avs_is_yuv420 608 | AVSC_API(int, avs_is_y32)(const AVS_VideoInfo * p); // deprecated, use avs_is_y 609 | 610 | AVSC_API(int, avs_is_444)(const AVS_VideoInfo * p); 611 | 612 | AVSC_API(int, avs_is_422)(const AVS_VideoInfo * p); 613 | 614 | AVSC_API(int, avs_is_420)(const AVS_VideoInfo * p); 615 | 616 | AVSC_API(int, avs_is_y)(const AVS_VideoInfo * p); 617 | 618 | AVSC_API(int, avs_is_yuva)(const AVS_VideoInfo * p); 619 | 620 | AVSC_API(int, avs_is_planar_rgb)(const AVS_VideoInfo * p); 621 | 622 | AVSC_API(int, avs_is_planar_rgba)(const AVS_VideoInfo * p); 623 | 624 | AVSC_API(int, avs_num_components)(const AVS_VideoInfo * p); 625 | 626 | AVSC_API(int, avs_component_size)(const AVS_VideoInfo * p); 627 | 628 | AVSC_API(int, avs_bits_per_component)(const AVS_VideoInfo * p); 629 | 630 | // end of Avisynth+ specific 631 | 632 | ///////////////////////////////////////////////////////////////////// 633 | // 634 | // AVS_VideoFrame 635 | // 636 | 637 | // VideoFrameBuffer holds information about a memory block which is used 638 | // for video data. For efficiency, instances of this class are not deleted 639 | // when the refcount reaches zero; instead they're stored in a linked list 640 | // to be reused. The instances are deleted when the corresponding AVS 641 | // file is closed. 642 | 643 | // AVS_VideoFrameBuffer is laid out identically to VideoFrameBuffer 644 | // DO NOT USE THIS STRUCTURE DIRECTLY 645 | typedef struct AVS_VideoFrameBuffer { 646 | BYTE * data; 647 | int data_size; 648 | // sequence_number is incremented every time the buffer is changed, so 649 | // that stale views can tell they're no longer valid. 650 | volatile long sequence_number; 651 | 652 | volatile long refcount; 653 | 654 | void* device; // avs+ 655 | } AVS_VideoFrameBuffer; 656 | 657 | // VideoFrame holds a "window" into a VideoFrameBuffer. 658 | 659 | // AVS_VideoFrame is laid out identically to IVideoFrame 660 | // DO NOT USE THIS STRUCTURE DIRECTLY 661 | typedef struct AVS_VideoFrame { 662 | volatile long refcount; 663 | AVS_VideoFrameBuffer * vfb; 664 | int offset; 665 | int pitch, row_size, height; 666 | int offsetU, offsetV; 667 | int pitchUV; // U&V offsets are from top of picture. 668 | int row_sizeUV, heightUV; // for Planar RGB offsetU, offsetV is for the 2nd and 3rd Plane. 669 | // for Planar RGB pitchUV and row_sizeUV = 0, because when no VideoInfo (MakeWriteable) 670 | // the decision on existence of UV is checked by zero pitch 671 | // AVS+ extension, avisynth.h: class does not break plugins if appended here 672 | int offsetA; 673 | int pitchA, row_sizeA; // 4th alpha plane support, pitch and row_size is 0 is none 674 | void* properties; // frame properties 675 | } AVS_VideoFrame; 676 | 677 | // Access functions for AVS_VideoFrame 678 | AVSC_API(int, avs_get_pitch_p)(const AVS_VideoFrame * p, int plane); 679 | 680 | AVSC_API(int, avs_get_row_size_p)(const AVS_VideoFrame * p, int plane); 681 | 682 | AVSC_API(int, avs_get_height_p)(const AVS_VideoFrame * p, int plane); 683 | 684 | AVSC_API(const BYTE *, avs_get_read_ptr_p)(const AVS_VideoFrame * p, int plane); 685 | 686 | AVSC_API(int, avs_is_writable)(const AVS_VideoFrame * p); 687 | 688 | AVSC_API(BYTE *, avs_get_write_ptr_p)(const AVS_VideoFrame * p, int plane); 689 | 690 | AVSC_API(void, avs_release_video_frame)(AVS_VideoFrame *); 691 | // makes a shallow copy of a video frame 692 | AVSC_API(AVS_VideoFrame *, avs_copy_video_frame)(AVS_VideoFrame *); 693 | 694 | // no API for these, inline helper functions 695 | #ifndef AVSC_NO_DECLSPEC 696 | // this inline function is calling an API function 697 | AVSC_INLINE int avs_get_pitch(const AVS_VideoFrame * p) { 698 | return avs_get_pitch_p(p, 0); 699 | } 700 | #endif 701 | 702 | #ifndef AVSC_NO_DECLSPEC 703 | // this inline function is calling an API function 704 | AVSC_INLINE int avs_get_row_size(const AVS_VideoFrame * p) { 705 | return avs_get_row_size_p(p, 0); } 706 | #endif 707 | 708 | 709 | #ifndef AVSC_NO_DECLSPEC 710 | // this inline function is calling an API function 711 | AVSC_INLINE int avs_get_height(const AVS_VideoFrame * p) { 712 | return avs_get_height_p(p, 0); 713 | } 714 | #endif 715 | 716 | #ifndef AVSC_NO_DECLSPEC 717 | // this inline function is calling an API function 718 | AVSC_INLINE const BYTE* avs_get_read_ptr(const AVS_VideoFrame * p) { 719 | return avs_get_read_ptr_p(p, 0);} 720 | #endif 721 | 722 | #ifndef AVSC_NO_DECLSPEC 723 | // this inline function is calling an API function 724 | AVSC_INLINE BYTE* avs_get_write_ptr(const AVS_VideoFrame * p) { 725 | return avs_get_write_ptr_p(p, 0);} 726 | #endif 727 | 728 | #ifndef AVSC_NO_DECLSPEC 729 | // this inline function is calling an API function 730 | AVSC_INLINE void avs_release_frame(AVS_VideoFrame * f) 731 | {avs_release_video_frame(f);} 732 | #endif 733 | 734 | #ifndef AVSC_NO_DECLSPEC 735 | // this inline function is calling an API function 736 | AVSC_INLINE AVS_VideoFrame * avs_copy_frame(AVS_VideoFrame * f) 737 | {return avs_copy_video_frame(f);} 738 | #endif 739 | 740 | // Interface V8: frame properties 741 | // AVS_Map is just a placeholder for AVSMap 742 | typedef struct AVS_Map { 743 | void* data; 744 | } AVS_Map; 745 | 746 | 747 | ///////////////////////////////////////////////////////////////////// 748 | // 749 | // AVS_Value 750 | // 751 | 752 | // Treat AVS_Value as a fat pointer. That is use avs_copy_value 753 | // and avs_release_value appropriately as you would if AVS_Value was 754 | // a pointer. 755 | 756 | // To maintain source code compatibility with future versions of the 757 | // avisynth_c API don't use the AVS_Value directly. Use the helper 758 | // functions below. 759 | 760 | // AVS_Value is laid out identically to AVSValue 761 | typedef struct AVS_Value AVS_Value; 762 | struct AVS_Value { 763 | short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong, or fu'n'ction 764 | // for some function e'rror 765 | short array_size; 766 | union { 767 | void * clip; // do not use directly, use avs_take_clip 768 | char boolean; 769 | int integer; 770 | float floating_pt; 771 | const char * string; 772 | const AVS_Value * array; 773 | void * function; // not supported on C interface 774 | #ifdef X86_64 775 | // if ever, only x64 will support. It breaks struct size on 32 bit 776 | int64_t longlong; // 8 bytes 777 | double double_pt; // 8 bytes 778 | #endif 779 | } d; 780 | }; 781 | 782 | // AVS_Value should be initialized with avs_void. 783 | // Should also set to avs_void after the value is released 784 | // with avs_copy_value. Consider it the equivalent of setting 785 | // a pointer to NULL 786 | static const AVS_Value avs_void = {'v'}; 787 | 788 | AVSC_API(void, avs_copy_value)(AVS_Value * dest, AVS_Value src); 789 | AVSC_API(void, avs_release_value)(AVS_Value); 790 | AVSC_API(AVS_Clip *, avs_take_clip)(AVS_Value, AVS_ScriptEnvironment *); 791 | AVSC_API(void, avs_set_to_clip)(AVS_Value *, AVS_Clip *); 792 | 793 | 794 | // no API for these, inline helper functions 795 | AVSC_INLINE int avs_defined(AVS_Value v) { return v.type != 'v'; } 796 | AVSC_INLINE int avs_is_clip(AVS_Value v) { return v.type == 'c'; } 797 | AVSC_INLINE int avs_is_bool(AVS_Value v) { return v.type == 'b'; } 798 | AVSC_INLINE int avs_is_int(AVS_Value v) { return v.type == 'i'; } 799 | AVSC_INLINE int avs_is_float(AVS_Value v) { return v.type == 'f' || v.type == 'i'; } 800 | AVSC_INLINE int avs_is_string(AVS_Value v) { return v.type == 's'; } 801 | AVSC_INLINE int avs_is_array(AVS_Value v) { return v.type == 'a'; } 802 | AVSC_INLINE int avs_is_error(AVS_Value v) { return v.type == 'e'; } 803 | 804 | AVSC_INLINE int avs_as_bool(AVS_Value v) 805 | { return v.d.boolean; } 806 | AVSC_INLINE int avs_as_int(AVS_Value v) 807 | { return v.d.integer; } 808 | AVSC_INLINE const char * avs_as_string(AVS_Value v) 809 | { return avs_is_error(v) || avs_is_string(v) ? v.d.string : 0; } 810 | AVSC_INLINE double avs_as_float(AVS_Value v) 811 | { return avs_is_int(v) ? v.d.integer : v.d.floating_pt; } 812 | AVSC_INLINE const char * avs_as_error(AVS_Value v) 813 | { return avs_is_error(v) ? v.d.string : 0; } 814 | AVSC_INLINE const AVS_Value * avs_as_array(AVS_Value v) 815 | { return v.d.array; } 816 | AVSC_INLINE int avs_array_size(AVS_Value v) 817 | { return avs_is_array(v) ? v.array_size : 1; } 818 | AVSC_INLINE AVS_Value avs_array_elt(AVS_Value v, int index) 819 | { return avs_is_array(v) ? v.d.array[index] : v; } 820 | 821 | // only use these functions on an AVS_Value that does not already have 822 | // an active value. Remember, treat AVS_Value as a fat pointer. 823 | AVSC_INLINE AVS_Value avs_new_value_bool(int v0) 824 | { AVS_Value v; v.type = 'b'; v.d.boolean = v0 == 0 ? 0 : 1; return v; } 825 | AVSC_INLINE AVS_Value avs_new_value_int(int v0) 826 | { AVS_Value v; v.type = 'i'; v.d.integer = v0; return v; } 827 | AVSC_INLINE AVS_Value avs_new_value_string(const char * v0) 828 | { AVS_Value v; v.type = 's'; v.d.string = v0; return v; } 829 | AVSC_INLINE AVS_Value avs_new_value_float(float v0) 830 | { AVS_Value v; v.type = 'f'; v.d.floating_pt = v0; return v;} 831 | AVSC_INLINE AVS_Value avs_new_value_error(const char * v0) 832 | { AVS_Value v; v.type = 'e'; v.d.string = v0; return v; } 833 | #ifndef AVSC_NO_DECLSPEC 834 | // this inline function is calling an API function 835 | AVSC_INLINE AVS_Value avs_new_value_clip(AVS_Clip * v0) 836 | { AVS_Value v; avs_set_to_clip(&v, v0); return v; } 837 | #endif 838 | AVSC_INLINE AVS_Value avs_new_value_array(AVS_Value * v0, int size) 839 | { AVS_Value v; v.type = 'a'; v.d.array = v0; v.array_size = (short)size; return v; } 840 | // end of inline helper functions 841 | 842 | ///////////////////////////////////////////////////////////////////// 843 | // 844 | // AVS_Clip 845 | // 846 | 847 | AVSC_API(void, avs_release_clip)(AVS_Clip *); 848 | AVSC_API(AVS_Clip *, avs_copy_clip)(AVS_Clip *); 849 | 850 | AVSC_API(const char *, avs_clip_get_error)(AVS_Clip *); // return 0 if no error 851 | 852 | AVSC_API(const AVS_VideoInfo *, avs_get_video_info)(AVS_Clip *); 853 | 854 | AVSC_API(int, avs_get_version)(AVS_Clip *); 855 | 856 | AVSC_API(AVS_VideoFrame *, avs_get_frame)(AVS_Clip *, int n); 857 | // The returned video frame must be released with avs_release_video_frame 858 | 859 | AVSC_API(int, avs_get_parity)(AVS_Clip *, int n); 860 | // return field parity if field_based, else parity of first field in frame 861 | 862 | AVSC_API(int, avs_get_audio)(AVS_Clip *, void * buf, 863 | int64_t start, int64_t count); 864 | // start and count are in samples 865 | 866 | AVSC_API(int, avs_set_cache_hints)(AVS_Clip *, 867 | int cachehints, int frame_range); 868 | 869 | // This is the callback type used by avs_add_function 870 | typedef AVS_Value (AVSC_CC * AVS_ApplyFunc) 871 | (AVS_ScriptEnvironment *, AVS_Value args, void * user_data); 872 | 873 | typedef struct AVS_FilterInfo AVS_FilterInfo; 874 | struct AVS_FilterInfo 875 | { 876 | // these members should not be modified outside of the AVS_ApplyFunc callback 877 | AVS_Clip * child; 878 | AVS_VideoInfo vi; 879 | AVS_ScriptEnvironment * env; 880 | AVS_VideoFrame * (AVSC_CC * get_frame)(AVS_FilterInfo *, int n); 881 | int (AVSC_CC * get_parity)(AVS_FilterInfo *, int n); 882 | int (AVSC_CC * get_audio)(AVS_FilterInfo *, void * buf, 883 | int64_t start, int64_t count); 884 | int (AVSC_CC * set_cache_hints)(AVS_FilterInfo *, int cachehints, 885 | int frame_range); 886 | void (AVSC_CC * free_filter)(AVS_FilterInfo *); 887 | 888 | // Should be set when ever there is an error to report. 889 | // It is cleared before any of the above methods are called 890 | const char * error; 891 | // this is to store whatever and may be modified at will 892 | void * user_data; 893 | }; 894 | 895 | // Create a new filter 896 | // fi is set to point to the AVS_FilterInfo so that you can 897 | // modify it once it is initialized. 898 | // store_child should generally be set to true. If it is not 899 | // set than ALL methods (the function pointers) must be defined 900 | // If it is set than you do not need to worry about freeing the child 901 | // clip. 902 | AVSC_API(AVS_Clip *, avs_new_c_filter)(AVS_ScriptEnvironment * e, 903 | AVS_FilterInfo * * fi, 904 | AVS_Value child, int store_child); 905 | 906 | ///////////////////////////////////////////////////////////////////// 907 | // 908 | // AVS_ScriptEnvironment 909 | // 910 | 911 | // For GetCPUFlags. These are backwards-compatible with those in VirtualDub. 912 | enum { 913 | /* slowest CPU to support extension */ 914 | AVS_CPU_FORCE = 0x01, // N/A 915 | AVS_CPU_FPU = 0x02, // 386/486DX 916 | AVS_CPU_MMX = 0x04, // P55C, K6, PII 917 | AVS_CPU_INTEGER_SSE = 0x08, // PIII, Athlon 918 | AVS_CPU_SSE = 0x10, // PIII, Athlon XP/MP 919 | AVS_CPU_SSE2 = 0x20, // PIV, Hammer 920 | AVS_CPU_3DNOW = 0x40, // K6-2 921 | AVS_CPU_3DNOW_EXT = 0x80, // Athlon 922 | AVS_CPU_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, 923 | // which only Hammer will have anyway) 924 | AVS_CPUF_SSE3 = 0x100, // PIV+, K8 Venice 925 | AVS_CPUF_SSSE3 = 0x200, // Core 2 926 | AVS_CPUF_SSE4 = 0x400, // Penryn, Wolfdale, Yorkfield 927 | AVS_CPUF_SSE4_1 = 0x400, 928 | AVS_CPUF_AVX = 0x800, // Sandy Bridge, Bulldozer 929 | AVS_CPUF_SSE4_2 = 0x1000, // Nehalem 930 | // AVS+ 931 | AVS_CPUF_AVX2 = 0x2000, // Haswell 932 | AVS_CPUF_FMA3 = 0x4000, 933 | AVS_CPUF_F16C = 0x8000, 934 | AVS_CPUF_MOVBE = 0x10000, // Big Endian Move 935 | AVS_CPUF_POPCNT = 0x20000, 936 | AVS_CPUF_AES = 0x40000, 937 | AVS_CPUF_FMA4 = 0x80000, 938 | 939 | AVS_CPUF_AVX512F = 0x100000, // AVX-512 Foundation. 940 | AVS_CPUF_AVX512DQ = 0x200000, // AVX-512 DQ (Double/Quad granular) Instructions 941 | AVS_CPUF_AVX512PF = 0x400000, // AVX-512 Prefetch 942 | AVS_CPUF_AVX512ER = 0x800000, // AVX-512 Exponential and Reciprocal 943 | AVS_CPUF_AVX512CD = 0x1000000, // AVX-512 Conflict Detection 944 | AVS_CPUF_AVX512BW = 0x2000000, // AVX-512 BW (Byte/Word granular) Instructions 945 | AVS_CPUF_AVX512VL = 0x4000000, // AVX-512 VL (128/256 Vector Length) Extensions 946 | AVS_CPUF_AVX512IFMA = 0x8000000, // AVX-512 IFMA integer 52 bit 947 | AVS_CPUF_AVX512VBMI = 0x10000000 // AVX-512 VBMI 948 | }; 949 | 950 | 951 | AVSC_API(const char *, avs_get_error)(AVS_ScriptEnvironment *); // return 0 if no error 952 | 953 | AVSC_API(int, avs_get_cpu_flags)(AVS_ScriptEnvironment *); 954 | AVSC_API(int, avs_check_version)(AVS_ScriptEnvironment *, int version); 955 | 956 | AVSC_API(char *, avs_save_string)(AVS_ScriptEnvironment *, const char* s, int length); 957 | AVSC_API(char *, avs_sprintf)(AVS_ScriptEnvironment *, const char * fmt, ...); 958 | 959 | AVSC_API(char *, avs_vsprintf)(AVS_ScriptEnvironment *, const char * fmt, va_list val); 960 | 961 | AVSC_API(int, avs_add_function)(AVS_ScriptEnvironment *, 962 | const char * name, const char * params, 963 | AVS_ApplyFunc apply, void * user_data); 964 | 965 | AVSC_API(int, avs_function_exists)(AVS_ScriptEnvironment *, const char * name); 966 | 967 | AVSC_API(AVS_Value, avs_invoke)(AVS_ScriptEnvironment *, const char * name, 968 | AVS_Value args, const char** arg_names); 969 | // The returned value must be be released with avs_release_value 970 | 971 | AVSC_API(AVS_Value, avs_get_var)(AVS_ScriptEnvironment *, const char* name); 972 | // The returned value must be be released with avs_release_value 973 | 974 | AVSC_API(int, avs_set_var)(AVS_ScriptEnvironment *, const char* name, AVS_Value val); 975 | 976 | AVSC_API(int, avs_set_global_var)(AVS_ScriptEnvironment *, const char* name, const AVS_Value val); 977 | 978 | //void avs_push_context(AVS_ScriptEnvironment *, int level=0); 979 | //void avs_pop_context(AVS_ScriptEnvironment *); 980 | 981 | // partially deprecated, from V8 use avs_new_video_frame_p_a (frame property copy) 982 | AVSC_API(AVS_VideoFrame *, avs_new_video_frame_a)(AVS_ScriptEnvironment *, 983 | const AVS_VideoInfo * vi, int align); 984 | // align should be at least 16 for classic Avisynth 985 | // Avisynth+: any value, Avs+ ensures a minimum alignment if too small align is provided 986 | 987 | // no API for these, inline helper functions 988 | #ifndef AVSC_NO_DECLSPEC 989 | // partially deprecated, from V8 use avs_new_video_frame_p (frame property copy) 990 | // this inline function is calling an API function 991 | AVSC_INLINE AVS_VideoFrame * avs_new_video_frame(AVS_ScriptEnvironment * env, 992 | const AVS_VideoInfo * vi) 993 | {return avs_new_video_frame_a(env,vi,AVS_FRAME_ALIGN);} 994 | 995 | // an older compatibility alias 996 | // this inline function is calling an API function 997 | AVSC_INLINE AVS_VideoFrame * avs_new_frame(AVS_ScriptEnvironment * env, 998 | const AVS_VideoInfo * vi) 999 | {return avs_new_video_frame_a(env,vi,AVS_FRAME_ALIGN);} 1000 | #endif 1001 | // end of inline helper functions 1002 | 1003 | AVSC_API(int, avs_make_writable)(AVS_ScriptEnvironment *, AVS_VideoFrame * * pvf); 1004 | 1005 | AVSC_API(void, avs_bit_blt)(AVS_ScriptEnvironment *, BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height); 1006 | 1007 | typedef void (AVSC_CC *AVS_ShutdownFunc)(void* user_data, AVS_ScriptEnvironment * env); 1008 | AVSC_API(void, avs_at_exit)(AVS_ScriptEnvironment *, AVS_ShutdownFunc function, void * user_data); 1009 | 1010 | AVSC_API(AVS_VideoFrame *, avs_subframe)(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height); 1011 | // The returned video frame must be be released 1012 | AVSC_API(AVS_VideoFrame*, avs_subframe_planar)(AVS_ScriptEnvironment*, AVS_VideoFrame* src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV); 1013 | // The returned video frame must be be released 1014 | // see also avs_subframe_planar_a in interface V8 1015 | 1016 | AVSC_API(int, avs_set_memory_max)(AVS_ScriptEnvironment *, int mem); 1017 | 1018 | AVSC_API(int, avs_set_working_dir)(AVS_ScriptEnvironment *, const char * newdir); 1019 | 1020 | // avisynth.dll exports this; it's a way to use it as a library, without 1021 | // writing an AVS script or without going through AVIFile. 1022 | AVSC_API(AVS_ScriptEnvironment *, avs_create_script_environment)(int version); 1023 | 1024 | // this symbol is the entry point for the plugin and must 1025 | // be defined 1026 | AVSC_EXPORT 1027 | const char * AVSC_CC avisynth_c_plugin_init(AVS_ScriptEnvironment* env); 1028 | 1029 | 1030 | AVSC_API(void, avs_delete_script_environment)(AVS_ScriptEnvironment *); 1031 | 1032 | /////////////////////////////////////////////////////////////////////////////// 1033 | // 1034 | // Avisynth+ V8 interface elements 1035 | // 1036 | 1037 | AVSC_API(AVS_VideoFrame*, avs_subframe_planar_a)(AVS_ScriptEnvironment*, AVS_VideoFrame* src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV, int rel_offsetA); 1038 | // The returned video frame must be be released 1039 | 1040 | AVSC_API(void, avs_copy_frame_props)(AVS_ScriptEnvironment* p, const AVS_VideoFrame* src, AVS_VideoFrame* dst); 1041 | AVSC_API(const AVS_Map*, avs_get_frame_props_ro)(AVS_ScriptEnvironment* p, const AVS_VideoFrame* frame); 1042 | AVSC_API(AVS_Map*, avs_get_frame_props_rw)(AVS_ScriptEnvironment* p, AVS_VideoFrame* frame); 1043 | AVSC_API(int, avs_prop_num_keys)(AVS_ScriptEnvironment* p, const AVS_Map* map); 1044 | AVSC_API(const char*, avs_prop_get_key)(AVS_ScriptEnvironment* p, const AVS_Map* map, int index); 1045 | AVSC_API(int, avs_prop_num_elements)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key); 1046 | 1047 | // see AVS_PROPTYPE_... enums 1048 | AVSC_API(char, avs_prop_get_type)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key); 1049 | 1050 | // see AVS_GETPROPERROR_... enums 1051 | AVSC_API(int64_t, avs_prop_get_int)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key, int index, int* error); 1052 | AVSC_API(double, avs_prop_get_float)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key, int index, int* error); 1053 | AVSC_API(const char*, avs_prop_get_data)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key, int index, int* error); 1054 | AVSC_API(int, avs_prop_get_data_size)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key, int index, int* error); 1055 | AVSC_API(AVS_Clip*, avs_prop_get_clip)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key, int index, int* error); 1056 | AVSC_API(const AVS_VideoFrame*, avs_prop_get_frame)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key, int index, int* error); 1057 | 1058 | AVSC_API(int, avs_prop_delete_key)(AVS_ScriptEnvironment* p, AVS_Map* map, const char* key); 1059 | 1060 | // see AVS_PROPAPPENDMODE_... enums 1061 | AVSC_API(int, avs_prop_set_int)(AVS_ScriptEnvironment* p, AVS_Map* map, const char* key, int64_t i, int append); 1062 | AVSC_API(int, avs_prop_set_float)(AVS_ScriptEnvironment* p, AVS_Map* map, const char* key, double d, int append); 1063 | AVSC_API(int, avs_prop_set_data)(AVS_ScriptEnvironment* p, AVS_Map* map, const char* key, const char* d, int length, int append); 1064 | AVSC_API(int, avs_prop_set_clip)(AVS_ScriptEnvironment* p, AVS_Map* map, const char* key, AVS_Clip* clip, int append); 1065 | AVSC_API(int, avs_prop_set_frame)(AVS_ScriptEnvironment* p, AVS_Map* map, const char* key, const AVS_VideoFrame* frame, int append); 1066 | 1067 | AVSC_API(const int64_t*, avs_prop_get_int_array)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key, int* error); 1068 | AVSC_API(const double*, avs_prop_get_float_array)(AVS_ScriptEnvironment* p, const AVS_Map* map, const char* key, int* error); 1069 | AVSC_API(int, avs_prop_set_int_array)(AVS_ScriptEnvironment* p, AVS_Map* map, const char* key, const int64_t* i, int size); 1070 | AVSC_API(int, avs_prop_set_float_array)(AVS_ScriptEnvironment* p, AVS_Map* map, const char* key, const double* d, int size); 1071 | 1072 | AVSC_API(void, avs_clear_map)(AVS_ScriptEnvironment* p, AVS_Map* map); 1073 | 1074 | // with frame property source 1075 | AVSC_API(AVS_VideoFrame*, avs_new_video_frame_p)(AVS_ScriptEnvironment*, 1076 | const AVS_VideoInfo* vi, AVS_VideoFrame* propSrc); 1077 | 1078 | // with frame property source 1079 | AVSC_API(AVS_VideoFrame*, avs_new_video_frame_p_a)(AVS_ScriptEnvironment*, 1080 | const AVS_VideoInfo* vi, AVS_VideoFrame* propSrc, int align); 1081 | 1082 | // Generic query to ask for various system properties, see AVS_AEP_xxx enums 1083 | AVSC_API(size_t, avs_get_env_property)(AVS_ScriptEnvironment*, int avs_aep_prop); 1084 | 1085 | // buffer pool, see AVS_ALLOCTYPE enums 1086 | AVSC_API(void *, avs_pool_allocate)(AVS_ScriptEnvironment*, size_t nBytes, size_t alignment, int avs_alloc_type); 1087 | AVSC_API(void, avs_pool_free)(AVS_ScriptEnvironment*, void *ptr); 1088 | 1089 | // Interface V8 1090 | // Returns TRUE (1) and the requested variable. If the method fails, returns 0 (FALSE) and does not touch 'val'. 1091 | // The returned AVS_Value *val value must be be released with avs_release_value only on success 1092 | // AVS_Value *val is not caller allocated 1093 | AVSC_API(int, avs_get_var_try)(AVS_ScriptEnvironment*, const char* name, AVS_Value* val); 1094 | 1095 | // Interface V8 1096 | // Return the value of the requested variable. 1097 | // If the variable was not found or had the wrong type, 1098 | // return the supplied default value. 1099 | AVSC_API(int, avs_get_var_bool)(AVS_ScriptEnvironment*, const char* name, int def); 1100 | AVSC_API(int, avs_get_var_int)(AVS_ScriptEnvironment*, const char* name, int def); 1101 | AVSC_API(double, avs_get_var_double)(AVS_ScriptEnvironment*, const char* name, double def); 1102 | AVSC_API(const char*, avs_get_var_string)(AVS_ScriptEnvironment*, const char* name, const char* def); 1103 | AVSC_API(int64_t, avs_get_var_long)(AVS_ScriptEnvironment*, const char* name, int64_t def); 1104 | 1105 | #if defined(AVS_WINDOWS) 1106 | // The following stuff is only relevant for Windows DLL handling; Linux does it completely differently. 1107 | #ifdef AVSC_NO_DECLSPEC 1108 | // This part uses LoadLibrary and related functions to dynamically load Avisynth instead of declspec(dllimport) 1109 | // When AVSC_NO_DECLSPEC is defined, you can use avs_load_library to populate API functions into a struct 1110 | // AVSC_INLINE functions which call onto an API functions should be treated specially (todo) 1111 | 1112 | /* 1113 | The following functions needs to have been declared, probably from windows.h 1114 | 1115 | void* malloc(size_t) 1116 | void free(void*); 1117 | 1118 | HMODULE LoadLibraryA(const char*); 1119 | void* GetProcAddress(HMODULE, const char*); 1120 | FreeLibrary(HMODULE); 1121 | */ 1122 | 1123 | 1124 | typedef struct AVS_Library AVS_Library; 1125 | 1126 | #define AVSC_DECLARE_FUNC(name) name##_func name 1127 | 1128 | // AVSC_DECLARE_FUNC helps keeping naming convention: type is xxxxx_func, function name is xxxxx 1129 | // e.g. "AVSC_DECLARE_FUNC(avs_add_function);" 1130 | // is a shortcut for "avs_add_function_func avs_add_function;" 1131 | 1132 | // Note: AVSC_INLINE functions which call into API, 1133 | // are guarded by #ifndef AVSC_NO_DECLSPEC 1134 | // They should call the appropriate library-> API entry 1135 | 1136 | struct AVS_Library { 1137 | HMODULE handle; 1138 | 1139 | AVSC_DECLARE_FUNC(avs_add_function); 1140 | AVSC_DECLARE_FUNC(avs_at_exit); 1141 | AVSC_DECLARE_FUNC(avs_bit_blt); 1142 | AVSC_DECLARE_FUNC(avs_check_version); 1143 | AVSC_DECLARE_FUNC(avs_clip_get_error); 1144 | AVSC_DECLARE_FUNC(avs_copy_clip); 1145 | AVSC_DECLARE_FUNC(avs_copy_value); 1146 | AVSC_DECLARE_FUNC(avs_copy_video_frame); 1147 | AVSC_DECLARE_FUNC(avs_create_script_environment); 1148 | AVSC_DECLARE_FUNC(avs_delete_script_environment); 1149 | AVSC_DECLARE_FUNC(avs_function_exists); 1150 | AVSC_DECLARE_FUNC(avs_get_audio); 1151 | AVSC_DECLARE_FUNC(avs_get_cpu_flags); 1152 | AVSC_DECLARE_FUNC(avs_get_frame); 1153 | AVSC_DECLARE_FUNC(avs_get_parity); 1154 | AVSC_DECLARE_FUNC(avs_get_var); 1155 | AVSC_DECLARE_FUNC(avs_get_version); 1156 | AVSC_DECLARE_FUNC(avs_get_video_info); 1157 | AVSC_DECLARE_FUNC(avs_invoke); 1158 | AVSC_DECLARE_FUNC(avs_make_writable); 1159 | AVSC_DECLARE_FUNC(avs_new_c_filter); 1160 | AVSC_DECLARE_FUNC(avs_new_video_frame_a); 1161 | AVSC_DECLARE_FUNC(avs_release_clip); 1162 | AVSC_DECLARE_FUNC(avs_release_value); 1163 | AVSC_DECLARE_FUNC(avs_release_video_frame); 1164 | AVSC_DECLARE_FUNC(avs_save_string); 1165 | AVSC_DECLARE_FUNC(avs_set_cache_hints); 1166 | AVSC_DECLARE_FUNC(avs_set_global_var); 1167 | AVSC_DECLARE_FUNC(avs_set_memory_max); 1168 | AVSC_DECLARE_FUNC(avs_set_to_clip); 1169 | AVSC_DECLARE_FUNC(avs_set_var); 1170 | AVSC_DECLARE_FUNC(avs_set_working_dir); 1171 | AVSC_DECLARE_FUNC(avs_sprintf); 1172 | AVSC_DECLARE_FUNC(avs_subframe); 1173 | AVSC_DECLARE_FUNC(avs_subframe_planar); 1174 | AVSC_DECLARE_FUNC(avs_take_clip); 1175 | AVSC_DECLARE_FUNC(avs_vsprintf); 1176 | 1177 | AVSC_DECLARE_FUNC(avs_get_error); 1178 | AVSC_DECLARE_FUNC(avs_is_yv24); 1179 | AVSC_DECLARE_FUNC(avs_is_yv16); 1180 | AVSC_DECLARE_FUNC(avs_is_yv12); 1181 | AVSC_DECLARE_FUNC(avs_is_yv411); 1182 | AVSC_DECLARE_FUNC(avs_is_y8); 1183 | AVSC_DECLARE_FUNC(avs_is_color_space); 1184 | 1185 | AVSC_DECLARE_FUNC(avs_get_plane_width_subsampling); 1186 | AVSC_DECLARE_FUNC(avs_get_plane_height_subsampling); 1187 | AVSC_DECLARE_FUNC(avs_bits_per_pixel); 1188 | AVSC_DECLARE_FUNC(avs_bytes_from_pixels); 1189 | AVSC_DECLARE_FUNC(avs_row_size); 1190 | AVSC_DECLARE_FUNC(avs_bmp_size); 1191 | AVSC_DECLARE_FUNC(avs_get_pitch_p); 1192 | AVSC_DECLARE_FUNC(avs_get_row_size_p); 1193 | AVSC_DECLARE_FUNC(avs_get_height_p); 1194 | AVSC_DECLARE_FUNC(avs_get_read_ptr_p); 1195 | AVSC_DECLARE_FUNC(avs_is_writable); 1196 | AVSC_DECLARE_FUNC(avs_get_write_ptr_p); 1197 | 1198 | // Avisynth+ specific 1199 | // Note: these functions are simulated/use fallback to existing functions 1200 | AVSC_DECLARE_FUNC(avs_is_rgb48); 1201 | AVSC_DECLARE_FUNC(avs_is_rgb64); 1202 | AVSC_DECLARE_FUNC(avs_is_yuv444p16); 1203 | AVSC_DECLARE_FUNC(avs_is_yuv422p16); 1204 | AVSC_DECLARE_FUNC(avs_is_yuv420p16); 1205 | AVSC_DECLARE_FUNC(avs_is_y16); 1206 | AVSC_DECLARE_FUNC(avs_is_yuv444ps); 1207 | AVSC_DECLARE_FUNC(avs_is_yuv422ps); 1208 | AVSC_DECLARE_FUNC(avs_is_yuv420ps); 1209 | AVSC_DECLARE_FUNC(avs_is_y32); 1210 | AVSC_DECLARE_FUNC(avs_is_444); 1211 | AVSC_DECLARE_FUNC(avs_is_422); 1212 | AVSC_DECLARE_FUNC(avs_is_420); 1213 | AVSC_DECLARE_FUNC(avs_is_y); 1214 | AVSC_DECLARE_FUNC(avs_is_yuva); 1215 | AVSC_DECLARE_FUNC(avs_is_planar_rgb); 1216 | AVSC_DECLARE_FUNC(avs_is_planar_rgba); 1217 | AVSC_DECLARE_FUNC(avs_num_components); 1218 | AVSC_DECLARE_FUNC(avs_component_size); 1219 | AVSC_DECLARE_FUNC(avs_bits_per_component); 1220 | 1221 | /////////////////////////////////////////////////////////////////////////////// 1222 | // Avisynth+ new interface elements from interface version 8 1223 | // avs_subframe_planar with alpha support 1224 | AVSC_DECLARE_FUNC(avs_subframe_planar_a); 1225 | 1226 | // frame properties 1227 | AVSC_DECLARE_FUNC(avs_copy_frame_props); 1228 | AVSC_DECLARE_FUNC(avs_get_frame_props_ro); 1229 | AVSC_DECLARE_FUNC(avs_get_frame_props_rw); 1230 | AVSC_DECLARE_FUNC(avs_prop_num_keys); 1231 | AVSC_DECLARE_FUNC(avs_prop_get_key); 1232 | AVSC_DECLARE_FUNC(avs_prop_num_elements); 1233 | AVSC_DECLARE_FUNC(avs_prop_get_type); 1234 | AVSC_DECLARE_FUNC(avs_prop_get_int); 1235 | AVSC_DECLARE_FUNC(avs_prop_get_float); 1236 | AVSC_DECLARE_FUNC(avs_prop_get_data); 1237 | AVSC_DECLARE_FUNC(avs_prop_get_data_size); 1238 | AVSC_DECLARE_FUNC(avs_prop_get_clip); 1239 | AVSC_DECLARE_FUNC(avs_prop_get_frame); 1240 | AVSC_DECLARE_FUNC(avs_prop_delete_key); 1241 | AVSC_DECLARE_FUNC(avs_prop_set_int); 1242 | AVSC_DECLARE_FUNC(avs_prop_set_float); 1243 | AVSC_DECLARE_FUNC(avs_prop_set_data); 1244 | AVSC_DECLARE_FUNC(avs_prop_set_clip); 1245 | AVSC_DECLARE_FUNC(avs_prop_set_frame); 1246 | 1247 | AVSC_DECLARE_FUNC(avs_prop_get_int_array); 1248 | AVSC_DECLARE_FUNC(avs_prop_get_float_array); 1249 | AVSC_DECLARE_FUNC(avs_prop_set_int_array); 1250 | AVSC_DECLARE_FUNC(avs_prop_set_float_array); 1251 | 1252 | AVSC_DECLARE_FUNC(avs_clear_map); 1253 | 1254 | // NewVideoFrame with frame properties 1255 | AVSC_DECLARE_FUNC(avs_new_video_frame_p); 1256 | AVSC_DECLARE_FUNC(avs_new_video_frame_p_a); 1257 | 1258 | AVSC_DECLARE_FUNC(avs_get_env_property); 1259 | 1260 | AVSC_DECLARE_FUNC(avs_get_var_try); 1261 | AVSC_DECLARE_FUNC(avs_get_var_bool); 1262 | AVSC_DECLARE_FUNC(avs_get_var_int); 1263 | AVSC_DECLARE_FUNC(avs_get_var_double); 1264 | AVSC_DECLARE_FUNC(avs_get_var_string); 1265 | AVSC_DECLARE_FUNC(avs_get_var_long); 1266 | 1267 | AVSC_DECLARE_FUNC(avs_pool_allocate); 1268 | AVSC_DECLARE_FUNC(avs_pool_free); 1269 | }; 1270 | 1271 | #undef AVSC_DECLARE_FUNC 1272 | 1273 | #ifdef AVS26_FALLBACK_SIMULATION 1274 | // Helper functions for fallback simulation 1275 | // Avisynth+ extensions do not exist in classic Avisynth so they are simulated 1276 | AVSC_INLINE int avs_is_xx_fallback_return_false(const AVS_VideoInfo * p) 1277 | { 1278 | return 0; 1279 | } 1280 | 1281 | // Avisynth+ extensions do not exist in classic Avisynth so they are simulated 1282 | AVSC_INLINE int avs_num_components_fallback(const AVS_VideoInfo * p) 1283 | { 1284 | switch (p->pixel_type) { 1285 | case AVS_CS_UNKNOWN: 1286 | return 0; 1287 | case AVS_CS_RAW32: 1288 | case AVS_CS_Y8: 1289 | return 1; 1290 | case AVS_CS_BGR32: 1291 | return 4; // not planar but return the count 1292 | default: 1293 | return 3; 1294 | } 1295 | } 1296 | 1297 | // Avisynth+ extensions do not exist in classic Avisynth so they are simulated 1298 | AVSC_INLINE int avs_component_size_fallback(const AVS_VideoInfo * p) 1299 | { 1300 | return 1; 1301 | } 1302 | 1303 | // Avisynth+ extensions do not exist in classic Avisynth so they are simulated 1304 | AVSC_INLINE int avs_bits_per_component_fallback(const AVS_VideoInfo * p) 1305 | { 1306 | return 8; 1307 | } 1308 | // End of helper functions for fallback simulation 1309 | #endif // AVS26_FALLBACK_SIMULATION 1310 | 1311 | // avs_load_library() allocates an array for API procedure entries 1312 | // reads and fills the entries with live procedure addresses. 1313 | // AVSC_INLINE helpers which are calling into API procedures are not treated here (todo) 1314 | 1315 | AVSC_INLINE AVS_Library * avs_load_library() { 1316 | AVS_Library *library = (AVS_Library *)malloc(sizeof(AVS_Library)); 1317 | if (library == NULL) 1318 | return NULL; 1319 | library->handle = LoadLibraryA("avisynth"); 1320 | if (library->handle == NULL) 1321 | goto fail; 1322 | 1323 | #define __AVSC_STRINGIFY(x) #x 1324 | #define AVSC_STRINGIFY(x) __AVSC_STRINGIFY(x) 1325 | #define AVSC_LOAD_FUNC(name) {\ 1326 | library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name));\ 1327 | if (library->name == NULL)\ 1328 | goto fail;\ 1329 | } 1330 | 1331 | #ifdef AVS26_FALLBACK_SIMULATION 1332 | // When an API function is not loadable, let's try a replacement 1333 | // Missing Avisynth+ functions will be substituted with classic Avisynth compatible methods 1334 | /* 1335 | Avisynth+ When method is missing (classic Avisynth) 1336 | avs_is_rgb48 constant false 1337 | avs_is_rgb64 constant false 1338 | avs_is_444 avs_is_yv24 1339 | avs_is_422 avs_is_yv16 1340 | avs_is_420 avs_is_yv12 1341 | avs_is_y avs_is_y8 1342 | avs_is_yuva constant false 1343 | avs_is_planar_rgb constant false 1344 | avs_is_planar_rgba constant false 1345 | avs_num_components special: avs_num_components_fake Y8:1 RGB32:4 else 3 1346 | avs_component_size constant 1 (1 bytes/component) 1347 | avs_bits_per_component constant 8 (8 bits/component) 1348 | */ 1349 | 1350 | // try to load an alternative function 1351 | #define AVSC_LOAD_FUNC_FALLBACK(name,name2) {\ 1352 | library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name));\ 1353 | if (library->name == NULL)\ 1354 | library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name2));\ 1355 | if (library->name == NULL)\ 1356 | goto fail;\ 1357 | } 1358 | 1359 | // try to assign a replacement function 1360 | #define AVSC_LOAD_FUNC_FALLBACK_SIMULATED(name,name2) {\ 1361 | library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name));\ 1362 | if (library->name == NULL)\ 1363 | library->name = name2;\ 1364 | if (library->name == NULL)\ 1365 | goto fail;\ 1366 | } 1367 | #endif // AVS26_FALLBACK_SIMULATION 1368 | 1369 | AVSC_LOAD_FUNC(avs_add_function); 1370 | AVSC_LOAD_FUNC(avs_at_exit); 1371 | AVSC_LOAD_FUNC(avs_bit_blt); 1372 | AVSC_LOAD_FUNC(avs_check_version); 1373 | AVSC_LOAD_FUNC(avs_clip_get_error); 1374 | AVSC_LOAD_FUNC(avs_copy_clip); 1375 | AVSC_LOAD_FUNC(avs_copy_value); 1376 | AVSC_LOAD_FUNC(avs_copy_video_frame); 1377 | AVSC_LOAD_FUNC(avs_create_script_environment); 1378 | AVSC_LOAD_FUNC(avs_delete_script_environment); 1379 | AVSC_LOAD_FUNC(avs_function_exists); 1380 | AVSC_LOAD_FUNC(avs_get_audio); 1381 | AVSC_LOAD_FUNC(avs_get_cpu_flags); 1382 | AVSC_LOAD_FUNC(avs_get_frame); 1383 | AVSC_LOAD_FUNC(avs_get_parity); 1384 | AVSC_LOAD_FUNC(avs_get_var); 1385 | AVSC_LOAD_FUNC(avs_get_version); 1386 | AVSC_LOAD_FUNC(avs_get_video_info); 1387 | AVSC_LOAD_FUNC(avs_invoke); 1388 | AVSC_LOAD_FUNC(avs_make_writable); 1389 | AVSC_LOAD_FUNC(avs_new_c_filter); 1390 | AVSC_LOAD_FUNC(avs_new_video_frame_a); 1391 | 1392 | 1393 | 1394 | AVSC_LOAD_FUNC(avs_release_clip); 1395 | AVSC_LOAD_FUNC(avs_release_value); 1396 | AVSC_LOAD_FUNC(avs_release_video_frame); 1397 | AVSC_LOAD_FUNC(avs_save_string); 1398 | AVSC_LOAD_FUNC(avs_set_cache_hints); 1399 | AVSC_LOAD_FUNC(avs_set_global_var); 1400 | AVSC_LOAD_FUNC(avs_set_memory_max); 1401 | AVSC_LOAD_FUNC(avs_set_to_clip); 1402 | AVSC_LOAD_FUNC(avs_set_var); 1403 | AVSC_LOAD_FUNC(avs_set_working_dir); 1404 | AVSC_LOAD_FUNC(avs_sprintf); 1405 | AVSC_LOAD_FUNC(avs_subframe); 1406 | AVSC_LOAD_FUNC(avs_subframe_planar); 1407 | AVSC_LOAD_FUNC(avs_take_clip); 1408 | AVSC_LOAD_FUNC(avs_vsprintf); 1409 | 1410 | AVSC_LOAD_FUNC(avs_get_error); 1411 | AVSC_LOAD_FUNC(avs_is_yv24); 1412 | AVSC_LOAD_FUNC(avs_is_yv16); 1413 | AVSC_LOAD_FUNC(avs_is_yv12); 1414 | AVSC_LOAD_FUNC(avs_is_yv411); 1415 | AVSC_LOAD_FUNC(avs_is_y8); 1416 | AVSC_LOAD_FUNC(avs_is_color_space); 1417 | 1418 | AVSC_LOAD_FUNC(avs_get_plane_width_subsampling); 1419 | AVSC_LOAD_FUNC(avs_get_plane_height_subsampling); 1420 | AVSC_LOAD_FUNC(avs_bits_per_pixel); 1421 | AVSC_LOAD_FUNC(avs_bytes_from_pixels); 1422 | AVSC_LOAD_FUNC(avs_row_size); 1423 | AVSC_LOAD_FUNC(avs_bmp_size); 1424 | AVSC_LOAD_FUNC(avs_get_pitch_p); 1425 | AVSC_LOAD_FUNC(avs_get_row_size_p); 1426 | AVSC_LOAD_FUNC(avs_get_height_p); 1427 | AVSC_LOAD_FUNC(avs_get_read_ptr_p); 1428 | AVSC_LOAD_FUNC(avs_is_writable); 1429 | AVSC_LOAD_FUNC(avs_get_write_ptr_p); 1430 | 1431 | // Avisynth+ specific 1432 | #ifdef AVS26_FALLBACK_SIMULATION 1433 | // replace with fallback fn when does not exist 1434 | AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_rgb48, avs_is_xx_fallback_return_false); 1435 | AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_rgb64, avs_is_xx_fallback_return_false); 1436 | AVSC_LOAD_FUNC_FALLBACK(avs_is_444, avs_is_yv24); 1437 | AVSC_LOAD_FUNC_FALLBACK(avs_is_422, avs_is_yv16); 1438 | AVSC_LOAD_FUNC_FALLBACK(avs_is_420, avs_is_yv12); 1439 | AVSC_LOAD_FUNC_FALLBACK(avs_is_y, avs_is_y8); 1440 | AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_yuva, avs_is_xx_fallback_return_false); 1441 | AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_planar_rgb, avs_is_xx_fallback_return_false); 1442 | AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_planar_rgba, avs_is_xx_fallback_return_false); 1443 | AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_num_components, avs_num_components_fallback); 1444 | AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_component_size, avs_component_size_fallback); 1445 | AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_bits_per_component, avs_bits_per_component_fallback); 1446 | #else 1447 | // Avisynth+ specific 1448 | AVSC_LOAD_FUNC(avs_is_rgb48); 1449 | AVSC_LOAD_FUNC(avs_is_rgb64); 1450 | AVSC_LOAD_FUNC(avs_is_444); 1451 | AVSC_LOAD_FUNC(avs_is_422); 1452 | AVSC_LOAD_FUNC(avs_is_420); 1453 | AVSC_LOAD_FUNC(avs_is_y); 1454 | AVSC_LOAD_FUNC(avs_is_yuva); 1455 | AVSC_LOAD_FUNC(avs_is_planar_rgb); 1456 | AVSC_LOAD_FUNC(avs_is_planar_rgba); 1457 | AVSC_LOAD_FUNC(avs_num_components); 1458 | AVSC_LOAD_FUNC(avs_component_size); 1459 | AVSC_LOAD_FUNC(avs_bits_per_component); 1460 | #endif 1461 | // Avisynth+ interface V8, no backward compatible simulation 1462 | AVSC_LOAD_FUNC(avs_subframe_planar_a); 1463 | // frame properties 1464 | AVSC_LOAD_FUNC(avs_copy_frame_props); 1465 | AVSC_LOAD_FUNC(avs_get_frame_props_ro); 1466 | AVSC_LOAD_FUNC(avs_get_frame_props_rw); 1467 | AVSC_LOAD_FUNC(avs_prop_num_keys); 1468 | AVSC_LOAD_FUNC(avs_prop_get_key); 1469 | AVSC_LOAD_FUNC(avs_prop_num_elements); 1470 | AVSC_LOAD_FUNC(avs_prop_get_type); 1471 | AVSC_LOAD_FUNC(avs_prop_get_int); 1472 | AVSC_LOAD_FUNC(avs_prop_get_float); 1473 | AVSC_LOAD_FUNC(avs_prop_get_data); 1474 | AVSC_LOAD_FUNC(avs_prop_get_data_size); 1475 | AVSC_LOAD_FUNC(avs_prop_get_clip); 1476 | AVSC_LOAD_FUNC(avs_prop_get_frame); 1477 | AVSC_LOAD_FUNC(avs_prop_delete_key); 1478 | AVSC_LOAD_FUNC(avs_prop_set_int); 1479 | AVSC_LOAD_FUNC(avs_prop_set_float); 1480 | AVSC_LOAD_FUNC(avs_prop_set_data); 1481 | AVSC_LOAD_FUNC(avs_prop_set_clip); 1482 | AVSC_LOAD_FUNC(avs_prop_set_frame); 1483 | 1484 | AVSC_LOAD_FUNC(avs_prop_get_int_array); 1485 | AVSC_LOAD_FUNC(avs_prop_get_float_array); 1486 | AVSC_LOAD_FUNC(avs_prop_set_int_array); 1487 | AVSC_LOAD_FUNC(avs_prop_set_float_array); 1488 | 1489 | AVSC_LOAD_FUNC(avs_clear_map); 1490 | 1491 | // NewVideoFrame with frame properties 1492 | AVSC_LOAD_FUNC(avs_new_video_frame_p); 1493 | AVSC_LOAD_FUNC(avs_new_video_frame_p_a); 1494 | 1495 | AVSC_LOAD_FUNC(avs_get_env_property); 1496 | 1497 | AVSC_LOAD_FUNC(avs_get_var_try); 1498 | AVSC_LOAD_FUNC(avs_get_var_bool); 1499 | AVSC_LOAD_FUNC(avs_get_var_int); 1500 | AVSC_LOAD_FUNC(avs_get_var_double); 1501 | AVSC_LOAD_FUNC(avs_get_var_string); 1502 | AVSC_LOAD_FUNC(avs_get_var_long); 1503 | 1504 | AVSC_LOAD_FUNC(avs_pool_allocate); 1505 | AVSC_LOAD_FUNC(avs_pool_free); 1506 | 1507 | #undef __AVSC_STRINGIFY 1508 | #undef AVSC_STRINGIFY 1509 | #undef AVSC_LOAD_FUNC 1510 | #undef AVSC_LOAD_FUNC_FALLBACK 1511 | #undef AVSC_LOAD_FUNC_FALLBACK_SIMULATED 1512 | 1513 | return library; 1514 | 1515 | fail: 1516 | free(library); 1517 | return NULL; 1518 | } 1519 | 1520 | AVSC_INLINE void avs_free_library(AVS_Library *library) { 1521 | if (library == NULL) 1522 | return; 1523 | FreeLibrary(library->handle); 1524 | free(library); 1525 | } 1526 | #endif 1527 | 1528 | #endif // AVS_WINDOWS 1529 | 1530 | #endif 1531 | --------------------------------------------------------------------------------