18
18
#endif
19
19
20
20
int log_level = 3 ;
21
+ int *is_event_animated;
21
22
22
23
typedef struct {
23
24
void *buffer;
@@ -62,6 +63,7 @@ void buffer_init(buffer_t *buf) {
62
63
63
64
void buffer_free (buffer_t *buf) {
64
65
free (buf->buffer );
66
+ buffer_init (buf);
65
67
}
66
68
67
69
void msg_callback (int level, const char *fmt, va_list va, void *data) {
@@ -102,31 +104,115 @@ double libassjs_find_next_event_start(double tm) {
102
104
return closest / 1000.0 ;
103
105
}
104
106
105
- int _is_event_complex (ASS_Event *event) {
107
+ static int _is_move_tag_animated (char *begin, char *end) {
108
+ int params[6 ];
109
+ int count = 0 , value = 0 , num_digits = 0 ;
110
+ for (; begin < end; begin++) {
111
+ switch (*begin) {
112
+ case ' ' : // fallthrough
113
+ case ' \t ' :
114
+ break ;
115
+ case ' ,' :
116
+ params[count] = value;
117
+ count++;
118
+ value = 0 ;
119
+ num_digits = 0 ;
120
+ break ;
121
+ default : {
122
+ int digit = *begin - ' 0' ;
123
+ if (digit < 0 || digit > 9 ) return 0 ; // invalid move
124
+ value = value * 10 + digit;
125
+ num_digits++;
126
+ break ;
127
+ }
128
+ }
129
+ }
130
+ if (num_digits > 0 ) {
131
+ params[count] = value;
132
+ count++;
133
+ }
134
+ if (count < 4 ) return 0 ; // invalid move
135
+
136
+ // move is animated if (x1,y1) != (x2,y2)
137
+ return params[0 ] != params[2 ] || params[1 ] != params[3 ];
138
+ }
139
+
140
+ static int _is_animated_tag (char *begin, char *end) {
141
+ // strip whitespaces around the tag
142
+ while (begin < end && (*begin == ' ' || *begin == ' \t ' )) begin++;
143
+ while (end > begin && (end[-1 ] == ' ' || end[-1 ] == ' \t ' )) end--;
144
+
145
+ int length = end - begin;
146
+ if (length < 3 || *begin != ' \\ ' ) return 0 ; // too short to be animated or not a command
147
+
148
+ switch (begin[1 ]) {
149
+ case ' k' : // fallthrough
150
+ case ' K' :
151
+ // \kXX is karaoke
152
+ return 1 ;
153
+ case ' t' :
154
+ // \t(...) is transition
155
+ return length >= 4 && begin[2 ] == ' (' && end[-1 ] == ' )' ;
156
+ case ' m' :
157
+ if (length >=7 && end[-1 ] == ' )' && strcmp (begin, " \\ move(" ) == 0 ) {
158
+ return _is_move_tag_animated (begin + 6 , end - 1 );
159
+ }
160
+ break ;
161
+ case ' f' :
162
+ // \fad() or \fade() are fades
163
+ return (length >= 7 && end[-1 ] == ' )' &&
164
+ (strcmp (begin, " \\ fad(" ) == 0 || strcmp (begin, " \\ fade(" ) == 0 ));
165
+ }
166
+
167
+ return 0 ;
168
+ }
169
+
170
+ static int _is_event_animated (ASS_Event *event) {
106
171
// event is complex if it's animated in any way,
107
172
// either by having non-empty Effect or
108
173
// by having tags (enclosed in '{}' in Text)
109
174
if (event->Effect && event->Effect [0 ] != ' \0 ' ) return 1 ;
110
175
111
176
int escaped = 0 ;
177
+ char *tagStart = NULL ;
112
178
for (char *p = event->Text ; *p != ' \0 ' ; p++) {
113
179
switch (*p) {
114
180
case ' \\ ' :
115
181
escaped = !escaped;
116
182
break ;
117
183
case ' {' :
118
- if (escaped) return 1 ;
184
+ if (!escaped && tagStart == NULL ) tagStart = p + 1 ;
185
+ break ;
186
+ case ' }' :
187
+ if (!escaped && tagStart != NULL ) {
188
+ if (_is_animated_tag (tagStart, p)) return 1 ;
189
+ tagStart = NULL ;
190
+ }
191
+ break ;
192
+ case ' ;' :
193
+ if (tagStart != NULL ) {
194
+ if (_is_animated_tag (tagStart, p)) return 1 ;
195
+ }
196
+ tagStart = p + 1 ;
119
197
break ;
120
198
}
121
199
}
122
200
123
201
return 0 ;
124
202
}
125
203
126
- int libassjs_find_event_stop_times (double tm, double *eventFinish, double *emptyFinish) {
204
+ static void detect_animated_events () {
205
+ ASS_Event *cur = track->events ;
206
+ int *animated = is_animated_events;
207
+ for (int i = 0 ; i < track->n_events ; i++, cur++, animated++) {
208
+ *animated = _is_event_animated (cur);
209
+ }
210
+ }
211
+
212
+ void libassjs_find_event_stop_times (double tm, double *eventFinish, double *emptyFinish, int *is_animated) {
127
213
if (!track || track->n_events == 0 ) {
128
214
*eventFinish = *emptyFinish = -1 ;
129
- return 0 ;
215
+ return ;
130
216
}
131
217
132
218
ASS_Event *cur = track->events ;
@@ -146,12 +232,13 @@ int libassjs_find_event_stop_times(double tm, double *eventFinish, double *empty
146
232
if (finish > maxFinish) {
147
233
maxFinish = finish;
148
234
}
149
- if (!current_animated && _is_event_complex (cur)) current_animated = 1 ;
235
+ if (!current_animated) current_animated = is_event_animated[i] ;
150
236
}
151
237
} else if (start < minStart || minStart == -1 ) {
152
238
minStart = start;
153
239
}
154
240
}
241
+ *is_animated = current_animated;
155
242
156
243
if (minFinish != -1 ) {
157
244
// some event is going on, so we need to re-draw either when it stops
@@ -169,8 +256,6 @@ int libassjs_find_event_stop_times(double tm, double *eventFinish, double *empty
169
256
// there's no empty space after eventFinish happens
170
257
*emptyFinish = *eventFinish;
171
258
}
172
-
173
- return current_animated;
174
259
}
175
260
176
261
class SubtitleOctopus {
@@ -216,6 +301,7 @@ class SubtitleOctopus {
216
301
217
302
reloadFonts ();
218
303
buffer_init (&m_blend);
304
+ is_event_animated = NULL ;
219
305
}
220
306
221
307
/* TRACK */
@@ -226,6 +312,14 @@ class SubtitleOctopus {
226
312
printf (" Failed to start a track\n " );
227
313
exit (4 );
228
314
}
315
+
316
+ free (is_event_animated);
317
+ is_event_animated = (int *)malloc (sizeof (int ) * track->n_events );
318
+ if (is_event_animated == NULL ) {
319
+ printf (" cannot parse animated events\n " );
320
+ exit (5 );
321
+ }
322
+ detect_animated_events ();
229
323
}
230
324
231
325
void createTrackMem (char *buf, unsigned long bufsize) {
@@ -242,6 +336,8 @@ class SubtitleOctopus {
242
336
ass_free_track (track);
243
337
track = NULL ;
244
338
}
339
+ free (is_event_animated);
340
+ is_event_animated = NULL ;
245
341
}
246
342
/* TRACK */
247
343
@@ -262,6 +358,8 @@ class SubtitleOctopus {
262
358
ass_renderer_done (ass_renderer);
263
359
ass_library_done (ass_library);
264
360
buffer_free (&m_blend);
361
+ free (is_event_animated);
362
+ is_event_animated = NULL ;
265
363
}
266
364
void reloadLibrary () {
267
365
quitLibrary ();
0 commit comments