GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/dvdsubdec.c Lines: 273 448 60.9 %
Date: 2019-11-20 04:07:19 Branches: 140 276 50.7 %

Line Branch Exec 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 "get_bits.h"
24
#include "internal.h"
25
26
#include "libavutil/attributes.h"
27
#include "libavutil/colorspace.h"
28
#include "libavutil/opt.h"
29
#include "libavutil/imgutils.h"
30
#include "libavutil/avstring.h"
31
#include "libavutil/bswap.h"
32
33
typedef struct DVDSubContext
34
{
35
  AVClass *class;
36
  uint32_t palette[16];
37
  char    *palette_str;
38
  char    *ifo_str;
39
  int      has_palette;
40
  uint8_t  colormap[4];
41
  uint8_t  alpha[256];
42
  uint8_t  buf[0x10000];
43
  int      buf_size;
44
  int      forced_subs_only;
45
  uint8_t  used_color[256];
46
#ifdef DEBUG
47
  int sub_id;
48
#endif
49
} DVDSubContext;
50
51
static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
52
{
53
    const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
54
    uint8_t r, g, b;
55
    int i, y, cb, cr;
56
    int r_add, g_add, b_add;
57
58
    for (i = num_values; i > 0; i--) {
59
        y = *ycbcr++;
60
        cr = *ycbcr++;
61
        cb = *ycbcr++;
62
        YUV_TO_RGB1_CCIR(cb, cr);
63
        YUV_TO_RGB2_CCIR(r, g, b, y);
64
        *rgba++ = ((unsigned)*alpha++ << 24) | (r << 16) | (g << 8) | b;
65
    }
66
}
67
68
149254
static int decode_run_2bit(GetBitContext *gb, int *color)
69
{
70
    unsigned int v, t;
71
72
149254
    v = 0;
73

398577
    for (t = 1; v < t && t <= 0x40; t <<= 2)
74
249323
        v = (v << 4) | get_bits(gb, 4);
75
149254
    *color = v & 3;
76
149254
    if (v < 4) { /* Code for fill rest of line */
77
21028
        return INT_MAX;
78
    }
79
128226
    return v >> 2;
80
}
81
82
static int decode_run_8bit(GetBitContext *gb, int *color)
83
{
84
    int len;
85
    int has_run = get_bits1(gb);
86
    *color = get_bits(gb, 2 + 6*get_bits1(gb));
87
    if (has_run) {
88
        if (get_bits1(gb)) {
89
            len = get_bits(gb, 7);
90
            if (len == 0)
91
                len = INT_MAX;
92
            else
93
                len += 9;
94
        } else
95
            len = get_bits(gb, 3) + 2;
96
    } else
97
        len = 1;
98
    return len;
99
}
100
101
88
static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, uint8_t used_color[256],
102
                      const uint8_t *buf, int start, int buf_size, int is_8bit)
103
{
104
    GetBitContext gb;
105
    int bit_len;
106
    int x, y, len, color;
107
    uint8_t *d;
108
109
88
    if (start >= buf_size)
110
        return -1;
111
112

88
    if (w <= 0 || h <= 0)
113
        return -1;
114
115
88
    bit_len = (buf_size - start) * 8;
116
88
    init_get_bits(&gb, buf + start, bit_len);
117
118
88
    x = 0;
119
88
    y = 0;
120
88
    d = bitmap;
121
    for(;;) {
122
149254
        if (get_bits_count(&gb) > bit_len)
123
            return -1;
124
149254
        if (is_8bit)
125
            len = decode_run_8bit(&gb, &color);
126
        else
127
149254
            len = decode_run_2bit(&gb, &color);
128

149254
        if (len != INT_MAX && len > w - x)
129
            return AVERROR_INVALIDDATA;
130
149254
        len = FFMIN(len, w - x);
131
149254
        memset(d + x, color, len);
132
149254
        used_color[color] = 1;
133
149254
        x += len;
134
149254
        if (x >= w) {
135
21028
            y++;
136
21028
            if (y >= h)
137
88
                break;
138
20940
            d += linesize;
139
20940
            x = 0;
140
            /* byte align */
141
20940
            align_get_bits(&gb);
142
        }
143
    }
144
88
    return 0;
145
}
146
147
44
static void guess_palette(DVDSubContext* ctx,
148
                          uint32_t *rgba_palette,
149
                          uint32_t subtitle_color)
150
{
151
    static const uint8_t level_map[4][4] = {
152
        // this configuration (full range, lowest to highest) in tests
153
        // seemed most common, so assume this
154
        {0xff},
155
        {0x00, 0xff},
156
        {0x00, 0x80, 0xff},
157
        {0x00, 0x55, 0xaa, 0xff},
158
    };
159
44
    uint8_t color_used[16] = { 0 };
160
    int nb_opaque_colors, i, level, j, r, g, b;
161
44
    uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
162
163
44
    if(ctx->has_palette) {
164
220
        for(i = 0; i < 4; i++)
165
176
            rgba_palette[i] = (ctx->palette[colormap[i]] & 0x00ffffff)
166
176
                              | ((alpha[i] * 17U) << 24);
167
44
        return;
168
    }
169
170
    for(i = 0; i < 4; i++)
171
        rgba_palette[i] = 0;
172
173
    nb_opaque_colors = 0;
174
    for(i = 0; i < 4; i++) {
175
        if (alpha[i] != 0 && !color_used[colormap[i]]) {
176
            color_used[colormap[i]] = 1;
177
            nb_opaque_colors++;
178
        }
179
    }
180
181
    if (nb_opaque_colors == 0)
182
        return;
183
184
    j = 0;
185
    memset(color_used, 0, 16);
186
    for(i = 0; i < 4; i++) {
187
        if (alpha[i] != 0) {
188
            if (!color_used[colormap[i]])  {
189
                level = level_map[nb_opaque_colors - 1][j];
190
                r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
191
                g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
192
                b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
193
                rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17U) << 24);
194
                color_used[colormap[i]] = (i + 1);
195
                j++;
196
            } else {
197
                rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) |
198
                                    ((alpha[i] * 17U) << 24);
199
            }
200
        }
201
    }
202
}
203
204
44
static void reset_rects(AVSubtitle *sub_header)
205
{
206
    int i;
207
208
44
    if (sub_header->rects) {
209
        for (i = 0; i < sub_header->num_rects; i++) {
210
            av_freep(&sub_header->rects[i]->data[0]);
211
            av_freep(&sub_header->rects[i]->data[1]);
212
            av_freep(&sub_header->rects[i]);
213
        }
214
        av_freep(&sub_header->rects);
215
        sub_header->num_rects = 0;
216
    }
217
44
}
218
219
#define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
220
221
47
static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
222
                                const uint8_t *buf, int buf_size)
223
{
224
    int cmd_pos, pos, cmd, x1, y1, x2, y2, next_cmd_pos;
225
47
    int big_offsets, offset_size, is_8bit = 0;
226
47
    const uint8_t *yuv_palette = NULL;
227
47
    uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
228
    int date;
229
    int i;
230
47
    int is_menu = 0;
231
    uint32_t size;
232
    int64_t offset1, offset2;
233
234
47
    if (buf_size < 10)
235
        return -1;
236
237
47
    if (AV_RB16(buf) == 0) {   /* HD subpicture with 4-byte offsets */
238
        big_offsets = 1;
239
        offset_size = 4;
240
        cmd_pos = 6;
241
    } else {
242
47
        big_offsets = 0;
243
47
        offset_size = 2;
244
47
        cmd_pos = 2;
245
    }
246
247

47
    size = READ_OFFSET(buf + (big_offsets ? 2 : 0));
248
47
    cmd_pos = READ_OFFSET(buf + cmd_pos);
249
250

47
    if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size) {
251
3
        if (cmd_pos > size) {
252
            av_log(ctx, AV_LOG_ERROR, "Discarding invalid packet\n");
253
            return 0;
254
        }
255
3
        return AVERROR(EAGAIN);
256
    }
257
258

87
    while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) {
259
87
        date = AV_RB16(buf + cmd_pos);
260
87
        next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2);
261
        ff_dlog(NULL, "cmd_pos=0x%04x next=0x%04x date=%d\n",
262
                cmd_pos, next_cmd_pos, date);
263
87
        pos = cmd_pos + 2 + offset_size;
264
87
        offset1 = -1;
265
87
        offset2 = -1;
266
87
        x1 = y1 = x2 = y2 = 0;
267
350
        while (pos < buf_size) {
268
350
            cmd = buf[pos++];
269
            ff_dlog(NULL, "cmd=%02x\n", cmd);
270



350
            switch(cmd) {
271
            case 0x00:
272
                /* menu subpicture */
273
                is_menu = 1;
274
                break;
275
44
            case 0x01:
276
                /* set start date */
277
44
                sub_header->start_display_time = (date << 10) / 90;
278
44
                break;
279
43
            case 0x02:
280
                /* set end date */
281
43
                sub_header->end_display_time = (date << 10) / 90;
282
43
                break;
283
44
            case 0x03:
284
                /* set colormap */
285
44
                if ((buf_size - pos) < 2)
286
                    goto fail;
287
44
                colormap[3] = buf[pos] >> 4;
288
44
                colormap[2] = buf[pos] & 0x0f;
289
44
                colormap[1] = buf[pos + 1] >> 4;
290
44
                colormap[0] = buf[pos + 1] & 0x0f;
291
44
                pos += 2;
292
44
                break;
293
44
            case 0x04:
294
                /* set alpha */
295
44
                if ((buf_size - pos) < 2)
296
                    goto fail;
297
44
                alpha[3] = buf[pos] >> 4;
298
44
                alpha[2] = buf[pos] & 0x0f;
299
44
                alpha[1] = buf[pos + 1] >> 4;
300
44
                alpha[0] = buf[pos + 1] & 0x0f;
301
44
                pos += 2;
302
                ff_dlog(NULL, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
303
44
                break;
304
44
            case 0x05:
305
            case 0x85:
306
44
                if ((buf_size - pos) < 6)
307
                    goto fail;
308
44
                x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4);
309
44
                x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2];
310
44
                y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4);
311
44
                y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5];
312
44
                if (cmd & 0x80)
313
                    is_8bit = 1;
314
                ff_dlog(NULL, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2);
315
44
                pos += 6;
316
44
                break;
317
44
            case 0x06:
318
44
                if ((buf_size - pos) < 4)
319
                    goto fail;
320
44
                offset1 = AV_RB16(buf + pos);
321
44
                offset2 = AV_RB16(buf + pos + 2);
322
                ff_dlog(NULL, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2);
323
44
                pos += 4;
324
44
                break;
325
            case 0x86:
326
                if ((buf_size - pos) < 8)
327
                    goto fail;
328
                offset1 = AV_RB32(buf + pos);
329
                offset2 = AV_RB32(buf + pos + 4);
330
                ff_dlog(NULL, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2);
331
                pos += 8;
332
                break;
333
334
            case 0x83:
335
                /* HD set palette */
336
                if ((buf_size - pos) < 768)
337
                    goto fail;
338
                yuv_palette = buf + pos;
339
                pos += 768;
340
                break;
341
            case 0x84:
342
                /* HD set contrast (alpha) */
343
                if ((buf_size - pos) < 256)
344
                    goto fail;
345
                for (i = 0; i < 256; i++)
346
                    alpha[i] = 0xFF - buf[pos+i];
347
                pos += 256;
348
                break;
349
350
87
            case 0xff:
351
87
                goto the_end;
352
            default:
353
                ff_dlog(NULL, "unrecognised subpicture command 0x%x\n", cmd);
354
                goto the_end;
355
            }
356
        }
357
    the_end:
358

87
        if (offset1 >= buf_size || offset2 >= buf_size)
359
            goto fail;
360
361

87
        if (offset1 >= 0 && offset2 >= 0) {
362
            int w, h;
363
            uint8_t *bitmap;
364
365
            /* decode the bitmap */
366
44
            w = x2 - x1 + 1;
367
44
            if (w < 0)
368
                w = 0;
369
44
            h = y2 - y1 + 1;
370
44
            if (h < 0)
371
                h = 0;
372

44
            if (w > 0 && h > 1) {
373
44
                reset_rects(sub_header);
374
44
                memset(ctx->used_color, 0, sizeof(ctx->used_color));
375
44
                sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
376
44
                if (!sub_header->rects)
377
                    goto fail;
378
44
                sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect));
379
44
                if (!sub_header->rects[0])
380
                    goto fail;
381
44
                sub_header->num_rects = 1;
382
44
                bitmap = sub_header->rects[0]->data[0] = av_malloc(w * h);
383
44
                if (!bitmap)
384
                    goto fail;
385
44
                if (decode_rle(bitmap, w * 2, w, (h + 1) / 2, ctx->used_color,
386
                               buf, offset1, buf_size, is_8bit) < 0)
387
                    goto fail;
388
44
                if (decode_rle(bitmap + w, w * 2, w, h / 2, ctx->used_color,
389
                               buf, offset2, buf_size, is_8bit) < 0)
390
                    goto fail;
391
44
                sub_header->rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE);
392
44
                if (!sub_header->rects[0]->data[1])
393
                    goto fail;
394
44
                if (is_8bit) {
395
                    if (!yuv_palette)
396
                        goto fail;
397
                    sub_header->rects[0]->nb_colors = 256;
398
                    yuv_a_to_rgba(yuv_palette, alpha,
399
                                  (uint32_t *)sub_header->rects[0]->data[1],
400
                                  256);
401
                } else {
402
44
                    sub_header->rects[0]->nb_colors = 4;
403
44
                    guess_palette(ctx, (uint32_t*)sub_header->rects[0]->data[1],
404
                                  0xffff00);
405
                }
406
44
                sub_header->rects[0]->x = x1;
407
44
                sub_header->rects[0]->y = y1;
408
44
                sub_header->rects[0]->w = w;
409
44
                sub_header->rects[0]->h = h;
410
44
                sub_header->rects[0]->type = SUBTITLE_BITMAP;
411
44
                sub_header->rects[0]->linesize[0] = w;
412
44
                sub_header->rects[0]->flags = is_menu ? AV_SUBTITLE_FLAG_FORCED : 0;
413
414
#if FF_API_AVPICTURE
415
FF_DISABLE_DEPRECATION_WARNINGS
416
220
                for (i = 0; i < 4; i++) {
417
176
                    sub_header->rects[0]->pict.data[i] = sub_header->rects[0]->data[i];
418
176
                    sub_header->rects[0]->pict.linesize[i] = sub_header->rects[0]->linesize[i];
419
                }
420
FF_ENABLE_DEPRECATION_WARNINGS
421
#endif
422
            }
423
        }
424
87
        if (next_cmd_pos < cmd_pos) {
425
            av_log(ctx, AV_LOG_ERROR, "Invalid command offset\n");
426
            break;
427
        }
428
87
        if (next_cmd_pos == cmd_pos)
429
44
            break;
430
43
        cmd_pos = next_cmd_pos;
431
    }
432
44
    if (sub_header->num_rects > 0)
433
44
        return is_menu;
434
 fail:
435
    reset_rects(sub_header);
436
    return -1;
437
}
438
439
38664
static int is_transp(const uint8_t *buf, int pitch, int n,
440
                     const uint8_t *transp_color)
441
{
442
    int i;
443
23192950
    for(i = 0; i < n; i++) {
444
23154462
        if (!transp_color[*buf])
445
176
            return 0;
446
23154286
        buf += pitch;
447
    }
448
38488
    return 1;
449
}
450
451
/* return 0 if empty rectangle, 1 if non empty */
452
44
static int find_smallest_bounding_rectangle(DVDSubContext *ctx, AVSubtitle *s)
453
{
454
44
    uint8_t transp_color[256] = { 0 };
455
    int y1, y2, x1, x2, y, w, h, i;
456
    uint8_t *bitmap;
457
44
    int transparent = 1;
458
459


44
    if (s->num_rects == 0 || !s->rects || s->rects[0]->w <= 0 || s->rects[0]->h <= 0)
460
        return 0;
461
462
220
    for(i = 0; i < s->rects[0]->nb_colors; i++) {
463
176
        if ((((uint32_t *)s->rects[0]->data[1])[i] >> 24) == 0) {
464
88
            transp_color[i] = 1;
465
88
        } else if (ctx->used_color[i])
466
88
            transparent = 0;
467
    }
468
44
    if (transparent)
469
        return 0;
470
44
    y1 = 0;
471

32048
    while (y1 < s->rects[0]->h && is_transp(s->rects[0]->data[0] + y1 * s->rects[0]->linesize[0],
472
16024
                                  1, s->rects[0]->w, transp_color))
473
15980
        y1++;
474
44
    if (y1 == s->rects[0]->h) {
475
        av_freep(&s->rects[0]->data[0]);
476
        s->rects[0]->w = s->rects[0]->h = 0;
477
        return 0;
478
    }
479
480
44
    y2 = s->rects[0]->h - 1;
481

6988
    while (y2 > 0 && is_transp(s->rects[0]->data[0] + y2 * s->rects[0]->linesize[0], 1,
482
3494
                               s->rects[0]->w, transp_color))
483
3450
        y2--;
484
44
    x1 = 0;
485

19078
    while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->data[0] + x1, s->rects[0]->linesize[0],
486
9539
                                        s->rects[0]->h, transp_color))
487
9495
        x1++;
488
44
    x2 = s->rects[0]->w - 1;
489

9607
    while (x2 > 0 && is_transp(s->rects[0]->data[0] + x2, s->rects[0]->linesize[0], s->rects[0]->h,
490
                                  transp_color))
491
9563
        x2--;
492
44
    w = x2 - x1 + 1;
493
44
    h = y2 - y1 + 1;
494
44
    bitmap = av_malloc(w * h);
495
44
    if (!bitmap)
496
        return 1;
497
1642
    for(y = 0; y < h; y++) {
498
1598
        memcpy(bitmap + w * y, s->rects[0]->data[0] + x1 + (y1 + y) * s->rects[0]->linesize[0], w);
499
    }
500
44
    av_freep(&s->rects[0]->data[0]);
501
44
    s->rects[0]->data[0] = bitmap;
502
44
    s->rects[0]->linesize[0] = w;
503
44
    s->rects[0]->w = w;
504
44
    s->rects[0]->h = h;
505
44
    s->rects[0]->x += x1;
506
44
    s->rects[0]->y += y1;
507
508
#if FF_API_AVPICTURE
509
FF_DISABLE_DEPRECATION_WARNINGS
510
220
    for (i = 0; i < 4; i++) {
511
176
        s->rects[0]->pict.data[i] = s->rects[0]->data[i];
512
176
        s->rects[0]->pict.linesize[i] = s->rects[0]->linesize[i];
513
    }
514
FF_ENABLE_DEPRECATION_WARNINGS
515
#endif
516
517
44
    return 1;
518
}
519
520
#ifdef DEBUG
521
#define ALPHA_MIX(A,BACK,FORE) (((255-(A)) * (BACK) + (A) * (FORE)) / 255)
522
static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
523
                     uint32_t *rgba_palette)
524
{
525
    int x, y, alpha;
526
    uint32_t v;
527
    int back[3] = {0, 255, 0};  /* green background */
528
    FILE *f;
529
530
    f = fopen(filename, "w");
531
    if (!f) {
532
        perror(filename);
533
        return;
534
    }
535
    fprintf(f, "P6\n"
536
            "%d %d\n"
537
            "%d\n",
538
            w, h, 255);
539
    for(y = 0; y < h; y++) {
540
        for(x = 0; x < w; x++) {
541
            v = rgba_palette[bitmap[y * w + x]];
542
            alpha = v >> 24;
543
            putc(ALPHA_MIX(alpha, back[0], (v >> 16) & 0xff), f);
544
            putc(ALPHA_MIX(alpha, back[1], (v >> 8) & 0xff), f);
545
            putc(ALPHA_MIX(alpha, back[2], (v >> 0) & 0xff), f);
546
        }
547
    }
548
    fclose(f);
549
}
550
#endif
551
552
6
static int append_to_cached_buf(AVCodecContext *avctx,
553
                                const uint8_t *buf, int buf_size)
554
{
555
6
    DVDSubContext *ctx = avctx->priv_data;
556
557

6
    av_assert0(buf_size >= 0 && ctx->buf_size <= sizeof(ctx->buf));
558
6
    if (buf_size >= sizeof(ctx->buf) - ctx->buf_size) {
559
        av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct "
560
               "too large SPU packets aborted.\n");
561
        ctx->buf_size = 0;
562
        return AVERROR_INVALIDDATA;
563
    }
564
6
    memcpy(ctx->buf + ctx->buf_size, buf, buf_size);
565
6
    ctx->buf_size += buf_size;
566
6
    return 0;
567
}
568
569
47
static int dvdsub_decode(AVCodecContext *avctx,
570
                         void *data, int *data_size,
571
                         AVPacket *avpkt)
572
{
573
47
    DVDSubContext *ctx = avctx->priv_data;
574
47
    const uint8_t *buf = avpkt->data;
575
47
    int buf_size = avpkt->size;
576
47
    AVSubtitle *sub = data;
577
47
    int appended = 0;
578
    int is_menu;
579
580
47
    if (ctx->buf_size) {
581
3
        int ret = append_to_cached_buf(avctx, buf, buf_size);
582
3
        if (ret < 0) {
583
            *data_size = 0;
584
            return ret;
585
        }
586
3
        buf = ctx->buf;
587
3
        buf_size = ctx->buf_size;
588
3
        appended = 1;
589
    }
590
591
47
    is_menu = decode_dvd_subtitles(ctx, sub, buf, buf_size);
592
47
    if (is_menu == AVERROR(EAGAIN)) {
593
3
        *data_size = 0;
594
3
        return appended ? 0 : append_to_cached_buf(avctx, buf, buf_size);
595
    }
596
597
44
    if (is_menu < 0) {
598
        ctx->buf_size = 0;
599
    no_subtitle:
600
        reset_rects(sub);
601
        *data_size = 0;
602
603
        return buf_size;
604
    }
605

44
    if (!is_menu && find_smallest_bounding_rectangle(ctx, sub) == 0)
606
        goto no_subtitle;
607
608

44
    if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED))
609
        goto no_subtitle;
610
611
#if defined(DEBUG)
612
    {
613
    char ppm_name[32];
614
615
    snprintf(ppm_name, sizeof(ppm_name), "/tmp/%05d.ppm", ctx->sub_id++);
616
    ff_dlog(NULL, "start=%d ms end =%d ms\n",
617
            sub->start_display_time,
618
            sub->end_display_time);
619
    ppm_save(ppm_name, sub->rects[0]->data[0],
620
             sub->rects[0]->w, sub->rects[0]->h, (uint32_t*) sub->rects[0]->data[1]);
621
    }
622
#endif
623
624
44
    ctx->buf_size = 0;
625
44
    *data_size = 1;
626
44
    return buf_size;
627
}
628
629
6
static void parse_palette(DVDSubContext *ctx, char *p)
630
{
631
    int i;
632
633
6
    ctx->has_palette = 1;
634
102
    for(i=0;i<16;i++) {
635
96
        ctx->palette[i] = strtoul(p, &p, 16);
636

282
        while(*p == ',' || av_isspace(*p))
637
186
            p++;
638
    }
639
6
}
640
641
static int parse_ifo_palette(DVDSubContext *ctx, char *p)
642
{
643
    FILE *ifo;
644
    char ifostr[12];
645
    uint32_t sp_pgci, pgci, off_pgc, pgc;
646
    uint8_t r, g, b, yuv[65], *buf;
647
    int i, y, cb, cr, r_add, g_add, b_add;
648
    int ret = 0;
649
    const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
650
651
    ctx->has_palette = 0;
652
    if ((ifo = fopen(p, "r")) == NULL) {
653
        av_log(ctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno)));
654
        return AVERROR_EOF;
655
    }
656
    if (fread(ifostr, 12, 1, ifo) != 1 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) {
657
        av_log(ctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p);
658
        ret = AVERROR_INVALIDDATA;
659
        goto end;
660
    }
661
    if (fseek(ifo, 0xCC, SEEK_SET) == -1) {
662
        ret = AVERROR(errno);
663
        goto end;
664
    }
665
    if (fread(&sp_pgci, 4, 1, ifo) == 1) {
666
        pgci = av_be2ne32(sp_pgci) * 2048;
667
        if (fseek(ifo, pgci + 0x0C, SEEK_SET) == -1) {
668
            ret = AVERROR(errno);
669
            goto end;
670
        }
671
        if (fread(&off_pgc, 4, 1, ifo) == 1) {
672
            pgc = pgci + av_be2ne32(off_pgc);
673
            if (fseek(ifo, pgc + 0xA4, SEEK_SET) == -1) {
674
                ret = AVERROR(errno);
675
                goto end;
676
            }
677
            if (fread(yuv, 64, 1, ifo) == 1) {
678
                buf = yuv;
679
                for(i=0; i<16; i++) {
680
                    y  = *++buf;
681
                    cr = *++buf;
682
                    cb = *++buf;
683
                    YUV_TO_RGB1_CCIR(cb, cr);
684
                    YUV_TO_RGB2_CCIR(r, g, b, y);
685
                    ctx->palette[i] = (r << 16) + (g << 8) + b;
686
                    buf++;
687
                }
688
                ctx->has_palette = 1;
689
            }
690
        }
691
    }
692
    if (ctx->has_palette == 0) {
693
        av_log(ctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p);
694
        ret = AVERROR_INVALIDDATA;
695
    }
696
end:
697
    fclose(ifo);
698
    return ret;
699
}
700
701
8
static int dvdsub_parse_extradata(AVCodecContext *avctx)
702
{
703
8
    DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data;
704
    char *dataorig, *data;
705
8
    int ret = 1;
706
707

8
    if (!avctx->extradata || !avctx->extradata_size)
708
2
        return 1;
709
710
6
    dataorig = data = av_malloc(avctx->extradata_size+1);
711
6
    if (!data)
712
        return AVERROR(ENOMEM);
713
6
    memcpy(data, avctx->extradata, avctx->extradata_size);
714
6
    data[avctx->extradata_size] = '\0';
715
716
50
    for(;;) {
717
56
        int pos = strcspn(data, "\n\r");
718

56
        if (pos==0 && *data==0)
719
6
            break;
720
721
50
        if (strncmp("palette:", data, 8) == 0) {
722
6
            parse_palette(ctx, data + 8);
723
44
        } else if (strncmp("size:", data, 5) == 0) {
724
            int w, h;
725
6
            if (sscanf(data + 5, "%dx%d", &w, &h) == 2) {
726
6
               ret = ff_set_dimensions(avctx, w, h);
727
6
               if (ret < 0)
728
                   goto fail;
729
            }
730
        }
731
732
50
        data += pos;
733
50
        data += strspn(data, "\n\r");
734
    }
735
736
6
fail:
737
6
    av_free(dataorig);
738
6
    return ret;
739
}
740
741
8
static av_cold int dvdsub_init(AVCodecContext *avctx)
742
{
743
8
    DVDSubContext *ctx = avctx->priv_data;
744
    int ret;
745
746
8
    if ((ret = dvdsub_parse_extradata(avctx)) < 0)
747
        return ret;
748
749
8
    if (ctx->ifo_str)
750
        parse_ifo_palette(ctx, ctx->ifo_str);
751
8
    if (ctx->palette_str)
752
        parse_palette(ctx, ctx->palette_str);
753
8
    if (ctx->has_palette) {
754
        int i;
755
6
        av_log(avctx, AV_LOG_DEBUG, "palette:");
756
102
        for(i=0;i<16;i++)
757
96
            av_log(avctx, AV_LOG_DEBUG, " 0x%06"PRIx32, ctx->palette[i]);
758
6
        av_log(avctx, AV_LOG_DEBUG, "\n");
759
    }
760
761
8
    return 1;
762
}
763
764
8
static void dvdsub_flush(AVCodecContext *avctx)
765
{
766
8
    DVDSubContext *ctx = avctx->priv_data;
767
8
    ctx->buf_size = 0;
768
8
}
769
770
8
static av_cold int dvdsub_close(AVCodecContext *avctx)
771
{
772
8
    dvdsub_flush(avctx);
773
8
    return 0;
774
}
775
776
#define OFFSET(field) offsetof(DVDSubContext, field)
777
#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
778
static const AVOption options[] = {
779
    { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
780
    { "ifo_palette", "obtain the global palette from .IFO file", OFFSET(ifo_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
781
    { "forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, SD},
782
    { NULL }
783
};
784
static const AVClass dvdsub_class = {
785
    .class_name = "dvdsubdec",
786
    .item_name  = av_default_item_name,
787
    .option     = options,
788
    .version    = LIBAVUTIL_VERSION_INT,
789
};
790
791
AVCodec ff_dvdsub_decoder = {
792
    .name           = "dvdsub",
793
    .long_name      = NULL_IF_CONFIG_SMALL("DVD subtitles"),
794
    .type           = AVMEDIA_TYPE_SUBTITLE,
795
    .id             = AV_CODEC_ID_DVD_SUBTITLE,
796
    .priv_data_size = sizeof(DVDSubContext),
797
    .init           = dvdsub_init,
798
    .decode         = dvdsub_decode,
799
    .flush          = dvdsub_flush,
800
    .close          = dvdsub_close,
801
    .priv_class     = &dvdsub_class,
802
};