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 <assert.h> |
20 | | #include <math.h> |
21 | | |
22 | | #include <libavcodec/avcodec.h> |
23 | | #include <libavutil/common.h> |
24 | | #include <libavutil/intreadwrite.h> |
25 | | #include <libavutil/opt.h> |
26 | | |
27 | | #include "mpv_talloc.h" |
28 | | #include "common/msg.h" |
29 | | #include "common/av_common.h" |
30 | | #include "demux/stheader.h" |
31 | | #include "options/options.h" |
32 | | #include "video/mp_image.h" |
33 | | #include "video/out/bitmap_packer.h" |
34 | | #include "img_convert.h" |
35 | | #include "sd.h" |
36 | | #include "dec_sub.h" |
37 | | |
38 | 30.8k | #define MAX_QUEUE 4 |
39 | | |
40 | | struct sub { |
41 | | bool valid; |
42 | | AVSubtitle avsub; |
43 | | struct sub_bitmap *inbitmaps; |
44 | | int count; |
45 | | struct mp_image *data; |
46 | | int bound_w, bound_h; |
47 | | int src_w, src_h; |
48 | | double pts; |
49 | | double endpts; |
50 | | int64_t id; |
51 | | }; |
52 | | |
53 | | struct seekpoint { |
54 | | double pts; |
55 | | double endpts; |
56 | | }; |
57 | | |
58 | | struct sd_lavc_priv { |
59 | | struct mp_codec_params *codec; |
60 | | AVCodecContext *avctx; |
61 | | AVPacket *avpkt; |
62 | | AVRational pkt_timebase; |
63 | | struct sub subs[MAX_QUEUE]; // most recent event first |
64 | | struct sub_bitmap *outbitmaps; |
65 | | struct sub_bitmap *prevret; |
66 | | int prevret_num; |
67 | | int64_t displayed_id; |
68 | | int64_t new_id; |
69 | | struct mp_image_params video_params; |
70 | | double current_pts; |
71 | | struct seekpoint *seekpoints; |
72 | | int num_seekpoints; |
73 | | struct bitmap_packer *packer; |
74 | | |
75 | | // DVD-nav menu/highlight overlay state. |
76 | | bool menu_active; // in-menu: gates the highlight overlay |
77 | | struct mp_dvdnav_highlight hl; // focused button rect + palette |
78 | | uint32_t hli_change_id; |
79 | | }; |
80 | | |
81 | | static int init(struct sd *sd) |
82 | 2.78k | { |
83 | 2.78k | enum AVCodecID cid = mp_codec_to_av_codec_id(sd->codec->codec); |
84 | | |
85 | | // Supported codecs must be known to decode to paletted bitmaps |
86 | 2.78k | switch (cid) { |
87 | 0 | case AV_CODEC_ID_DVB_SUBTITLE: |
88 | 0 | case AV_CODEC_ID_DVB_TELETEXT: |
89 | 1 | case AV_CODEC_ID_HDMV_PGS_SUBTITLE: |
90 | 1 | case AV_CODEC_ID_XSUB: |
91 | 262 | case AV_CODEC_ID_DVD_SUBTITLE: |
92 | 262 | case AV_CODEC_ID_ARIB_CAPTION: |
93 | 262 | break; |
94 | 2.52k | default: |
95 | 2.52k | return -1; |
96 | 2.78k | } |
97 | | |
98 | 262 | struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv); |
99 | 262 | AVCodecContext *ctx = NULL; |
100 | 262 | const AVCodec *sub_codec = avcodec_find_decoder(cid); |
101 | 262 | if (!sub_codec) |
102 | 0 | goto error_probe; |
103 | 262 | ctx = avcodec_alloc_context3(sub_codec); |
104 | 262 | if (!ctx) |
105 | 0 | goto error_probe; |
106 | | |
107 | 262 | mp_set_avopts(sd->log, ctx, sd->opts->sub_avopts); |
108 | | |
109 | 262 | switch (cid) { |
110 | 0 | case AV_CODEC_ID_DVB_TELETEXT: { |
111 | 0 | int64_t format = -1; |
112 | 0 | int ret = av_opt_get_int(ctx, "txt_format", AV_OPT_SEARCH_CHILDREN, &format); |
113 | | // libzvbi_teletextdec: format == 0 is bitmap |
114 | 0 | if (ret || format) |
115 | 0 | goto error_probe; |
116 | 0 | break; |
117 | 0 | } |
118 | 0 | case AV_CODEC_ID_ARIB_CAPTION: { |
119 | 0 | int64_t format = -1; |
120 | | // FFmpeg has both libaribb24 and libaribcaption as decoders. Only the latter |
121 | | // can produce bitmaps, so abort if we don't find the option. |
122 | 0 | int ret = av_opt_get_int(ctx, "sub_type", AV_OPT_SEARCH_CHILDREN, &format); |
123 | 0 | if (ret || format != SUBTITLE_BITMAP) |
124 | 0 | goto error_probe; |
125 | 0 | break; |
126 | 0 | } |
127 | 262 | } |
128 | | |
129 | 262 | MP_VERBOSE(sd, "Using subtitle decoder %s\n", sub_codec->name); |
130 | | |
131 | 262 | priv->avpkt = av_packet_alloc(); |
132 | 262 | priv->codec = sd->codec; |
133 | 262 | if (!priv->avpkt) |
134 | 0 | goto error; |
135 | 262 | if (mp_set_avctx_codec_headers(ctx, sd->codec) < 0) |
136 | 0 | goto error; |
137 | 262 | priv->pkt_timebase = mp_get_codec_timebase(sd->codec); |
138 | 262 | ctx->pkt_timebase = priv->pkt_timebase; |
139 | 262 | if (avcodec_open2(ctx, sub_codec, NULL) < 0) |
140 | 3 | goto error; |
141 | 259 | priv->avctx = ctx; |
142 | 259 | sd->priv = priv; |
143 | 259 | priv->displayed_id = -1; |
144 | 259 | priv->current_pts = MP_NOPTS_VALUE; |
145 | 259 | priv->packer = talloc_zero(priv, struct bitmap_packer); |
146 | 259 | return 0; |
147 | | |
148 | 3 | error: |
149 | 3 | MP_FATAL(sd, "Could not open libavcodec subtitle decoder\n"); |
150 | 3 | error_probe: |
151 | 3 | avcodec_free_context(&ctx); |
152 | 3 | mp_free_av_packet(&priv->avpkt); |
153 | 3 | talloc_free(priv); |
154 | 3 | return -1; |
155 | 3 | } |
156 | | |
157 | | static void clear_sub(struct sub *sub) |
158 | 3.12k | { |
159 | 3.12k | sub->count = 0; |
160 | 3.12k | sub->pts = MP_NOPTS_VALUE; |
161 | 3.12k | sub->endpts = MP_NOPTS_VALUE; |
162 | 3.12k | if (sub->valid) |
163 | 0 | avsubtitle_free(&sub->avsub); |
164 | 3.12k | sub->valid = false; |
165 | 3.12k | } |
166 | | |
167 | | static void alloc_sub(struct sd_lavc_priv *priv) |
168 | 0 | { |
169 | 0 | clear_sub(&priv->subs[MAX_QUEUE - 1]); |
170 | 0 | struct sub tmp = priv->subs[MAX_QUEUE - 1]; |
171 | 0 | for (int n = MAX_QUEUE - 1; n > 0; n--) |
172 | 0 | priv->subs[n] = priv->subs[n - 1]; |
173 | 0 | priv->subs[0] = tmp; |
174 | | // clear only some fields; the memory allocs can be reused |
175 | 0 | priv->subs[0].valid = false; |
176 | 0 | priv->subs[0].count = 0; |
177 | 0 | priv->subs[0].src_w = 0; |
178 | 0 | priv->subs[0].src_h = 0; |
179 | 0 | priv->subs[0].id = priv->new_id++; |
180 | 0 | } |
181 | | |
182 | | static void convert_pal(uint32_t *colors, size_t count, bool gray) |
183 | 0 | { |
184 | 0 | for (int n = 0; n < count; n++) { |
185 | 0 | uint32_t c = colors[n]; |
186 | 0 | uint32_t b = c & 0xFF; |
187 | 0 | uint32_t g = (c >> 8) & 0xFF; |
188 | 0 | uint32_t r = (c >> 16) & 0xFF; |
189 | 0 | uint32_t a = (c >> 24) & 0xFF; |
190 | 0 | if (gray) |
191 | 0 | r = g = b = (r + g + b) / 3; |
192 | | // from straight to pre-multiplied alpha |
193 | 0 | b = b * a / 255; |
194 | 0 | g = g * a / 255; |
195 | 0 | r = r * a / 255; |
196 | 0 | colors[n] = b | (g << 8) | (r << 16) | (a << 24); |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | // Initialize sub from sub->avsub. |
201 | | static void read_sub_bitmaps(struct sd *sd, struct sub *sub) |
202 | 0 | { |
203 | 0 | struct mp_subtitle_opts *opts = sd->opts; |
204 | 0 | struct sd_lavc_priv *priv = sd->priv; |
205 | 0 | AVSubtitle *avsub = &sub->avsub; |
206 | |
|
207 | 0 | MP_TARRAY_GROW(priv, sub->inbitmaps, avsub->num_rects); |
208 | |
|
209 | 0 | packer_set_size(priv->packer, avsub->num_rects); |
210 | | |
211 | | // If we blur, we want a transparent region around the bitmap data to |
212 | | // avoid "cut off" artifacts on the borders. |
213 | 0 | bool apply_blur = opts->sub_gauss != 0.0f; |
214 | 0 | int extend = apply_blur ? 5 : 0; |
215 | | // Assume consumers may use bilinear scaling on it (2x2 filter) |
216 | 0 | int padding = 1 + extend; |
217 | |
|
218 | 0 | priv->packer->padding = padding; |
219 | | |
220 | | // For the sake of libswscale, which in some cases takes sub-rects as |
221 | | // source images, and wants 16 byte start pointer and stride alignment. |
222 | 0 | int align = 4; |
223 | |
|
224 | 0 | for (int i = 0; i < avsub->num_rects; i++) { |
225 | 0 | struct AVSubtitleRect *r = avsub->rects[i]; |
226 | 0 | struct sub_bitmap *b = &sub->inbitmaps[sub->count]; |
227 | |
|
228 | 0 | if (r->type != SUBTITLE_BITMAP) { |
229 | 0 | MP_ERR(sd, "unsupported subtitle type from decoder (%d)\n", r->type); |
230 | 0 | continue; |
231 | 0 | } |
232 | 0 | if (!(r->flags & AV_SUBTITLE_FLAG_FORCED) && opts->sub_forced_events_only) |
233 | 0 | continue; |
234 | 0 | if (r->w <= 0 || r->h <= 0) |
235 | 0 | continue; |
236 | | |
237 | | // save the rect for later (dumb hack to avoid more complexity) |
238 | 0 | *b = (struct sub_bitmap){ .bitmap = r }; |
239 | |
|
240 | 0 | priv->packer->in[sub->count] = (struct pos){r->w + (align - 1), r->h}; |
241 | 0 | sub->count++; |
242 | 0 | } |
243 | |
|
244 | 0 | priv->packer->count = sub->count; |
245 | |
|
246 | 0 | if (packer_pack(priv->packer) < 0) { |
247 | 0 | MP_ERR(sd, "Unable to pack subtitle bitmaps.\n"); |
248 | 0 | sub->count = 0; |
249 | 0 | } |
250 | |
|
251 | 0 | if (!sub->count) |
252 | 0 | return; |
253 | | |
254 | 0 | struct pos bb[2]; |
255 | 0 | packer_get_bb(priv->packer, bb); |
256 | |
|
257 | 0 | sub->bound_w = bb[1].x; |
258 | 0 | sub->bound_h = bb[1].y; |
259 | |
|
260 | 0 | if (!sub->data || sub->data->w < sub->bound_w || sub->data->h < sub->bound_h) { |
261 | 0 | talloc_free(sub->data); |
262 | 0 | sub->data = mp_image_alloc(IMGFMT_BGRA, priv->packer->w, priv->packer->h); |
263 | 0 | if (!sub->data) { |
264 | 0 | sub->count = 0; |
265 | 0 | return; |
266 | 0 | } |
267 | 0 | talloc_steal(priv, sub->data); |
268 | 0 | } |
269 | | |
270 | 0 | if (!mp_image_make_writeable(sub->data)) { |
271 | 0 | sub->count = 0; |
272 | 0 | return; |
273 | 0 | } |
274 | | |
275 | 0 | for (int i = 0; i < sub->count; i++) { |
276 | 0 | struct sub_bitmap *b = &sub->inbitmaps[i]; |
277 | 0 | struct pos pos = priv->packer->result[i]; |
278 | 0 | struct AVSubtitleRect *r = b->bitmap; |
279 | 0 | uint8_t **data = r->data; |
280 | 0 | int *linesize = r->linesize; |
281 | 0 | b->w = r->w; |
282 | 0 | b->h = r->h; |
283 | 0 | b->x = r->x; |
284 | 0 | b->y = r->y; |
285 | | |
286 | | // Choose such that the extended start position is aligned. |
287 | 0 | pos.x = MP_ALIGN_UP(pos.x - extend, align) + extend; |
288 | |
|
289 | 0 | b->src_x = pos.x; |
290 | 0 | b->src_y = pos.y; |
291 | 0 | b->stride = sub->data->stride[0]; |
292 | 0 | b->bitmap = sub->data->planes[0] + pos.y * b->stride + pos.x * 4; |
293 | |
|
294 | 0 | sub->src_w = MPMAX(sub->src_w, b->x + b->w); |
295 | 0 | sub->src_h = MPMAX(sub->src_h, b->y + b->h); |
296 | |
|
297 | 0 | mp_assert(r->nb_colors > 0); |
298 | 0 | mp_assert(r->nb_colors <= 256); |
299 | 0 | uint32_t pal[256] = {0}; |
300 | 0 | memcpy(pal, data[1], r->nb_colors * 4); |
301 | 0 | convert_pal(pal, 256, opts->sub_gray); |
302 | | |
303 | | // DVD navigation highlight |
304 | 0 | struct mp_rect hlr = priv->hl.rect; |
305 | 0 | bool hli_active = priv->menu_active && |
306 | 0 | mp_rect_w(hlr) > 0 && mp_rect_h(hlr) > 0 && |
307 | 0 | r->x < hlr.x1 && r->y < hlr.y1 && |
308 | 0 | r->x + r->w > hlr.x0 && r->y + r->h > hlr.y0; |
309 | 0 | uint32_t hli_pal[4] = {0}; |
310 | 0 | if (hli_active) { |
311 | 0 | memcpy(hli_pal, priv->hl.palette, sizeof(hli_pal)); |
312 | 0 | convert_pal(hli_pal, 4, opts->sub_gray); |
313 | 0 | } |
314 | 0 | int hli_x0 = hlr.x0 - r->x; |
315 | 0 | int hli_y0 = hlr.y0 - r->y; |
316 | 0 | int hli_x1 = hlr.x1 - r->x; |
317 | 0 | int hli_y1 = hlr.y1 - r->y; |
318 | |
|
319 | 0 | for (int y = -padding; y < b->h + padding; y++) { |
320 | 0 | uint32_t *out = (uint32_t*)((char*)b->bitmap + y * b->stride); |
321 | 0 | int start = 0; |
322 | 0 | for (int x = -padding; x < 0; x++) |
323 | 0 | out[x] = 0; |
324 | 0 | if (y >= 0 && y < b->h) { |
325 | 0 | uint8_t *in = data[0] + y * linesize[0]; |
326 | 0 | bool y_in_hli = hli_active && y >= hli_y0 && y < hli_y1; |
327 | 0 | for (int x = 0; x < b->w; x++) { |
328 | 0 | uint8_t pv = *in++; |
329 | 0 | if (y_in_hli && x >= hli_x0 && x < hli_x1 && pv < 4) |
330 | 0 | *out++ = hli_pal[pv]; |
331 | 0 | else |
332 | 0 | *out++ = pal[pv]; |
333 | 0 | } |
334 | 0 | start = b->w; |
335 | 0 | } |
336 | 0 | for (int x = start; x < b->w + padding; x++) |
337 | 0 | *out++ = 0; |
338 | 0 | } |
339 | |
|
340 | 0 | b->bitmap = (char*)b->bitmap - extend * b->stride - extend * 4; |
341 | 0 | b->src_x -= extend; |
342 | 0 | b->src_y -= extend; |
343 | 0 | b->x -= extend; |
344 | 0 | b->y -= extend; |
345 | 0 | b->w += extend * 2; |
346 | 0 | b->h += extend * 2; |
347 | |
|
348 | 0 | if (apply_blur) |
349 | 0 | mp_blur_rgba_sub_bitmap(b, opts->sub_gauss); |
350 | 0 | } |
351 | 0 | } |
352 | | |
353 | | static void rerender_queued_subs(struct sd *sd) |
354 | 0 | { |
355 | 0 | struct sd_lavc_priv *priv = sd->priv; |
356 | 0 | for (int n = 0; n < MAX_QUEUE; n++) { |
357 | 0 | struct sub *sub = &priv->subs[n]; |
358 | 0 | if (!sub->valid) |
359 | 0 | continue; |
360 | 0 | sub->count = 0; |
361 | 0 | sub->src_w = 0; |
362 | 0 | sub->src_h = 0; |
363 | 0 | sub->id = priv->new_id++; |
364 | 0 | read_sub_bitmaps(sd, sub); |
365 | 0 | } |
366 | 0 | } |
367 | | |
368 | | static void decode(struct sd *sd, struct demux_packet *packet) |
369 | 50 | { |
370 | 50 | struct mp_subtitle_opts *opts = sd->opts; |
371 | 50 | struct sd_lavc_priv *priv = sd->priv; |
372 | 50 | AVCodecContext *ctx = priv->avctx; |
373 | 50 | double pts = packet->pts; |
374 | 50 | double endpts = MP_NOPTS_VALUE; |
375 | 50 | AVSubtitle sub; |
376 | | |
377 | 50 | if (pts == MP_NOPTS_VALUE) |
378 | 50 | MP_WARN(sd, "Subtitle with unknown start time.\n"); |
379 | | |
380 | 50 | mp_set_av_packet(priv->avpkt, packet, &priv->pkt_timebase); |
381 | | |
382 | 50 | if (ctx->codec_id == AV_CODEC_ID_DVB_TELETEXT) { |
383 | 0 | if (!opts->teletext_page) { |
384 | 0 | av_opt_set(ctx, "txt_page", "subtitle", AV_OPT_SEARCH_CHILDREN); |
385 | 0 | } else if (opts->teletext_page == -1) { |
386 | 0 | av_opt_set(ctx, "txt_page", "*", AV_OPT_SEARCH_CHILDREN); |
387 | 0 | } else { |
388 | 0 | char page[4]; |
389 | 0 | snprintf(page, sizeof(page), "%d", opts->teletext_page); |
390 | 0 | av_opt_set(ctx, "txt_page", page, AV_OPT_SEARCH_CHILDREN); |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | 50 | int got_sub; |
395 | 50 | int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, priv->avpkt); |
396 | 50 | if (res < 0 || !got_sub) |
397 | 50 | return; |
398 | | |
399 | 0 | mp_codec_info_from_av(ctx, priv->codec); |
400 | |
|
401 | 0 | packet->sub_duration = sub.end_display_time; |
402 | |
|
403 | 0 | if (sub.pts != AV_NOPTS_VALUE) |
404 | 0 | pts = sub.pts / (double)AV_TIME_BASE; |
405 | |
|
406 | 0 | if (pts != MP_NOPTS_VALUE) { |
407 | 0 | if (sub.end_display_time > sub.start_display_time && |
408 | 0 | sub.end_display_time != UINT32_MAX) |
409 | 0 | { |
410 | 0 | endpts = pts + sub.end_display_time / 1000.0; |
411 | 0 | } |
412 | 0 | pts += sub.start_display_time / 1000.0; |
413 | | |
414 | | // set end time of previous sub |
415 | 0 | struct sub *prev = &priv->subs[0]; |
416 | 0 | if (prev->valid) { |
417 | 0 | if (prev->endpts == MP_NOPTS_VALUE || prev->endpts > pts) |
418 | 0 | prev->endpts = pts; |
419 | |
|
420 | 0 | if (opts->sub_fix_timing && pts - prev->endpts <= opts->sub_fix_timing_threshold / 1000.0) |
421 | 0 | prev->endpts = pts; |
422 | |
|
423 | 0 | for (int n = 0; n < priv->num_seekpoints; n++) { |
424 | 0 | if (priv->seekpoints[n].pts == prev->pts) { |
425 | 0 | priv->seekpoints[n].endpts = prev->endpts; |
426 | 0 | break; |
427 | 0 | } |
428 | 0 | } |
429 | 0 | } |
430 | | |
431 | | // This subtitle packet only signals the end of subtitle display. |
432 | 0 | if (!sub.num_rects) { |
433 | 0 | avsubtitle_free(&sub); |
434 | 0 | return; |
435 | 0 | } |
436 | 0 | } |
437 | | |
438 | 0 | alloc_sub(priv); |
439 | 0 | struct sub *current = &priv->subs[0]; |
440 | |
|
441 | 0 | current->valid = true; |
442 | 0 | current->pts = pts; |
443 | 0 | current->endpts = endpts; |
444 | 0 | current->avsub = sub; |
445 | |
|
446 | 0 | read_sub_bitmaps(sd, current); |
447 | |
|
448 | 0 | if (pts != MP_NOPTS_VALUE) { |
449 | 0 | for (int n = 0; n < priv->num_seekpoints; n++) { |
450 | 0 | if (priv->seekpoints[n].pts == pts) |
451 | 0 | goto skip; |
452 | 0 | } |
453 | | // Set arbitrary limit as safe-guard against insane files. |
454 | 0 | if (priv->num_seekpoints >= 10000) |
455 | 0 | MP_TARRAY_REMOVE_AT(priv->seekpoints, priv->num_seekpoints, 0); |
456 | 0 | MP_TARRAY_APPEND(priv, priv->seekpoints, priv->num_seekpoints, |
457 | 0 | (struct seekpoint){.pts = pts, .endpts = endpts}); |
458 | 0 | skip: ; |
459 | 0 | } |
460 | 0 | } |
461 | | |
462 | | static struct sub *get_current(struct sd_lavc_priv *priv, double pts) |
463 | 0 | { |
464 | 0 | struct sub *current = NULL; |
465 | 0 | for (int n = 0; n < MAX_QUEUE; n++) { |
466 | 0 | struct sub *sub = &priv->subs[n]; |
467 | 0 | if (!sub->valid) |
468 | 0 | continue; |
469 | 0 | if (pts == MP_NOPTS_VALUE || |
470 | 0 | ((sub->pts == MP_NOPTS_VALUE || pts + 1e-6 >= sub->pts) && |
471 | 0 | (sub->endpts == MP_NOPTS_VALUE || pts + 1e-6 < sub->endpts))) |
472 | 0 | { |
473 | | // Ignore "trailing" subtitles with unknown length after 1 minute. |
474 | 0 | if (sub->endpts == MP_NOPTS_VALUE && pts >= sub->pts + 60) |
475 | 0 | break; |
476 | 0 | current = sub; |
477 | 0 | break; |
478 | 0 | } |
479 | 0 | } |
480 | 0 | return current; |
481 | 0 | } |
482 | | |
483 | | static struct sub_bitmaps *get_bitmaps(struct sd *sd, struct mp_osd_res d, |
484 | | int format, double pts) |
485 | 0 | { |
486 | 0 | struct sd_lavc_priv *priv = sd->priv; |
487 | 0 | struct mp_subtitle_opts *opts = sd->opts; |
488 | 0 | struct mp_subtitle_shared_opts *shared_opts = sd->shared_opts; |
489 | |
|
490 | 0 | priv->current_pts = pts; |
491 | |
|
492 | 0 | struct sub *current = get_current(priv, pts); |
493 | |
|
494 | 0 | if (!current) |
495 | 0 | return NULL; |
496 | | |
497 | 0 | MP_TARRAY_GROW(priv, priv->outbitmaps, current->count); |
498 | 0 | for (int n = 0; n < current->count; n++) |
499 | 0 | priv->outbitmaps[n] = current->inbitmaps[n]; |
500 | |
|
501 | 0 | struct sub_bitmaps *res = &(struct sub_bitmaps){0}; |
502 | 0 | res->parts = priv->outbitmaps; |
503 | 0 | res->num_parts = current->count; |
504 | 0 | if (priv->displayed_id != current->id) |
505 | 0 | res->change_id++; |
506 | 0 | priv->displayed_id = current->id; |
507 | 0 | res->packed = current->data; |
508 | 0 | res->packed_w = current->bound_w; |
509 | 0 | res->packed_h = current->bound_h; |
510 | 0 | res->format = SUBBITMAP_BGRA; |
511 | 0 | res->video_color_space = true; |
512 | |
|
513 | 0 | double video_par = 0; |
514 | 0 | if (priv->avctx->codec_id == AV_CODEC_ID_DVD_SUBTITLE && |
515 | 0 | opts->stretch_dvd_subs) |
516 | 0 | { |
517 | | // For DVD subs, try to keep the subtitle PAR at display PAR. |
518 | 0 | double par = priv->video_params.p_w / (double)priv->video_params.p_h; |
519 | 0 | if (isnormal(par)) |
520 | 0 | video_par = par; |
521 | 0 | } |
522 | 0 | if (priv->avctx->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE) |
523 | 0 | { |
524 | | // For Blu-ray subs on SD video, try to match the video PAR. |
525 | 0 | if (priv->video_params.w == 720 && |
526 | 0 | (priv->video_params.h == 480 || |
527 | 0 | priv->video_params.h == 576)) |
528 | 0 | { |
529 | 0 | double par = priv->video_params.p_w / (double)priv->video_params.p_h; |
530 | 0 | if (isnormal(par)) |
531 | 0 | video_par = par * -1; |
532 | 0 | else |
533 | 0 | video_par = -1; |
534 | 0 | } |
535 | 0 | else |
536 | 0 | { |
537 | | // Force letter-boxing on all other Blu-ray subtitles |
538 | 0 | video_par = -1; |
539 | 0 | } |
540 | 0 | } |
541 | 0 | if (opts->stretch_image_subs) |
542 | 0 | d.ml = d.mr = d.mt = d.mb = 0; |
543 | 0 | int w = priv->avctx->width; |
544 | 0 | int h = priv->avctx->height; |
545 | 0 | if (w <= 0 || h <= 0 || opts->image_subs_video_res) { |
546 | 0 | w = priv->video_params.w; |
547 | 0 | h = priv->video_params.h; |
548 | 0 | } |
549 | 0 | if (current->src_w > w || current->src_h > h) { |
550 | 0 | w = MPMAX(priv->video_params.w, current->src_w); |
551 | 0 | h = MPMAX(priv->video_params.h, current->src_h); |
552 | 0 | } |
553 | |
|
554 | 0 | if (shared_opts->sub_pos[sd->order] != 100.0f && shared_opts->ass_style_override[sd->order]) { |
555 | 0 | float offset = (100.0f - shared_opts->sub_pos[sd->order]) / 100.0f * h; |
556 | |
|
557 | 0 | for (int n = 0; n < res->num_parts; n++) { |
558 | 0 | struct sub_bitmap *sub = &res->parts[n]; |
559 | | |
560 | | // Decide by heuristic whether this is a sub-title or something |
561 | | // else (top-title, covering whole screen). |
562 | 0 | if (sub->y < h / 2) |
563 | 0 | continue; |
564 | | |
565 | | // Allow moving up the subtitle, but only until it clips. |
566 | 0 | sub->y = MPMAX(sub->y - offset, 0); |
567 | 0 | sub->y = MPMIN(sub->y + sub->h, h) - sub->h; |
568 | 0 | } |
569 | 0 | } |
570 | |
|
571 | 0 | osd_rescale_bitmaps(res, w, h, d, video_par); |
572 | |
|
573 | 0 | if (shared_opts->sub_scale[sd->order] != 1.0 && shared_opts->ass_style_override[sd->order]) { |
574 | 0 | for (int n = 0; n < res->num_parts; n++) { |
575 | 0 | struct sub_bitmap *sub = &res->parts[n]; |
576 | |
|
577 | 0 | float shit = (shared_opts->sub_scale[sd->order] - 1.0f) / 2; |
578 | | |
579 | | // Fortunately VO isn't supposed to give a FUCKING FUCK about |
580 | | // whether the sub might e.g. go outside of the screen. |
581 | 0 | sub->x -= sub->dw * shit; |
582 | 0 | sub->y -= sub->dh * shit; |
583 | 0 | sub->dw += sub->dw * shit * 2; |
584 | 0 | sub->dh += sub->dh * shit * 2; |
585 | 0 | } |
586 | 0 | } |
587 | |
|
588 | 0 | if (priv->prevret_num != res->num_parts) |
589 | 0 | res->change_id++; |
590 | |
|
591 | 0 | if (!res->change_id) { |
592 | 0 | mp_assert(priv->prevret_num == res->num_parts); |
593 | 0 | for (int n = 0; n < priv->prevret_num; n++) { |
594 | 0 | struct sub_bitmap *a = &res->parts[n]; |
595 | 0 | struct sub_bitmap *b = &priv->prevret[n]; |
596 | |
|
597 | 0 | if (a->x != b->x || a->y != b->y || |
598 | 0 | a->dw != b->dw || a->dh != b->dh) |
599 | 0 | { |
600 | 0 | res->change_id++; |
601 | 0 | break; |
602 | 0 | } |
603 | 0 | } |
604 | 0 | } |
605 | | |
606 | 0 | priv->prevret_num = res->num_parts; |
607 | 0 | MP_TARRAY_GROW(priv, priv->prevret, priv->prevret_num); |
608 | 0 | memcpy(priv->prevret, res->parts, res->num_parts * sizeof(priv->prevret[0])); |
609 | |
|
610 | 0 | return sub_bitmaps_copy(NULL, res); |
611 | 0 | } |
612 | | |
613 | | static struct sd_times get_times(struct sd *sd, double pts) |
614 | 0 | { |
615 | 0 | struct sd_lavc_priv *priv = sd->priv; |
616 | 0 | struct sd_times res = { .start = MP_NOPTS_VALUE, .end = MP_NOPTS_VALUE }; |
617 | |
|
618 | 0 | if (pts == MP_NOPTS_VALUE) |
619 | 0 | return res; |
620 | | |
621 | 0 | struct sub *current = get_current(priv, pts); |
622 | |
|
623 | 0 | if (!current) |
624 | 0 | return res; |
625 | | |
626 | 0 | res.start = current->pts; |
627 | 0 | res.end = current->endpts; |
628 | |
|
629 | 0 | return res; |
630 | 0 | } |
631 | | |
632 | | static bool accepts_packet(struct sd *sd, double min_pts) |
633 | 4.49k | { |
634 | 4.49k | struct sd_lavc_priv *priv = sd->priv; |
635 | | |
636 | 4.49k | double pts = priv->current_pts; |
637 | 4.49k | if (min_pts != MP_NOPTS_VALUE) { |
638 | | // guard against bogus rendering PTS in the future. |
639 | 3.55k | if (pts == MP_NOPTS_VALUE || min_pts < pts) |
640 | 3.55k | pts = min_pts; |
641 | | // Heuristic: we assume rendering cannot lag behind more than 1 second |
642 | | // behind decoding. |
643 | 3.55k | if (pts + 1 < min_pts) |
644 | 0 | pts = min_pts; |
645 | 3.55k | } |
646 | | |
647 | 4.49k | int last_needed = -1; |
648 | 22.4k | for (int n = 0; n < MAX_QUEUE; n++) { |
649 | 17.9k | struct sub *sub = &priv->subs[n]; |
650 | 17.9k | if (!sub->valid) |
651 | 17.9k | continue; |
652 | 0 | if (pts == MP_NOPTS_VALUE || |
653 | 0 | ((sub->pts == MP_NOPTS_VALUE || sub->pts >= pts) || |
654 | 0 | (sub->endpts == MP_NOPTS_VALUE || pts < sub->endpts))) |
655 | 0 | { |
656 | 0 | last_needed = n; |
657 | 0 | } |
658 | 0 | } |
659 | | // We can accept a packet if it wouldn't overflow the fixed subtitle queue. |
660 | | // We assume that get_bitmaps() never decreases the PTS. |
661 | 4.49k | return last_needed + 1 < MAX_QUEUE; |
662 | 4.49k | } |
663 | | |
664 | | static void reset(struct sd *sd) |
665 | 521 | { |
666 | 521 | struct sd_lavc_priv *priv = sd->priv; |
667 | | |
668 | 2.60k | for (int n = 0; n < MAX_QUEUE; n++) |
669 | 2.08k | clear_sub(&priv->subs[n]); |
670 | | // lavc might not do this right for all codecs; may need close+reopen |
671 | 521 | avcodec_flush_buffers(priv->avctx); |
672 | | |
673 | 521 | priv->current_pts = MP_NOPTS_VALUE; |
674 | 521 | } |
675 | | |
676 | | static void uninit(struct sd *sd) |
677 | 259 | { |
678 | 259 | struct sd_lavc_priv *priv = sd->priv; |
679 | | |
680 | 1.29k | for (int n = 0; n < MAX_QUEUE; n++) |
681 | 1.03k | clear_sub(&priv->subs[n]); |
682 | 259 | avcodec_free_context(&priv->avctx); |
683 | 259 | mp_free_av_packet(&priv->avpkt); |
684 | 259 | talloc_free(priv); |
685 | 259 | } |
686 | | |
687 | | static int compare_seekpoint(const void *pa, const void *pb) |
688 | 0 | { |
689 | 0 | const struct seekpoint *a = pa, *b = pb; |
690 | 0 | return a->pts == b->pts ? 0 : (a->pts < b->pts ? -1 : +1); |
691 | 0 | } |
692 | | |
693 | | // taken from ass_step_sub(), libass (ISC) |
694 | | static double step_sub(struct sd *sd, double now, int movement) |
695 | 0 | { |
696 | 0 | struct sd_lavc_priv *priv = sd->priv; |
697 | 0 | int best = -1; |
698 | 0 | double target = now; |
699 | 0 | int direction = (movement > 0 ? 1 : -1) * !!movement; |
700 | |
|
701 | 0 | if (priv->num_seekpoints == 0) |
702 | 0 | return MP_NOPTS_VALUE; |
703 | | |
704 | 0 | qsort(priv->seekpoints, priv->num_seekpoints, sizeof(priv->seekpoints[0]), |
705 | 0 | compare_seekpoint); |
706 | |
|
707 | 0 | do { |
708 | 0 | int closest = -1; |
709 | 0 | double closest_time = 0; |
710 | 0 | for (int i = 0; i < priv->num_seekpoints; i++) { |
711 | 0 | struct seekpoint *p = &priv->seekpoints[i]; |
712 | 0 | double start = p->pts; |
713 | 0 | if (direction < 0) { |
714 | 0 | double end = p->endpts == MP_NOPTS_VALUE ? INFINITY : p->endpts; |
715 | 0 | if (end < target) { |
716 | 0 | if (closest < 0 || end > closest_time) { |
717 | 0 | closest = i; |
718 | 0 | closest_time = end; |
719 | 0 | } |
720 | 0 | } |
721 | 0 | } else if (direction > 0) { |
722 | 0 | if (start > target) { |
723 | 0 | if (closest < 0 || start < closest_time) { |
724 | 0 | closest = i; |
725 | 0 | closest_time = start; |
726 | 0 | } |
727 | 0 | } |
728 | 0 | } else { |
729 | 0 | if (start < target) { |
730 | 0 | if (closest < 0 || start >= closest_time) { |
731 | 0 | closest = i; |
732 | 0 | closest_time = start; |
733 | 0 | } |
734 | 0 | } |
735 | 0 | } |
736 | 0 | } |
737 | 0 | if (closest < 0) |
738 | 0 | break; |
739 | 0 | target = closest_time + direction; |
740 | 0 | best = closest; |
741 | 0 | movement -= direction; |
742 | 0 | } while (movement); |
743 | |
|
744 | 0 | return best < 0 ? now : priv->seekpoints[best].pts; |
745 | 0 | } |
746 | | |
747 | | static int control(struct sd *sd, enum sd_ctrl cmd, void *arg) |
748 | 8.06k | { |
749 | 8.06k | struct sd_lavc_priv *priv = sd->priv; |
750 | 8.06k | switch (cmd) { |
751 | 0 | case SD_CTRL_SUB_STEP: { |
752 | 0 | double *a = arg; |
753 | 0 | double res = step_sub(sd, a[0], a[1]); |
754 | 0 | if (res == MP_NOPTS_VALUE) |
755 | 0 | return false; |
756 | 0 | a[0] = res; |
757 | 0 | return true; |
758 | 0 | } |
759 | 3.61k | case SD_CTRL_SET_VIDEO_PARAMS: |
760 | 3.61k | priv->video_params = *(struct mp_image_params *)arg; |
761 | 3.61k | return CONTROL_OK; |
762 | 0 | case SD_CTRL_APPLY_DVDNAV: { |
763 | 0 | const struct stream_nav_state *nav = arg; |
764 | 0 | bool menu_closed = priv->menu_active && !nav->menu_active; |
765 | 0 | bool changed = priv->hli_change_id != nav->change_id; |
766 | 0 | priv->menu_active = nav->menu_active; |
767 | 0 | priv->hl = nav->hl; |
768 | 0 | priv->hli_change_id = nav->change_id; |
769 | | // Don't let menu subpictures leak into title playback. |
770 | 0 | if (menu_closed) { |
771 | 0 | for (int n = 0; n < MAX_QUEUE; n++) |
772 | 0 | clear_sub(&priv->subs[n]); |
773 | 0 | } |
774 | | // Re-render any decoded subtitles, after style update. |
775 | 0 | if (changed) |
776 | 0 | rerender_queued_subs(sd); |
777 | 0 | return CONTROL_OK; |
778 | 0 | } |
779 | 4.44k | default: |
780 | 4.44k | return CONTROL_UNKNOWN; |
781 | 8.06k | } |
782 | 8.06k | } |
783 | | |
784 | | const struct sd_functions sd_lavc = { |
785 | | .name = "lavc", |
786 | | .init = init, |
787 | | .decode = decode, |
788 | | .get_bitmaps = get_bitmaps, |
789 | | .get_times = get_times, |
790 | | .accepts_packet = accepts_packet, |
791 | | .control = control, |
792 | | .reset = reset, |
793 | | .uninit = uninit, |
794 | | }; |