Line | Count | Source |
1 | | /* |
2 | | * This file is part of mpv. |
3 | | * |
4 | | * mpv is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Lesser General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2.1 of the License, or (at your option) any later version. |
8 | | * |
9 | | * mpv is distributed in the hope that it will be useful, |
10 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | * GNU Lesser General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU Lesser General Public |
15 | | * License along with mpv. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | |
18 | | #include <stdlib.h> |
19 | | #include <stdbool.h> |
20 | | #include <string.h> |
21 | | #include <math.h> |
22 | | #include <assert.h> |
23 | | #include <limits.h> |
24 | | |
25 | | #include "demux/demux.h" |
26 | | #include "demux/packet_pool.h" |
27 | | #include "sd.h" |
28 | | #include "dec_sub.h" |
29 | | #include "options/m_config.h" |
30 | | #include "options/options.h" |
31 | | #include "common/global.h" |
32 | | #include "common/msg.h" |
33 | | #include "common/recorder.h" |
34 | | #include "misc/dispatch.h" |
35 | | #include "osdep/threads.h" |
36 | | |
37 | | extern const struct sd_functions sd_ass; |
38 | | extern const struct sd_functions sd_lavc; |
39 | | #if HAVE_SUBRANDR |
40 | | extern const struct sd_functions sd_sbr; |
41 | | #endif |
42 | | |
43 | | static const struct sd_functions *const sd_list[] = { |
44 | | &sd_lavc, |
45 | | #if HAVE_SUBRANDR |
46 | | &sd_sbr, |
47 | | #endif |
48 | | &sd_ass, |
49 | | NULL |
50 | | }; |
51 | | |
52 | | struct dec_sub { |
53 | | mp_mutex lock; |
54 | | |
55 | | struct mp_log *log; |
56 | | struct mpv_global *global; |
57 | | struct demux_packet_pool *packet_pool; |
58 | | struct mp_subtitle_opts *opts; |
59 | | struct mp_subtitle_shared_opts *shared_opts; |
60 | | struct m_config_cache *opts_cache; |
61 | | struct m_config_cache *shared_opts_cache; |
62 | | |
63 | | struct mp_recorder_sink *recorder_sink; |
64 | | |
65 | | struct attachment_list *attachments; |
66 | | |
67 | | struct sh_stream *sh; |
68 | | int play_dir; |
69 | | int order; |
70 | | double last_pkt_pts; |
71 | | bool preload_attempted; |
72 | | double video_fps; |
73 | | double sub_speed; |
74 | | bool sub_visible; |
75 | | |
76 | | struct mp_codec_params *codec; |
77 | | double start, end; |
78 | | char *lang; |
79 | | |
80 | | double last_vo_pts; |
81 | | struct sd *sd; |
82 | | |
83 | | struct demux_packet *new_segment; |
84 | | struct demux_packet **cached_pkts; |
85 | | int cached_pkt_pos; |
86 | | int num_cached_pkts; |
87 | | }; |
88 | | |
89 | | static void update_subtitle_speed(struct dec_sub *sub) |
90 | 3.45k | { |
91 | 3.45k | struct mp_subtitle_opts *opts = sub->opts; |
92 | 3.45k | sub->sub_speed = 1.0; |
93 | | |
94 | 3.45k | if (sub->video_fps > 0 && sub->codec->frame_based > 0) { |
95 | 0 | MP_VERBOSE(sub, "Frame based format, dummy FPS: %f, video FPS: %f\n", |
96 | 0 | sub->codec->frame_based, sub->video_fps); |
97 | 0 | sub->sub_speed *= sub->codec->frame_based / sub->video_fps; |
98 | 0 | } |
99 | | |
100 | 3.45k | if (opts->sub_fps && sub->video_fps) |
101 | 0 | sub->sub_speed *= opts->sub_fps / sub->video_fps; |
102 | | |
103 | 3.45k | sub->sub_speed *= opts->sub_speed; |
104 | 3.45k | } |
105 | | |
106 | | // Return the subtitle PTS used for a given video PTS. |
107 | | static double pts_to_subtitle(struct dec_sub *sub, double pts) |
108 | 27.5k | { |
109 | 27.5k | struct mp_subtitle_shared_opts *opts = sub->shared_opts; |
110 | 27.5k | float delay = sub->order < 0 ? 0.0f : opts->sub_delay[sub->order]; |
111 | | |
112 | 27.5k | if (pts != MP_NOPTS_VALUE) |
113 | 23.7k | pts = (pts * sub->play_dir - delay) / sub->sub_speed; |
114 | | |
115 | 27.5k | return pts; |
116 | 27.5k | } |
117 | | |
118 | | static double pts_from_subtitle(struct dec_sub *sub, double pts) |
119 | 0 | { |
120 | 0 | struct mp_subtitle_shared_opts *opts = sub->shared_opts; |
121 | 0 | float delay = sub->order < 0 ? 0.0f : opts->sub_delay[sub->order]; |
122 | |
|
123 | 0 | if (pts != MP_NOPTS_VALUE) |
124 | 0 | pts = (pts * sub->sub_speed + delay) * sub->play_dir; |
125 | |
|
126 | 0 | return pts; |
127 | 0 | } |
128 | | |
129 | | static void wakeup_demux(void *ctx) |
130 | 0 | { |
131 | 0 | struct mp_dispatch_queue *q = ctx; |
132 | 0 | mp_dispatch_interrupt(q); |
133 | 0 | } |
134 | | |
135 | | static void destroy_cached_pkts(struct dec_sub *sub) |
136 | 3.45k | { |
137 | 3.45k | int index = 0; |
138 | 5.00k | while (index < sub->num_cached_pkts) { |
139 | 1.55k | demux_packet_pool_push(sub->packet_pool, sub->cached_pkts[index]); |
140 | 1.55k | sub->cached_pkts[index] = NULL; |
141 | 1.55k | ++index; |
142 | 1.55k | } |
143 | 3.45k | sub->cached_pkt_pos = 0; |
144 | 3.45k | sub->num_cached_pkts = 0; |
145 | 3.45k | } |
146 | | |
147 | | void sub_destroy(struct dec_sub *sub) |
148 | 1.79k | { |
149 | 1.79k | if (!sub) |
150 | 0 | return; |
151 | 1.79k | demux_set_stream_wakeup_cb(sub->sh, NULL, NULL); |
152 | 1.79k | if (sub->sd) { |
153 | 1.72k | sub_reset(sub); |
154 | 1.72k | sub->sd->driver->uninit(sub->sd); |
155 | 1.72k | } |
156 | 1.79k | talloc_free(sub->sd); |
157 | 1.79k | mp_mutex_destroy(&sub->lock); |
158 | 1.79k | talloc_free(sub); |
159 | 1.79k | } |
160 | | |
161 | | static struct sd *init_decoder(struct dec_sub *sub) |
162 | 1.79k | { |
163 | 3.43k | for (int n = 0; sd_list[n]; n++) { |
164 | 3.36k | const struct sd_functions *driver = sd_list[n]; |
165 | 3.36k | struct sd *sd = talloc(NULL, struct sd); |
166 | 3.36k | *sd = (struct sd){ |
167 | 3.36k | .global = sub->global, |
168 | 3.36k | .log = mp_log_new(sd, sub->log, driver->name), |
169 | 3.36k | .opts = sub->opts, |
170 | 3.36k | .shared_opts = sub->shared_opts, |
171 | 3.36k | .driver = driver, |
172 | 3.36k | .order = sub->order, |
173 | 3.36k | .attachments = sub->attachments, |
174 | 3.36k | .codec = sub->codec, |
175 | 3.36k | .lang = sub->lang, |
176 | 3.36k | .preload_ok = true, |
177 | 3.36k | }; |
178 | | |
179 | 3.36k | if (sd->driver->init(sd) >= 0) |
180 | 1.72k | return sd; |
181 | | |
182 | 1.64k | talloc_free(sd); |
183 | 1.64k | } |
184 | | |
185 | 70 | MP_ERR(sub, "Could not find subtitle decoder for format '%s'.\n", |
186 | 70 | sub->codec->codec); |
187 | 70 | return NULL; |
188 | 1.79k | } |
189 | | |
190 | | // Thread-safety of the returned object: all functions are thread-safe, |
191 | | // except sub_get_bitmaps() and sub_get_text(). Decoder backends (sd_*) |
192 | | // do not need to acquire locks. |
193 | | // Ownership of attachments goes to the callee, and is released with |
194 | | // talloc_free() (even on failure). |
195 | | struct dec_sub *sub_create(struct mpv_global *global, struct track *track, |
196 | | struct attachment_list *attachments, int order) |
197 | 1.79k | { |
198 | 1.79k | mp_assert(track->stream && track->stream->type == STREAM_SUB); |
199 | | |
200 | 1.79k | struct dec_sub *sub = talloc(NULL, struct dec_sub); |
201 | 1.79k | *sub = (struct dec_sub){ |
202 | 1.79k | .log = mp_log_new(sub, global->log, "sub"), |
203 | 1.79k | .global = global, |
204 | 1.79k | .packet_pool = demux_packet_pool_get(global), |
205 | 1.79k | .opts_cache = m_config_cache_alloc(sub, global, &mp_subtitle_sub_opts), |
206 | 1.79k | .shared_opts_cache = m_config_cache_alloc(sub, global, &mp_subtitle_shared_sub_opts), |
207 | 1.79k | .sh = track->stream, |
208 | 1.79k | .codec = track->stream->codec, |
209 | 1.79k | .lang = track->lang, |
210 | 1.79k | .attachments = talloc_steal(sub, attachments), |
211 | 1.79k | .play_dir = 1, |
212 | 1.79k | .order = order, |
213 | 1.79k | .last_pkt_pts = MP_NOPTS_VALUE, |
214 | 1.79k | .last_vo_pts = MP_NOPTS_VALUE, |
215 | 1.79k | .start = MP_NOPTS_VALUE, |
216 | 1.79k | .end = MP_NOPTS_VALUE, |
217 | 1.79k | }; |
218 | 1.79k | sub->opts = sub->opts_cache->opts; |
219 | 1.79k | sub->shared_opts = sub->shared_opts_cache->opts; |
220 | 1.79k | mp_mutex_init(&sub->lock); |
221 | | |
222 | 1.79k | sub->sd = init_decoder(sub); |
223 | 1.79k | if (sub->sd) { |
224 | 1.72k | update_subtitle_speed(sub); |
225 | 1.72k | return sub; |
226 | 1.72k | } |
227 | | |
228 | 70 | sub_destroy(sub); |
229 | 70 | return NULL; |
230 | 1.79k | } |
231 | | |
232 | | // Called locked. |
233 | | static void update_segment(struct dec_sub *sub) |
234 | 460 | { |
235 | 460 | if (sub->new_segment && sub->last_vo_pts != MP_NOPTS_VALUE && |
236 | 0 | sub->last_vo_pts >= sub->new_segment->start) |
237 | 0 | { |
238 | 0 | MP_VERBOSE(sub, "Switch segment: %f at %f\n", sub->new_segment->start, |
239 | 0 | sub->last_vo_pts); |
240 | |
|
241 | 0 | sub->codec = sub->new_segment->codec; |
242 | 0 | sub->start = sub->new_segment->start; |
243 | 0 | sub->end = sub->new_segment->end; |
244 | 0 | struct sd *new = init_decoder(sub); |
245 | 0 | if (new) { |
246 | 0 | sub->sd->driver->uninit(sub->sd); |
247 | 0 | talloc_free(sub->sd); |
248 | 0 | sub->sd = new; |
249 | 0 | update_subtitle_speed(sub); |
250 | 0 | } else { |
251 | | // We'll just keep the current decoder, and feed it possibly |
252 | | // invalid data (not our fault if it crashes or something). |
253 | 0 | MP_ERR(sub, "Can't change to new codec.\n"); |
254 | 0 | } |
255 | 0 | sub->sd->driver->decode(sub->sd, sub->new_segment); |
256 | 0 | talloc_free(sub->new_segment); |
257 | 0 | sub->new_segment = NULL; |
258 | 0 | } |
259 | 460 | } |
260 | | |
261 | | bool sub_can_preload(struct dec_sub *sub) |
262 | 0 | { |
263 | 0 | bool r; |
264 | 0 | mp_mutex_lock(&sub->lock); |
265 | 0 | r = sub->sd->driver->accept_packets_in_advance && !sub->preload_attempted; |
266 | 0 | mp_mutex_unlock(&sub->lock); |
267 | 0 | return r; |
268 | 0 | } |
269 | | |
270 | | void sub_preload(struct dec_sub *sub) |
271 | 0 | { |
272 | 0 | mp_mutex_lock(&sub->lock); |
273 | |
|
274 | 0 | struct mp_dispatch_queue *demux_waiter = mp_dispatch_create(NULL); |
275 | 0 | demux_set_stream_wakeup_cb(sub->sh, wakeup_demux, demux_waiter); |
276 | |
|
277 | 0 | sub->preload_attempted = true; |
278 | |
|
279 | 0 | for (;;) { |
280 | 0 | struct demux_packet *pkt = NULL; |
281 | 0 | int r = demux_read_packet_async(sub->sh, &pkt); |
282 | 0 | if (r == 0) { |
283 | 0 | mp_dispatch_queue_process(demux_waiter, INFINITY); |
284 | 0 | continue; |
285 | 0 | } |
286 | 0 | if (!pkt) |
287 | 0 | break; |
288 | 0 | sub->sd->driver->decode(sub->sd, pkt); |
289 | 0 | MP_TARRAY_APPEND(sub, sub->cached_pkts, sub->num_cached_pkts, pkt); |
290 | 0 | } |
291 | |
|
292 | 0 | demux_set_stream_wakeup_cb(sub->sh, NULL, NULL); |
293 | 0 | talloc_free(demux_waiter); |
294 | |
|
295 | 0 | mp_mutex_unlock(&sub->lock); |
296 | 0 | } |
297 | | |
298 | | static bool is_new_segment(struct dec_sub *sub, struct demux_packet *p) |
299 | 1.55k | { |
300 | 1.55k | return p->segmented && |
301 | 0 | (p->start != sub->start || p->end != sub->end || p->codec != sub->codec); |
302 | 1.55k | } |
303 | | |
304 | | static bool is_packet_visible(struct demux_packet *p, double video_pts) |
305 | 16.4k | { |
306 | 16.4k | return p && p->pts <= video_pts && (video_pts <= p->pts + p->sub_duration || |
307 | 405 | p->sub_duration < 0); |
308 | 16.4k | } |
309 | | |
310 | | static bool update_pkt_cache(struct dec_sub *sub, double video_pts) |
311 | 16.4k | { |
312 | 16.4k | if (!sub->cached_pkts[sub->cached_pkt_pos]) |
313 | 0 | return false; |
314 | | |
315 | 16.4k | struct demux_packet *pkt = sub->cached_pkts[sub->cached_pkt_pos]; |
316 | 16.4k | struct demux_packet *next_pkt = sub->cached_pkt_pos + 1 < sub->num_cached_pkts ? |
317 | 16.4k | sub->cached_pkts[sub->cached_pkt_pos + 1] : NULL; |
318 | 16.4k | if (!pkt) |
319 | 0 | return false; |
320 | | |
321 | 16.4k | double pts = video_pts + sub->shared_opts->sub_delay[sub->order]; |
322 | 16.4k | double next_pts = next_pkt ? next_pkt->pts : INT_MAX; |
323 | 16.4k | double end_pts = pkt->sub_duration >= 0 ? pkt->pts + pkt->sub_duration : INT_MAX; |
324 | | |
325 | 16.4k | if (next_pts < pts || end_pts < pts) { |
326 | 600 | if (sub->cached_pkt_pos + 1 < sub->num_cached_pkts) { |
327 | 423 | TA_FREEP(&sub->cached_pkts[sub->cached_pkt_pos]); |
328 | 423 | pkt = NULL; |
329 | 423 | sub->cached_pkt_pos++; |
330 | 423 | } |
331 | 600 | if (next_pts < pts) |
332 | 419 | return true; |
333 | 600 | } |
334 | | |
335 | 16.0k | if (pkt && pkt->animated == 1) |
336 | 102 | return true; |
337 | | |
338 | 15.9k | return false; |
339 | 16.0k | } |
340 | | |
341 | | // Read packets from the demuxer stream passed to sub_create(). Signals if |
342 | | // enough packets were read and if the subtitle state updated in anyway. If |
343 | | // packets_read is false, the player should wait until the demuxer signals new |
344 | | // packets and retry. |
345 | | void sub_read_packets(struct dec_sub *sub, double video_pts, bool force, |
346 | | bool *packets_read, bool *sub_updated) |
347 | 27.0k | { |
348 | 27.0k | *packets_read = true; |
349 | 27.0k | mp_mutex_lock(&sub->lock); |
350 | 27.0k | video_pts = pts_to_subtitle(sub, video_pts); |
351 | 28.6k | while (1) { |
352 | 28.6k | bool read_more = true; |
353 | 28.6k | if (sub->sd->driver->accepts_packet) |
354 | 4.36k | read_more = sub->sd->driver->accepts_packet(sub->sd, video_pts); |
355 | | |
356 | 28.6k | if (!read_more) |
357 | 0 | break; |
358 | | |
359 | 28.6k | if (sub->new_segment && sub->new_segment->start < video_pts) { |
360 | 0 | sub->last_vo_pts = video_pts; |
361 | 0 | update_segment(sub); |
362 | 0 | } |
363 | | |
364 | 28.6k | if (sub->new_segment) |
365 | 0 | break; |
366 | | |
367 | | // (Use this mechanism only if sub_delay matters to avoid corner cases.) |
368 | 28.6k | float delay = sub->order < 0 ? 0.0f : sub->shared_opts->sub_delay[sub->order]; |
369 | 28.6k | double min_pts = delay < 0 || force ? video_pts : MP_NOPTS_VALUE; |
370 | | |
371 | 28.6k | struct demux_packet *pkt; |
372 | 28.6k | int st = demux_read_packet_async_until(sub->sh, min_pts, &pkt); |
373 | | // Note: "wait" (st==0) happens with non-interleaved streams only, and |
374 | | // then we should stop the playloop until a new enough packet has been |
375 | | // seen (or the subtitle decoder's queue is full). This usually does not |
376 | | // happen for interleaved subtitle streams, which never return "wait" |
377 | | // when reading, unless min_pts is set. |
378 | 28.6k | if (st <= 0) { |
379 | 27.0k | *packets_read = st < 0 || (sub->last_pkt_pts != MP_NOPTS_VALUE && |
380 | 0 | sub->last_pkt_pts > video_pts); |
381 | 27.0k | break; |
382 | 27.0k | } |
383 | | |
384 | 1.55k | if (sub->recorder_sink) |
385 | 0 | mp_recorder_feed_packet(sub->recorder_sink, pkt); |
386 | | |
387 | 1.55k | sub->last_pkt_pts = pkt->pts; |
388 | 1.55k | MP_TARRAY_APPEND(sub, sub->cached_pkts, sub->num_cached_pkts, pkt); |
389 | | |
390 | 1.55k | if (is_new_segment(sub, pkt)) { |
391 | 0 | sub->new_segment = demux_copy_packet(sub->packet_pool, pkt); |
392 | | // Note that this can be delayed to a much later point in time. |
393 | 0 | update_segment(sub); |
394 | 0 | break; |
395 | 0 | } |
396 | | |
397 | 1.55k | if (!(sub->preload_attempted && sub->sd->preload_ok)) |
398 | 1.55k | sub->sd->driver->decode(sub->sd, pkt); |
399 | 1.55k | } |
400 | 27.0k | if (sub->cached_pkts && sub->num_cached_pkts) { |
401 | 16.4k | bool visible = is_packet_visible(sub->cached_pkts[sub->cached_pkt_pos], video_pts); |
402 | 16.4k | *sub_updated = update_pkt_cache(sub, video_pts) || sub->sub_visible != visible; |
403 | 16.4k | sub->sub_visible = visible; |
404 | 16.4k | } |
405 | 27.0k | mp_mutex_unlock(&sub->lock); |
406 | 27.0k | } |
407 | | |
408 | | // Redecode all cached packets if needed. |
409 | | // Used with UPDATE_SUB_HARD and UPDATE_SUB_FILT. |
410 | | void sub_redecode_cached_packets(struct dec_sub *sub) |
411 | 554 | { |
412 | 554 | mp_mutex_lock(&sub->lock); |
413 | 554 | int index = sub->cached_pkt_pos; |
414 | 558 | while (index < sub->num_cached_pkts) { |
415 | 4 | sub->sd->driver->decode(sub->sd, sub->cached_pkts[index]); |
416 | 4 | ++index; |
417 | 4 | } |
418 | 554 | mp_mutex_unlock(&sub->lock); |
419 | 554 | } |
420 | | |
421 | | // Unref sub_bitmaps.rc to free the result. May return NULL. |
422 | | struct sub_bitmaps *sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, |
423 | | int format, double pts) |
424 | 0 | { |
425 | 0 | mp_mutex_lock(&sub->lock); |
426 | |
|
427 | 0 | pts = pts_to_subtitle(sub, pts); |
428 | |
|
429 | 0 | sub->last_vo_pts = pts; |
430 | 0 | update_segment(sub); |
431 | |
|
432 | 0 | struct sub_bitmaps *res = NULL; |
433 | |
|
434 | 0 | if (!(sub->end != MP_NOPTS_VALUE && pts >= sub->end) && |
435 | 0 | sub->sd->driver->get_bitmaps) |
436 | 0 | res = sub->sd->driver->get_bitmaps(sub->sd, dim, format, pts); |
437 | |
|
438 | 0 | mp_mutex_unlock(&sub->lock); |
439 | 0 | return res; |
440 | 0 | } |
441 | | |
442 | | // The returned string is talloc'ed. |
443 | | char *sub_get_text(struct dec_sub *sub, double pts, enum sd_text_type type) |
444 | 460 | { |
445 | 460 | mp_mutex_lock(&sub->lock); |
446 | 460 | char *text = NULL; |
447 | | |
448 | 460 | pts = pts_to_subtitle(sub, pts); |
449 | | |
450 | 460 | sub->last_vo_pts = pts; |
451 | 460 | update_segment(sub); |
452 | | |
453 | 460 | if (sub->sd->driver->get_text) |
454 | 193 | text = sub->sd->driver->get_text(sub->sd, pts, type); |
455 | 460 | mp_mutex_unlock(&sub->lock); |
456 | 460 | return text; |
457 | 460 | } |
458 | | |
459 | | char *sub_ass_get_extradata(struct dec_sub *sub) |
460 | 0 | { |
461 | 0 | char *data = NULL; |
462 | 0 | mp_mutex_lock(&sub->lock); |
463 | 0 | if (strcmp(sub->sd->codec->codec, "ass") != 0) |
464 | 0 | goto done; |
465 | 0 | char *extradata = sub->sd->codec->extradata; |
466 | 0 | int extradata_size = sub->sd->codec->extradata_size; |
467 | 0 | data = talloc_strndup(NULL, extradata, extradata_size); |
468 | 0 | done: |
469 | 0 | mp_mutex_unlock(&sub->lock); |
470 | 0 | return data; |
471 | 0 | } |
472 | | |
473 | | struct sd_times sub_get_times(struct dec_sub *sub, double pts) |
474 | 0 | { |
475 | 0 | mp_mutex_lock(&sub->lock); |
476 | 0 | struct sd_times res = { .start = MP_NOPTS_VALUE, .end = MP_NOPTS_VALUE }; |
477 | |
|
478 | 0 | pts = pts_to_subtitle(sub, pts); |
479 | |
|
480 | 0 | sub->last_vo_pts = pts; |
481 | 0 | update_segment(sub); |
482 | |
|
483 | 0 | if (sub->sd->driver->get_times) |
484 | 0 | res = sub->sd->driver->get_times(sub->sd, pts); |
485 | |
|
486 | 0 | mp_mutex_unlock(&sub->lock); |
487 | 0 | return res; |
488 | 0 | } |
489 | | |
490 | | void sub_reset(struct dec_sub *sub) |
491 | 3.45k | { |
492 | 3.45k | mp_mutex_lock(&sub->lock); |
493 | 3.45k | if (sub->sd->driver->reset) |
494 | 3.45k | sub->sd->driver->reset(sub->sd); |
495 | 3.45k | sub->last_pkt_pts = MP_NOPTS_VALUE; |
496 | 3.45k | sub->last_vo_pts = MP_NOPTS_VALUE; |
497 | 3.45k | destroy_cached_pkts(sub); |
498 | 3.45k | demux_packet_pool_push(sub->packet_pool, sub->new_segment); |
499 | 3.45k | sub->new_segment = NULL; |
500 | 3.45k | mp_mutex_unlock(&sub->lock); |
501 | 3.45k | } |
502 | | |
503 | | void sub_select(struct dec_sub *sub, bool selected) |
504 | 3.45k | { |
505 | 3.45k | mp_mutex_lock(&sub->lock); |
506 | 3.45k | if (sub->sd->driver->select) |
507 | 3.00k | sub->sd->driver->select(sub->sd, selected); |
508 | 3.45k | mp_mutex_unlock(&sub->lock); |
509 | 3.45k | } |
510 | | |
511 | | int sub_control(struct dec_sub *sub, enum sd_ctrl cmd, void *arg) |
512 | 53.0k | { |
513 | 53.0k | int r = CONTROL_UNKNOWN; |
514 | 53.0k | mp_mutex_lock(&sub->lock); |
515 | 53.0k | bool propagate = false; |
516 | 53.0k | switch (cmd) { |
517 | 1.72k | case SD_CTRL_SET_VIDEO_DEF_FPS: |
518 | 1.72k | sub->video_fps = *(double *)arg; |
519 | 1.72k | update_subtitle_speed(sub); |
520 | 1.72k | break; |
521 | 0 | case SD_CTRL_SUB_STEP: { |
522 | 0 | double *a = arg; |
523 | 0 | double arg2[2] = {a[0], a[1]}; |
524 | 0 | arg2[0] = pts_to_subtitle(sub, arg2[0]); |
525 | 0 | if (sub->sd->driver->control) |
526 | 0 | r = sub->sd->driver->control(sub->sd, cmd, arg2); |
527 | 0 | if (r == CONTROL_OK) |
528 | 0 | a[0] = pts_from_subtitle(sub, arg2[0]); |
529 | 0 | break; |
530 | 0 | } |
531 | 0 | case SD_CTRL_UPDATE_OPTS: { |
532 | 0 | uint64_t flags = *(uint64_t *)arg; |
533 | 0 | if (m_config_cache_update(sub->opts_cache)) |
534 | 0 | update_subtitle_speed(sub); |
535 | 0 | m_config_cache_update(sub->shared_opts_cache); |
536 | 0 | propagate = true; |
537 | 0 | if (flags & UPDATE_SUB_HARD) { |
538 | | // forget about the previous preload because |
539 | | // UPDATE_SUB_HARD will cause a sub reinit |
540 | | // that clears all preloaded sub packets |
541 | 0 | sub->preload_attempted = false; |
542 | 0 | } |
543 | 0 | break; |
544 | 0 | } |
545 | 51.3k | default: |
546 | 51.3k | propagate = true; |
547 | 53.0k | } |
548 | 53.0k | if (propagate && sub->sd->driver->control) |
549 | 51.3k | r = sub->sd->driver->control(sub->sd, cmd, arg); |
550 | 53.0k | mp_mutex_unlock(&sub->lock); |
551 | 53.0k | return r; |
552 | 53.0k | } |
553 | | |
554 | | void sub_set_recorder_sink(struct dec_sub *sub, struct mp_recorder_sink *sink) |
555 | 0 | { |
556 | 0 | mp_mutex_lock(&sub->lock); |
557 | 0 | sub->recorder_sink = sink; |
558 | 0 | mp_mutex_unlock(&sub->lock); |
559 | 0 | } |
560 | | |
561 | | void sub_set_play_dir(struct dec_sub *sub, int dir) |
562 | 1.72k | { |
563 | 1.72k | mp_mutex_lock(&sub->lock); |
564 | 1.72k | sub->play_dir = dir; |
565 | 1.72k | mp_mutex_unlock(&sub->lock); |
566 | 1.72k | } |
567 | | |
568 | | bool sub_is_primary_visible(struct dec_sub *sub) |
569 | 0 | { |
570 | 0 | mp_mutex_lock(&sub->lock); |
571 | 0 | bool ret = sub->shared_opts->sub_visibility[0]; |
572 | 0 | mp_mutex_unlock(&sub->lock); |
573 | 0 | return ret; |
574 | 0 | } |
575 | | |
576 | | bool sub_is_secondary_visible(struct dec_sub *sub) |
577 | 0 | { |
578 | 0 | mp_mutex_lock(&sub->lock); |
579 | 0 | bool ret = sub->shared_opts->sub_visibility[1]; |
580 | 0 | mp_mutex_unlock(&sub->lock); |
581 | 0 | return ret; |
582 | 0 | } |
583 | | |
584 | | static int sub_line_cmp(const void *a, const void *b) |
585 | 0 | { |
586 | 0 | const struct sub_line *la = a, *lb = b; |
587 | 0 | if (la->start < lb->start) return -1; |
588 | 0 | if (la->start > lb->start) return 1; |
589 | 0 | return 0; |
590 | 0 | } |
591 | | |
592 | | static void dedup_sub_lines(struct sub_lines *lines) |
593 | 0 | { |
594 | 0 | int window_start = 0; |
595 | 0 | int window_end = 1; |
596 | 0 | int current_shift = 0; |
597 | |
|
598 | 0 | while (window_end < lines->num_entries) { |
599 | 0 | struct sub_line next = lines->entries[window_end + current_shift]; |
600 | 0 | for (int i = window_start; i < window_end; ++i) { |
601 | 0 | if (lines->entries[i].end < next.start) { |
602 | 0 | struct sub_line tmp = lines->entries[window_start]; |
603 | 0 | lines->entries[window_start++] = lines->entries[i]; |
604 | 0 | lines->entries[i] = tmp; |
605 | 0 | continue; |
606 | 0 | } |
607 | | |
608 | 0 | if (!strcmp(lines->entries[i].text, next.text)) { |
609 | 0 | lines->entries[i].end = MPMAX(next.end, lines->entries[i].end); |
610 | 0 | TA_FREEP(&next.text); |
611 | 0 | ++current_shift, --lines->num_entries; |
612 | 0 | goto skip; |
613 | 0 | } |
614 | 0 | } |
615 | | |
616 | 0 | lines->entries[window_end++] = next; |
617 | |
|
618 | 0 | skip:; |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | | struct sub_lines *sub_get_lines(struct dec_sub *sub) |
623 | 0 | { |
624 | 0 | mp_mutex_lock(&sub->lock); |
625 | 0 | struct sub_lines *res = NULL; |
626 | 0 | if (sub->sd->driver->get_lines) { |
627 | 0 | res = sub->sd->driver->get_lines(sub->sd); |
628 | 0 | qsort(res->entries, res->num_entries, sizeof(res->entries[0]), |
629 | 0 | sub_line_cmp); |
630 | 0 | dedup_sub_lines(res); |
631 | | // dedup may sometimes reorder lines to keep its window smaller |
632 | 0 | qsort(res->entries, res->num_entries, sizeof(res->entries[0]), |
633 | 0 | sub_line_cmp); |
634 | 0 | } |
635 | 0 | mp_mutex_unlock(&sub->lock); |
636 | 0 | return res; |
637 | 0 | } |