dvdsubdec.c 15.6 KB
Newer Older
1 2
/*
 * DVD subtitle decoding for ffmpeg
3
 * Copyright (c) 2005 Fabrice Bellard
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
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.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
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
20 21
 */
#include "avcodec.h"
22
#include "get_bits.h"
23 24
#include "colorspace.h"
#include "dsputil.h"
25 26 27

//#define DEBUG

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
{
    uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
    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++;
        cb = *ycbcr++;
        cr = *ycbcr++;
        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)
60
{
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    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;
79 80
}

81
static int decode_rle(uint8_t *bitmap, int linesize, int w, int h,
82
                      const uint8_t *buf, int start, int buf_size, int is_8bit)
83
{
84 85 86
    GetBitContext gb;
    int bit_len;
    int x, y, len, color;
87 88
    uint8_t *d;

89 90 91
    bit_len = (buf_size - start) * 8;
    init_get_bits(&gb, buf + start, bit_len);

92 93 94 95
    x = 0;
    y = 0;
    d = bitmap;
    for(;;) {
96
        if (get_bits_count(&gb) > bit_len)
97
            return -1;
98 99 100 101 102
        if (is_8bit)
            len = decode_run_8bit(&gb, &color);
        else
            len = decode_run_2bit(&gb, &color);
        len = FFMIN(len, w - x);
103 104 105 106 107 108 109 110 111
        memset(d + x, color, len);
        x += len;
        if (x >= w) {
            y++;
            if (y >= h)
                break;
            d += linesize;
            x = 0;
            /* byte align */
112
            align_get_bits(&gb);
113 114 115 116 117 118
        }
    }
    return 0;
}

static void guess_palette(uint32_t *rgba_palette,
119
                          uint8_t *colormap,
120 121 122 123 124
                          uint8_t *alpha,
                          uint32_t subtitle_color)
{
    uint8_t color_used[16];
    int nb_opaque_colors, i, level, j, r, g, b;
125

126 127 128 129 130 131
    for(i = 0; i < 4; i++)
        rgba_palette[i] = 0;

    memset(color_used, 0, 16);
    nb_opaque_colors = 0;
    for(i = 0; i < 4; i++) {
132 133
        if (alpha[i] != 0 && !color_used[colormap[i]]) {
            color_used[colormap[i]] = 1;
134 135 136
            nb_opaque_colors++;
        }
    }
137

138 139
    if (nb_opaque_colors == 0)
        return;
140

141
    j = nb_opaque_colors;
142 143 144
    memset(color_used, 0, 16);
    for(i = 0; i < 4; i++) {
        if (alpha[i] != 0) {
145
            if (!color_used[colormap[i]])  {
146
                level = (0xff * j) / nb_opaque_colors;
147 148 149
                r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
                g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
                b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
150
                rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24);
151
                color_used[colormap[i]] = (i + 1);
152
                j--;
153
            } else {
154
                rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) |
155
                                    ((alpha[i] * 17) << 24);
156 157 158 159 160
            }
        }
    }
}

161 162
#define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))

163
static int decode_dvd_subtitles(AVSubtitle *sub_header,
164 165 166
                                const uint8_t *buf, int buf_size)
{
    int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos;
167 168 169
    int big_offsets, offset_size, is_8bit = 0;
    const uint8_t *yuv_palette = 0;
    uint8_t colormap[4], alpha[256];
170
    int date;
171
    int i;
172
    int is_menu = 0;
173

174
    if (buf_size < 10)
175
        return -1;
176 177
    sub_header->rects = NULL;
    sub_header->num_rects = 0;
178
    sub_header->format = 0;
179 180 181
    sub_header->start_display_time = 0;
    sub_header->end_display_time = 0;

182 183 184 185 186 187 188 189 190 191 192 193 194
    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);

    while ((cmd_pos + 2 + offset_size) < buf_size) {
195
        date = AV_RB16(buf + cmd_pos);
196
        next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2);
197
#ifdef DEBUG
198
        av_log(NULL, AV_LOG_INFO, "cmd_pos=0x%04x next=0x%04x date=%d\n",
199 200
               cmd_pos, next_cmd_pos, date);
#endif
201
        pos = cmd_pos + 2 + offset_size;
202 203 204 205 206 207 208 209 210 211
        offset1 = -1;
        offset2 = -1;
        x1 = y1 = x2 = y2 = 0;
        while (pos < buf_size) {
            cmd = buf[pos++];
#ifdef DEBUG
            av_log(NULL, AV_LOG_INFO, "cmd=%02x\n", cmd);
#endif
            switch(cmd) {
            case 0x00:
212 213
                /* menu subpicture */
                is_menu = 1;
214 215 216
                break;
            case 0x01:
                /* set start date */
217
                sub_header->start_display_time = (date << 10) / 90;
218 219 220
                break;
            case 0x02:
                /* set end date */
221
                sub_header->end_display_time = (date << 10) / 90;
222 223
                break;
            case 0x03:
224
                /* set colormap */
225 226
                if ((buf_size - pos) < 2)
                    goto fail;
227 228 229 230
                colormap[3] = buf[pos] >> 4;
                colormap[2] = buf[pos] & 0x0f;
                colormap[1] = buf[pos + 1] >> 4;
                colormap[0] = buf[pos + 1] & 0x0f;
231 232 233 234 235 236
                pos += 2;
                break;
            case 0x04:
                /* set alpha */
                if ((buf_size - pos) < 2)
                    goto fail;
237 238 239 240
                alpha[3] = buf[pos] >> 4;
                alpha[2] = buf[pos] & 0x0f;
                alpha[1] = buf[pos + 1] >> 4;
                alpha[0] = buf[pos + 1] & 0x0f;
241
                pos += 2;
242 243 244
#ifdef DEBUG
            av_log(NULL, AV_LOG_INFO, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
#endif
245 246
                break;
            case 0x05:
247
            case 0x85:
248 249 250 251 252 253
                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];
254 255
                if (cmd & 0x80)
                    is_8bit = 1;
256 257 258 259 260 261 262 263 264
#ifdef DEBUG
                av_log(NULL, AV_LOG_INFO, "x1=%d x2=%d y1=%d y2=%d\n",
                       x1, x2, y1, y2);
#endif
                pos += 6;
                break;
            case 0x06:
                if ((buf_size - pos) < 4)
                    goto fail;
265 266
                offset1 = AV_RB16(buf + pos);
                offset2 = AV_RB16(buf + pos + 2);
267 268 269 270 271
#ifdef DEBUG
                av_log(NULL, AV_LOG_INFO, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
#endif
                pos += 4;
                break;
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
            case 0x86:
                if ((buf_size - pos) < 8)
                    goto fail;
                offset1 = AV_RB32(buf + pos);
                offset2 = AV_RB32(buf + pos + 4);
#ifdef DEBUG
                av_log(NULL, AV_LOG_INFO, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
#endif
                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;

299
            case 0xff:
300
                goto the_end;
301
            default:
302 303 304
#ifdef DEBUG
                av_log(NULL, AV_LOG_INFO, "unrecognised subpicture command 0x%x\n", cmd);
#endif
305 306 307 308 309 310 311
                goto the_end;
            }
        }
    the_end:
        if (offset1 >= 0) {
            int w, h;
            uint8_t *bitmap;
312

313 314 315 316 317 318 319 320
            /* 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) {
321 322
                if (sub_header->rects != NULL) {
                    for (i = 0; i < sub_header->num_rects; i++) {
323 324
                        av_freep(&sub_header->rects[i]->pict.data[0]);
                        av_freep(&sub_header->rects[i]->pict.data[1]);
325
                        av_freep(&sub_header->rects[i]);
326 327 328 329 330
                    }
                    av_freep(&sub_header->rects);
                    sub_header->num_rects = 0;
                }

331
                bitmap = av_malloc(w * h);
332 333
                sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
                sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect));
334
                sub_header->num_rects = 1;
335
                sub_header->rects[0]->pict.data[0] = bitmap;
336
                decode_rle(bitmap, w * 2, w, (h + 1) / 2,
337
                           buf, offset1, buf_size, is_8bit);
338
                decode_rle(bitmap + w, w * 2, w, h / 2,
339 340 341 342
                           buf, offset2, buf_size, is_8bit);
                if (is_8bit) {
                    if (yuv_palette == 0)
                        goto fail;
343
                    sub_header->rects[0]->pict.data[1] = av_malloc(256 * 4);
344
                    sub_header->rects[0]->nb_colors = 256;
345
                    yuv_a_to_rgba(yuv_palette, alpha, (uint32_t*)sub_header->rects[0]->pict.data[1], 256);
346
                } else {
347
                    sub_header->rects[0]->pict.data[1] = av_malloc(4 * 4);
348
                    sub_header->rects[0]->nb_colors = 4;
349
                    guess_palette((uint32_t*)sub_header->rects[0]->pict.data[1],
Ian Caulfield's avatar
Ian Caulfield committed
350
                                  colormap, alpha, 0xffff00);
351
                }
352 353 354 355
                sub_header->rects[0]->x = x1;
                sub_header->rects[0]->y = y1;
                sub_header->rects[0]->w = w;
                sub_header->rects[0]->h = h;
356
                sub_header->rects[0]->pict.linesize[0] = w;
357 358 359 360 361 362
            }
        }
        if (next_cmd_pos == cmd_pos)
            break;
        cmd_pos = next_cmd_pos;
    }
363
    if (sub_header->num_rects > 0)
364
        return is_menu;
365
 fail:
366 367
    if (sub_header->rects != NULL) {
        for (i = 0; i < sub_header->num_rects; i++) {
368 369
            av_freep(&sub_header->rects[i]->pict.data[0]);
            av_freep(&sub_header->rects[i]->pict.data[1]);
370
            av_freep(&sub_header->rects[i]);
371 372 373 374
        }
        av_freep(&sub_header->rects);
        sub_header->num_rects = 0;
    }
375 376 377
    return -1;
}

378
static int is_transp(const uint8_t *buf, int pitch, int n,
379 380 381 382 383 384 385 386 387 388 389 390
                     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 */
391
static int find_smallest_bounding_rectangle(AVSubtitle *s)
392 393 394 395 396
{
    uint8_t transp_color[256];
    int y1, y2, x1, x2, y, w, h, i;
    uint8_t *bitmap;

397
    if (s->num_rects == 0 || s->rects == NULL || s->rects[0]->w <= 0 || s->rects[0]->h <= 0)
398 399 400
        return 0;

    memset(transp_color, 0, 256);
401
    for(i = 0; i < s->rects[0]->nb_colors; i++) {
402
        if ((((uint32_t*)s->rects[0]->pict.data[1])[i] >> 24) == 0)
403 404 405
            transp_color[i] = 1;
    }
    y1 = 0;
406
    while (y1 < s->rects[0]->h && is_transp(s->rects[0]->pict.data[0] + y1 * s->rects[0]->pict.linesize[0],
407
                                  1, s->rects[0]->w, transp_color))
408
        y1++;
409
    if (y1 == s->rects[0]->h) {
410
        av_freep(&s->rects[0]->pict.data[0]);
411
        s->rects[0]->w = s->rects[0]->h = 0;
412 413 414
        return 0;
    }

415
    y2 = s->rects[0]->h - 1;
416
    while (y2 > 0 && is_transp(s->rects[0]->pict.data[0] + y2 * s->rects[0]->pict.linesize[0], 1,
417
                               s->rects[0]->w, transp_color))
418 419
        y2--;
    x1 = 0;
420
    while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->pict.data[0] + x1, s->rects[0]->pict.linesize[0],
421
                                        s->rects[0]->h, transp_color))
422
        x1++;
423
    x2 = s->rects[0]->w - 1;
424
    while (x2 > 0 && is_transp(s->rects[0]->pict.data[0] + x2, s->rects[0]->pict.linesize[0], s->rects[0]->h,
425 426 427 428 429 430 431 432
                                  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++) {
433
        memcpy(bitmap + w * y, s->rects[0]->pict.data[0] + x1 + (y1 + y) * s->rects[0]->pict.linesize[0], w);
434
    }
435 436 437
    av_freep(&s->rects[0]->pict.data[0]);
    s->rects[0]->pict.data[0] = bitmap;
    s->rects[0]->pict.linesize[0] = w;
438 439 440 441
    s->rects[0]->w = w;
    s->rects[0]->h = h;
    s->rects[0]->x += x1;
    s->rects[0]->y += y1;
442 443 444 445 446
    return 1;
}

#ifdef DEBUG
#undef fprintf
447 448
#undef perror
#undef exit
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
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

static int dvdsub_decode(AVCodecContext *avctx,
                         void *data, int *data_size,
478
                         AVPacket *avpkt)
479
{
480 481
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
482
    AVSubtitle *sub = (void *)data;
483 484 485
    int is_menu;

    is_menu = decode_dvd_subtitles(sub, buf, buf_size);
486

487
    if (is_menu < 0) {
488 489 490 491 492
    no_subtitle:
        *data_size = 0;

        return buf_size;
    }
493
    if (!is_menu && find_smallest_bounding_rectangle(sub) == 0)
494 495 496
        goto no_subtitle;

#if defined(DEBUG)
497
    av_log(NULL, AV_LOG_INFO, "start=%d ms end =%d ms\n",
498 499
           sub->start_display_time,
           sub->end_display_time);
500 501
    ppm_save("/tmp/a.ppm", sub->rects[0]->pict.data[0],
             sub->rects[0]->w, sub->rects[0]->h, sub->rects[0]->pict.data[1]);
502 503 504 505 506 507 508 509 510 511
#endif

    *data_size = 1;
    return buf_size;
}

AVCodec dvdsub_decoder = {
    "dvdsub",
    CODEC_TYPE_SUBTITLE,
    CODEC_ID_DVD_SUBTITLE,
Steve L'Homme's avatar
Steve L'Homme committed
512
    0,
513
    NULL,
514 515
    NULL,
    NULL,
516
    dvdsub_decode,
517
    .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
518
};