AviSynth Syntax - Frame properties ================================== The concept was ported from VapourSynth. Frame properties are per-frame data. Source or other filters can store useful data into frame properties such as information on colorimetry. Imagine them as an array of zero or more elements of PropertyName=Value pairs. Reading or writing them is possible either in runtime environment or at the normal script level. Avisynth provides the necessary framework for handling (set, read, clear, pass) such properties, both from users scripts and from the Filter SDK. Before v3.6.2test7 none of its internal functions (such as color space converters) were able to set or work upon frame property values. However the set of frame properties which are actively used by Avisynth core can extend in later versions. E.g. in 3.7.x color space converters or even "Text" filter read and/or set some colormetry or color matrix related properties. And there are external filters (like avsresize) and source plugins that use frame properties. Developer info (see also in Filter SDK): On filter level the set of frame properties should be copied from a previous (or specific) input frame. When a filter is using ``env->MakeWritable`` in its ``GetFrame`` method this happens automatically. A simple ``env->NewVideoFrame`` however means a dead-end for frame property passing mechanism. Filter must either use ``env->NewVideoFrameP`` which has an additional parameter: a source frame (origin) of the frame properties. Or frame properties have to be copied later, programatically by the ``copyFrameProps`` ``ScriptEnvironment`` function. For compatibility reasons ``NewVideoFrameP`` must be called adaptively instead of the traditional ``NewVideoFrame``, since it does not exist in older Avisynth versions. Only usable after detecting Avisynth interface version 8 (NewVideoFrameP was introduced in v8). What happens if this copy is not done properly? Nothing deadly, but then the filter is a dead-end for the flow of frame properties since NewVideoFrame constructs new frame without them. Old filters which are not written with this in mind will behave like this. Frame property getter functions are evaluated at every frame. They can be used inside the scripts passed to runtime filters (ScriptClip). Frame property setters can be called both at script level and in runtime. When a property is set on script level it will be constant along the lifetime of the whole clip, unless it is changed in runtime, inside ScriptClip. Definition ---------- Frame properties are stored as key-value pairs. Each video frame can contain such a list, which can even be different from frame to frame. * Key is an alphanumeric identifier. * Value can be of single value or array of type * 64 bit integer (32 bit integer when converted to AVSValue inside Avisynth+, AVSValue limitation) * 64 bit double (32 bit float when converted to AVSValue inside Avisynth+, AVSValue limitation) * string (or byte data) with given length. Strings are null terminated. The content whether it is string or binary data can be given as a hint; from Avisynth scripting only strings allowed. * frame reference (PVideoFrame) * clip reference (PClip) Manipulation modes ------------------ Property setting has 3 modes: 0-replace 1-append 2-touch. (for developers: see ``AVSPropAppendMode`` in avisynth.h) * 0 - single value for that key is replaced * 1 - property is appended (make arrays by calling with mode=1 consecutively) * 2 - touch (deprecated, just creates the key) Reserved frame property names ----------------------------- There are quasi-standard frame property names which are used widespread. Some of them are used in Avisynth core: - _ChromaLocation - _ColorRange - _Matrix but the others are used only by external plugins. Frame property concept came from VapourSynth (see "Reserved Frame Properties" at http://www.vapoursynth.com/doc/apireference.html). But it is convenient that Avisynth plugins use the same property names and their and values. Keys starting with _ have strictly defined meanings specified below. It is acceptable to not set any of these keys if they are unknown. It is also a fatal error to set them to a value not specified below. _ChromaLocation ~~~~~~~~~~~~~~~ int _ChromaLocation Chroma sample position in YUV formats. 0=left, 1=center, 2=topleft, 3=top, 4=bottomleft, 5=bottom. Synonyms: * left, mpeg2 * center, jpeg, mpeg1 _ColorRange ~~~~~~~~~~~ int _ColorRange Full or limited range (PC/TV range). Primarily used with YUV formats, but can mark Studio RGB as well. 0=full range, 1=limited range (RGB: narrow range). _Primaries ~~~~~~~~~~ int _Primaries Color primaries as specified in ITU-T H.265 Table E.3. _Matrix ~~~~~~~ int _Matrix Matrix coefficients as specified in ITU-T H.265 Table E.5. _Transfer ~~~~~~~~~ int _Transfer Transfer characteristics as specified in ITU-T H.265 Table E.4. _FieldBased ~~~~~~~~~~~ int _FieldBased If the frame is composed of two independent fields (interlaced). 0=frame based (progressive), 1=bottom field first, 2=top field first _AbsoluteTime ~~~~~~~~~~~~~ float _AbsoluteTime The frame’s absolute timestamp in seconds if reported by the source filter. Should only be set by the source filter and not be modified. Use durations for all operations that depend on frame length. _DurationNum ~~~~~~~~~~~~ int _DurationNum _DurationDen ~~~~~~~~~~~~ int _DurationDen The frame’s duration in seconds as a rational number. Filters that modify the framerate should also change these values. This fraction (_DurationNum/_DurationDen) should always be normalized. _Combed ~~~~~~~ int _Combed (boolean) Whether or not the frame needs postprocessing, usually hinted from field matching filters. _Field ~~~~~~ int _Field This property signals which field was used to generate this frame. VapourSynth is using it in core.std.SeparateFields, in Avisynth core it is not used at all. 0=from bottom field, 1=from top field. _PictType ~~~~~~~~~ string _PictType A single character describing the frame type. It uses the common IPB letters but other letters may also be used for formats with additional frame types. _SARNum ~~~~~~~ int _SARNum _SARDen ~~~~~~~ int _SARDen Pixel (sample) aspect ratio as a rational number. _SceneChangeNext ~~~~~~~~~~~~~~~~ int _SceneChangeNext (boolean) If 1, this frame is the last frame of the current scene. The next frame starts a new scene. _SceneChangePrev ~~~~~~~~~~~~~~~~ int _SceneChangePrev (boolean) If 1, this frame starts a new scene. Property set ------------ Input value of setter functions are to be come either - from the return value of "function objects" - direct value Property setter function names begin with ``propSet`` Common parameters: :: clip c, string key_name, direct value of supported types (integer, float, string, array, clip) or a "function object" int "mode": 0=replace (default), 1=append, 2=touch. There is no append mode for inserting a full array into the property. propSet ~~~~~~~ :: propSet(clip, string key_name, function func_obj [, integer "mode"]) generic property setter, automatic type recognition by the return value of the function object :: propSet(clip, string key_name, integer value [, integer "mode"]) propSet(clip, string key_name, float value [, integer "mode"]) propSet(clip, string key_name, string value [, integer "mode"]) propSet(clip, string key_name, array value) propSet(clip, string key_name, clip value [, integer "mode"]) The above functions are setting a property from a directly passed values note: array must contain only the similarly typed values, e.g. cannot mix strings with integers. propSetInt ~~~~~~~~~~ :: propSetInt(clip, string key_name, function func_obj [, integer "mode"]) propSetFloat ~~~~~~~~~~~~ :: propSetFloat(clip, string key_name, function func_obj [, integer "mode"]) propSetString ~~~~~~~~~~~~~ :: propSetString(clip, string key_name, function func_obj [, integer "mode"]) propSetArray ~~~~~~~~~~~~ :: propSetArray(clip, string key_name, function func_obj [, integer "mode"]) propSetClip ~~~~~~~~~~~ :: propSetClip(clip, string key_name, function func_obj [, integer "mode"]) these setters accept only the specific type Property get ------------ Get properties by name or as a whole. Since AviSynth 3.7.1: allow propGetXXX property getter functions called as normal functions, outside runtime. By default frame property values are read from frame#0 which index can be overridden by the offset parameter. When called from inside runtime functions will return frame properties of the actual frame (+offset). Common parameters: :: clip c, string key_name, integer "index", (default 0): for zero based indexing array access integer "offset" (default 0), similar to the other runtime functions: frame offset (e.g. -1: previous, 2: next next) propGetAny ~~~~~~~~~~ :: propGetAny(clip, string key_name[, integer "index", integer "offset"]) returns the automatically detected type propGetInt ~~~~~~~~~~ :: propGetInt(clip, string key_name[, integer "index", integer "offset"]) returns only if value is integer, throws an error otherwise (note: unlike Avisynth integer frame properties internally use 64 bit integers) propGetFloat ~~~~~~~~~~~~ :: propGetFloat(clip, string key_name[, integer "index", integer "offset"]) If the content is not of floating point type, it throws an error. Until version 3.7.3, the internal representation of floating point numbers was 32-bit float. Starting from Avisynth 3.7.4, float frame properties are read as real 64-bit doubles. propGetString ~~~~~~~~~~~~~ :: propGetString(clip, string key_name[, integer "index", integer "offset"]) returns only if value is string, throws an error otherwise propGetAsArray ~~~~~~~~~~~~~~ :: propGetAsArray(clip, string key_name[, integer "index", integer "offset"]) A frame property can hold multiple values of the same type: it can be an array. ``propGetAsArray`` returns an array. For a single property the array size will be 1. propGetClip ~~~~~~~~~~~ :: propGetClip(clip, string key_name[, integer "index", integer "offset"]) returns only if value is clip, throws an error otherwise propGetAll ~~~~~~~~~~ :: propGetAll(clip [, integer "offset"]) Returns all frame properties in an array of [key-value] pairs. Array size will be ``numProps`` Each key-value pair is contained in a two dimensional subarray. If the property value itself is an array again then "value" will be an array as well. This array contains all properties of the specific frame. They are accessible with the associative feature of AviSynth array access. (See syntax there) **Example:** :: ScriptClip("""last.propSet("cica","hello"+String(current_frame)).\ propSetInt("test_i1",function[](clip c) { return current_frame*3 }).\ propSet("test_i2", current_frame * 2) """) ScriptClip("""p = propGetAll() \ SubTitle("size:" + String(p.ArraySize()) + " " + \ String(p["test_i1"]) + " " + \ String(p["cica"]) + " " + \ String(p["test_i2"]))""") ScriptClip("""p = propGetAll() \ SubTitle("size:" + String(p.ArraySize()) + " " + \ String(p[0,1]) + " " + \ String(p[1,1]) + " " + \ String(p[2,1]), x=0, y=20)""") **Example (read-write basic)** :: ColorBars() # just practicing with function objects ScriptClip(function[](clip c) { c.Subtitle(String(current_frame)) }) # write frame properties with function object ScriptClip("""propSetInt("frameprop_from_str",func(YPlaneMax))""") # write frame properties with traditional script string ScriptClip(function[](clip c) { propSetInt("frameluma_sc_func",func(AverageLuma)) }) # read frame properties (function object, string) ScriptClip(function[](clip c) { SubTitle(string(propGetInt("frameprop_from_str")), y=20) }) ScriptClip("""SubTitle(string(propGetInt("frameluma_sc_func")), y=40)""") return last **Example (almost everything)** :: ColorBars(width=640, height=480, pixel_type="yv12", staticframes=true) ScriptClip(function[](clip c) { propSetString("s",function[](clip c) { return "Hello " + string(current_frame) }) }) ScriptClip(function[](clip c) { propSetString("s",function[](clip c) { return "Hello array element #2 " }, mode=1) }) ScriptClip(function[](clip c) { propSetString("s",function[](clip c) { return "Hello array element #3 "}, mode=1 ) }) ScriptClip(function[](clip c) { propSetString("s2",function[](clip c) { return "Another property "} ) }) ScriptClip(function[](clip c) { propSetInt("s_int",function[](clip c) { return current_frame*1 }) }) ScriptClip(function[](clip c) { propSetInt("s_int",function[](clip c) { return current_frame*2 }, mode=1) }) ScriptClip(function[](clip c) { propSetInt("s_int",function[](clip c) { return current_frame*4 }, mode=1 ) }) ScriptClip(function[](clip c) { propSetFloat("s_float",function[](clip c) { return current_frame*1*3.14 }) }) ScriptClip(function[](clip c) { propSetFloat("s_float",function[](clip c) { return current_frame*2*3.14 }, mode=1) }) ScriptClip(function[](clip c) { propSetFloat("s_float",function[](clip c) { return current_frame*3*3.14 }, mode=1 ) }) ScriptClip(function[](clip c) { propSetArray("s_float_arr",function[](clip c) { return [1.1, 2.2] } ) }) ScriptClip(function[](clip c) { propSetArray("s_int_arr",function[](clip c) { return [-1,-2,-5] } ) }) ScriptClip(function[](clip c) { propSetArray("s_string",function[](clip c) { return ["ArrayElementS_1", "ArrayElementS_2"] } ) }) #ScriptClip("""propDelete("s")""") ScriptClip(function[](clip c) { y = 0 SubTitle("Prop Key count =" + String(propNumKeys), y=y) y = y + 15 numKeys = propNumKeys() - 1 for ( i = 0 , numKeys) { propName = propGetKeyByIndex(index = i) propType = propGetType(propName) SubTitle("#"+String(i) + " property: '" + propName + "', Type = " + String(propType) , y=y) y = y + 15 for(j=0, propNumElements(propName) - 1) { SubTitle("element #" + String(j) + ", size = " + String(propType == 3 ? propGetDataSize(propName, index=j) : 0) + ", Value = " + String(propGetAny(propName, index=j)), y = y) #SubTitle("element #" + String(j) + " size = " + String(propType == 3 ? propGetDataSize(propName, index=j) : 0) + ", Value = " + String(propGetAny(propName, index=j)), y = y) y = y + 15 } } return last }) ScriptClip(function[](clip c) { a = propGetAsArray("s") y = 100 x = 400 SubTitle(string(a.ArraySize()), x=x, y=y) for(i=0, a.ArraySize()-1) { SubTitle("["+String(i)+"]="+ String(a[i]),x=x,y=y) y = y + 15 } return last }) # get int array one pass ScriptClip(function[](clip c) { a = propGetAsArray("s_int") y = 440 x = 400 SubTitle("Array size=" + string(a.ArraySize()), x=x, y=y) y = y + 15 for(i=0, a.ArraySize()-1) { SubTitle("["+String(i)+"]="+ String(a[i]),x=x,y=y) y = y + 15 } return last }) # get float array one pass ScriptClip(function[](clip c) { a = propGetAsArray("s_float") y = 440 x = 200 SubTitle("Array size=" + string(a.ArraySize()), x=x, y=y) y = y + 15 for(i=0, a.ArraySize()-1) { SubTitle("["+String(i)+"]="+ String(a[i]),x=x,y=y) y = y + 15 } return last }) # get string array ScriptClip(function[](clip c) { a = propGetAsArray("s_string") y = 440 x = 000 SubTitle("Array size=" + string(a.ArraySize()), x=x, y=y) y = y + 15 for(i=0, a.ArraySize()-1) { SubTitle("["+String(i)+"]="+ String(a[i]),x=x,y=y) y = y + 15 } return last }) AviSynth 3.7.1: allow propGetXXX property getter functions called as normal functions, outside runtime. By default frame property values are read from frame#0 which index can be overridden by the offset parameter. **Example:** :: Colorbars() PropSet(last, "hello", 1) # Set to 1 for all frames # Override to 2 with runtime function except for frameNo=1 ScriptClip("""if(current_frame!=1) {propSet("hello",2)}""") n0 = propGetInt("hello") # same as propGetInt("hello",offset=0) # or get the frame property from the Nth frame n1 = propGetInt("hello",offset=1) n2 = propGetInt("hello",offset=2) # n0 and n2 is 2 (overridden in runtime) # n1 will be 1 (keeps global setting) SubTitle("n0/n1/n2=" + "{n0}/{n1}/{n2}".Format) Deleting properties ------------------- Deletes specific properties or all property entries propDelete ~~~~~~~~~~ :: propDelete(clip, string) Deletes a property by name. If property does not exist, do nothing. * clip (required) specifies clip. * string (required) or string array: key_name (case sensitive) specifies the - name of the parameter to delete - a regex expression, starts with "^", ends with "$" - a wildcard name specifier (contains ``*``) *Example:* :: ScriptClip("""propDelete("my_spec_prop")""") propDelete("_*") # deletes all properties starting with "_" propClearAll ~~~~~~~~~~~~ :: propClearAll(clip) Clears all properties for a given video frame * clip (required) specifies clip. Other property functions ------------------------ propShow ~~~~~~~~ This debug filter lists frame properties on screen. Listing appears as a name = value list and can be filtered See here: :doc:`propShow <../corefilters/propShow>`. propGetDataSize ~~~~~~~~~~~~~~~ :: propGetDataSize(clip, string key_name [, integer "index", integer "offset"]) returns the size of the string or underlying data array propNumElements ~~~~~~~~~~~~~~~ :: propNumElements(clip, string key_name [, integer "offset"]) returns the array size of a given property. 1=single value propNumKeys ~~~~~~~~~~~ :: propNumKeys(clip, [, integer "offset"]) returns number of entries (keys) for a frame propGetKeyByIndex ~~~~~~~~~~~~~~~~~ :: propGetKeyByIndex(clip, integer "index" [, integer "offset") returns the key name for the Nth property (zero based, 0<=index`. $Date: 2025/03/04 12:20:00 $