Coverage Report

Created: 2025-06-24 07:38

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