-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfield_mode_solver.py
More file actions
84 lines (71 loc) · 2.8 KB
/
field_mode_solver.py
File metadata and controls
84 lines (71 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import logging
from .ffprobe import FFprobeFrameCommand
from .cache import HashCache, CacheMissException
from .factory import ffprobe_factory
class AbstractFieldModeSolver:
IS_MIXED_OR_UNKNOWN = 0
IS_INTERLACED_TFF = 1
IS_INTERLACED_BFF = 2
IS_PROGRESSIVE = 3
DECISIONS = {
IS_MIXED_OR_UNKNOWN: 'MIXED OR UNKNOWN',
IS_INTERLACED_TFF: 'INTERLACED TFF',
IS_INTERLACED_BFF: 'INTERLACED BFF',
IS_PROGRESSIVE: 'PROGRESSIVE'
}
def solve(self, input_url: str, video_stream_number: int) -> int:
raise NotImplementedError
class FFprobeFieldModeSolver(AbstractFieldModeSolver):
READ_INTERVALS = '%+#10'
def __init__(self):
self._ffprobe_frame_cmd = ffprobe_factory.get_ffprobe_command(FFprobeFrameCommand)
self._cache = HashCache(10, logging.debug)
def _solve(self, total_count: int, tff_counf: int, bff_count: int, progressive_count: int) -> int:
if tff_counf == total_count:
return self.IS_INTERLACED_TFF
if bff_count == total_count:
return self.IS_INTERLACED_BFF
if progressive_count == total_count:
return self.IS_PROGRESSIVE
return self.IS_MIXED_OR_UNKNOWN
@staticmethod
def _collect(v_frame_list: list) -> tuple:
tff_count = 0
bff_count = 0
progressive_count = 0
total_count = len(v_frame_list)
for f in v_frame_list:
if f['interlaced_frame'] == 1:
if f['top_field_first'] == 1:
tff_count += 1
else:
bff_count += 1
else:
if f['top_field_first'] == 1:
tff_count += 1
else:
progressive_count += 1
return total_count, tff_count, bff_count, progressive_count
def solve(self, input_url: str, video_stream_number: int) -> int:
cache_id = '{}{}'.format(input_url, video_stream_number)
logging.debug('Trying to get field mode from cache...')
try:
result = self._cache.from_cache(cache_id)
except CacheMissException:
pass
else:
return result
logging.info('Decoding some frames to determine video stream field mode...')
v_frame_list = self._ffprobe_frame_cmd.exec(
input_url,
'v:{}'.format(video_stream_number),
self.READ_INTERVALS
)['frames']
collected = self._collect(v_frame_list)
logging.debug('FFprobe result: total - {}, tff count - {}, bff count - {}, progressive count - {}'.format(
*collected
))
decision = self._solve(*collected)
logging.info('Stream determined as {}'.format(self.DECISIONS[decision]))
self._cache.to_cache(cache_id, decision)
return decision