11import cython
22from cython .cimports .cpython import PyBuffer_FillInfo , PyBytes_FromString
3- from cython .cimports .libc .stdint import uint64_t
3+ from cython .cimports .libc .stdint import int64_t , uint64_t
4+ from cython .cimports .libc .string import memcpy , strlen
45
56
67@cython .cclass
@@ -9,6 +10,9 @@ def __dealloc__(self):
910 lib .avsubtitle_free (cython .address (self .struct ))
1011
1112
13+ _cinit_bypass_sentinel = object ()
14+
15+
1216@cython .cclass
1317class SubtitleSet :
1418 """
@@ -17,11 +21,94 @@ class SubtitleSet:
1721 Wraps :ffmpeg:`AVSubtitle`.
1822 """
1923
20- def __cinit__ (self , proxy : SubtitleProxy ):
21- self .proxy = proxy
22- self .rects = tuple (
23- build_subtitle (self , i ) for i in range (self .proxy .struct .num_rects )
24+ def __cinit__ (self , proxy_or_sentinel = None ):
25+ if proxy_or_sentinel is _cinit_bypass_sentinel :
26+ # Creating empty SubtitleSet for encoding
27+ self .proxy = SubtitleProxy ()
28+ self .rects = ()
29+ elif isinstance (proxy_or_sentinel , SubtitleProxy ):
30+ # Creating from decoded subtitle
31+ self .proxy = proxy_or_sentinel
32+ self .rects = tuple (
33+ build_subtitle (self , i ) for i in range (self .proxy .struct .num_rects )
34+ )
35+ else :
36+ raise TypeError (
37+ "SubtitleSet requires a SubtitleProxy or use SubtitleSet.create()"
38+ )
39+
40+ @staticmethod
41+ def create (
42+ text : bytes ,
43+ start : int ,
44+ end : int ,
45+ pts : int = 0 ,
46+ subtitle_format : int = 1 ,
47+ ) -> "SubtitleSet" :
48+ """
49+ Create a SubtitleSet for encoding.
50+
51+ Args:
52+ text: The subtitle text in ASS dialogue format
53+ (e.g. b"0,0,Default,,0,0,0,,Hello World")
54+ start: Start display time as offset from pts (typically 0)
55+ end: End display time as offset from pts (i.e., duration)
56+ pts: Presentation timestamp in stream time_base units
57+ subtitle_format: Subtitle format (default 1 for text)
58+
59+ Note:
60+ All timing values should be in stream time_base units.
61+ For MKV (time_base=1/1000), units are milliseconds.
62+ For MP4 (time_base=1/1000000), units are microseconds.
63+
64+ Returns:
65+ A SubtitleSet ready for encoding
66+ """
67+ subset : SubtitleSet = SubtitleSet (_cinit_bypass_sentinel )
68+
69+ subset .proxy .struct .format = subtitle_format
70+ subset .proxy .struct .start_display_time = start
71+ subset .proxy .struct .end_display_time = end
72+ subset .proxy .struct .pts = pts
73+
74+ subset .proxy .struct .num_rects = 1
75+ subset .proxy .struct .rects = cython .cast (
76+ cython .pointer [cython .pointer [lib .AVSubtitleRect ]],
77+ lib .av_mallocz (cython .sizeof (cython .pointer [lib .AVSubtitleRect ])),
78+ )
79+ if subset .proxy .struct .rects == cython .NULL :
80+ raise MemoryError ("Failed to allocate subtitle rects array" )
81+
82+ rect : cython .pointer [lib .AVSubtitleRect ] = cython .cast (
83+ cython .pointer [lib .AVSubtitleRect ],
84+ lib .av_mallocz (cython .sizeof (lib .AVSubtitleRect )),
2485 )
86+ if rect == cython .NULL :
87+ lib .av_free (subset .proxy .struct .rects )
88+ subset .proxy .struct .rects = cython .NULL
89+ raise MemoryError ("Failed to allocate subtitle rect" )
90+
91+ subset .proxy .struct .rects [0 ] = rect
92+
93+ rect .x = 0
94+ rect .y = 0
95+ rect .w = 0
96+ rect .h = 0
97+ rect .nb_colors = 0
98+ rect .type = lib .SUBTITLE_ASS
99+ rect .text = cython .NULL
100+ rect .flags = 0
101+
102+ text_len : cython .Py_ssize_t = len (text )
103+ rect .ass = cython .cast (cython .p_char , lib .av_malloc (text_len + 1 ))
104+ if rect .ass == cython .NULL :
105+ raise MemoryError ("Failed to allocate subtitle text" )
106+ memcpy (rect .ass , cython .cast (cython .p_char , text ), text_len )
107+ rect .ass [text_len ] = 0
108+
109+ subset .rects = (AssSubtitle (subset , 0 ),)
110+
111+ return subset
25112
26113 def __repr__ (self ):
27114 return (
@@ -32,19 +119,35 @@ def __repr__(self):
32119 def format (self ):
33120 return self .proxy .struct .format
34121
122+ @format .setter
123+ def format (self , value : int ):
124+ self .proxy .struct .format = value
125+
35126 @property
36127 def start_display_time (self ):
37128 return self .proxy .struct .start_display_time
38129
130+ @start_display_time .setter
131+ def start_display_time (self , value : int ):
132+ self .proxy .struct .start_display_time = value
133+
39134 @property
40135 def end_display_time (self ):
41136 return self .proxy .struct .end_display_time
42137
138+ @end_display_time .setter
139+ def end_display_time (self , value : int ):
140+ self .proxy .struct .end_display_time = value
141+
43142 @property
44143 def pts (self ):
45144 """Same as packet pts, in av.time_base."""
46145 return self .proxy .struct .pts
47146
147+ @pts .setter
148+ def pts (self , value : int ):
149+ self .proxy .struct .pts = value
150+
48151 def __len__ (self ):
49152 return len (self .rects )
50153
0 commit comments