Log in

View Full Version : Problem handling frame properties


Selur
28th April 2024, 15:24
Using the following script:
# Imports
import vapoursynth as vs
# getting Vapoursynth core
core = vs.core
# loading plugins
core.std.LoadPlugin(path="F:/Hybrid/64bit/vsfilters/SourceFilter/d2vSource/DGDecode.dll")
# Source: 'G:\TestClips&Co\files\MPEG-1\SEGALOGO_adpcm.mpg'
# Current color space: YUV420P8, bit depth: 8, resolution: 512x360, frame rate: 29.97fps, scanorder: progressive, yuv luminance scale: limited, matrix: 470bg
# Loading G:\TestClips&Co\files\MPEG-1\SEGALOGO_adpcm.mpg using DGDecode
clip = core.dgdecode.MPEG2Source("J:/tmp/mpg_320eb6e218bb9d250f02c92c33db174a_853323747.d2v", info=3)# 29.97 fps, scanorder: progressive
frame = clip.get_frame(0)
# Setting detected color matrix (470bg).
clip = core.std.SetFrameProps(clip, _Matrix=5)
# setting color transfer (170), if it is not set.
if ('_Transfer' not in frame.props) or (frame.props['_Transfer'] == '') or (frame.props['_Transfer'] == 0):
clip = core.std.SetFrameProps(clip, _Transfer=6)
# setting color primaries info (to 470), if it is not set.
if ('_Primaries' not in frame.props) or (frame.props['_Primaries'] == '') or (frame.props['_Primaries'] == 0):
clip = core.std.SetFrameProps(clip, _Primaries=5)
# setting color range to TV (limited) range.
clip = core.std.SetFrameProps(clip=clip, _ColorRange=1)
# making sure frame rate is set to 29.97fps
clip = core.std.AssumeFPS(clip=clip, fpsnum=30000, fpsden=1001)
# making sure the detected scan type is set (detected: progressive)
clip = core.std.SetFrameProps(clip=clip, _FieldBased=0)# progressive
# adjusting output color from: YUV420P8 to YUV420P10 for NVEncModel
clip = core.resize.Bicubic(clip=clip, format=vs.YUV420P10, range_s="limited")
# set output frame rate to 29.97fps (progressive)
clip = core.std.AssumeFPS(clip=clip, fpsnum=30000, fpsden=1001)

frame = clip.get_frame(0)
clip = core.std.BlankClip(clip).text.Text("Matrix: "+str(frame.props['_Matrix'])+"\nTransfer: "+str(frame.props['_Transfer'])+"\nPrimaries: "+str(frame.props['_Primaries']))

# output
clip.set_output()
and calling it multiple time with:
VSPipe.exe --info c:\Users\Selur\Desktop\test_1.vpy
it sometimes (maybe 1 in 20) fails with:
Script evaluation failed:
Python exception: 'No key named _Transfer exists'

Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 3115, in vapoursynth._vpy_evaluate
File "src\cython\vapoursynth.pyx", line 3116, in vapoursynth._vpy_evaluate
File "c:\Users\Selur\Desktop\test_1.vpy", line 32, in <module>
clip = core.std.BlankClip(clip).text.Text("Matrix: "+str(frame.props['_Matrix'])+"\nTransfer: "+str(frame.props['_Transfer'])+"\nPrimaries: "+str(frame.props['_Primaries']))
~~~~~~~~~~~^^^^^^^^^^^^^
File "src\cython\vapoursynth.pyx", line 1074, in vapoursynth.FrameProps.__getitem__
KeyError: 'No key named _Transfer exists'
and other times it works fine. (Using R65, can't switch to R66 atm.)

This is driving me nuts.
Am I doing something wrong? Should I set and get the properties in another way?

Cu Selur

Selur
28th April 2024, 15:35
Hmm,.. might be related to 'dgdecode.MPEG2Source' since it does not occur with other source filters.

_Al_
28th April 2024, 19:46
Checking for all possible wrong values might not be enough, possible future changes, returns, or you are not checking if value is 2,
how about this:

frame = clip.get_frame(0)
props_back_up = {'_Matrix':5, '_Transfer':5,'_Primaries':5}
for prop in props_back_up:
value = frame.props.get(prop, None)
if value in [None, 2, 3]:
clip = core.std.SetFrameProps(clip, prop=props_back_up[prop])

_Al_
28th April 2024, 20:59
Sorry, could not finish it, as I said, to allow only useful values, taken from defined dictionaries:

MATRIX = {
0: 'rgb',
1: '709',
2: None,
3: None,
4: 'fcc',
5: '470bg',
6: '170m',
7: '240m',
8: 'ycgco',
9: '2020ncl',
10: '2020cl',
12: 'chromancl',
13: 'chromacl',
14: 'ictcp'
}


TRANSFER = {
0: 'reserved',
1: '709',
2: None,
3: None,
4: '470m',
5: '470bg',
6: '601',
7: '240m',
8: 'linear',
9: 'log100',
10: 'log316',
11: 'xvycc',
13: 'srgb',
14: '2020_10', # use for '2020', as '709'
15: '2020_12', # as '709'
16: 'st2084', # SMPTE ST 2084 as PQ (perceptual quantizer)
18: 'std-b67',
30: 'prophoto'
}


PRIMARIES = {
1: '709',
2: None,
4: '470m',
5: '470bg',
6: '170m',
7: '240m',
8: 'film',
9: '2020',
10: 'st428', # use for 'xyz'
11: 'st431-2', # use for 'dci-p3'
12: 'st432-1', # use for 'display-p3'
22: 'jedec-p22',
30: 'prophoto'
}
frame = clip.get_frame(0)
props_back_up = {'_Matrix':5, '_Transfer':5,'_Primaries':5}
VALUES = (MATRIX, TRANSFER, PRIMARIES)
for i, prop in enumerate(props_back_up):
value = frame.props.get(prop, None)
if value in [None, 2,3] or value not in VALUES[i] :
clip = core.std.SetFrameProps(clip, prop=props_back_up[prop]

_Al_
28th April 2024, 23:46
or checking against vapoursynth built-in Enums seams more elegant, because we work here with only int values, not string values:
https://forum.doom9.org/showthread.php?p=2001135#post2001135

Selur
29th April 2024, 04:14
Thanks! I agree the build-in enums are the way to go!

Cu Selur