dvdsubdec.c 19.6 KB
Newer Older
F
Fabrice Bellard 已提交
1
/*
2
 * DVD subtitle decoding
3
 * Copyright (c) 2005 Fabrice Bellard
F
Fabrice Bellard 已提交
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
F
Fabrice Bellard 已提交
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
F
Fabrice Bellard 已提交
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
F
Fabrice Bellard 已提交
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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
F
Fabrice Bellard 已提交
20 21
 */
#include "avcodec.h"
22
#include "get_bits.h"
I
Ian Caulfield 已提交
23
#include "dsputil.h"
24 25
#include "internal.h"

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"
F
Fabrice Bellard 已提交
31

32 33
typedef struct DVDSubContext
{
34
  AVClass *class;
35
  uint32_t palette[16];
36
  char    *palette_str;
37
  int      has_palette;
38 39
  uint8_t  colormap[4];
  uint8_t  alpha[256];
40 41
  uint8_t *buf;
  int      buf_size;
42 43 44
#ifdef DEBUG
  int sub_id;
#endif
45 46
} DVDSubContext;

I
Ian Caulfield 已提交
47 48
static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
{
49
    const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
I
Ian Caulfield 已提交
50 51 52 53 54 55 56
    uint8_t r, g, b;
    int i, y, cb, cr;
    int r_add, g_add, b_add;

    for (i = num_values; i > 0; i--) {
        y = *ycbcr++;
        cr = *ycbcr++;
57
        cb = *ycbcr++;
I
Ian Caulfield 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
        YUV_TO_RGB1_CCIR(cb, cr);
        YUV_TO_RGB2_CCIR(r, g, b, y);
        *rgba++ = (*alpha++ << 24) | (r << 16) | (g << 8) | b;
    }
}

static int decode_run_2bit(GetBitContext *gb, int *color)
{
    unsigned int v, t;

    v = 0;
    for (t = 1; v < t && t <= 0x40; t <<= 2)
        v = (v << 4) | get_bits(gb, 4);
    *color = v & 3;
    if (v < 4) { /* Code for fill rest of line */
        return INT_MAX;
    }
    return v >> 2;
}

static int decode_run_8bit(GetBitContext *gb, int *color)
F
Fabrice Bellard 已提交
79
{
I
Ian Caulfield 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    int len;
    int has_run = get_bits1(gb);
    if (get_bits1(gb))
        *color = get_bits(gb, 8);
    else
        *color = get_bits(gb, 2);
    if (has_run) {
        if (get_bits1(gb)) {
            len = get_bits(gb, 7);
            if (len == 0)
                len = INT_MAX;
            else
                len += 9;
        } else
            len = get_bits(gb, 3) + 2;
    } else
        len = 1;
    return len;
F
Fabrice Bellard 已提交
98 99
}

100
static int decode_rle(uint8_t *bitmap, int linesize, int w, int h,
I
Ian Caulfield 已提交
101
                      const uint8_t *buf, int start, int buf_size, int is_8bit)
F
Fabrice Bellard 已提交
102
{
I
Ian Caulfield 已提交
103 104 105
    GetBitContext gb;
    int bit_len;
    int x, y, len, color;
F
Fabrice Bellard 已提交
106 107
    uint8_t *d;

I
Ian Caulfield 已提交
108 109 110
    bit_len = (buf_size - start) * 8;
    init_get_bits(&gb, buf + start, bit_len);

F
Fabrice Bellard 已提交
111 112 113 114
    x = 0;
    y = 0;
    d = bitmap;
    for(;;) {
I
Ian Caulfield 已提交
115
        if (get_bits_count(&gb) > bit_len)
F
Fabrice Bellard 已提交
116
            return -1;
I
Ian Caulfield 已提交
117 118 119 120 121
        if (is_8bit)
            len = decode_run_8bit(&gb, &color);
        else
            len = decode_run_2bit(&gb, &color);
        len = FFMIN(len, w - x);
F
Fabrice Bellard 已提交
122 123 124 125 126 127 128 129 130
        memset(d + x, color, len);
        x += len;
        if (x >= w) {
            y++;
            if (y >= h)
                break;
            d += linesize;
            x = 0;
            /* byte align */
I
Ian Caulfield 已提交
131
            align_get_bits(&gb);
F
Fabrice Bellard 已提交
132 133 134 135 136
        }
    }
    return 0;
}

J
Joakim Plate 已提交
137 138
static void guess_palette(DVDSubContext* ctx,
                          uint32_t *rgba_palette,
F
Fabrice Bellard 已提交
139 140
                          uint32_t subtitle_color)
{
141 142 143 144 145 146 147 148
    static const uint8_t level_map[4][4] = {
        // this configuration (full range, lowest to highest) in tests
        // seemed most common, so assume this
        {0xff},
        {0x00, 0xff},
        {0x00, 0x80, 0xff},
        {0x00, 0x55, 0xaa, 0xff},
    };
149
    uint8_t color_used[16] = { 0 };
F
Fabrice Bellard 已提交
150
    int nb_opaque_colors, i, level, j, r, g, b;
151
    uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
152

153 154 155
    if(ctx->has_palette) {
        for(i = 0; i < 4; i++)
            rgba_palette[i] = (ctx->palette[colormap[i]] & 0x00ffffff)
156
                              | ((alpha[i] * 17U) << 24);
157 158 159
        return;
    }

F
Fabrice Bellard 已提交
160 161 162 163 164
    for(i = 0; i < 4; i++)
        rgba_palette[i] = 0;

    nb_opaque_colors = 0;
    for(i = 0; i < 4; i++) {
165 166
        if (alpha[i] != 0 && !color_used[colormap[i]]) {
            color_used[colormap[i]] = 1;
F
Fabrice Bellard 已提交
167 168 169
            nb_opaque_colors++;
        }
    }
170

F
Fabrice Bellard 已提交
171 172
    if (nb_opaque_colors == 0)
        return;
173

174
    j = 0;
F
Fabrice Bellard 已提交
175 176 177
    memset(color_used, 0, 16);
    for(i = 0; i < 4; i++) {
        if (alpha[i] != 0) {
178
            if (!color_used[colormap[i]])  {
179
                level = level_map[nb_opaque_colors][j];
F
Fabrice Bellard 已提交
180 181 182
                r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
                g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
                b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
183
                rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24);
184
                color_used[colormap[i]] = (i + 1);
185
                j++;
F
Fabrice Bellard 已提交
186
            } else {
187
                rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) |
188
                                    ((alpha[i] * 17) << 24);
F
Fabrice Bellard 已提交
189 190 191 192 193
            }
        }
    }
}

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
static void reset_rects(AVSubtitle *sub_header)
{
    int i;

    if (sub_header->rects != NULL) {
        for (i = 0; i < sub_header->num_rects; i++) {
            av_freep(&sub_header->rects[i]->pict.data[0]);
            av_freep(&sub_header->rects[i]->pict.data[1]);
            av_freep(&sub_header->rects[i]);
        }
        av_freep(&sub_header->rects);
        sub_header->num_rects = 0;
    }
}

I
Ian Caulfield 已提交
209 210
#define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))

211
static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
F
Fabrice Bellard 已提交
212 213 214
                                const uint8_t *buf, int buf_size)
{
    int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos;
I
Ian Caulfield 已提交
215 216
    int big_offsets, offset_size, is_8bit = 0;
    const uint8_t *yuv_palette = 0;
217
    uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
F
Fabrice Bellard 已提交
218
    int date;
219
    int i;
220
    int is_menu = 0;
221

I
Ian Caulfield 已提交
222
    if (buf_size < 10)
F
Fabrice Bellard 已提交
223 224
        return -1;

I
Ian Caulfield 已提交
225 226 227 228 229 230 231 232 233 234 235 236
    if (AV_RB16(buf) == 0) {   /* HD subpicture with 4-byte offsets */
        big_offsets = 1;
        offset_size = 4;
        cmd_pos = 6;
    } else {
        big_offsets = 0;
        offset_size = 2;
        cmd_pos = 2;
    }

    cmd_pos = READ_OFFSET(buf + cmd_pos);

237 238 239
    if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size)
        return AVERROR(EAGAIN);

240
    while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) {
241
        date = AV_RB16(buf + cmd_pos);
I
Ian Caulfield 已提交
242
        next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2);
L
Luca Barbato 已提交
243
        av_dlog(NULL, "cmd_pos=0x%04x next=0x%04x date=%d\n",
244
                cmd_pos, next_cmd_pos, date);
I
Ian Caulfield 已提交
245
        pos = cmd_pos + 2 + offset_size;
F
Fabrice Bellard 已提交
246 247 248 249 250
        offset1 = -1;
        offset2 = -1;
        x1 = y1 = x2 = y2 = 0;
        while (pos < buf_size) {
            cmd = buf[pos++];
L
Luca Barbato 已提交
251
            av_dlog(NULL, "cmd=%02x\n", cmd);
F
Fabrice Bellard 已提交
252 253
            switch(cmd) {
            case 0x00:
254 255
                /* menu subpicture */
                is_menu = 1;
F
Fabrice Bellard 已提交
256 257 258
                break;
            case 0x01:
                /* set start date */
259
                sub_header->start_display_time = (date << 10) / 90;
F
Fabrice Bellard 已提交
260 261 262
                break;
            case 0x02:
                /* set end date */
263
                sub_header->end_display_time = (date << 10) / 90;
F
Fabrice Bellard 已提交
264 265
                break;
            case 0x03:
266
                /* set colormap */
F
Fabrice Bellard 已提交
267 268
                if ((buf_size - pos) < 2)
                    goto fail;
269 270 271 272
                colormap[3] = buf[pos] >> 4;
                colormap[2] = buf[pos] & 0x0f;
                colormap[1] = buf[pos + 1] >> 4;
                colormap[0] = buf[pos + 1] & 0x0f;
F
Fabrice Bellard 已提交
273 274 275 276 277 278
                pos += 2;
                break;
            case 0x04:
                /* set alpha */
                if ((buf_size - pos) < 2)
                    goto fail;
279 280 281 282
                alpha[3] = buf[pos] >> 4;
                alpha[2] = buf[pos] & 0x0f;
                alpha[1] = buf[pos + 1] >> 4;
                alpha[0] = buf[pos + 1] & 0x0f;
F
Fabrice Bellard 已提交
283
                pos += 2;
L
Luca Barbato 已提交
284
            av_dlog(NULL, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
F
Fabrice Bellard 已提交
285 286
                break;
            case 0x05:
I
Ian Caulfield 已提交
287
            case 0x85:
F
Fabrice Bellard 已提交
288 289 290 291 292 293
                if ((buf_size - pos) < 6)
                    goto fail;
                x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4);
                x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2];
                y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4);
                y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5];
I
Ian Caulfield 已提交
294 295
                if (cmd & 0x80)
                    is_8bit = 1;
L
Luca Barbato 已提交
296
                av_dlog(NULL, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2);
F
Fabrice Bellard 已提交
297 298 299 300 301
                pos += 6;
                break;
            case 0x06:
                if ((buf_size - pos) < 4)
                    goto fail;
302 303
                offset1 = AV_RB16(buf + pos);
                offset2 = AV_RB16(buf + pos + 2);
L
Luca Barbato 已提交
304
                av_dlog(NULL, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
F
Fabrice Bellard 已提交
305 306
                pos += 4;
                break;
I
Ian Caulfield 已提交
307 308 309 310 311
            case 0x86:
                if ((buf_size - pos) < 8)
                    goto fail;
                offset1 = AV_RB32(buf + pos);
                offset2 = AV_RB32(buf + pos + 4);
L
Luca Barbato 已提交
312
                av_dlog(NULL, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
I
Ian Caulfield 已提交
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
                pos += 8;
                break;

            case 0x83:
                /* HD set palette */
                if ((buf_size - pos) < 768)
                    goto fail;
                yuv_palette = buf + pos;
                pos += 768;
                break;
            case 0x84:
                /* HD set contrast (alpha) */
                if ((buf_size - pos) < 256)
                    goto fail;
                for (i = 0; i < 256; i++)
                    alpha[i] = 0xFF - buf[pos+i];
                pos += 256;
                break;

F
Fabrice Bellard 已提交
332
            case 0xff:
I
Ian Caulfield 已提交
333
                goto the_end;
F
Fabrice Bellard 已提交
334
            default:
L
Luca Barbato 已提交
335
                av_dlog(NULL, "unrecognised subpicture command 0x%x\n", cmd);
F
Fabrice Bellard 已提交
336 337 338 339 340 341 342
                goto the_end;
            }
        }
    the_end:
        if (offset1 >= 0) {
            int w, h;
            uint8_t *bitmap;
343

F
Fabrice Bellard 已提交
344 345 346 347 348 349 350 351
            /* decode the bitmap */
            w = x2 - x1 + 1;
            if (w < 0)
                w = 0;
            h = y2 - y1;
            if (h < 0)
                h = 0;
            if (w > 0 && h > 0) {
352
                reset_rects(sub_header);
353

F
Fabrice Bellard 已提交
354
                bitmap = av_malloc(w * h);
355 356
                sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
                sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect));
357
                sub_header->num_rects = 1;
358
                sub_header->rects[0]->pict.data[0] = bitmap;
359
                decode_rle(bitmap, w * 2, w, (h + 1) / 2,
I
Ian Caulfield 已提交
360
                           buf, offset1, buf_size, is_8bit);
F
Fabrice Bellard 已提交
361
                decode_rle(bitmap + w, w * 2, w, h / 2,
I
Ian Caulfield 已提交
362
                           buf, offset2, buf_size, is_8bit);
363
                sub_header->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
I
Ian Caulfield 已提交
364 365 366
                if (is_8bit) {
                    if (yuv_palette == 0)
                        goto fail;
367
                    sub_header->rects[0]->nb_colors = 256;
368
                    yuv_a_to_rgba(yuv_palette, alpha, (uint32_t*)sub_header->rects[0]->pict.data[1], 256);
I
Ian Caulfield 已提交
369
                } else {
370
                    sub_header->rects[0]->nb_colors = 4;
371
                    guess_palette(ctx, (uint32_t*)sub_header->rects[0]->pict.data[1],
372
                                  0xffff00);
I
Ian Caulfield 已提交
373
                }
374 375 376 377
                sub_header->rects[0]->x = x1;
                sub_header->rects[0]->y = y1;
                sub_header->rects[0]->w = w;
                sub_header->rects[0]->h = h;
378
                sub_header->rects[0]->type = SUBTITLE_BITMAP;
379
                sub_header->rects[0]->pict.linesize[0] = w;
380
                sub_header->rects[0]->flags = is_menu ? AV_SUBTITLE_FLAG_FORCED : 0;
F
Fabrice Bellard 已提交
381 382
            }
        }
383 384 385 386
        if (next_cmd_pos < cmd_pos) {
            av_log(NULL, AV_LOG_ERROR, "Invalid command offset\n");
            break;
        }
F
Fabrice Bellard 已提交
387 388 389 390
        if (next_cmd_pos == cmd_pos)
            break;
        cmd_pos = next_cmd_pos;
    }
391
    if (sub_header->num_rects > 0)
392
        return is_menu;
F
Fabrice Bellard 已提交
393
 fail:
394
    reset_rects(sub_header);
F
Fabrice Bellard 已提交
395 396 397
    return -1;
}

398
static int is_transp(const uint8_t *buf, int pitch, int n,
F
Fabrice Bellard 已提交
399 400 401 402 403 404 405 406 407 408 409 410
                     const uint8_t *transp_color)
{
    int i;
    for(i = 0; i < n; i++) {
        if (!transp_color[*buf])
            return 0;
        buf += pitch;
    }
    return 1;
}

/* return 0 if empty rectangle, 1 if non empty */
411
static int find_smallest_bounding_rectangle(AVSubtitle *s)
F
Fabrice Bellard 已提交
412
{
413
    uint8_t transp_color[256] = { 0 };
F
Fabrice Bellard 已提交
414 415 416
    int y1, y2, x1, x2, y, w, h, i;
    uint8_t *bitmap;

417
    if (s->num_rects == 0 || s->rects == NULL || s->rects[0]->w <= 0 || s->rects[0]->h <= 0)
F
Fabrice Bellard 已提交
418 419
        return 0;

420
    for(i = 0; i < s->rects[0]->nb_colors; i++) {
421
        if ((((uint32_t*)s->rects[0]->pict.data[1])[i] >> 24) == 0)
F
Fabrice Bellard 已提交
422 423 424
            transp_color[i] = 1;
    }
    y1 = 0;
425
    while (y1 < s->rects[0]->h && is_transp(s->rects[0]->pict.data[0] + y1 * s->rects[0]->pict.linesize[0],
426
                                  1, s->rects[0]->w, transp_color))
F
Fabrice Bellard 已提交
427
        y1++;
428
    if (y1 == s->rects[0]->h) {
429
        av_freep(&s->rects[0]->pict.data[0]);
430
        s->rects[0]->w = s->rects[0]->h = 0;
F
Fabrice Bellard 已提交
431 432 433
        return 0;
    }

434
    y2 = s->rects[0]->h - 1;
435
    while (y2 > 0 && is_transp(s->rects[0]->pict.data[0] + y2 * s->rects[0]->pict.linesize[0], 1,
436
                               s->rects[0]->w, transp_color))
F
Fabrice Bellard 已提交
437 438
        y2--;
    x1 = 0;
439
    while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->pict.data[0] + x1, s->rects[0]->pict.linesize[0],
440
                                        s->rects[0]->h, transp_color))
F
Fabrice Bellard 已提交
441
        x1++;
442
    x2 = s->rects[0]->w - 1;
443
    while (x2 > 0 && is_transp(s->rects[0]->pict.data[0] + x2, s->rects[0]->pict.linesize[0], s->rects[0]->h,
F
Fabrice Bellard 已提交
444 445 446 447 448 449 450 451
                                  transp_color))
        x2--;
    w = x2 - x1 + 1;
    h = y2 - y1 + 1;
    bitmap = av_malloc(w * h);
    if (!bitmap)
        return 1;
    for(y = 0; y < h; y++) {
452
        memcpy(bitmap + w * y, s->rects[0]->pict.data[0] + x1 + (y1 + y) * s->rects[0]->pict.linesize[0], w);
F
Fabrice Bellard 已提交
453
    }
454 455 456
    av_freep(&s->rects[0]->pict.data[0]);
    s->rects[0]->pict.data[0] = bitmap;
    s->rects[0]->pict.linesize[0] = w;
457 458 459 460
    s->rects[0]->w = w;
    s->rects[0]->h = h;
    s->rects[0]->x += x1;
    s->rects[0]->y += y1;
F
Fabrice Bellard 已提交
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
    return 1;
}

#ifdef DEBUG
static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
                     uint32_t *rgba_palette)
{
    int x, y, v;
    FILE *f;

    f = fopen(filename, "w");
    if (!f) {
        perror(filename);
        exit(1);
    }
    fprintf(f, "P6\n"
            "%d %d\n"
            "%d\n",
            w, h, 255);
    for(y = 0; y < h; y++) {
        for(x = 0; x < w; x++) {
            v = rgba_palette[bitmap[y * w + x]];
            putc((v >> 16) & 0xff, f);
            putc((v >> 8) & 0xff, f);
            putc((v >> 0) & 0xff, f);
        }
    }
    fclose(f);
}
#endif

492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
static int append_to_cached_buf(AVCodecContext *avctx,
                                const uint8_t *buf, int buf_size)
{
    DVDSubContext *ctx = avctx->priv_data;

    if (ctx->buf_size > 0xffff - buf_size) {
        av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct "
               "too large SPU packets aborted.\n");
        av_freep(&ctx->buf);
        return AVERROR_INVALIDDATA;
    }
    ctx->buf = av_realloc(ctx->buf, ctx->buf_size + buf_size);
    if (!ctx->buf)
        return AVERROR(ENOMEM);
    memcpy(ctx->buf + ctx->buf_size, buf, buf_size);
    ctx->buf_size += buf_size;
    return 0;
}

F
Fabrice Bellard 已提交
511 512
static int dvdsub_decode(AVCodecContext *avctx,
                         void *data, int *data_size,
513
                         AVPacket *avpkt)
F
Fabrice Bellard 已提交
514
{
J
Joakim Plate 已提交
515
    DVDSubContext *ctx = avctx->priv_data;
516 517
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
A
Aurelien Jacobs 已提交
518
    AVSubtitle *sub = data;
519 520
    int is_menu;

521 522 523 524 525 526 527 528 529 530
    if (ctx->buf) {
        int ret = append_to_cached_buf(avctx, buf, buf_size);
        if (ret < 0) {
            *data_size = 0;
            return ret;
        }
        buf = ctx->buf;
        buf_size = ctx->buf_size;
    }

531
    is_menu = decode_dvd_subtitles(ctx, sub, buf, buf_size);
532 533 534 535
    if (is_menu == AVERROR(EAGAIN)) {
        *data_size = 0;
        return append_to_cached_buf(avctx, buf, buf_size);
    }
F
Fabrice Bellard 已提交
536

537
    if (is_menu < 0) {
F
Fabrice Bellard 已提交
538 539 540 541 542
    no_subtitle:
        *data_size = 0;

        return buf_size;
    }
543
    if (!is_menu && find_smallest_bounding_rectangle(sub) == 0)
F
Fabrice Bellard 已提交
544 545 546
        goto no_subtitle;

#if defined(DEBUG)
547 548 549 550
    {
    char ppm_name[32];

    snprintf(ppm_name, sizeof(ppm_name), "/tmp/%05d.ppm", ctx->sub_id++);
L
Luca Barbato 已提交
551
    av_dlog(NULL, "start=%d ms end =%d ms\n",
552 553
            sub->start_display_time,
            sub->end_display_time);
554
    ppm_save(ppm_name, sub->rects[0]->pict.data[0],
555
             sub->rects[0]->w, sub->rects[0]->h, sub->rects[0]->pict.data[1]);
556
    }
F
Fabrice Bellard 已提交
557 558
#endif

559 560
    av_freep(&ctx->buf);
    ctx->buf_size = 0;
F
Fabrice Bellard 已提交
561 562 563 564
    *data_size = 1;
    return buf_size;
}

565 566 567 568 569 570 571
static void parse_palette(DVDSubContext *ctx, char *p)
{
    int i;

    ctx->has_palette = 1;
    for(i=0;i<16;i++) {
        ctx->palette[i] = strtoul(p, &p, 16);
572
        while(*p == ',' || av_isspace(*p))
573 574 575 576 577
            p++;
    }
}

static int dvdsub_parse_extradata(AVCodecContext *avctx)
578 579
{
    DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data;
580
    char *dataorig, *data;
581 582 583 584

    if (!avctx->extradata || !avctx->extradata_size)
        return 1;

585
    dataorig = data = av_malloc(avctx->extradata_size+1);
586 587 588 589 590 591 592 593 594 595 596
    if (!data)
        return AVERROR(ENOMEM);
    memcpy(data, avctx->extradata, avctx->extradata_size);
    data[avctx->extradata_size] = '\0';

    for(;;) {
        int pos = strcspn(data, "\n\r");
        if (pos==0 && *data==0)
            break;

        if (strncmp("palette:", data, 8) == 0) {
597
            parse_palette(ctx, data + 8);
598 599
        } else if (strncmp("size:", data, 5) == 0) {
            int w, h;
600
            if (sscanf(data + 5, "%dx%d", &w, &h) == 2) {
601 602 603 604
               int ret = ff_set_dimensions(avctx, w, h);
               if (ret < 0)
                   return ret;
            }
605 606 607 608 609 610
        }

        data += pos;
        data += strspn(data, "\n\r");
    }

611 612 613 614
    av_free(dataorig);
    return 1;
}

615
static av_cold int dvdsub_init(AVCodecContext *avctx)
616
{
617
    DVDSubContext *ctx = avctx->priv_data;
618 619 620 621 622 623 624
    int ret;

    if ((ret = dvdsub_parse_extradata(avctx)) < 0)
        return ret;

    if (ctx->palette_str)
        parse_palette(ctx, ctx->palette_str);
625 626 627 628 629 630 631 632 633 634 635
    if (ctx->has_palette) {
        int i;
        av_log(avctx, AV_LOG_DEBUG, "palette:");
        for(i=0;i<16;i++)
            av_log(avctx, AV_LOG_DEBUG, " 0x%06x", ctx->palette[i]);
        av_log(avctx, AV_LOG_DEBUG, "\n");
    }

    return 1;
}

636 637 638 639 640 641 642 643
static av_cold int dvdsub_close(AVCodecContext *avctx)
{
    DVDSubContext *ctx = avctx->priv_data;
    av_freep(&ctx->buf);
    ctx->buf_size = 0;
    return 0;
}

644 645 646 647 648 649
#define OFFSET(field) offsetof(DVDSubContext, field)
#define VD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
    { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
    { NULL }
};
650
static const AVClass dvdsub_class = {
651 652 653 654 655 656
    .class_name = "dvdsubdec",
    .item_name  = av_default_item_name,
    .option     = options,
    .version    = LIBAVUTIL_VERSION_INT,
};

657
AVCodec ff_dvdsub_decoder = {
658
    .name           = "dvdsub",
659
    .long_name      = NULL_IF_CONFIG_SMALL("DVD subtitles"),
660
    .type           = AVMEDIA_TYPE_SUBTITLE,
661
    .id             = AV_CODEC_ID_DVD_SUBTITLE,
662 663
    .priv_data_size = sizeof(DVDSubContext),
    .init           = dvdsub_init,
664
    .decode         = dvdsub_decode,
665
    .close          = dvdsub_close,
666
    .priv_class     = &dvdsub_class,
F
Fabrice Bellard 已提交
667
};