Skip to content

Commit e31818a

Browse files
committed
rewrite rff
1 parent 0c973fb commit e31818a

File tree

4 files changed

+60
-60
lines changed

4 files changed

+60
-60
lines changed

vssource/formats/dvd/title.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ def _assert_dvdsrc2(self, func: FuncExceptT) -> None:
257257

258258
def dump_vob(self, outpath: str):
259259
self._assert_dvdsrc2(self.dump_vob)
260-
if not hasattr(vs.core.dvdsrc2,"RawVob"):
260+
if not hasattr(vs.core.dvdsrc2, "RawVob"):
261261
raise CustomValueError('Newer dvdsrc2 is needed for dump_raw', self.dump_vob)
262262

263263
nd = vs.core.dvdsrc2.RawVob(str(self._core.iso_path), self._vts, self._dvdsrc_ranges)

vssource/indexers/D2VWitch.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def parse_vts(
171171
prog = [int((a & 0b01000000) != 0) for a in fflags]
172172

173173
node = apply_rff_video(node, rff, tff, prog, progseq)
174-
vobids = apply_rff_array(vobids, rff, tff, progseq)
174+
vobids = apply_rff_array(vobids, rff, tff, prog, progseq)
175175

176176
return node, rff, vobids, []
177177

vssource/indexers/dvdsrc.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def parse_vts(
5252

5353
if not disable_rff:
5454
rnode = apply_rff_video(rawnode, staff.rff, staff.tff, staff.prog, staff.progseq)
55-
_vobids = apply_rff_array(staff.vobids, staff.rff, staff.tff, staff.progseq)
55+
_vobids = apply_rff_array(staff.vobids, staff.rff, staff.tff,staff.prog,staff.progseq)
5656
else:
5757
rnode = rawnode
5858
_vobids = staff.vobids

vssource/rff.py

+57-57
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
from dataclasses import dataclass
34
import warnings
45
from copy import deepcopy
56
from itertools import count
@@ -12,58 +13,31 @@
1213
'cut_array_on_ranges'
1314
]
1415

16+
@dataclass
17+
class Field:
18+
n: int
19+
is_tf: bool
20+
is_repeat: bool
21+
prog: bool
22+
user_data: object
1523

16-
def apply_rff_array(old_array: Sequence[T], rff: Sequence[int], tff: Sequence[int], prog_seq: Sequence[int]) -> list[T]:
17-
array_double_rate = list[T]()
24+
def rff_frames_to_fields(rff: list[int], tff: list[int], prog: list[int], prog_seq: list[int], user_data: list[T]):
25+
fields = list[Field]()
1826

19-
for prog, arr, rffv, tffv in zip(prog_seq, old_array, rff, tff):
20-
repeat_amount = (3 if rffv else 2) if prog == 0 else ((6 if tffv else 4) if rffv else 2)
21-
22-
array_double_rate.extend([arr] * repeat_amount)
23-
24-
# assert (len(array_double_rate) % 2) == 0
25-
if (len(array_double_rate) % 2) != 0:
26-
warnings.warn('uneven amount of fields removing last\n')
27-
array_double_rate = array_double_rate[:-1]
28-
29-
# It seems really weird thats its allowed to have rff stuff across
30-
# vob boundries even for multi angle stuff i have seen this so often though it is ok to remove the warnings
31-
# for i, f1, f2 in zip(count(), array_double_rate[::2], array_double_rate[1::2]):
32-
# if f1 != f2:
33-
# warnings.warn(
34-
# f'Ambiguous pattern due to rff {f1}!={f2} on index {i}\n'
35-
# 'This probably just means telecine happened across chapters boundary.'
36-
# )
37-
38-
return array_double_rate[::2]
39-
40-
41-
def apply_rff_video(
42-
node: vs.VideoNode, rff: list[int], tff: list[int], prog: list[int], prog_seq: list[int]
43-
) -> vs.VideoNode:
44-
assert len(node) == len(rff) == len(tff) == len(prog) == len(prog_seq)
45-
46-
fields = list[dict[str, int]]()
47-
tfffs = node.std.RemoveFrameProps(['_FieldBased', '_Field']).std.SeparateFields(True)
48-
49-
for i, current_prg_seq, current_prg, current_rff, current_tff in zip(count(), prog_seq, prog, rff, tff):
27+
for i, current_prg_seq, current_prg, current_rff, current_tff,current_ud in zip(count(), prog_seq, prog, rff, tff, user_data):
5028
if not current_prg_seq:
51-
if current_tff:
52-
first_field = 2 * i
53-
second_field = 2 * i + 1
54-
else:
55-
first_field = 2 * i + 1
56-
second_field = 2 * i
29+
first_field = [2*i+1, 2*i+0][current_tff]
30+
second_field = [2*i+0, 2*i+1][current_tff]
5731

5832
fields += [
59-
{'n': first_field, 'tf': current_tff, 'prg': False, 'repeat': False},
60-
{'n': second_field, 'tf': not current_tff, 'prg': False, 'repeat': False}
33+
Field(first_field, current_tff, False,False,current_ud),
34+
Field(second_field, not current_tff, False,False,current_ud)
6135
]
6236

6337
if current_rff:
6438
assert current_prg
6539
repeat_field = deepcopy(fields[-2])
66-
repeat_field['repeat'] = True
40+
repeat_field.is_repeat = True
6741
fields.append(repeat_field)
6842
else:
6943
assert current_prg
@@ -72,37 +46,63 @@ def apply_rff_video(
7246
if current_rff:
7347
field_count += 1 + int(current_tff)
7448

49+
#maybe set is_repeat even for progressive repeats ?
7550
fields += [
76-
{'n': 2 * i, 'tf': 1, 'prg': True, 'repeat': False},
77-
{'n': 2 * i + 1, 'tf': 0, 'prg': True, 'repeat': False}
51+
Field(2 * i, True, False,True,current_ud),
52+
Field(2 * i + 1, False, False,True,current_ud),
7853
] * field_count
7954

80-
# TODO: mark known progressive frames as progressive
55+
#There might be a need to make this adjustable
56+
fixmode_invalid_tff_parity: int = 1
57+
58+
59+
a = 0
60+
while a < (len(fields) // 2) * 2:
61+
tf = fields[a]
62+
bf = fields[a+1]
63+
if tf.is_tf == bf.is_tf:
64+
warnings.warn(f'Invalid field transition at {a / 2} {tf} {bf}')
65+
66+
if fixmode_invalid_tff_parity == 0:
67+
bf.is_tf = not bf.is_tf
68+
else:
69+
fc = deepcopy(tf)
70+
fc.is_tf = not fc.is_tf
71+
fields.insert(a+1,fc)
72+
a += 2
8173

82-
# assert (len(fields) % 2) == 0
8374
if (len(fields) % 2) != 0:
8475
warnings.warn('uneven amount of fields removing last\n')
8576
fields = fields[:-1]
8677

87-
for a, tf, bf in zip(count(), fields[::2], fields[1::2]):
88-
if tf['tf'] == bf['tf']:
89-
bf['tf'] = not bf['tf']
78+
return fields
79+
80+
81+
82+
def apply_rff_array(old_array: list[T], rff: list[int], tff: list[int], prog: list[int], prog_seq: list[int]) -> list[T]:
83+
return list([f.user_data for f in rff_frames_to_fields(rff,tff,prog,prog_seq,old_array)][1::2])
9084

91-
warnings.warn(f'Invalid field transition at {a}')
85+
def apply_rff_video(
86+
node: vs.VideoNode, rff: list[int], tff: list[int], prog: list[int], prog_seq: list[int]
87+
) -> vs.VideoNode:
88+
assert len(node) == len(rff) == len(tff) == len(prog) == len(prog_seq)
89+
90+
tfffs = node.std.RemoveFrameProps(['_FieldBased', '_Field']).std.SeparateFields(True)
91+
fields = rff_frames_to_fields(rff,tff,prog,prog_seq,list(range(len(tff))))
9292

9393
for fcurr, fnext in zip(fields[::2], fields[1::2]):
94-
if fcurr['tf'] == fnext['tf']:
94+
if fcurr.is_tf == fnext.is_tf:
9595
raise CustomRuntimeError(
96-
f'Found invalid stream with two consecutive {"top" if fcurr["tf"] else "bottom"} fields!'
96+
f'Found invalid stream with two consecutive {"top" if fcurr.is_tf else "bottom"} fields!'
9797
)
9898

99-
final = remap_frames(tfffs, [x['n'] for x in fields])
99+
final = remap_frames(tfffs, [x.n for x in fields])
100100

101101
def _set_field(n: int, f: vs.VideoFrame) -> vs.VideoFrame:
102102
f = f.copy()
103103

104104
f.props.pop('_FieldBased', None)
105-
f.props._Field = fields[n]['tf']
105+
f.props._Field = fields[n].is_tf
106106

107107
return f
108108

@@ -112,9 +112,9 @@ def _set_field(n: int, f: vs.VideoFrame) -> vs.VideoFrame:
112112

113113
def _set_repeat(n: int, f: vs.VideoFrame) -> vs.VideoFrame:
114114
f = f.copy()
115-
if fields[n * 2]['repeat']:
115+
if fields[n * 2].is_repeat:
116116
f.props['RepeatedField'] = 1
117-
elif fields[n * 2 + 1]['repeat']:
117+
elif fields[n * 2 + 1].is_repeat:
118118
f.props['RepeatedField'] = 0
119119
else:
120120
f.props['RepeatedField'] = -1
@@ -129,7 +129,7 @@ def _update_progressive(n: int, f: vs.VideoFrame) -> vs.VideoFrame:
129129
tf = fields[n * 2]
130130
bf = fields[n * 2 + 1]
131131

132-
if tf['prg'] and bf['prg']:
132+
if tf.prog and bf.prog:
133133
fout.props['_FieldBased'] = 0
134134

135135
return fout

0 commit comments

Comments
 (0)