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.

    • 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

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"])

returns only if value is float, throws an error otherwise (note: unlike Avisynth float frame properties internally use 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 one specific property 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) key_name (case sensitive) specifies the name of the parameter to delete

Example:

ScriptClip("""propDelete("my_spec_prop")""")

propClearAll

propClearAll(clip)

Clears all properties for a given video frame

  • clip (required) specifies clip.

Other property functions

propShow

This debug filter lists all frame properties on screen. Listing appears as a name = value list.

See here: <todo link>

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<propNumKeys)

propGetType

propGetType(clip, string key_name [, integer "offset"])

returns the type of the given key

  • unset: 0

  • integer: 1

  • float: 2

  • string: 3

  • clip: 4

  • frame: 5

propCopy

propCopy(clip, clip [,bool "merge"])   AVS+(v3.7.1)

Copies the frame properties of the second clip to the first.

Parameter merge (default false):

  • when false: exact copy (original target properties will be lost)

  • when true: keeps original properties, appends all parameters from source but overwrite if a parameter with the same name already exists.

Changelog

Version

Changes

AviSynth 3.7.1

allow propGetXXX called outside runtime functions
add propCopy

AviSynth 3.7.0

add propGetType

Back to Internal functions.

$Date: 2024/01/05 15:57:00 $