Coverage Report

Created: 2026-01-16 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/dvdsubdec.c
Line
Count
Source
1
/*
2
 * DVD subtitle decoding
3
 * Copyright (c) 2005 Fabrice Bellard
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include "avcodec.h"
23
#include "codec_internal.h"
24
#include "decode.h"
25
#include "dvdsub.h"
26
#include "get_bits.h"
27
28
#include "libavutil/attributes.h"
29
#include "libavutil/colorspace.h"
30
#include "libavutil/file_open.h"
31
#include "libavutil/mem.h"
32
#include "libavutil/opt.h"
33
#include "libavutil/bswap.h"
34
35
typedef struct DVDSubContext
36
{
37
  AVClass *class;
38
  uint32_t palette[16];
39
  char    *palette_str;
40
  char    *ifo_str;
41
  int      has_palette;
42
  uint8_t  colormap[4];
43
  uint8_t  alpha[256];
44
  uint8_t  buf[0x10000];
45
  int      buf_size;
46
  int      forced_subs_only;
47
  uint8_t  used_color[256];
48
} DVDSubContext;
49
50
static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
51
3.76k
{
52
3.76k
    const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
53
3.76k
    uint8_t r, g, b;
54
3.76k
    int i, y, cb, cr;
55
3.76k
    int r_add, g_add, b_add;
56
57
968k
    for (i = num_values; i > 0; i--) {
58
964k
        y = *ycbcr++;
59
964k
        cr = *ycbcr++;
60
964k
        cb = *ycbcr++;
61
964k
        YUV_TO_RGB1_CCIR(cb, cr);
62
964k
        YUV_TO_RGB2_CCIR(r, g, b, y);
63
964k
        *rgba++ = ((unsigned)*alpha++ << 24) | (r << 16) | (g << 8) | b;
64
964k
    }
65
3.76k
}
66
67
static int decode_run_2bit(GetBitContext *gb, int *color)
68
1.19M
{
69
1.19M
    unsigned int v, t;
70
71
1.19M
    v = 0;
72
3.34M
    for (t = 1; v < t && t <= 0x40; t <<= 2)
73
2.14M
        v = (v << 4) | get_bits(gb, 4);
74
1.19M
    *color = v & 3;
75
1.19M
    if (v < 4) { /* Code for fill rest of line */
76
165k
        return INT_MAX;
77
165k
    }
78
1.03M
    return v >> 2;
79
1.19M
}
80
81
static int decode_run_8bit(GetBitContext *gb, int *color)
82
10.4M
{
83
10.4M
    int len;
84
10.4M
    int has_run = get_bits1(gb);
85
10.4M
    *color = get_bits(gb, 2 + 6*get_bits1(gb));
86
10.4M
    if (has_run) {
87
1.95M
        if (get_bits1(gb)) {
88
236k
            len = get_bits(gb, 7);
89
236k
            if (len == 0)
90
49.5k
                len = INT_MAX;
91
186k
            else
92
186k
                len += 9;
93
236k
        } else
94
1.71M
            len = get_bits(gb, 3) + 2;
95
1.95M
    } else
96
8.52M
        len = 1;
97
10.4M
    return len;
98
10.4M
}
99
100
static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, uint8_t used_color[256],
101
                      const uint8_t *buf, int start, int buf_size, int is_8bit)
102
20.8k
{
103
20.8k
    GetBitContext gb;
104
20.8k
    int bit_len;
105
20.8k
    int x, y, len, color;
106
20.8k
    uint8_t *d;
107
108
20.8k
    if (start >= buf_size)
109
0
        return -1;
110
111
20.8k
    if (w <= 0 || h <= 0)
112
0
        return -1;
113
114
20.8k
    bit_len = (buf_size - start) * 8;
115
20.8k
    init_get_bits(&gb, buf + start, bit_len);
116
117
20.8k
    x = 0;
118
20.8k
    y = 0;
119
20.8k
    d = bitmap;
120
11.6M
    for(;;) {
121
11.6M
        if (get_bits_count(&gb) > bit_len)
122
823
            return -1;
123
11.6M
        if (is_8bit)
124
10.4M
            len = decode_run_8bit(&gb, &color);
125
1.19M
        else
126
1.19M
            len = decode_run_2bit(&gb, &color);
127
11.6M
        if (len != INT_MAX && len > w - x)
128
440
            return AVERROR_INVALIDDATA;
129
11.6M
        len = FFMIN(len, w - x);
130
11.6M
        memset(d + x, color, len);
131
11.6M
        used_color[color] = 1;
132
11.6M
        x += len;
133
11.6M
        if (x >= w) {
134
217k
            y++;
135
217k
            if (y >= h)
136
19.6k
                break;
137
197k
            d += linesize;
138
197k
            x = 0;
139
            /* byte align */
140
197k
            align_get_bits(&gb);
141
197k
        }
142
11.6M
    }
143
19.6k
    return 0;
144
20.8k
}
145
146
static void guess_palette(DVDSubContext* ctx,
147
                          uint32_t *rgba_palette,
148
                          uint32_t subtitle_color)
149
5.64k
{
150
5.64k
    static const uint8_t level_map[4][4] = {
151
        // this configuration (full range, lowest to highest) in tests
152
        // seemed most common, so assume this
153
5.64k
        {0xff},
154
5.64k
        {0x00, 0xff},
155
5.64k
        {0x00, 0x80, 0xff},
156
5.64k
        {0x00, 0x55, 0xaa, 0xff},
157
5.64k
    };
158
5.64k
    uint8_t color_used[16] = { 0 };
159
5.64k
    int nb_opaque_colors, i, level, j, r, g, b;
160
5.64k
    uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
161
162
5.64k
    if(ctx->has_palette) {
163
3.10k
        for(i = 0; i < 4; i++)
164
2.48k
            rgba_palette[i] = (ctx->palette[colormap[i]] & 0x00ffffff)
165
2.48k
                              | ((alpha[i] * 17U) << 24);
166
621
        return;
167
621
    }
168
169
25.1k
    for(i = 0; i < 4; i++)
170
20.0k
        rgba_palette[i] = 0;
171
172
5.02k
    nb_opaque_colors = 0;
173
25.1k
    for(i = 0; i < 4; i++) {
174
20.0k
        if (alpha[i] != 0 && !color_used[colormap[i]]) {
175
3.69k
            color_used[colormap[i]] = 1;
176
3.69k
            nb_opaque_colors++;
177
3.69k
        }
178
20.0k
    }
179
180
5.02k
    if (nb_opaque_colors == 0)
181
2.84k
        return;
182
183
2.17k
    j = 0;
184
2.17k
    memset(color_used, 0, 16);
185
10.8k
    for(i = 0; i < 4; i++) {
186
8.70k
        if (alpha[i] != 0) {
187
5.35k
            if (!color_used[colormap[i]])  {
188
3.69k
                level = level_map[nb_opaque_colors - 1][j];
189
3.69k
                r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
190
3.69k
                g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
191
3.69k
                b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
192
3.69k
                rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17U) << 24);
193
3.69k
                color_used[colormap[i]] = (i + 1);
194
3.69k
                j++;
195
3.69k
            } else {
196
1.65k
                rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) |
197
1.65k
                                    ((alpha[i] * 17U) << 24);
198
1.65k
            }
199
5.35k
        }
200
8.70k
    }
201
2.17k
}
202
203
static void reset_rects(AVSubtitle *sub_header)
204
88.6k
{
205
88.6k
    int i;
206
207
88.6k
    if (sub_header->rects) {
208
18.4k
        for (i = 0; i < sub_header->num_rects; i++) {
209
9.24k
            av_freep(&sub_header->rects[i]->data[0]);
210
9.24k
            av_freep(&sub_header->rects[i]->data[1]);
211
9.24k
            av_freep(&sub_header->rects[i]);
212
9.24k
        }
213
9.24k
        av_freep(&sub_header->rects);
214
9.24k
        sub_header->num_rects = 0;
215
9.24k
    }
216
88.6k
}
217
218
64.1k
#define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
219
220
static int decode_dvd_subtitles(void *logctx, DVDSubContext *ctx,
221
                                AVSubtitle *sub_header, const uint8_t *buf, int buf_size)
222
82.4k
{
223
82.4k
    int cmd_pos, pos, cmd, x1, y1, x2, y2, next_cmd_pos;
224
82.4k
    int big_offsets, offset_size, is_8bit = 0;
225
82.4k
    const uint8_t *yuv_palette = NULL;
226
82.4k
    uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
227
82.4k
    int date;
228
82.4k
    int i;
229
82.4k
    int is_menu = 0;
230
82.4k
    uint32_t size;
231
82.4k
    int64_t offset1, offset2;
232
233
82.4k
    if (buf_size < 10)
234
58.4k
        return -1;
235
236
24.0k
    if (AV_RB16(buf) == 0) {   /* HD subpicture with 4-byte offsets */
237
8.80k
        big_offsets = 1;
238
8.80k
        offset_size = 4;
239
8.80k
        cmd_pos = 6;
240
15.2k
    } else {
241
15.2k
        big_offsets = 0;
242
15.2k
        offset_size = 2;
243
15.2k
        cmd_pos = 2;
244
15.2k
    }
245
246
24.0k
    size = READ_OFFSET(buf + (big_offsets ? 2 : 0));
247
24.0k
    cmd_pos = READ_OFFSET(buf + cmd_pos);
248
249
24.0k
    if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size) {
250
9.55k
        if (cmd_pos > size) {
251
1.07k
            av_log(logctx, AV_LOG_ERROR, "Discarding invalid packet\n");
252
1.07k
            return 0;
253
1.07k
        }
254
8.47k
        return AVERROR(EAGAIN);
255
9.55k
    }
256
257
24.7k
    while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) {
258
16.1k
        date = AV_RB16(buf + cmd_pos);
259
16.1k
        next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2);
260
16.1k
        ff_dlog(logctx, "cmd_pos=0x%04x next=0x%04x date=%d\n",
261
16.1k
                cmd_pos, next_cmd_pos, date);
262
16.1k
        pos = cmd_pos + 2 + offset_size;
263
16.1k
        offset1 = -1;
264
16.1k
        offset2 = -1;
265
16.1k
        x1 = y1 = x2 = y2 = 0;
266
111k
        while (pos < buf_size) {
267
109k
            cmd = buf[pos++];
268
109k
            ff_dlog(logctx, "cmd=%02x\n", cmd);
269
109k
            switch(cmd) {
270
36.6k
            case 0x00:
271
                /* menu subpicture */
272
36.6k
                is_menu = 1;
273
36.6k
                break;
274
6.83k
            case 0x01:
275
                /* set start date */
276
6.83k
                sub_header->start_display_time = (date << 10) / 90;
277
6.83k
                break;
278
5.27k
            case 0x02:
279
                /* set end date */
280
5.27k
                sub_header->end_display_time = (date << 10) / 90;
281
5.27k
                break;
282
2.17k
            case 0x03:
283
                /* set colormap */
284
2.17k
                if ((buf_size - pos) < 2)
285
201
                    goto fail;
286
1.97k
                colormap[3] = buf[pos] >> 4;
287
1.97k
                colormap[2] = buf[pos] & 0x0f;
288
1.97k
                colormap[1] = buf[pos + 1] >> 4;
289
1.97k
                colormap[0] = buf[pos + 1] & 0x0f;
290
1.97k
                pos += 2;
291
1.97k
                break;
292
2.84k
            case 0x04:
293
                /* set alpha */
294
2.84k
                if ((buf_size - pos) < 2)
295
196
                    goto fail;
296
2.64k
                alpha[3] = buf[pos] >> 4;
297
2.64k
                alpha[2] = buf[pos] & 0x0f;
298
2.64k
                alpha[1] = buf[pos + 1] >> 4;
299
2.64k
                alpha[0] = buf[pos + 1] & 0x0f;
300
2.64k
                pos += 2;
301
2.64k
                ff_dlog(logctx, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
302
2.64k
                break;
303
12.5k
            case 0x05:
304
17.4k
            case 0x85:
305
17.4k
                if ((buf_size - pos) < 6)
306
221
                    goto fail;
307
17.1k
                x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4);
308
17.1k
                x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2];
309
17.1k
                y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4);
310
17.1k
                y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5];
311
17.1k
                if (cmd & 0x80)
312
4.81k
                    is_8bit = 1;
313
17.1k
                ff_dlog(logctx, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2);
314
17.1k
                pos += 6;
315
17.1k
                break;
316
15.4k
            case 0x06:
317
15.4k
                if ((buf_size - pos) < 4)
318
200
                    goto fail;
319
15.2k
                offset1 = AV_RB16(buf + pos);
320
15.2k
                offset2 = AV_RB16(buf + pos + 2);
321
15.2k
                ff_dlog(logctx, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2);
322
15.2k
                pos += 4;
323
15.2k
                break;
324
4.11k
            case 0x86:
325
4.11k
                if ((buf_size - pos) < 8)
326
198
                    goto fail;
327
3.91k
                offset1 = AV_RB32(buf + pos);
328
3.91k
                offset2 = AV_RB32(buf + pos + 4);
329
3.91k
                ff_dlog(logctx, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2);
330
3.91k
                pos += 8;
331
3.91k
                break;
332
333
4.01k
            case 0x83:
334
                /* HD set palette */
335
4.01k
                if ((buf_size - pos) < 768)
336
220
                    goto fail;
337
3.79k
                yuv_palette = buf + pos;
338
3.79k
                pos += 768;
339
3.79k
                break;
340
2.34k
            case 0x84:
341
                /* HD set contrast (alpha) */
342
2.34k
                if ((buf_size - pos) < 256)
343
202
                    goto fail;
344
549k
                for (i = 0; i < 256; i++)
345
547k
                    alpha[i] = 0xFF - buf[pos+i];
346
2.14k
                pos += 256;
347
2.14k
                break;
348
349
949
            case 0xff:
350
949
                goto the_end;
351
11.0k
            default:
352
11.0k
                ff_dlog(logctx, "unrecognised subpicture command 0x%x\n", cmd);
353
11.0k
                goto the_end;
354
109k
            }
355
109k
        }
356
14.6k
    the_end:
357
14.6k
        if (offset1 >= buf_size || offset2 >= buf_size)
358
565
            goto fail;
359
360
14.1k
        if (offset1 >= 0 && offset2 >= 0) {
361
11.7k
            int w, h;
362
11.7k
            uint8_t *bitmap;
363
364
            /* decode the bitmap */
365
11.7k
            w = x2 - x1 + 1;
366
11.7k
            if (w < 0)
367
253
                w = 0;
368
11.7k
            h = y2 - y1 + 1;
369
11.7k
            if (h < 0)
370
371
                h = 0;
371
11.7k
            if (w > 0 && h > 1) {
372
10.9k
                reset_rects(sub_header);
373
10.9k
                memset(ctx->used_color, 0, sizeof(ctx->used_color));
374
10.9k
                sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
375
10.9k
                if (!sub_header->rects)
376
0
                    goto fail;
377
10.9k
                sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect));
378
10.9k
                if (!sub_header->rects[0])
379
0
                    goto fail;
380
10.9k
                sub_header->num_rects = 1;
381
10.9k
                bitmap = sub_header->rects[0]->data[0] = av_malloc(w * h);
382
10.9k
                if (!bitmap)
383
0
                    goto fail;
384
10.9k
                if (decode_rle(bitmap, w * 2, w, (h + 1) / 2, ctx->used_color,
385
10.9k
                               buf, offset1, buf_size, is_8bit) < 0)
386
913
                    goto fail;
387
9.98k
                if (decode_rle(bitmap + w, w * 2, w, h / 2, ctx->used_color,
388
9.98k
                               buf, offset2, buf_size, is_8bit) < 0)
389
350
                    goto fail;
390
9.63k
                sub_header->rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE);
391
9.63k
                if (!sub_header->rects[0]->data[1])
392
0
                    goto fail;
393
9.63k
                if (is_8bit) {
394
3.99k
                    if (!yuv_palette)
395
227
                        goto fail;
396
3.76k
                    sub_header->rects[0]->nb_colors = 256;
397
3.76k
                    yuv_a_to_rgba(yuv_palette, alpha,
398
3.76k
                                  (uint32_t *)sub_header->rects[0]->data[1],
399
3.76k
                                  256);
400
5.64k
                } else {
401
5.64k
                    sub_header->rects[0]->nb_colors = 4;
402
5.64k
                    guess_palette(ctx, (uint32_t*)sub_header->rects[0]->data[1],
403
5.64k
                                  0xffffff);
404
5.64k
                }
405
9.41k
                sub_header->rects[0]->x = x1;
406
9.41k
                sub_header->rects[0]->y = y1;
407
9.41k
                sub_header->rects[0]->w = w;
408
9.41k
                sub_header->rects[0]->h = h;
409
9.41k
                sub_header->rects[0]->type = SUBTITLE_BITMAP;
410
9.41k
                sub_header->rects[0]->linesize[0] = w;
411
9.41k
                sub_header->rects[0]->flags = is_menu ? AV_SUBTITLE_FLAG_FORCED : 0;
412
9.41k
            }
413
11.7k
        }
414
12.6k
        if (next_cmd_pos < cmd_pos) {
415
2.08k
            av_log(logctx, AV_LOG_ERROR, "Invalid command offset\n");
416
2.08k
            break;
417
2.08k
        }
418
10.5k
        if (next_cmd_pos == cmd_pos)
419
214
            break;
420
10.3k
        cmd_pos = next_cmd_pos;
421
10.3k
    }
422
10.9k
    if (sub_header->num_rects > 0)
423
9.10k
        return is_menu;
424
5.37k
 fail:
425
5.37k
    reset_rects(sub_header);
426
5.37k
    return -1;
427
10.9k
}
428
429
static int is_transp(const uint8_t *buf, int pitch, int n,
430
                     const uint8_t *transp_color)
431
587k
{
432
587k
    int i;
433
37.2M
    for(i = 0; i < n; i++) {
434
36.6M
        if (!transp_color[*buf])
435
3.36k
            return 0;
436
36.6M
        buf += pitch;
437
36.6M
    }
438
584k
    return 1;
439
587k
}
440
441
/* return 0 if empty rectangle, 1 if non empty */
442
static int find_smallest_bounding_rectangle(DVDSubContext *ctx, AVSubtitle *s)
443
9.67k
{
444
9.67k
    uint8_t transp_color[256] = { 0 };
445
9.67k
    int y1, y2, x1, x2, y, w, h, i;
446
9.67k
    uint8_t *bitmap;
447
9.67k
    int transparent = 1;
448
449
9.67k
    if (s->num_rects == 0 || !s->rects || s->rects[0]->w <= 0 || s->rects[0]->h <= 0)
450
1.07k
        return 0;
451
452
989k
    for(i = 0; i < s->rects[0]->nb_colors; i++) {
453
980k
        if ((((uint32_t *)s->rects[0]->data[1])[i] >> 24) == 0) {
454
976k
            transp_color[i] = 1;
455
976k
        } else if (ctx->used_color[i])
456
2.04k
            transparent = 0;
457
980k
    }
458
8.60k
    if (transparent)
459
7.44k
        return 0;
460
1.15k
    y1 = 0;
461
4.51k
    while (y1 < s->rects[0]->h && is_transp(s->rects[0]->data[0] + y1 * s->rects[0]->linesize[0],
462
4.51k
                                  1, s->rects[0]->w, transp_color))
463
3.35k
        y1++;
464
1.15k
    if (y1 == s->rects[0]->h) {
465
0
        av_freep(&s->rects[0]->data[0]);
466
0
        s->rects[0]->w = s->rects[0]->h = 0;
467
0
        return 0;
468
0
    }
469
470
1.15k
    y2 = s->rects[0]->h - 1;
471
3.19k
    while (y2 > 0 && is_transp(s->rects[0]->data[0] + y2 * s->rects[0]->linesize[0], 1,
472
2.79k
                               s->rects[0]->w, transp_color))
473
2.04k
        y2--;
474
1.15k
    x1 = 0;
475
2.32k
    while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->data[0] + x1, s->rects[0]->linesize[0],
476
1.95k
                                        s->rects[0]->h, transp_color))
477
1.16k
        x1++;
478
1.15k
    x2 = s->rects[0]->w - 1;
479
578k
    while (x2 > 0 && is_transp(s->rects[0]->data[0] + x2, s->rects[0]->linesize[0], s->rects[0]->h,
480
578k
                                  transp_color))
481
577k
        x2--;
482
1.15k
    w = x2 - x1 + 1;
483
1.15k
    h = y2 - y1 + 1;
484
1.15k
    bitmap = av_malloc(w * h);
485
1.15k
    if (!bitmap)
486
0
        return 1;
487
28.3k
    for(y = 0; y < h; y++) {
488
27.1k
        memcpy(bitmap + w * y, s->rects[0]->data[0] + x1 + (y1 + y) * s->rects[0]->linesize[0], w);
489
27.1k
    }
490
1.15k
    av_freep(&s->rects[0]->data[0]);
491
1.15k
    s->rects[0]->data[0] = bitmap;
492
1.15k
    s->rects[0]->linesize[0] = w;
493
1.15k
    s->rects[0]->w = w;
494
1.15k
    s->rects[0]->h = h;
495
1.15k
    s->rects[0]->x += x1;
496
1.15k
    s->rects[0]->y += y1;
497
498
1.15k
    return 1;
499
1.15k
}
500
501
static int append_to_cached_buf(AVCodecContext *avctx,
502
                                const uint8_t *buf, int buf_size)
503
16.2k
{
504
16.2k
    DVDSubContext *ctx = avctx->priv_data;
505
506
16.2k
    av_assert0(buf_size >= 0 && ctx->buf_size <= sizeof(ctx->buf));
507
16.2k
    if (buf_size >= sizeof(ctx->buf) - ctx->buf_size) {
508
66
        av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct "
509
66
               "too large SPU packets aborted.\n");
510
66
        ctx->buf_size = 0;
511
66
        return AVERROR_INVALIDDATA;
512
66
    }
513
16.1k
    memcpy(ctx->buf + ctx->buf_size, buf, buf_size);
514
16.1k
    ctx->buf_size += buf_size;
515
16.1k
    return 0;
516
16.2k
}
517
518
static int dvdsub_decode(AVCodecContext *avctx, AVSubtitle *sub,
519
                         int *data_size, const AVPacket *avpkt)
520
82.5k
{
521
82.5k
    DVDSubContext *ctx = avctx->priv_data;
522
82.5k
    const uint8_t *buf = avpkt->data;
523
82.5k
    int buf_size = avpkt->size;
524
82.5k
    int appended = 0;
525
82.5k
    int is_menu;
526
527
82.5k
    if (ctx->buf_size) {
528
14.8k
        int ret = append_to_cached_buf(avctx, buf, buf_size);
529
14.8k
        if (ret < 0) {
530
35
            *data_size = 0;
531
35
            return ret;
532
35
        }
533
14.8k
        buf = ctx->buf;
534
14.8k
        buf_size = ctx->buf_size;
535
14.8k
        appended = 1;
536
14.8k
    }
537
538
82.4k
    is_menu = decode_dvd_subtitles(avctx, ctx, sub, buf, buf_size);
539
82.4k
    if (is_menu == AVERROR(EAGAIN)) {
540
8.47k
        *data_size = 0;
541
8.47k
        return appended ? 0 : append_to_cached_buf(avctx, buf, buf_size);
542
8.47k
    }
543
544
73.9k
    if (is_menu < 0) {
545
63.8k
        ctx->buf_size = 0;
546
72.3k
    no_subtitle:
547
72.3k
        reset_rects(sub);
548
72.3k
        *data_size = 0;
549
550
72.3k
        return buf_size;
551
63.8k
    }
552
10.1k
    if (!is_menu && find_smallest_bounding_rectangle(ctx, sub) == 0)
553
8.51k
        goto no_subtitle;
554
555
1.65k
    if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED))
556
0
        goto no_subtitle;
557
558
1.65k
    ctx->buf_size = 0;
559
1.65k
    *data_size = 1;
560
1.65k
    return buf_size;
561
1.65k
}
562
563
static int parse_ifo_palette(void *logctx, DVDSubContext *ctx, char *p)
564
0
{
565
0
    FILE *ifo;
566
0
    char ifostr[12];
567
0
    uint32_t sp_pgci, pgci, off_pgc, pgc;
568
0
    uint8_t r, g, b, yuv[65], *buf;
569
0
    int i, y, cb, cr, r_add, g_add, b_add;
570
0
    int ret = 0;
571
0
    const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
572
573
0
    ctx->has_palette = 0;
574
0
    if ((ifo = avpriv_fopen_utf8(p, "r")) == NULL) {
575
0
        av_log(logctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno)));
576
0
        return AVERROR_EOF;
577
0
    }
578
0
    if (fread(ifostr, 12, 1, ifo) != 1 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) {
579
0
        av_log(logctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p);
580
0
        ret = AVERROR_INVALIDDATA;
581
0
        goto end;
582
0
    }
583
0
    if (fseek(ifo, 0xCC, SEEK_SET) == -1) {
584
0
        ret = AVERROR(errno);
585
0
        goto end;
586
0
    }
587
0
    if (fread(&sp_pgci, 4, 1, ifo) == 1) {
588
0
        pgci = av_be2ne32(sp_pgci) * 2048;
589
0
        if (fseek(ifo, pgci + 0x0C, SEEK_SET) == -1) {
590
0
            ret = AVERROR(errno);
591
0
            goto end;
592
0
        }
593
0
        if (fread(&off_pgc, 4, 1, ifo) == 1) {
594
0
            pgc = pgci + av_be2ne32(off_pgc);
595
0
            if (fseek(ifo, pgc + 0xA4, SEEK_SET) == -1) {
596
0
                ret = AVERROR(errno);
597
0
                goto end;
598
0
            }
599
0
            if (fread(yuv, 64, 1, ifo) == 1) {
600
0
                buf = yuv;
601
0
                for(i=0; i<16; i++) {
602
0
                    y  = *++buf;
603
0
                    cr = *++buf;
604
0
                    cb = *++buf;
605
0
                    YUV_TO_RGB1_CCIR(cb, cr);
606
0
                    YUV_TO_RGB2_CCIR(r, g, b, y);
607
0
                    ctx->palette[i] = (r << 16) + (g << 8) + b;
608
0
                    buf++;
609
0
                }
610
0
                ctx->has_palette = 1;
611
0
            }
612
0
        }
613
0
    }
614
0
    if (ctx->has_palette == 0) {
615
0
        av_log(logctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p);
616
0
        ret = AVERROR_INVALIDDATA;
617
0
    }
618
0
end:
619
0
    fclose(ifo);
620
0
    return ret;
621
0
}
622
623
static int dvdsub_parse_extradata(AVCodecContext *avctx)
624
2.08k
{
625
2.08k
    DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data;
626
2.08k
    char *dataorig, *data;
627
2.08k
    int ret;
628
629
2.08k
    if (!avctx->extradata || !avctx->extradata_size)
630
1.85k
        return 0;
631
632
235
    dataorig = data = av_malloc(avctx->extradata_size+1);
633
235
    if (!data)
634
0
        return AVERROR(ENOMEM);
635
235
    memcpy(data, avctx->extradata, avctx->extradata_size);
636
235
    data[avctx->extradata_size] = '\0';
637
638
2.76k
    for(;;) {
639
2.76k
        int pos = strcspn(data, "\n\r");
640
2.76k
        if (pos==0 && *data==0)
641
235
            break;
642
643
2.52k
        if (strncmp("palette:", data, 8) == 0) {
644
376
            ctx->has_palette = 1;
645
376
            ff_dvdsub_parse_palette(ctx->palette, data + 8);
646
2.15k
        } else if (strncmp("size:", data, 5) == 0) {
647
92
            int w, h;
648
92
            if (sscanf(data + 5, "%dx%d", &w, &h) == 2) {
649
0
               ret = ff_set_dimensions(avctx, w, h);
650
0
               if (ret < 0)
651
0
                   goto fail;
652
0
            }
653
92
        }
654
655
2.52k
        data += pos;
656
2.52k
        data += strspn(data, "\n\r");
657
2.52k
    }
658
659
235
    ret = 0;
660
235
fail:
661
235
    av_free(dataorig);
662
235
    return ret;
663
235
}
664
665
static av_cold int dvdsub_init(AVCodecContext *avctx)
666
2.08k
{
667
2.08k
    DVDSubContext *ctx = avctx->priv_data;
668
2.08k
    int ret;
669
670
2.08k
    if ((ret = dvdsub_parse_extradata(avctx)) < 0)
671
0
        return ret;
672
673
2.08k
    if (ctx->ifo_str)
674
0
        parse_ifo_palette(avctx, ctx, ctx->ifo_str);
675
2.08k
    if (ctx->palette_str) {
676
0
        ctx->has_palette = 1;
677
0
        ff_dvdsub_parse_palette(ctx->palette, ctx->palette_str);
678
0
    }
679
2.08k
    if (ctx->has_palette) {
680
120
        int i;
681
120
        av_log(avctx, AV_LOG_DEBUG, "palette:");
682
2.04k
        for(i=0;i<16;i++)
683
1.92k
            av_log(avctx, AV_LOG_DEBUG, " 0x%06"PRIx32, ctx->palette[i]);
684
120
        av_log(avctx, AV_LOG_DEBUG, "\n");
685
120
    }
686
687
2.08k
    return 0;
688
2.08k
}
689
690
static av_cold void dvdsub_flush(AVCodecContext *avctx)
691
31.2k
{
692
31.2k
    DVDSubContext *ctx = avctx->priv_data;
693
31.2k
    ctx->buf_size = 0;
694
31.2k
}
695
696
#define OFFSET(field) offsetof(DVDSubContext, field)
697
#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
698
static const AVOption options[] = {
699
    { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
700
    { "ifo_palette", "obtain the global palette from .IFO file", OFFSET(ifo_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
701
    { "forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, SD},
702
    { NULL }
703
};
704
static const AVClass dvdsub_class = {
705
    .class_name = "dvdsubdec",
706
    .item_name  = av_default_item_name,
707
    .option     = options,
708
    .version    = LIBAVUTIL_VERSION_INT,
709
};
710
711
const FFCodec ff_dvdsub_decoder = {
712
    .p.name         = "dvdsub",
713
    CODEC_LONG_NAME("DVD subtitles"),
714
    .p.type         = AVMEDIA_TYPE_SUBTITLE,
715
    .p.id           = AV_CODEC_ID_DVD_SUBTITLE,
716
    .priv_data_size = sizeof(DVDSubContext),
717
    .init           = dvdsub_init,
718
    FF_CODEC_DECODE_SUB_CB(dvdsub_decode),
719
    .flush          = dvdsub_flush,
720
    .p.priv_class   = &dvdsub_class,
721
};