Coverage Report

Created: 2026-11-11 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/sub/sd_lavc.c
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
};