1. Introduction
The language provides a familiar C-style infix syntax that supports variables, operators, user-defined functions, and special constructs for video processing. It is designed to be expressive and readable, abstracting away the complexities of writing raw postfix expressions.
The infix transpiler supports two distinct execution models, corresponding to VapourSynth's Expr and SingleExpr functions.
1.1. Expr Mode: Per-Pixel Execution
This is the traditional model, used by both llvmexpr.Expr (CPU) and llvmexpr.VkExpr (GPU). The script is executed once for every single pixel of the output frame. It is ideal for standard image filtering, such as applying a brightness curve, combining clips, or spatial filtering.
VkExpr additionally supports a multi-pass pipeline: you can split the expr string into multiple infix stages with ---. Each stage still runs per-pixel, but stages execute sequentially and later stages can read earlier results via $bufN (see VkExpr Multi-Pass Pipeline & Intermediate Buffers).
- Key Characteristics:
- Operates on a "current pixel" concept, with $X and $Y coordinates available.
- The final value assigned to the special RESULT variable is implicitly written to the current pixel's location.
1.2. SingleExpr Mode: Per-Frame Execution
This is a specialized model where the script is executed only once for the entire frame. This model is not suitable for general image processing but excels at tasks that require summarizing or distributing data across a frame, such as calculating average brightness or copying frame properties.
- Key Characteristics:
- No "current pixel" concept; $X and $Y are unavailable.
- All output must be performed explicitly by writing to absolute pixel coordinates (store()) or by writing to frame properties (set_prop()).
- The special RESULT variable has no effect on the output frame.
2. Preprocessor
The compiler includes a powerful preprocessor that runs before the source code is parsed. It supports macro definitions, conditional compilation, and compile-time expression evaluation, enabling advanced code organization and configuration.
2.1. Overview
- Activation: Preprocessor directives are lines that begin with an @ symbol, optionally preceded by whitespace.
- Execution: The preprocessor first evaluates all directives and expands all macros to generate an intermediate source text. This text is then tokenized and parsed by the main compiler. The combination of @define, constant expression evaluation, and the conditional ternary operator (? :) effectively makes the preprocessor a Turing-complete, pure functional language that executes at compile time.
2.2. Macro Definition Directives
Macros allow you to define reusable names for constants and parameterized expressions.
2.2.1. @define
The @define directive is used to create both simple and function-like macros.
Object-Like Macros
These are used to define constants or feature flags.
- Syntax: @define NAME [value]
- Behavior:
- If a value is provided, all subsequent occurrences of NAME as a whole word will be replaced by the value.
- If the value is a constant expression that can be evaluated at compile time, it will be replaced with the computed result.
- If no value is provided, NAME is defined with an empty body, which is useful for @ifdef checks.
Examples:
@define MAX_VALUE 255
@define PI 3.14159
@define ENABLE_FEATURE
@define COMPUTED (2 * 3 + 1) # Expands to 7
Function-Like Macros
These provide parameterized text replacement, similar to C preprocessor macros.
- Syntax: @define NAME(param1, param2, ...) body
- Important
- There must be no space between the macro name and the opening parenthesis (. A space will cause it to be parsed as an object-like macro.
- Invocation: To invoke a function-like macro, use its name followed by parentheses containing the arguments. If a function-like macro's name appears without (), it will not be expanded.
@define MAX(a, b) ((a) > (b) ? (a) : (b))
@define SQR(x) ((x) * (x))
result = MAX(10, 20); # Expands to: ((10) > (20) ? (10) : (20))
value = SQR(5); # Expands to: ((5) * (5))
addr = MAX; # NOT expanded, remains 'MAX'
2.2.2. @undef
You can remove a macro definition using the @undef directive.
2.3. Conditional Compilation Directives
Conditional directives allow you to include or exclude blocks of code based on certain conditions.
2.3.1. @if, @else, @endif
The @if directive provides powerful conditional compilation based on the value of a constant expression.
- Syntax:
@if expression
// Code to include if expression evaluates to non-zero
@else
// Optional: code to include otherwise
@endif
- Behavior: The directive evaluates the expression at compile time. The code block is included if the result is non-zero. For details on what constitutes a valid expression, see Section 2.6. Constant Expression Evaluation.
2.3.2. @ifdef and @ifndef
These directives check whether a macro is defined, regardless of its value.
- Syntax:
@ifdef MACRO_NAME
// Code to include if MACRO_NAME is defined
@else
// Optional: code to include if not defined
@endif
- @ifndef is the reverse: it includes code if a macro is not defined.
2.4. Other Directives
2.4.1. @error
You can use @error to force a compilation error with a custom message. This is useful for asserting configurations or flagging deprecated macro usage inside a conditional block.
Example:
@if defined(OLD_FEATURE)
@error OLD_FEATURE is deprecated. Please use NEW_FEATURE instead.
@endif
2.4.2. @requires
You can include built-in standard libraries using the @requires directive. This is the primary way to access a rich set of pre-defined functions and constants.
- Syntax: @requires library_name
- Library Name: Must be a valid identifier (e.g., algorithms, meta).
Example:
@requires algorithms
@requires meta
2.5. The Macro Expansion Process
The preprocessor expands macros according to the following rules:
- Multiple Passes: The preprocessor makes multiple passes over the source text, expanding macros until no more expansions can be performed. A recursion limit (1000) prevents infinite loops.
- Token-Based Matching: Macro replacement is performed on a whole-word basis. For example, if V is a macro, it will not be expanded inside the identifier VALUE.
- Argument Expansion: For function-like macros, the preprocessor fully expands a macro's arguments before substituting them into the macro body, with one key exception (see Token Pasting below). An important consequence of this is that if an expanded argument forms a valid constant expression (e.g., (2+3)), it is immediately evaluated and replaced by its result (e.g., 5) before being passed to the outer macro. This mechanism is crucial for advanced techniques like recursive macros that generate new values at each step. The resulting text is then rescanned for further macro expansions.
- Differences from C/C++: This preprocessor is similar to C/C++ but lacks a stringification (#) operator and variadic macros (..., __VA_ARGS__). Also, macro definitions must be on a single line.
2.5.1. Token Pasting (@@)
The preprocessor supports the @@ operator for token pasting, which concatenates two tokens into one.
- Syntax: token1 @@ token2
- Behavior: During macro expansion, @@ is removed, and the adjacent tokens are merged into a single new token. This new token is then available for further macro expansion.
Example:
@define CONCAT(a, b) a@@b
@define xy 100
# Expands to CONCAT(x, y) -> xy -> 100
RESULT = CONCAT(x, y)
The Argument Expansion Problem
A common and powerful pattern is to generate identifiers dynamically (e.g., src0, src1). However, the @@ operator has a special rule: if a macro parameter is adjacent to @@ in a macro definition, the corresponding argument is not expanded before pasting.
Problem:
@define PASTE(prefix, num) prefix@@num
@define ONE 1
# This expands to PASTE($src, ONE) -> $src@@ONE -> $srcONE, NOT $src1
RESULT = PASTE($src, ONE)
Solution: The Two-Step Macro
To force an argument to be evaluated before pasting, you must use a two-level macro definition. This is a standard C preprocessor technique.
- Inner Macro: Performs the direct pasting.
- Outer Macro: Calls the inner macro. Its arguments will be expanded because they are not next to @@ in its own definition.
# Inner macro for direct pasting
@define PASTE_IMPL(prefix, num) prefix@@num
# Outer macro to force argument evaluation
@define PASTE(prefix, num) PASTE_IMPL(prefix, num)
@define ONE 1
# This now works correctly:
# 1. PASTE($src, ONE) is called.
# 2. Its arguments are expanded: $src remains $src, ONE becomes 1.
# 3. PASTE_IMPL($src, 1) is called.
# 4. It pastes '$src' and '1' into '$src1'.
RESULT = PASTE($src, ONE) # Expands to $src1
2.6. Constant Expression Evaluation
The preprocessor can evaluate integer and floating-point expressions at compile time. This capability is the engine behind the @if directive and allows macros to compute values before the main compilation phase.
An expression is considered a "constant expression" if it consists of literals and other macros that expand to constant values.
The expression evaluator supports:
- Literals: Integers (123, 0xFF) and floating-point numbers (3.14, 1.0e-5).
- Macros: Previously defined macros are expanded before evaluation.
- defined(MACRO) Operator: Returns 1 if MACRO is defined, 0 otherwise. This is primarily used within @if expressions.
- Operators: The following operators are supported, with standard C-like precedence:
| Precedence | Operator | Description | Arity | Associativity |
| 1 | ? : | Ternary Conditional | Ternary | Right |
| 2 | || | Logical OR | Binary | Left |
| 3 | && | Logical AND | Binary | Left |
| 4 | | | Bitwise OR | Binary | Left |
| 5 | ^ | Bitwise XOR | Binary | Left |
| 6 | & | Bitwise AND | Binary | Left |
| 7 | ==, != | Equality | Binary | Left |
| 8 | <, <=, >, >= | Relational | Binary | Left |
| 9 | +, - | Addition, Subtraction | Binary | Left |
| 10 | *, / | Multiplication, Division | Binary | Left |
| % | Modulus | Binary | Left |
| 11 | ** | Exponentiation (Power) | Binary | Right |
| 12 | - | Negation | Unary | Right |
| ! | Logical NOT | Unary | Right |
| ~ | Bitwise NOT | Unary | Right |
Evaluation Order:
- The ternary operator ? : is short-circuiting: only the selected branch is evaluated.
- The logical operators && and || are not short-circuiting in the preprocessor's constant expression evaluator: both operands are evaluated.
Because the preprocessor is pure/functional, eager evaluation does not change the final numeric result, but it can still affect whether evaluation succeeds. For terminating recursive macros, rely on ? : branch elimination rather than && / ||.
2.7. Compile-Time Intrinsics
The preprocessor provides special intrinsic functions to interact with the constant expression evaluator.
- is_consteval(expr)
- Returns 1 if expr can be fully evaluated as a compile-time constant; otherwise returns 0.
- This intrinsic never raises an error. An expression that cannot be evaluated (e.g., contains variables) simply yields 0.
- consteval(expr)
- Forces compile-time evaluation of expr. If successful, it is replaced by the computed numeric result.
- If the expression cannot be evaluated at compile-time, a preprocessing error is raised.
- static_assert(condition, message)
- Evaluates condition at compile time. If the expression cannot be evaluated to a constant, or if the result is 0, it raises a compilation error with the specified message.
- If the condition evaluates to a non-zero value, the intrinsic is replaced by the value 1. This allows static_assert to be chained inside other compile-time expressions.
Example:
@define FAST_PATH(n) ((n) * (n))
@define SLOW_PATH(x) (fma((x), (x), 0))
# Dispatch to a faster implementation if 'x' is a compile-time constant
@define DISPATCH(x) (is_consteval(x) ? FAST_PATH(consteval(x)) : SLOW_PATH(x))
@if is_consteval(LEN)
# Ensure LEN is a constant before using it to define another macro
@define BUF_LEN consteval(LEN)
@else
@define BUF_LEN 256
@endif
2.8. Advanced Techniques and Examples
By combining macros, conditional logic, and compile-time evaluation, you can achieve powerful metaprogramming effects.
2.8.1. Conditional Expansion with the Ternary Operator
A top-level ternary operator (? :) within a macro body acts as a powerful code generation tool. If the condition is a constant expression, the preprocessor performs branch elimination: the entire construct—including the condition, the ? : symbols, and the surrounding parentheses—is replaced only by the tokens from the chosen branch. The condition itself and the unelected branch are completely discarded from the source text passed to the compiler. This means the unelected branch does not need to be syntactically valid or evaluable.
Example: Conditional Code Selection
@define CHECK(cond, val) (cond ? val : static_assert(0, Error))
# Because the condition '1' is constant, this expands ONLY to '10'.
# The static_assert(0, Error) branch is never included in the final source code.
RESULT = CHECK(1, 10)
2.8.2. Recursive Macros
Macros can be defined recursively. When combined with the short-circuiting ternary operator, this enables powerful compile-time computation.
Example: Compile-Time Factorial
# The recursion terminates because when n == 0, the second branch is not evaluated.
@define FACTORIAL(n) ((n) == 0 ? 1 : ((n) * FACTORIAL((n) - 1)))
# The preprocessor evaluates this entire expression to the constant value 120.
RESULT = FACTORIAL(5)
- Note
- Parentheses around parameters are essential to avoid operator precedence issues.
-
In this example, the expression (n) - 1 is passed unevaluated at each step, accumulating into a large final expression ((5) * ((4) * ...)). This is acceptable for simple arithmetic, but will fail if a step inside the recursion requires a single evaluated number (e.g., for token pasting). See Next Section for how to force evaluation at each step.
2.8.3. Forcing Step-by-Step Evaluation in Recursive Macros
A critical subtlety of recursive macros arises when an argument needs to be evaluated at each step of the recursion, rather than accumulating into a large expression. This is often necessary when the argument is passed to another macro that requires a simple value, such as a token-pasting macro.
The Problem: Unevaluated Expressions as Arguments
In the FACTORIAL example, the argument n - 1 is not evaluated to a number at each step. Instead, the preprocessor builds a nested expression like (5 * (4 * (3 * ...))), which is evaluated only at the very end. This works for arithmetic, but fails if an intermediate step requires a single token.
Let's attempt to write a macro that finds the first input clip with a bit depth greater than 16. This requires checking __INPUT_BITDEPTH_0__, __INPUT_BITDEPTH_1__, etc., by dynamically building the macro name.
Incorrect Implementation:
@requires meta
@define BITDEPTH_OF(i) PASTE(PASTE(__INPUT_BITDEPTH_, i), __)
# Tries to recurse using `i + 1` directly
@define _FIND_FIRST_GT16(i, n) ((i) >= (n) ? -1 : (BITDEPTH_OF(i) > 16 ? (i) : _FIND_FIRST_GT16((i) + 1, (n))))
This produces incorrect results. On the first recursion, the argument (i) + 1 is passed as a sequence of tokens (, i, ), +, 1, not as a computed numeric value. When BITDEPTH_OF((i) + 1) is called, PASTE concatenates these tokens literally, generating the invalid macro name __INPUT_BITDEPTH_(0)+1__ instead of the intended __INPUT_BITDEPTH_1__. Since this malformed name is not defined as a macro, it remains unexpanded in the output, causing the expression to fail.
The Solution: Helper Macros to Force Evaluation
To force evaluation at each step, the expression must be wrapped in another macro so that arguments are expanded beforehand.
Correct Implementation:
@requires meta
@define INC(n) ((n) + 1)
@define BITDEPTH_OF(i) PASTE(PASTE(__INPUT_BITDEPTH_, i), __)
@define _FIND_FIRST_GT16(i, n) ((i) >= (n) ? -1 : (BITDEPTH_OF(i) > 16 ? (i) : _FIND_FIRST_GT16(INC(i), (n))))
@define FIND_FIRST_GT16() _FIND_FIRST_GT16(0, __INPUT_NUM__)
# Usage:
# This will expand and evaluate at compile time to the index, or -1.
index = consteval(FIND_FIRST_GT16())
Why It Works: The preprocessor's argument expansion rule is the key. Before calling _FIND_FIRST_GT16, it first fully expands its arguments.
- The argument is the macro call INC(i).
- The preprocessor expands INC(i), which results in the token sequence for the expression ((i) + 1).
- A special rule applies after a macro is fully expanded: if the resulting sequence of tokens forms a valid constant expression, it is immediately evaluated and replaced by a single numeric token.
- Therefore, if i was 0, INC(0) becomes ((0)+1), which is evaluated to the single token 1.
- The recursive call is then _FIND_FIRST_GT16(1, (n)), with 1 being a single token. BITDEPTH_OF(1) now works as expected.
This technique is essential for writing complex recursive macros that perform operations like token pasting or anything else that depends on single-token arguments within the recursion.
2.9. Predefined Macros
The preprocessor provides several built-in macros that expose information about the execution context.
Mode-Specific Macros
| Macro | Description |
| __EXPR__ | Defined when compiling in Expr mode (per-pixel). |
| __SINGLEEXPR__ | Defined when compiling in SingleExpr mode (per-frame). |
| __GPU__ | Defined when the code is compiled for VkExpr (GPU backend). |
Context Macros (when infix=1 is used)
These are defined by the VapourSynth filter when it invokes the transpiler.
| Macro | Description |
| __WIDTH__ | Output frame width (integer, sub-sampling not counted). |
| __HEIGHT__ | Output frame height (integer, sub-sampling not counted). |
| __INPUT_NUM__ | Number of input clips (integer). |
| __OUTPUT_BITDEPTH__ | Output bit depth. |
| __OUTPUT_COLORFAMILY__ | Output ColorFamily (0=cfUndefined, 1=cfGray, 2=cfRGB, 3=cfYUV). |
| __OUTPUT_SAMPLETYPE__ | Output sample type (0=stInteger, 1=stFloat). |
| __SUBSAMPLE_W__ | Horizontal chroma subsampling of the output (1 for 4:2:x, 0 otherwise). |
| __SUBSAMPLE_H__ | Vertical chroma subsampling of the output (1 for 4:2:0, 0 otherwise). |
| __NUM_PLANES__ | Number of planes in the output frame. |
| __INPUT_BITDEPTH_N__ | Bit depth of the (N+1)-th input clip (e.g., __INPUT_BITDEPTH_0__). |
| __INPUT_COLORFAMILY_N__ | ColorFamily of the (N+1)-th input clip (e.g., __INPUT_COLORFAMILY_0__). |
| __INPUT_SAMPLETYPE_N__ | Sample type of the (N+1)-th input clip (e.g., __INPUT_SAMPLETYPE_0__). 0=stInteger, 1=stFloat. |
| __INPUT_WIDTH_N__ | Width of the (N+1)-th input clip's luma plane. (SingleExpr mode only) |
| __INPUT_HEIGHT_N__ | Height of the (N+1)-th input clip's luma plane. (SingleExpr mode only) |
| __INPUT_SUBSAMPLE_W_N__ | Horizontal chroma subsampling of the (N+1)-th input clip. (SingleExpr mode only) |
| __INPUT_SUBSAMPLE_H_N__ | Vertical chroma subsampling of the (N+1)-th input clip. (SingleExpr mode only) |
| __INPUT_NUM_PLANES_N__ | Number of planes of the (N+1)-th input clip (e.g., __INPUT_NUM_PLANES_0__). |
| __PLANE_NO__ | Current plane being processed (0, 1, or 2). (Expr mode only) |
- Note
- For dynamic access to input clip formats (e.g., when the clip index is a variable), use the functions in the `std` library.
2.10. Debugging Macros
The cli tool infix2postfix includes a -E option that outputs the preprocessed code and a trace of macro expansions.
infix2postfix input.expr -m [expr/single] -E
This can be very helpful for debugging macro definitions and expansion.
3. Lexical Structure
3.1. Comments
Comments begin with a # character and extend to the end of the line. They are ignored by the parser.
# This is a comment.
a = 1 # This is an inline comment.
3.2. Whitespace
Whitespace characters (spaces, tabs, newlines) are used to separate tokens. Multiple whitespace characters are treated as a single separator. Newlines are significant as they terminate statements.
3.3. Identifiers
Identifiers are used for naming variables and functions.
- Rules: Must begin with a letter (a-z, A-Z) or an underscore (_) and can be followed by any number of letters, digits, or underscores. The pattern is [a-zA-Z_]\w*.
- Case-Sensitivity: Identifiers are case-sensitive. myVar and myvar are different.
- Important
- Reserved Prefix: Identifiers starting with __internal_ are reserved for internal use by the transpiler and must not be used in user code.
3.4. Literals
Numeric Literals
The language supports several formats for numeric constants:
- Decimal: Standard integers (100, -42) and floating-point numbers (3.14, -0.5, 1.2e-5). The decimal separator is always a period (.), regardless of the system's locale settings.
- Hexadecimal: Prefixed with 0x. Can include a fractional part and a binary exponent (p-exponent). Examples: 0xFF, 0x1.9p-2.
- Octal: Prefixed with a leading 0. Example: 0755.
4. Program Structure
A program is a script composed of one or more statements.
4.1. Statements
- Statements can be terminated by either a newline or a semicolon (;).
- Semicolons are optional if a statement is on its own line.
- To place multiple statements on a single line, you must separate them with semicolons.
Assignment Statements
An assignment statement computes the value of an expression and stores it in a variable.
- Syntax: variable = expression
- The stack must be balanced after an assignment (i.e., the expression must result in exactly one value).
Expression Statements
A statement can consist of a single expression, such as a function call that does not return a value. The expression is evaluated, and its result is discarded. The net stack effect of such a statement must be zero.
# Assignment statement (newline terminated)
my_var = 10 * 2
# Expression statement (semicolon terminated)
my_func(my_var);
# Multiple statements on one line
a = 1; b = 2; c = a + b
4.2. Final Result (Expr mode)
In Expr mode, the final output for each pixel is determined by the value assigned to the special RESULT variable. This assignment is typically the last statement in the global scope.
# ... calculations ...
RESULT = final_value
In SingleExpr mode, assigning to RESULT has no effect. Output in this mode is handled explicitly via the store() and set_prop() functions.
5. Variables and Constants
5.1. Variables
- Declaration: Variables are declared implicitly upon their first assignment.
- Usage: A variable must be guaranteed to be assigned a value before it is used in an expression. The transpiler performs a static analysis to ensure a variable is defined on all possible execution paths before any use. Referencing a variable that is not guaranteed to be initialized will result in a syntax error.
The identifier _ is treated as a special "write-only" variable for discarding values. You can assign any value to it, but you cannot read from it. This is useful for explicitly ignoring a value you don't need.
- No Unused Warnings: Assigning a value to _ will not trigger an "unused variable" warning.
- Usage Error: Attempting to use _ in an expression (i.e., read its value) will result in a compile-time error.
Example:
# Correct: assigning a value to _ is allowed
_ = 10 * 2
# Error: attempting to read the value of _
# result = _ + 10
5.1.1. Formal Verification of Definite Assignment
The robustness of the static analysis mentioned above is backed by a formal proof using the Coq Proof Assistant. The validity of this proof relies on the consistency between the language's control flow constraints and the proof's axioms.
Consistency of Hypotheses
The proof relies on the step_safety_rule, which posits that control flow cannot arbitrarily jump into a variable's scope from the outside without passing through its definition. This hypothesis is satisfied by language constraint described in Section 10.2.
Safety Conclusion
Given this constraint, the Definite Assignment Theorem (definition_dominates_use) is proven to hold. Formally, for any valid execution path \(\text{trace}\) starting from the beginning of the script ( \(\text{start}\)) to a variable usage point ( \(\text{target}\)):
\[(\mathrm{start} < \mathrm{def\_pos}) \land (\mathrm{InScope}(\mathrm{target})) \Longrightarrow \mathrm{def\_pos} \in \mathrm{trace}
\]
This theorem mathematically guarantees that the variable definition dominates its use; i.e., it is impossible to reach a usage point without executing the definition. For the rigorous formal proof, refer to proof.v.
5.2. Constants
Constants represent fixed values and are always identified by a $ prefix. They are treated as literal values and do not require prior assignment.
5.3. Built-in Constants
The language provides several built-in constants.
- Warning
- Deprecation Notice: The $width and $height constants are deprecated and will be removed in a future version. Please use the corresponding functions provided by the std standard library instead.
| Constant | Description | Availability |
| $pi | The value of π. | Both |
| $N | The current frame number (0-based). | Both |
| $X | The current column coordinate (chroma-subsampling counted). | Expr only |
| $Y | The current row coordinate (chroma-subsampling counted). | Expr only |
| $width | (Deprecated) The width of the video plane. In Expr, this is the width of the current plane. In SingleExpr, this is the width of the luma plane. | Both |
| $height | (Deprecated) The height of the video plane. In Expr, this is the height of the current plane. In SingleExpr, this is the height of the luma plane. | Both |
5.4. Source Clips
Source clips are special constants used to reference input video clips. They must be prefixed with a $.
Source clips can be referenced in two equivalent ways:
- Single Letters: The lowercase letters xyzabcdefghijklmnopqrstuvw are aliases for src0 through src25 respectively:
- $x is equivalent to $src0
- $y is equivalent to $src1
- $z is equivalent to $src2
- $a is equivalent to $src3
- And so on through $w which is equivalent to $src25
- src Prefixed: The identifier src followed by one or more digits, prefixed with $ (e.g., $src0, $src1).
6. Operators
Operators are left-associative, except for the unary and ternary operators. The following table lists operators in order of precedence, from lowest to highest.
| Precedence | Operator | Description | Arity | Associativity |
| 1 | ? : | Ternary Conditional | Ternary | Right |
| 2 | || | Logical OR | Binary | Left |
| 3 | && | Logical AND | Binary | Left |
| 4 | | | Bitwise OR | Binary | Left |
| 5 | ^ | Bitwise XOR | Binary | Left |
| 6 | & | Bitwise AND | Binary | Left |
| 7 | ==, != | Equality | Binary | Left |
| 8 | <, <=, >, >= | Relational | Binary | Left |
| 9 | +, - | Addition, Subtraction | Binary | Left |
| 10 | *, / | Multiplication, Division | Binary | Left |
| % | Modulus | Binary | Left |
| 11 | ** | Exponentiation (Power) | Binary | Right |
| 12 | - | Negation | Unary | Right |
| ! | Logical NOT | Unary | Right |
| ~ | Bitwise NOT | Unary | Right |
- Note
- Bitwise operators operate on integer values. When operating on floating-point values, operands are first rounded to the nearest integer.
-
All conditional contexts in the infix syntax use consistent != 0 semantics, which is different from that of the underlying RPN language.
- Warning
- &&, ||, and ? : are not short-circuiting: both operands (and both ternary branches) are evaluated. Use if / else statements when you need conditional execution.
7. Data Access
Data access methods for pixels and frame properties differ significantly between Expr and SingleExpr modes.
7.1. Frame Property Access
Reading (Both Modes)
Read a property from a clip's frame properties using clip.propname syntax.
- Syntax: clip.propname
- clip must be a valid source clip identifier (e.g., $a, $src1). The $ prefix is required. For example: $a.propname or $src1._Matrix.
Checking Existence (Both Modes)
Check if a frame property exists using the is_prop_exist built-in function.
- Signature: is_prop_exist(clip, property_name)
- Parameters:
- clip: A source clip constant (e.g., $a, $src1).
- property_name: Property name as an identifier.
- Returns: 1.0 if the property exists, 0.0 otherwise.
Writing (SingleExpr only)
Write a frame property using the set_prop family of built-in functions. These functions allow you to specify the data type of the property being written.
- Signatures:
- set_prop(property_name, value) (alias for set_propf)
- set_propf(property_name, value)
- set_propi(property_name, value)
- set_propaf(property_name, value)
- set_propai(property_name, value)
- Parameters:
- property_name: Property name as an identifier (not a string). The transpiler treats property_name as a literal key for the property map; it is not evaluated as a variable.
- value: The value to write, which can be the result of an expression.
- Type Suffixes: Each function corresponds to a type suffix in the underlying postfix language, controlling how the property is stored:
| Function | Postfix Suffix | Resulting Type |
| set_propf | $f | Float |
| set_propi | $i | Integer (value is rounded to the nearest integer) |
| set_propaf | $af | Auto Float: Keeps the type of an existing property on the first source frame, otherwise defaults to float. |
| set_propai | $ai | Auto Integer: Keeps the type of an existing property on the first source frame, otherwise defaults to integer. |
Conditional Writes and Fallback Behavior
If a set_prop call is inside a conditional block (e.g., an if statement) and that block is not executed, the property is not written by the expression. In this case, VapourSynth's default behavior takes effect:
- If a property with the same name exists on the first source frame ($x or $src0), it will be copied to the output frame.
- If the property does not exist on the first source frame, it will not be created on the output frame.
Type Consistency
- Important
- The compiler enforces type consistency at compile time. You cannot write to the same property using functions that imply different types (e.g., mixing set_propi and set_propai for MyProp will result in an error).
- Note
- Type Conversion Timing
The type conversion specified by functions like set_propi and set_propai applies to how the property is stored on the final output frame's properties. Within the same expression execution, reading a property after it has been written will always yield the original floating-point value that was passed to the set_prop function, before any rounding or conversion. The integer conversion happens only when the filter returns the new clip with its frame properties.
-
Read-After-Write Behavior for Properties
In SingleExpr mode, writing a property via set_prop immediately updates the value returned by subsequent reads of that property from the first source clip ($src0 or $x).
- set_prop(MyProp, 100); val = $src0.MyProp; -> val will be 100.
- This "shadowing" allows you to use properties as mutable variables during the execution.
- This only applies to $src0. Properties from other clips ($src1, etc.) are read-only and independent.
Example:
# Write a simple integer value
set_propi(MyInteger, 123);
# Conditionally write a property
if ($N > 10) {
set_propaf(MyAutoFloat, 99.9);
}
- Note
- If N <= 10, MyAutoFloat will be initialized from the property on the source frame of clip $x. If it doesn't exist there, the result frame won't contain this property.
Deleting (SingleExpr only)
Delete a frame property using the remove_prop built-in function.
- Signature:
- remove_prop(property_name)
- Parameters:
- property_name: The name of the property to delete, as an identifier (not a string).
Example:
# Remove a property that might exist on the source frame
remove_prop(MyOldProp);
7.2. Pixel and Data I/O
- Important
- Read-After-Write Behavior for Pixels
Pixel access in llvmexpr (both Expr and SingleExpr modes) is not atomic in the sense of read-after-write visibility.
- Reading (e.g., dyn(), $src0[...], []) always reads from the input frames.
- Writing (e.g., @[], store(), RESULT) always writes to the output frame.
Therefore, if you write a value to a pixel and then immediately read from the same coordinate, you will get the original input value, not the value you just wrote. To pass data between steps, use Arrays.
7.2.1 Expr mode
In Expr mode, you can access pixels from source clips relative to the current pixel or at absolute coordinates.
Static Relative Pixel Access
Access a pixel at a fixed, constant offset from the current coordinate ($X, $Y).
- Syntax: $clip[offsetX, offsetY] or $clip[offsetX, offsetY]:m or $clip[offsetX, offsetY]:c
- $clip must be a source clip constant.
- offsetX and offsetY must be integer literals.
- Boundary Suffixes:
- :c: Forces clamped boundary (edge pixels are repeated).
- :m: Forces mirrored boundary.
- If omitted, the filter's global boundary parameter is used.
Dynamic Absolute Pixel Access
Access a pixel at a dynamically calculated coordinate using the 3-argument dyn() function. See section 8.3 for details.
VkExpr Multi-Pass Pipeline & Intermediate Buffers
VkExpr can chain multiple infix stages by separating them with --- inside a single expr string.
- Stages are executed in order, and each segment is converted to postfix independently.
- Stage k can read intermediate results from $buf0 … $buf{k-1}; stage 0 has no buffers available.
- $bufN behaves like a clip for pixel reads: use $bufN, $bufN[x,y]:c|:m, or dyn($bufN, x, y, plane) in later stages.
- Intermediate buffers match the output resolution/format and are stored as float32; frame property access on $bufN is not supported.
- Within a single stage, reads still come from the original input frames (no read-after-write). Use stage boundaries and $bufN when you need to feed one computation step into the next.
- On CPU, “multi-pass” is typically just multiple Expr calls in your VapourSynth script. On GPU, multiple plugin calls can introduce extra synchronization and transfers; VkExpr stages keep intermediates on the GPU.
7.2.2 SingleExpr mode
In SingleExpr mode, all data I/O is explicit and uses absolute coordinates.
Plane-Specific Dimensions
- Warning
- Deprecation Notice: frame.width[N] and frame.height[N] are deprecated. Use the functions from the std standard library instead.
Access the width and height of specific planes using frame.width[N] and frame.height[N].
w0 = frame.width[0]; # Width of plane 0 (luma)
h1 = frame.height[1]; # Height of plane 1 (chroma U)
- Note
- The plane index N must be a literal constant. frame.width and frame.height are special built-in syntax forms, not member access on an object.
Absolute Pixel Reading
Read pixels from specific coordinates and planes using the 4-argument version of dyn(). See section 8.3 for details.
Absolute Pixel Writing
Write values to specific output frame locations using the 4-argument version of store(). See section 8.3 for details.
8. Functions
8.1. Function Calls
Functions are called using standard syntax: functionName(argument1, argument2, ...)
8.2. Built-in Functions
| Function | Arity | Description |
| sin, cos, tan | 1 | Trigonometric sine, cosine, tangent. |
| asin, acos, atan | 1 | Inverse trigonometric functions. |
| atan2 | 2 | Two-argument arctangent; atan2(y, x). |
| exp, exp2 | 1 | Exponential functions e^x, 2^x. |
| log, log2, log10 | 1 | Natural/base-2/base-10 logarithms. |
| sqrt | 1 | Square root. |
| abs | 1 | Absolute value. |
| sgn | 1 | Signum function: -1 if x < 0, 0 if x == 0, 1 if x > 0. |
| floor, ceil, round, trunc | 1 | Rounding family. round(x) rounds to nearest integer; halfway cases round away from zero. |
| min, max | 2 | Minimum/maximum. |
| copysign | 2 | Magnitude of first operand, sign of second. |
| clamp | 3 | clamp(x, lo, hi); clamps to [lo, hi]. |
| fma | 3 | Fused multiply-add: (a * b) + c. |
| nth_N | M (where M ≥ N) | Returns the N-th smallest value (1-indexed). E.g., nth_3(1,2,3,4,5,6) returns 3. |
| new | 1 | Allocates an array. In Expr mode, size must be a literal. In SingleExpr, size can be an expression. |
| resize | 1 | Resizes an array in SingleExpr mode only. The array must be previously allocated with new(). |
Notes:
- All built-ins are recognized by name and arity; wrong arity will raise a syntax error.
- nth_N(...) supports any N ≥ 1. It sorts its M arguments internally and returns the N-th smallest. This compiles to stack ops using sortM/dropK under the hood.
8.3. Mode-Specific Functions
dyn() - Dynamic Pixel Access
The dyn() function has different signatures for Expr and SingleExpr modes.
- Expr mode: dyn($clip, x_expr, y_expr, [boundary_mode])
- Accesses a pixel at a dynamically calculated coordinate.
- $clip must be a source clip constant.
- x_expr and y_expr can be any valid expressions. If the coordinates are not integers, they will be rounded half to even.
- boundary_mode (optional): Boundary handling mode.
- If omitted (3 arguments): Clamped boundary (default, same as 2).
- 0: Use the filter's global boundary parameter (same as the boundary mode in Section 7.2).
- 1: Mirrored boundary.
- 2: Clamped boundary.
- dyn($src0, $X + 2, $Y + 3, 0) is roughly equivalent to $src0[2, 3].
- SingleExpr mode: dyn($clip, x, y, plane)
- Reads a pixel from an absolute coordinate on a specific plane.
- Signature: dyn($clip, x, y, plane)
- $clip: Clip constant (e.g., $x, $y, $z, or $srcN).
- x, y: Absolute coordinates (can be expressions).
- plane: Plane index (must be a literal constant).
- Example: val = dyn($x, 100, 200, 0);
store() - Pixel Writing
The store() function has different signatures for Expr and SingleExpr modes.
- Expr mode: store(x, y, val)
- Writes val to the output pixel at [trunc(x), trunc(y)].
- This allows an expression for one pixel to write to another location.
- SingleExpr mode: store(x, y, plane, value)
- Writes a value to an absolute coordinate on a specific output plane.
- Signature: store(x, y, plane, value)
- x, y: Absolute coordinates (can be expressions).
- plane: Plane index (must be a literal constant).
- value: Value to write (can be an expression).
- Example: store(0, 0, 0, 255);
- Warning
- No boundary checking is performed. Writing outside valid frame dimensions causes undefined behavior.
exit() (Expr only)
- Signature: exit()
- Suppresses the default pixel write to the current coordinate ($X, $Y). This is useful when an expression only writes to other pixels using store().
8.4. User-Defined Functions
Functions are defined using the function keyword. The function name cannot conflict with any built-in function names.
function functionName(Type1 param1, Type2 param2) {
# Body of the function
local_var = param1 * param2
return local_var + 10
}
- Parameter Types:
- Value: A standard floating-point value, the most general type. This is the default if no type is specified.
- Clip: A source clip constant (e.g., $a, $src1).
- Literal: A literal constant value (numeric literal).
- Array: A reference to an array created with new().
- Return Type: All functions that return a value return type Value. There is no syntax for specifying a return type.
Return Statement: The return statement exits a function. It can appear multiple times within a function body and can be used with or without a value.
- return expression;: Exits the function and provides a return value.
- return;: Exits a function that does not return a value (a "void" function).
The language enforces the following rules for return statements:
- Consistency: Within a single function, all return statements must be consistent. You cannot mix return <value>; and return;.
- Completeness for Value-Returning Functions: If a function returns a value (i.e., contains at least one return <value>;), the compiler will verify that all possible control flow paths end in a return statement. If any path can exit without returning a value, a compile-time error is raised.
- Flexibility for Void Functions: If a function does not return a value (it only contains empty return; statements or no return statements at all), it is not required for all paths to have a return. The function can simply "fall off" the end when its last statement is executed.
- Inlining: Function calls are effectively inlined at compile time. Recursion is not supported.
- Important
- Recursion Not Supported: Function calls are inlined at compile time. Recursive function calls will cause compilation errors.
- Nesting: Function definitions cannot be nested.
8.5. Function Overloading
The language supports function overloading, allowing multiple functions to share the same name as long as their parameter lists are different in number or type.
When an overloaded function is called, the compiler selects the best-matching overload based on the provided arguments:
- Exact Match: An overload with parameter types that exactly match the argument types is always chosen.
- Best Fit (Fewest Conversions): If no exact match is found, the compiler chooses the overload that requires the minimum number of implicit type conversions (e.g., from Clip to Value).
- Tie-Breaking: If multiple overloads have the same number of conversions, the one where the first conversion occurs on a later argument (further to the right in the parameter list) is selected.
- Ambiguity: If a single best overload cannot be determined from these rules, a compile-time error is raised.
Example: (Expr mode)
# Overloaded function 'process'
function process(Clip c) {
# processes a clip
return c * 2 - 1
}
function process(Value v) {
# processes a numeric value
return v * 2
}
# Calling the overloads
a = process($x) # Calls process(Clip c)
b = process(10.0) # Calls process(Value v)
9. Scope and Globals
9.1. Scopes
- Global Scope: Variables defined at the top level of the script.
- Function Scope: Each function has its own local scope. This includes its parameters and any variables assigned within its body.
- Block Scope: Variables defined inside if, else, and while blocks are local to that specific block. They cannot be accessed outside of the block they are defined in.
Example of Block Scope:
if ($x > 10) {
a = 5 # 'a' is defined only inside this block
}
# Attempting to use 'a' here would cause a syntax error
# because 'a' is not defined in the global scope.
# RESULT = a
9.2. Global Variable Access
By default, functions operate in an isolated scope and cannot access global variables. This behavior can be modified with a global declaration placed immediately before a function definition.
- <global.none>: (Default) The function cannot access any global variables.
- <global.all>: The function can access any global variable defined in the script at the time of the function's call.
- <global<var1><var2>...>: The function can access only the specified global variables.
Example:
<global<my_global>>
function useGlobal(x) {
return x + my_global # Accesses global 'my_global'
}
my_global = 100
RESULT = useGlobal(5) # Evaluates to 105
- Any global variable a function depends on must be defined before that function is called.
10. Control Flow (if/else/while and Labels)
The infix syntax supports structured conditionals, loops, and low-level jumps at both global and function scope.
10.1. If / Else Blocks
if (condition) {
# statements
} else {
# statements
}
- else is optional. Nested blocks are supported.
- The condition is any valid expression; any non-zero value (including negative values) is treated as true, and zero is treated as false.
- Each block is a sequence of normal statements (assignments or expressions).
10.2. Goto and Labels
- Define a label: label_name: (at the start of a line)
- Unconditional jump: goto label_name
Constraints and rules:
- Jumps may cross if/else braces (C-like).
- The goto statement cannot jump over a variable's initialization statement and enter that variable's lexical scope.
- The target label must exist somewhere in the script; otherwise a syntax error is raised.
- Goto cannot jump across global scope and functions, or between functions.
- Labels only mark positions; they do not execute anything by themselves.
10.3. While Loops
A while loop provides a C-style syntax for repeated execution as long as a condition is true.
while (condition) {
# statements
}
- The condition is any valid expression; any non-zero value (including negative values) is treated as true, and zero is treated as false.
- The loop continues to execute as long as the condition evaluates to true.
Example:
A countdown loop using while:
counter = 4
while (counter > 0) {
counter = counter - 1
}
RESULT = counter # will be 0
11. Arrays
Arrays are collections of values that can be created and accessed by an index. They are especially useful in SingleExpr mode for tasks like building lookup tables, histograms, or buffering data for complex calculations.
11.1. Declaration and Initialization
Arrays are created by calling the built-in new() function and assigning the result to a variable.
- Expr Mode (Fixed-Size Only):
- The size must be a literal constant.
- my_lut = new(256);
- SingleExpr mode (Fixed or Dynamic Size):
- Fixed size: my_array = new(100);
- Dynamic size: The size can be any expression that results in a value.
# Create an array to hold a value for each pixel
frame_size = $width * $height;
pixel_buffer = new(frame_size);
- Float to Integer Conversion: If the size expression evaluates to a floating-point value, it will be truncated toward zero.
- Examples: new(10.9) allocates size 10, new(3.1) allocates size 3, new(-2.9) allocates size -2 (which would cause undefined behavior).
- Note
- This is truncation, not rounding. new(10.9) will allocate 10 elements, not 11.
- The resize() function can be used to change an array's size.
pixel_buffer = resize(new_size);
-
An array must be allocated using new() before it can be resized. The same float-to-integer truncation applies to resize().
11.2. Element Access
C-style square brackets [] are used to read from and write to array elements.
- Writing: my_array[index_expression] = value_expression;
- Reading: value = my_array[index_expression];
Float to Integer Conversion: If the index expression evaluates to a floating-point value, it will be truncated toward zero.
- Examples: my_array[3.7] accesses index 3, my_array[0.1] accesses index 0, my_array[-1.5] accesses index -1 (may cause undefined behavior).
- This is truncation, not rounding: my_array[3.9] accesses index 3, not 4.
Syntax Disambiguation: Array access is distinguished from relative pixel access by the number of arguments in the brackets.
- my_array[i] (1 argument) is an array access.
- $x[0, 1] (2 arguments) is a pixel access.
Example (SingleExpr mode):
# Create and populate a lookup table
lut = new(256);
i = 0;
while (i < 256) {
lut[i] = i * i; # Store the square of the index
i = i + 1;
}
# In a later part of the script, use the LUT
some_value = dyn($x, 10, 10, 0);
result_from_lut = lut[some_value]; # Read from the LUT
11.3. Arrays as Function Parameters
Arrays can be passed to user-defined functions by specifying the Array type in the function signature. The array is passed by reference, meaning the function can modify the original array.
Example:
# Function to fill an array with a value
function fill_array(Array a, Value fill_val, Value len) {
i = 0;
while (i < len) {
a[i] = fill_val;
i = i + 1;
}
}
# Usage
my_data = new(10);
fill_array(my_data, 3.14, 10); # my_data is now filled with 3.14
11.4. Scope and Lifetime
The lifetime of an array depends on the execution mode:
- Expr mode: Arrays are temporary and exist only for the evaluation of a single pixel. They cannot be used to share data between pixels.
- SingleExpr mode: An array's lifetime is confined to the processing of a single frame. Its contents are not guaranteed to be preserved between frames due to VapourSynth's parallel processing. You should assume arrays are uninitialized at the start of each frame's evaluation.
11.5. Safety
- Warning
- The language does not perform runtime bounds checking on array access. Accessing an index outside the allocated size (e.g., my_array[-1] or my_array[size]) will result in undefined behavior, which may include crashes or memory corruption. It is the script author's responsibility to ensure all access is within bounds.
- Attention
- Floating-point indices: While the language accepts floating-point values for array indices and sizes, they are truncated toward zero, not rounded. This may lead to unexpected behavior if you assume rounding. Use explicit rounding functions (floor(), ceil(), round()) if you need specific rounding behavior (note round(x) is nearest with halfway cases away from zero).
Negative sizes/indices: Passing negative values to new() or resize(), or using negative array indices (which can result from truncating small negative floats like -0.5 → 0 or larger ones like -1.5 → -1), will cause undefined behavior.
12. Standard Library Reference
The @requires directive can be used to import built-in standard libraries to extend the language's functionality.
12.1. The meta Library
The meta library provides a collection of powerful macros for compile-time metaprogramming. These macros help you generate repetitive code, perform compile-time assertions, and carry out more advanced preprocessing tasks.
To use this library, add the following to your code:
Macro Functions
- ERROR(message)
- Function: Generates a compile-time error with the specified message, useful in ternary operators.
- ASSERT_CONST(expression, context, message)
- Function: Asserts that an expression must evaluate to true at compile time. If the expression is not a constant or evaluates to false, compilation will fail.
- Parameters:
- expression: The compile-time expression to check.
- context: A token representing the context where the error occurred.
- message: A token describing the reason for the assertion failure.
- Example: ASSERT_CONST(__WIDTH__ > 1024, Clip_width_, must_be_greater_than_1024)
- PASTE(token1, token2)
- Function: Pastes two tokens into one. It uses a two-step macro expansion to ensure that token1 and token2 are fully expanded before pasting.
- Example:
@requires meta
@define VAR_NAME my_var_
@define INDEX 5
@section autotoc_md98 Expands to my_var_5
var = PASTE(VAR_NAME, INDEX)
- JOIN(count, macro, separator)
- Function: A recursive macro that generates a sequence of expressions joined by a separator. It calls macro(i) for each index i from 0 to count - 1. count must be a compile-time constant.
- Parameters:
- count: The number of repetitions.
- macro: A single-argument macro that generates each element in the sequence.
- separator: The token used to join the elements (e.g., +, ,).
- Example: Generate $src0 + $src1 + $src2
@define GET_SRC(i) PASTE($src, i)
@section autotoc_md99 Expands to (($src0 + $src1) + $src2)
RESULT = JOIN(3, GET_SRC, +)
- UNROLL(count, macro)
- Function: Similar to JOIN, but generates a sequence of statements separated by semicolons. It calls macro(i) for each index from 0 to count - 1. count must be a compile-time constant.
- Example: Generate an unrolled loop
@define PROCESS(i) data[i] = data[i] * 2
@section autotoc_md100 Expands to: data[0] = data[0] * 2; data[1] = data[1] * 2; ...
UNROLL(5, PROCESS)
12.2. The algorithms Library
The algorithms library provides a set of common algorithms for operating on arrays.
To use this library, add the following to your code:
Functions
- swap(Array a, Value i, Value j)
- Function: Swaps the two elements at indices i and j in array a.
- reverse(Array a, Value begin, Value end)
- Function: Reverses the order of elements in array a within the range [begin, end).
- sort(Array a, Value begin, Value end)
- Function: Sorts the elements in array a within the range [begin, end) in ascending order.
- Implementation: This function uses Introsort to achieve an average and worst-case time complexity of O(N log N).
- find_kth_smallest(Array a, Value begin, Value end, Value k)
- Function: Finds the k-th smallest element (0-indexed) in array a within the range [begin, end). This operation is more efficient than a full sort, with an average time complexity of O(N).
- Parameters: k is a 0-based index where 0 <= k < (end - begin).
- Implementation: This function uses a quickselect algorithm. In Expr mode, if the range size is not a compile-time constant, it falls back to a slower but correct implementation.
12.3. The std Library
The std library provides functions to access frame properties (width, height, bitdepth, format) of input clips using runtime values for clip index and plane index. This is particularly useful when the clip or plane index is not known at compile time. For information about the output frame, use the Context Macros instead.
To use this library, add the following to your code:
Functions
- get_width(plane_idx)
- Mode: Expr
- Function: Returns the width of the specified plane. Returns -1 if the clip index or plane index is invalid.
- Parameters:
- plane_idx: The index of the plane (0-based).
- get_width(clip_idx, plane_idx)
- Mode: SingleExpr
- Function: Returns the width of the specified plane of the specified clip. Returns -1 if the clip index or plane index is invalid.
- Parameters:
- clip_idx: The index of the input clip (0-based).
- plane_idx: The index of the plane (0-based).
- get_height(plane_idx)
- Mode: Expr
- Function: Returns the height of the specified plane. Returns -1 if the clip index or plane index is invalid.
- Parameters:
- plane_idx: The index of the plane (0-based).
- get_height(clip_idx, plane_idx)
- Mode: SingleExpr
- Function: Returns the height of the specified plane of the specified clip. Returns -1 if the clip index or plane index is invalid.
- Parameters:
- clip_idx: The index of the input clip (0-based).
- plane_idx: The index of the plane (0-based).
- get_bitdepth(clip_idx)
- Mode: Both
- Function: Returns the bit depth of the specified clip. Returns -1 if the clip index is invalid.
- Parameters:
- clip_idx: The index of the input clip (0-based).
- get_sampletype(clip_idx)
- Mode: Both
- Function: Returns the sample type of the specified clip (0 for integer/stInteger, 1 for float/stFloat). Returns -1 if the clip index is invalid.
- Parameters:
- clip_idx: The index of the input clip (0-based).
- get_colorfamily(clip_idx)
- Mode: Both
- Function: Returns the ColorFamily of the specified clip (0=cfUndefined, 1=cfGray, 2=cfRGB, 3=cfYUV). Returns -1 if the clip index is invalid.
- Parameters:
- clip_idx: The index of the input clip (0-based).
Constants
The std library provides helpful constants for ColorFamily and SampleType comparisons:
- ColorFamily Constants:
- cfUndefined = 0
- cfGray = 1
- cfRGB = 2
- cfYUV = 3
- SampleType Constants:
- stInteger = 0
- stFloat = 1
Example:
@requires std
# Get the width of the luma plane (plane 0) of the first input clip (clip 0)
w = get_width(0, 0)
# Get the bitdepth of the second input clip (clip 1)
bd = get_bitdepth(1)