dvbsubdec.c 41.6 KB
Newer Older
1
/*
2
 * DVB subtitle decoding
3
 * Copyright (c) 2005 Ian Caulfield
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 22
 */
#include "avcodec.h"
#include "dsputil.h"
23
#include "get_bits.h"
24
#include "bytestream.h"
25
#include "libavutil/colorspace.h"
26 27 28 29 30

#define DVBSUB_PAGE_SEGMENT     0x10
#define DVBSUB_REGION_SEGMENT   0x11
#define DVBSUB_CLUT_SEGMENT     0x12
#define DVBSUB_OBJECT_SEGMENT   0x13
31
#define DVBSUB_DISPLAYDEFINITION_SEGMENT 0x14
32 33
#define DVBSUB_DISPLAY_SEGMENT  0x80

34
#define cm (ff_cropTbl + MAX_NEG_CROP)
35

36
#ifdef DEBUG
37
#undef fprintf
38
#undef perror
39 40 41 42 43 44 45 46
#if 0
static void png_save(const char *filename, uint8_t *bitmap, int w, int h,
                     uint32_t *rgba_palette)
{
    int x, y, v;
    FILE *f;
    char fname[40], fname2[40];
    char command[1024];
47

48 49 50 51 52
    snprintf(fname, 40, "%s.ppm", filename);

    f = fopen(fname, "w");
    if (!f) {
        perror(fname);
53
        return;
54 55 56 57 58 59 60 61 62 63 64 65 66 67
    }
    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);
68 69


70 71 72 73 74
    snprintf(fname2, 40, "%s-a.pgm", filename);

    f = fopen(fname2, "w");
    if (!f) {
        perror(fname2);
75
        return;
76 77 78 79 80 81 82 83 84 85 86 87
    }
    fprintf(f, "P5\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 >> 24) & 0xff, f);
        }
    }
    fclose(f);
88

89 90
    snprintf(command, 1024, "pnmtopng -alpha %s %s > %s.png 2> /dev/null", fname2, fname, filename);
    system(command);
91

92 93 94 95 96 97 98 99 100 101 102
    snprintf(command, 1024, "rm %s %s", fname, fname2);
    system(command);
}
#endif

static void png_save2(const char *filename, uint32_t *bitmap, int w, int h)
{
    int x, y, v;
    FILE *f;
    char fname[40], fname2[40];
    char command[1024];
103

104
    snprintf(fname, sizeof(fname), "%s.ppm", filename);
105 106 107 108

    f = fopen(fname, "w");
    if (!f) {
        perror(fname);
109
        return;
110 111 112 113 114 115 116 117 118 119 120 121 122 123
    }
    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 = bitmap[y * w + x];
            putc((v >> 16) & 0xff, f);
            putc((v >> 8) & 0xff, f);
            putc((v >> 0) & 0xff, f);
        }
    }
    fclose(f);
124 125


126
    snprintf(fname2, sizeof(fname2), "%s-a.pgm", filename);
127 128 129 130

    f = fopen(fname2, "w");
    if (!f) {
        perror(fname2);
131
        return;
132 133 134 135 136 137 138 139 140 141 142 143
    }
    fprintf(f, "P5\n"
            "%d %d\n"
            "%d\n",
            w, h, 255);
    for(y = 0; y < h; y++) {
        for(x = 0; x < w; x++) {
            v = bitmap[y * w + x];
            putc((v >> 24) & 0xff, f);
        }
    }
    fclose(f);
144

145
    snprintf(command, sizeof(command), "pnmtopng -alpha %s %s > %s.png 2> /dev/null", fname2, fname, filename);
146
    system(command);
147

148
    snprintf(command, sizeof(command), "rm %s %s", fname, fname2);
149 150 151 152
    system(command);
}
#endif

153
#define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
154 155 156

typedef struct DVBSubCLUT {
    int id;
157
    int version;
158 159 160 161

    uint32_t clut4[4];
    uint32_t clut16[16];
    uint32_t clut256[256];
162

163 164 165 166 167 168 169 170 171 172 173 174
    struct DVBSubCLUT *next;
} DVBSubCLUT;

static DVBSubCLUT default_clut;

typedef struct DVBSubObjectDisplay {
    int object_id;
    int region_id;

    int x_pos;
    int y_pos;

175 176
    int fgcolor;
    int bgcolor;
177

178
    struct DVBSubObjectDisplay *region_list_next;
179
    struct DVBSubObjectDisplay *object_list_next;
180 181 182 183
} DVBSubObjectDisplay;

typedef struct DVBSubObject {
    int id;
184
    int version;
185 186

    int type;
187 188 189

    DVBSubObjectDisplay *display_list;

190 191 192 193 194 195 196 197 198 199 200 201 202 203
    struct DVBSubObject *next;
} DVBSubObject;

typedef struct DVBSubRegionDisplay {
    int region_id;

    int x_pos;
    int y_pos;

    struct DVBSubRegionDisplay *next;
} DVBSubRegionDisplay;

typedef struct DVBSubRegion {
    int id;
204
    int version;
205 206 207 208

    int width;
    int height;
    int depth;
209

210
    int clut;
211
    int bgcolor;
212

213 214
    uint8_t *pbuf;
    int buf_size;
215
    int dirty;
216 217

    DVBSubObjectDisplay *display_list;
218

219 220 221
    struct DVBSubRegion *next;
} DVBSubRegion;

222 223 224 225 226 227 228 229 230
typedef struct DVBSubDisplayDefinition {
    int version;

    int x;
    int y;
    int width;
    int height;
} DVBSubDisplayDefinition;

231 232 233 234
typedef struct DVBSubContext {
    int composition_id;
    int ancillary_id;

235
    int version;
236 237 238 239
    int time_out;
    DVBSubRegion *region_list;
    DVBSubCLUT   *clut_list;
    DVBSubObject *object_list;
240

241 242
    int display_list_size;
    DVBSubRegionDisplay *display_list;
243
    DVBSubDisplayDefinition *display_definition;
244 245 246 247 248 249 250
} DVBSubContext;


static DVBSubObject* get_object(DVBSubContext *ctx, int object_id)
{
    DVBSubObject *ptr = ctx->object_list;

251
    while (ptr && ptr->id != object_id) {
252 253
        ptr = ptr->next;
    }
254

255 256 257 258 259 260 261
    return ptr;
}

static DVBSubCLUT* get_clut(DVBSubContext *ctx, int clut_id)
{
    DVBSubCLUT *ptr = ctx->clut_list;

262
    while (ptr && ptr->id != clut_id) {
263 264
        ptr = ptr->next;
    }
265

266 267 268 269 270 271 272
    return ptr;
}

static DVBSubRegion* get_region(DVBSubContext *ctx, int region_id)
{
    DVBSubRegion *ptr = ctx->region_list;

273
    while (ptr && ptr->id != region_id) {
274 275
        ptr = ptr->next;
    }
276

277 278 279 280 281 282 283 284
    return ptr;
}

static void delete_region_display_list(DVBSubContext *ctx, DVBSubRegion *region)
{
    DVBSubObject *object, *obj2, **obj2_ptr;
    DVBSubObjectDisplay *display, *obj_disp, **obj_disp_ptr;

285
    while (region->display_list) {
286
        display = region->display_list;
287

288
        object = get_object(ctx, display->object_id);
289

290
        if (object) {
291
            obj_disp_ptr = &object->display_list;
292
            obj_disp = *obj_disp_ptr;
293

294
            while (obj_disp && obj_disp != display) {
295
                obj_disp_ptr = &obj_disp->object_list_next;
296
                obj_disp = *obj_disp_ptr;
297
            }
298

299 300
            if (obj_disp) {
                *obj_disp_ptr = obj_disp->object_list_next;
301

302
                if (!object->display_list) {
303
                    obj2_ptr = &ctx->object_list;
304
                    obj2 = *obj2_ptr;
305

Michael Niedermayer's avatar
Michael Niedermayer committed
306 307
                    while (obj2 != object) {
                        assert(obj2);
308
                        obj2_ptr = &obj2->next;
309
                        obj2 = *obj2_ptr;
310
                    }
311

312
                    *obj2_ptr = obj2->next;
313

314 315 316 317
                    av_free(obj2);
                }
            }
        }
318

319
        region->display_list = display->region_list_next;
320

321 322
        av_free(display);
    }
323

324 325
}

326
static void delete_cluts(DVBSubContext *ctx)
327 328
{
    DVBSubCLUT *clut;
329

330
    while (ctx->clut_list) {
331 332 333 334 335 336
        clut = ctx->clut_list;

        ctx->clut_list = clut->next;

        av_free(clut);
    }
337
}
338

339 340 341
static void delete_objects(DVBSubContext *ctx)
{
    DVBSubObject *object;
342

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
    while (ctx->object_list) {
        object = ctx->object_list;

        ctx->object_list = object->next;

        av_free(object);
    }
}

static void delete_regions(DVBSubContext *ctx)
{
    DVBSubRegion *region;

    while (ctx->region_list) {
        region = ctx->region_list;

        ctx->region_list = region->next;

        delete_region_display_list(ctx, region);

        av_free(region->pbuf);
        av_free(region);
    }
366 367
}

368
static av_cold int dvbsub_init_decoder(AVCodecContext *avctx)
369 370
{
    int i, r, g, b, a = 0;
371
    DVBSubContext *ctx = avctx->priv_data;
372

373 374 375 376 377 378 379 380
    if (!avctx->extradata || avctx->extradata_size != 4) {
        av_log(avctx, AV_LOG_WARNING, "Invalid extradata, subtitle streams may be combined!\n");
        ctx->composition_id = -1;
        ctx->ancillary_id   = -1;
    } else {
        ctx->composition_id = AV_RB16(avctx->extradata);
        ctx->ancillary_id   = AV_RB16(avctx->extradata + 2);
    }
381

382 383
    ctx->version = -1;

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
    default_clut.id = -1;
    default_clut.next = NULL;

    default_clut.clut4[0] = RGBA(  0,   0,   0,   0);
    default_clut.clut4[1] = RGBA(255, 255, 255, 255);
    default_clut.clut4[2] = RGBA(  0,   0,   0, 255);
    default_clut.clut4[3] = RGBA(127, 127, 127, 255);

    default_clut.clut16[0] = RGBA(  0,   0,   0,   0);
    for (i = 1; i < 16; i++) {
        if (i < 8) {
            r = (i & 1) ? 255 : 0;
            g = (i & 2) ? 255 : 0;
            b = (i & 4) ? 255 : 0;
        } else {
            r = (i & 1) ? 127 : 0;
            g = (i & 2) ? 127 : 0;
            b = (i & 4) ? 127 : 0;
402
        }
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
        default_clut.clut16[i] = RGBA(r, g, b, 255);
    }

    default_clut.clut256[0] = RGBA(  0,   0,   0,   0);
    for (i = 1; i < 256; i++) {
        if (i < 8) {
            r = (i & 1) ? 255 : 0;
            g = (i & 2) ? 255 : 0;
            b = (i & 4) ? 255 : 0;
            a = 63;
        } else {
            switch (i & 0x88) {
            case 0x00:
                r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
                g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
                b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
                a = 255;
                break;
            case 0x08:
                r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
                g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
                b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
                a = 127;
                break;
            case 0x80:
                r = 127 + ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
                g = 127 + ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
                b = 127 + ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
                a = 255;
                break;
            case 0x88:
                r = ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
                g = ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
                b = ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
                a = 255;
                break;
            }
440
        }
441 442 443 444 445 446
        default_clut.clut256[i] = RGBA(r, g, b, a);
    }

    return 0;
}

447
static av_cold int dvbsub_close_decoder(AVCodecContext *avctx)
448
{
449
    DVBSubContext *ctx = avctx->priv_data;
450 451
    DVBSubRegionDisplay *display;

452 453 454 455 456 457 458
    delete_regions(ctx);

    delete_objects(ctx);

    delete_cluts(ctx);

    av_freep(&ctx->display_definition);
459

460
    while (ctx->display_list) {
461 462
        display = ctx->display_list;
        ctx->display_list = display->next;
463

464 465 466 467 468 469
        av_free(display);
    }

    return 0;
}

470
static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
Michael Niedermayer's avatar
Michael Niedermayer committed
471
                                   const uint8_t **srcbuf, int buf_size,
472
                                   int non_mod, uint8_t *map_table, int x_pos)
473 474
{
    GetBitContext gb;
475

476 477
    int bits;
    int run_length;
478
    int pixels_read = x_pos;
479

480
    init_get_bits(&gb, *srcbuf, buf_size << 3);
481

482 483
    destbuf += x_pos;

484
    while (get_bits_count(&gb) < buf_size << 3 && pixels_read < dbuf_len) {
485 486
        bits = get_bits(&gb, 2);

487
        if (bits) {
488
            if (non_mod != 1 || bits != 1) {
489
                if (map_table)
490 491 492 493 494 495
                    *destbuf++ = map_table[bits];
                else
                    *destbuf++ = bits;
            }
            pixels_read++;
        } else {
496
            bits = get_bits1(&gb);
497 498 499
            if (bits == 1) {
                run_length = get_bits(&gb, 3) + 3;
                bits = get_bits(&gb, 2);
500

501 502 503
                if (non_mod == 1 && bits == 1)
                    pixels_read += run_length;
                else {
504
                    if (map_table)
505 506 507 508 509 510 511
                        bits = map_table[bits];
                    while (run_length-- > 0 && pixels_read < dbuf_len) {
                        *destbuf++ = bits;
                        pixels_read++;
                    }
                }
            } else {
512
                bits = get_bits1(&gb);
513 514 515 516 517 518 519 520 521
                if (bits == 0) {
                    bits = get_bits(&gb, 2);
                    if (bits == 2) {
                        run_length = get_bits(&gb, 4) + 12;
                        bits = get_bits(&gb, 2);

                        if (non_mod == 1 && bits == 1)
                            pixels_read += run_length;
                        else {
522
                            if (map_table)
523 524 525 526 527 528 529 530 531 532 533 534 535
                                bits = map_table[bits];
                            while (run_length-- > 0 && pixels_read < dbuf_len) {
                                *destbuf++ = bits;
                                pixels_read++;
                            }
                        }
                    } else if (bits == 3) {
                        run_length = get_bits(&gb, 8) + 29;
                        bits = get_bits(&gb, 2);

                        if (non_mod == 1 && bits == 1)
                            pixels_read += run_length;
                        else {
536
                            if (map_table)
537 538 539 540 541 542 543
                                bits = map_table[bits];
                            while (run_length-- > 0 && pixels_read < dbuf_len) {
                                *destbuf++ = bits;
                                pixels_read++;
                            }
                        }
                    } else if (bits == 1) {
544
                        if (map_table)
545 546 547
                            bits = map_table[0];
                        else
                            bits = 0;
548 549
                        run_length = 2;
                        while (run_length-- > 0 && pixels_read < dbuf_len) {
550
                            *destbuf++ = bits;
551
                            pixels_read++;
552 553 554 555 556 557
                        }
                    } else {
                        (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
                        return pixels_read;
                    }
                } else {
558
                    if (map_table)
559 560 561 562 563 564 565 566 567
                        bits = map_table[0];
                    else
                        bits = 0;
                    *destbuf++ = bits;
                    pixels_read++;
                }
            }
        }
    }
568

569
    if (get_bits(&gb, 6))
570 571 572 573 574 575
        av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");

    (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;

    return pixels_read;
}
576 577

static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
Michael Niedermayer's avatar
Michael Niedermayer committed
578
                                   const uint8_t **srcbuf, int buf_size,
579
                                   int non_mod, uint8_t *map_table, int x_pos)
580 581
{
    GetBitContext gb;
582

583 584
    int bits;
    int run_length;
585
    int pixels_read = x_pos;
586

587
    init_get_bits(&gb, *srcbuf, buf_size << 3);
588

589 590
    destbuf += x_pos;

591
    while (get_bits_count(&gb) < buf_size << 3 && pixels_read < dbuf_len) {
592 593
        bits = get_bits(&gb, 4);

594
        if (bits) {
595
            if (non_mod != 1 || bits != 1) {
596
                if (map_table)
597 598 599 600 601 602
                    *destbuf++ = map_table[bits];
                else
                    *destbuf++ = bits;
            }
            pixels_read++;
        } else {
603
            bits = get_bits1(&gb);
604 605
            if (bits == 0) {
                run_length = get_bits(&gb, 3);
606

607 608 609 610
                if (run_length == 0) {
                    (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
                    return pixels_read;
                }
611

612
                run_length += 2;
613

614
                if (map_table)
615 616 617
                    bits = map_table[0];
                else
                    bits = 0;
618

619 620 621 622 623
                while (run_length-- > 0 && pixels_read < dbuf_len) {
                    *destbuf++ = bits;
                    pixels_read++;
                }
            } else {
624
                bits = get_bits1(&gb);
625 626 627 628 629 630 631
                if (bits == 0) {
                    run_length = get_bits(&gb, 2) + 4;
                    bits = get_bits(&gb, 4);

                    if (non_mod == 1 && bits == 1)
                        pixels_read += run_length;
                    else {
632
                        if (map_table)
633 634 635 636 637 638 639 640 641 642 643
                            bits = map_table[bits];
                        while (run_length-- > 0 && pixels_read < dbuf_len) {
                            *destbuf++ = bits;
                            pixels_read++;
                        }
                    }
                } else {
                    bits = get_bits(&gb, 2);
                    if (bits == 2) {
                        run_length = get_bits(&gb, 4) + 9;
                        bits = get_bits(&gb, 4);
644

645 646 647
                        if (non_mod == 1 && bits == 1)
                            pixels_read += run_length;
                        else {
648
                            if (map_table)
649 650 651 652 653 654 655 656 657 658 659 660 661
                                bits = map_table[bits];
                            while (run_length-- > 0 && pixels_read < dbuf_len) {
                                *destbuf++ = bits;
                                pixels_read++;
                            }
                        }
                    } else if (bits == 3) {
                        run_length = get_bits(&gb, 8) + 25;
                        bits = get_bits(&gb, 4);

                        if (non_mod == 1 && bits == 1)
                            pixels_read += run_length;
                        else {
662
                            if (map_table)
663 664 665 666 667 668 669
                                bits = map_table[bits];
                            while (run_length-- > 0 && pixels_read < dbuf_len) {
                                *destbuf++ = bits;
                                pixels_read++;
                            }
                        }
                    } else if (bits == 1) {
670
                        if (map_table)
671 672 673
                            bits = map_table[0];
                        else
                            bits = 0;
674 675
                        run_length = 2;
                        while (run_length-- > 0 && pixels_read < dbuf_len) {
676
                            *destbuf++ = bits;
677
                            pixels_read++;
678 679
                        }
                    } else {
680
                        if (map_table)
681 682 683 684 685 686 687 688 689 690
                            bits = map_table[0];
                        else
                            bits = 0;
                        *destbuf++ = bits;
                        pixels_read ++;
                    }
                }
            }
        }
    }
691

692
    if (get_bits(&gb, 8))
693
        av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");
694

695 696 697 698
    (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;

    return pixels_read;
}
699 700

static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len,
Michael Niedermayer's avatar
Michael Niedermayer committed
701
                                    const uint8_t **srcbuf, int buf_size,
702
                                    int non_mod, uint8_t *map_table, int x_pos)
703
{
Michael Niedermayer's avatar
Michael Niedermayer committed
704
    const uint8_t *sbuf_end = (*srcbuf) + buf_size;
705 706
    int bits;
    int run_length;
707 708 709
    int pixels_read = x_pos;

    destbuf += x_pos;
710

711 712
    while (*srcbuf < sbuf_end && pixels_read < dbuf_len) {
        bits = *(*srcbuf)++;
713

714
        if (bits) {
715
            if (non_mod != 1 || bits != 1) {
716
                if (map_table)
717 718 719 720 721 722 723 724 725 726 727 728
                    *destbuf++ = map_table[bits];
                else
                    *destbuf++ = bits;
            }
            pixels_read++;
        } else {
            bits = *(*srcbuf)++;
            run_length = bits & 0x7f;
            if ((bits & 0x80) == 0) {
                if (run_length == 0) {
                    return pixels_read;
                }
729

730
                if (map_table)
731 732 733 734 735 736 737 738 739 740 741 742
                    bits = map_table[0];
                else
                    bits = 0;
                while (run_length-- > 0 && pixels_read < dbuf_len) {
                    *destbuf++ = bits;
                    pixels_read++;
                }
            } else {
                bits = *(*srcbuf)++;

                if (non_mod == 1 && bits == 1)
                    pixels_read += run_length;
743
                if (map_table)
744 745 746 747 748 749 750 751
                    bits = map_table[bits];
                else while (run_length-- > 0 && pixels_read < dbuf_len) {
                    *destbuf++ = bits;
                    pixels_read++;
                }
            }
        }
    }
752

753
    if (*(*srcbuf)++)
754
        av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");
755

756 757
    return pixels_read;
}
758

759 760 761


static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDisplay *display,
Michael Niedermayer's avatar
Michael Niedermayer committed
762
                                          const uint8_t *buf, int buf_size, int top_bottom, int non_mod)
763
{
764
    DVBSubContext *ctx = avctx->priv_data;
765 766

    DVBSubRegion *region = get_region(ctx, display->region_id);
Michael Niedermayer's avatar
Michael Niedermayer committed
767
    const uint8_t *buf_end = buf + buf_size;
768 769 770
    uint8_t *pbuf;
    int x_pos, y_pos;
    int i;
771

772 773
    uint8_t map2to4[] = { 0x0,  0x7,  0x8,  0xf};
    uint8_t map2to8[] = {0x00, 0x77, 0x88, 0xff};
774
    uint8_t map4to8[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
775 776
                         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
    uint8_t *map_table;
777

778
#if 0
779
    av_dlog(avctx, "DVB pixel block size %d, %s field:\n", buf_size,
780
            top_bottom ? "bottom" : "top");
781

782
    for (i = 0; i < buf_size; i++) {
783
        if (i % 16 == 0)
784
            av_dlog(avctx, "0x%8p: ", buf+i);
785

786
        av_dlog(avctx, "%02x ", buf[i]);
787
        if (i % 16 == 15)
788
            av_dlog(avctx, "\n");
789
    }
790

791
    if (i % 16)
792
        av_dlog(avctx, "\n");
793
#endif
794 795 796

    if (region == 0)
        return;
797

798
    pbuf = region->pbuf;
799
    region->dirty = 1;
800

801 802
    x_pos = display->x_pos;
    y_pos = display->y_pos;
803

804
    y_pos += top_bottom;
805 806

    while (buf < buf_end) {
807
        if ((*buf!=0xf0 && x_pos >= region->width) || y_pos >= region->height) {
808
            av_log(avctx, AV_LOG_ERROR, "Invalid object location! %d-%d %d-%d %02x\n", x_pos, region->width, y_pos, region->height, *buf);
809 810
            return;
        }
811

812 813 814 815 816 817 818 819
        switch (*buf++) {
        case 0x10:
            if (region->depth == 8)
                map_table = map2to8;
            else if (region->depth == 4)
                map_table = map2to4;
            else
                map_table = NULL;
820

821 822 823
            x_pos = dvbsub_read_2bit_string(pbuf + (y_pos * region->width),
                                            region->width, &buf, buf_end - buf,
                                            non_mod, map_table, x_pos);
824 825 826 827 828 829
            break;
        case 0x11:
            if (region->depth < 4) {
                av_log(avctx, AV_LOG_ERROR, "4-bit pixel string in %d-bit region!\n", region->depth);
                return;
            }
830

831 832 833 834
            if (region->depth == 8)
                map_table = map4to8;
            else
                map_table = NULL;
835

836 837 838
            x_pos = dvbsub_read_4bit_string(pbuf + (y_pos * region->width),
                                            region->width, &buf, buf_end - buf,
                                            non_mod, map_table, x_pos);
839 840 841 842 843 844
            break;
        case 0x12:
            if (region->depth < 8) {
                av_log(avctx, AV_LOG_ERROR, "8-bit pixel string in %d-bit region!\n", region->depth);
                return;
            }
845

846 847 848
            x_pos = dvbsub_read_8bit_string(pbuf + (y_pos * region->width),
                                            region->width, &buf, buf_end - buf,
                                            non_mod, NULL, x_pos);
849
            break;
850

851 852 853 854 855 856 857 858 859 860 861 862 863 864
        case 0x20:
            map2to4[0] = (*buf) >> 4;
            map2to4[1] = (*buf++) & 0xf;
            map2to4[2] = (*buf) >> 4;
            map2to4[3] = (*buf++) & 0xf;
            break;
        case 0x21:
            for (i = 0; i < 4; i++)
                map2to8[i] = *buf++;
            break;
        case 0x22:
            for (i = 0; i < 16; i++)
                map4to8[i] = *buf++;
            break;
865

866 867 868 869 870 871 872 873
        case 0xf0:
            x_pos = display->x_pos;
            y_pos += 2;
            break;
        default:
            av_log(avctx, AV_LOG_INFO, "Unknown/unsupported pixel block 0x%x\n", *(buf-1));
        }
    }
874

875 876 877
}

static void dvbsub_parse_object_segment(AVCodecContext *avctx,
Michael Niedermayer's avatar
Michael Niedermayer committed
878
                                        const uint8_t *buf, int buf_size)
879
{
880
    DVBSubContext *ctx = avctx->priv_data;
881

Michael Niedermayer's avatar
Michael Niedermayer committed
882
    const uint8_t *buf_end = buf + buf_size;
883 884 885 886
    int object_id;
    DVBSubObject *object;
    DVBSubObjectDisplay *display;
    int top_field_len, bottom_field_len;
887

888
    int coding_method, non_modifying_color;
889

890
    object_id = AV_RB16(buf);
891
    buf += 2;
892

893 894
    object = get_object(ctx, object_id);

895 896 897
    if (!object)
        return;

898
    coding_method = ((*buf) >> 2) & 3;
899
    non_modifying_color = ((*buf++) >> 1) & 1;
900

901
    if (coding_method == 0) {
902
        top_field_len = AV_RB16(buf);
903
        buf += 2;
904
        bottom_field_len = AV_RB16(buf);
905
        buf += 2;
906

907 908 909
        if (buf + top_field_len + bottom_field_len > buf_end) {
            av_log(avctx, AV_LOG_ERROR, "Field data size too large\n");
            return;
910 911
        }

912
        for (display = object->display_list; display; display = display->object_list_next) {
913 914
            const uint8_t *block = buf;
            int bfl = bottom_field_len;
915 916

            dvbsub_parse_pixel_data_block(avctx, display, block, top_field_len, 0,
917
                                            non_modifying_color);
918 919 920 921

            if (bottom_field_len > 0)
                block = buf + top_field_len;
            else
922
                bfl = top_field_len;
923

924
            dvbsub_parse_pixel_data_block(avctx, display, block, bfl, 1,
925
                                            non_modifying_color);
926
        }
927

928
/*  } else if (coding_method == 1) {*/
929

930 931 932
    } else {
        av_log(avctx, AV_LOG_ERROR, "Unknown object coding %d\n", coding_method);
    }
933

934 935 936
}

static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
Michael Niedermayer's avatar
Michael Niedermayer committed
937
                                        const uint8_t *buf, int buf_size)
938
{
939
    DVBSubContext *ctx = avctx->priv_data;
940

Michael Niedermayer's avatar
Michael Niedermayer committed
941
    const uint8_t *buf_end = buf + buf_size;
942
    int i, clut_id;
943
    int version;
944 945 946 947 948
    DVBSubCLUT *clut;
    int entry_id, depth , full_range;
    int y, cr, cb, alpha;
    int r, g, b, r_add, g_add, b_add;

949
    av_dlog(avctx, "DVB clut packet:\n");
950

951
    for (i=0; i < buf_size; i++) {
952
        av_dlog(avctx, "%02x ", buf[i]);
953
        if (i % 16 == 15)
954
            av_dlog(avctx, "\n");
955
    }
956

957
    if (i % 16)
958
        av_dlog(avctx, "\n");
959 960

    clut_id = *buf++;
961
    version = ((*buf)>>4)&15;
962
    buf += 1;
963

964
    clut = get_clut(ctx, clut_id);
965

966
    if (!clut) {
967
        clut = av_malloc(sizeof(DVBSubCLUT));
968

969 970 971
        memcpy(clut, &default_clut, sizeof(DVBSubCLUT));

        clut->id = clut_id;
972
        clut->version = -1;
973 974

        clut->next = ctx->clut_list;
975 976
        ctx->clut_list = clut;
    }
977

978 979 980 981
    if (clut->version != version) {

    clut->version = version;

982
    while (buf + 4 < buf_end) {
983
        entry_id = *buf++;
984

985
        depth = (*buf) & 0xe0;
986

987 988 989 990
        if (depth == 0) {
            av_log(avctx, AV_LOG_ERROR, "Invalid clut depth 0x%x!\n", *buf);
            return;
        }
991

992
        full_range = (*buf++) & 1;
993

994 995 996 997 998 999 1000 1001 1002 1003
        if (full_range) {
            y = *buf++;
            cr = *buf++;
            cb = *buf++;
            alpha = *buf++;
        } else {
            y = buf[0] & 0xfc;
            cr = (((buf[0] & 3) << 2) | ((buf[1] >> 6) & 3)) << 4;
            cb = (buf[1] << 2) & 0xf0;
            alpha = (buf[1] << 6) & 0xc0;
1004

1005 1006
            buf += 2;
        }
1007

1008 1009
        if (y == 0)
            alpha = 0xff;
1010

1011 1012
        YUV_TO_RGB1_CCIR(cb, cr);
        YUV_TO_RGB2_CCIR(r, g, b, y);
1013

1014
        av_dlog(avctx, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha);
1015

1016 1017 1018 1019 1020 1021 1022
        if (depth & 0x80)
            clut->clut4[entry_id] = RGBA(r,g,b,255 - alpha);
        if (depth & 0x40)
            clut->clut16[entry_id] = RGBA(r,g,b,255 - alpha);
        if (depth & 0x20)
            clut->clut256[entry_id] = RGBA(r,g,b,255 - alpha);
    }
1023
    }
1024 1025 1026 1027
}


static void dvbsub_parse_region_segment(AVCodecContext *avctx,
Michael Niedermayer's avatar
Michael Niedermayer committed
1028
                                        const uint8_t *buf, int buf_size)
1029
{
1030
    DVBSubContext *ctx = avctx->priv_data;
1031

Michael Niedermayer's avatar
Michael Niedermayer committed
1032
    const uint8_t *buf_end = buf + buf_size;
1033
    int region_id, object_id;
1034
    int av_unused version;
1035 1036 1037 1038
    DVBSubRegion *region;
    DVBSubObject *object;
    DVBSubObjectDisplay *display;
    int fill;
1039

1040 1041
    if (buf_size < 10)
        return;
1042

1043
    region_id = *buf++;
1044

1045
    region = get_region(ctx, region_id);
1046

1047
    if (!region) {
1048
        region = av_mallocz(sizeof(DVBSubRegion));
1049

1050
        region->id = region_id;
1051
        region->version = -1;
1052

1053 1054 1055
        region->next = ctx->region_list;
        ctx->region_list = region;
    }
1056

1057
    version = ((*buf)>>4) & 15;
1058
    fill = ((*buf++) >> 3) & 1;
1059

1060
    region->width = AV_RB16(buf);
1061
    buf += 2;
1062
    region->height = AV_RB16(buf);
1063
    buf += 2;
1064

1065
    if (region->width * region->height != region->buf_size) {
1066
        av_free(region->pbuf);
1067

1068
        region->buf_size = region->width * region->height;
1069

1070
        region->pbuf = av_malloc(region->buf_size);
1071

1072
        fill = 1;
1073
        region->dirty = 0;
1074
    }
1075

1076
    region->depth = 1 << (((*buf++) >> 2) & 7);
1077 1078 1079 1080
    if(region->depth<2 || region->depth>8){
        av_log(avctx, AV_LOG_ERROR, "region depth %d is invalid\n", region->depth);
        region->depth= 4;
    }
1081
    region->clut = *buf++;
1082

1083
    if (region->depth == 8) {
1084
        region->bgcolor = *buf++;
1085 1086
        buf += 1;
    } else {
1087
        buf += 1;
1088

1089
        if (region->depth == 4)
1090
            region->bgcolor = (((*buf++) >> 4) & 15);
1091
        else
1092
            region->bgcolor = (((*buf++) >> 2) & 3);
1093 1094
    }

1095
    av_dlog(avctx, "Region %d, (%dx%d)\n", region_id, region->width, region->height);
1096 1097

    if (fill) {
1098
        memset(region->pbuf, region->bgcolor, region->buf_size);
1099
        av_dlog(avctx, "Fill region (%d)\n", region->bgcolor);
1100 1101 1102 1103 1104
    }

    delete_region_display_list(ctx, region);

    while (buf + 5 < buf_end) {
1105
        object_id = AV_RB16(buf);
1106
        buf += 2;
1107

1108 1109
        object = get_object(ctx, object_id);

1110
        if (!object) {
1111
            object = av_mallocz(sizeof(DVBSubObject));
1112

1113 1114 1115 1116
            object->id = object_id;
            object->next = ctx->object_list;
            ctx->object_list = object;
        }
1117

1118
        object->type = (*buf) >> 6;
1119

1120
        display = av_mallocz(sizeof(DVBSubObjectDisplay));
1121

1122 1123
        display->object_id = object_id;
        display->region_id = region_id;
1124

1125
        display->x_pos = AV_RB16(buf) & 0xfff;
1126
        buf += 2;
1127
        display->y_pos = AV_RB16(buf) & 0xfff;
1128
        buf += 2;
1129

1130
        if ((object->type == 1 || object->type == 2) && buf+1 < buf_end) {
1131 1132
            display->fgcolor = *buf++;
            display->bgcolor = *buf++;
1133
        }
1134

1135 1136
        display->region_list_next = region->display_list;
        region->display_list = display;
1137

1138 1139 1140 1141 1142 1143
        display->object_list_next = object->display_list;
        object->display_list = display;
    }
}

static void dvbsub_parse_page_segment(AVCodecContext *avctx,
Michael Niedermayer's avatar
Michael Niedermayer committed
1144
                                        const uint8_t *buf, int buf_size)
1145
{
1146
    DVBSubContext *ctx = avctx->priv_data;
1147 1148
    DVBSubRegionDisplay *display;
    DVBSubRegionDisplay *tmp_display_list, **tmp_ptr;
1149

Michael Niedermayer's avatar
Michael Niedermayer committed
1150
    const uint8_t *buf_end = buf + buf_size;
1151 1152
    int region_id;
    int page_state;
1153 1154
    int timeout;
    int version;
1155

1156 1157
    if (buf_size < 1)
        return;
1158

1159 1160
    timeout = *buf++;
    version = ((*buf)>>4) & 15;
1161
    page_state = ((*buf++) >> 2) & 3;
1162

1163 1164 1165 1166 1167
    if (ctx->version != version) {

    ctx->time_out = timeout;
    ctx->version = version;

1168
    av_dlog(avctx, "Page time out %ds, state %d\n", ctx->time_out, page_state);
1169

1170
    if (page_state == 1 || page_state == 2) {
1171 1172 1173
        delete_regions(ctx);
        delete_objects(ctx);
        delete_cluts(ctx);
1174
    }
1175

1176 1177 1178
    tmp_display_list = ctx->display_list;
    ctx->display_list = NULL;
    ctx->display_list_size = 0;
1179

1180 1181 1182
    while (buf + 5 < buf_end) {
        region_id = *buf++;
        buf += 1;
1183

1184 1185
        display = tmp_display_list;
        tmp_ptr = &tmp_display_list;
1186

1187
        while (display && display->region_id != region_id) {
1188 1189 1190
            tmp_ptr = &display->next;
            display = display->next;
        }
1191

1192
        if (!display)
1193
            display = av_mallocz(sizeof(DVBSubRegionDisplay));
1194

1195
        display->region_id = region_id;
1196

1197
        display->x_pos = AV_RB16(buf);
1198
        buf += 2;
1199
        display->y_pos = AV_RB16(buf);
1200
        buf += 2;
1201

1202
        *tmp_ptr = display->next;
1203

1204 1205 1206
        display->next = ctx->display_list;
        ctx->display_list = display;
        ctx->display_list_size++;
1207

1208
        av_dlog(avctx, "Region %d, (%d,%d)\n", region_id, display->x_pos, display->y_pos);
1209
    }
1210

1211
    while (tmp_display_list) {
1212
        display = tmp_display_list;
1213

1214
        tmp_display_list = display->next;
1215

1216 1217
        av_free(display);
    }
1218
    }
1219

1220 1221 1222
}


1223
#ifdef DEBUG
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
static void save_display_set(DVBSubContext *ctx)
{
    DVBSubRegion *region;
    DVBSubRegionDisplay *display;
    DVBSubCLUT *clut;
    uint32_t *clut_table;
    int x_pos, y_pos, width, height;
    int x, y, y_off, x_off;
    uint32_t *pbuf;
    char filename[32];
    static int fileno_index = 0;

    x_pos = -1;
    y_pos = -1;
    width = 0;
    height = 0;
1240

1241
    for (display = ctx->display_list; display; display = display->next) {
1242
        region = get_region(ctx, display->region_id);
1243

1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
        if (x_pos == -1) {
            x_pos = display->x_pos;
            y_pos = display->y_pos;
            width = region->width;
            height = region->height;
        } else {
            if (display->x_pos < x_pos) {
                width += (x_pos - display->x_pos);
                x_pos = display->x_pos;
            }
1254

1255 1256 1257 1258
            if (display->y_pos < y_pos) {
                height += (y_pos - display->y_pos);
                y_pos = display->y_pos;
            }
1259

1260 1261 1262
            if (display->x_pos + region->width > x_pos + width) {
                width = display->x_pos + region->width - x_pos;
            }
1263

1264 1265 1266 1267 1268
            if (display->y_pos + region->height > y_pos + height) {
                height = display->y_pos + region->height - y_pos;
            }
        }
    }
1269

1270
    if (x_pos >= 0) {
1271

1272 1273
        pbuf = av_malloc(width * height * 4);

1274
        for (display = ctx->display_list; display; display = display->next) {
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
            region = get_region(ctx, display->region_id);

            x_off = display->x_pos - x_pos;
            y_off = display->y_pos - y_pos;

            clut = get_clut(ctx, region->clut);

            if (clut == 0)
                clut = &default_clut;

            switch (region->depth) {
            case 2:
                clut_table = clut->clut4;
                break;
            case 8:
                clut_table = clut->clut256;
                break;
            case 4:
            default:
                clut_table = clut->clut16;
                break;
            }
1297

1298 1299
            for (y = 0; y < region->height; y++) {
                for (x = 0; x < region->width; x++) {
1300
                    pbuf[((y + y_off) * width) + x_off + x] =
1301 1302 1303 1304
                        clut_table[region->pbuf[y * region->width + x]];
                }
            }

1305
        }
1306

1307
        snprintf(filename, sizeof(filename), "dvbs.%d", fileno_index);
1308 1309 1310 1311 1312

        png_save2(filename, pbuf, width, height);

        av_free(pbuf);
    }
1313

1314 1315 1316 1317
    fileno_index++;
}
#endif

1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
static void dvbsub_parse_display_definition_segment(AVCodecContext *avctx,
                                                    const uint8_t *buf,
                                                    int buf_size)
{
    DVBSubContext *ctx = avctx->priv_data;
    DVBSubDisplayDefinition *display_def = ctx->display_definition;
    int dds_version, info_byte;

    if (buf_size < 5)
        return;

    info_byte   = bytestream_get_byte(&buf);
    dds_version = info_byte >> 4;
    if (display_def && display_def->version == dds_version)
        return; // already have this display definition version

    if (!display_def) {
        display_def             = av_mallocz(sizeof(*display_def));
        ctx->display_definition = display_def;
    }
    if (!display_def)
        return;

    display_def->version = dds_version;
    display_def->x       = 0;
    display_def->y       = 0;
    display_def->width   = bytestream_get_be16(&buf) + 1;
    display_def->height  = bytestream_get_be16(&buf) + 1;
1346 1347 1348 1349
    if (!avctx->width || !avctx->height) {
        avctx->width  = display_def->width;
        avctx->height = display_def->height;
    }
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361

    if (buf_size < 13)
        return;

    if (info_byte & 1<<3) { // display_window_flag
        display_def->x = bytestream_get_be16(&buf);
        display_def->y = bytestream_get_be16(&buf);
        display_def->width  = bytestream_get_be16(&buf) - display_def->x + 1;
        display_def->height = bytestream_get_be16(&buf) - display_def->y + 1;
    }
}

Michael Niedermayer's avatar
Michael Niedermayer committed
1362
static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
1363 1364
                                        int buf_size, AVSubtitle *sub)
{
1365
    DVBSubContext *ctx = avctx->priv_data;
1366
    DVBSubDisplayDefinition *display_def = ctx->display_definition;
1367 1368 1369 1370 1371 1372 1373

    DVBSubRegion *region;
    DVBSubRegionDisplay *display;
    AVSubtitleRect *rect;
    DVBSubCLUT *clut;
    uint32_t *clut_table;
    int i;
1374
    int offset_x=0, offset_y=0;
1375

1376 1377
    sub->end_display_time = ctx->time_out * 1000;

1378 1379 1380 1381 1382
    if (display_def) {
        offset_x = display_def->x;
        offset_y = display_def->y;
    }

1383
    sub->num_rects = ctx->display_list_size;
1384

1385 1386 1387 1388
    if (sub->num_rects > 0){
        sub->rects = av_mallocz(sizeof(*sub->rects) * sub->num_rects);
        for(i=0; i<sub->num_rects; i++)
            sub->rects[i] = av_mallocz(sizeof(*sub->rects[i]));
1389 1390 1391

    i = 0;

1392
    for (display = ctx->display_list; display; display = display->next) {
1393
        region = get_region(ctx, display->region_id);
1394

1395
        if (!region)
1396
            continue;
1397

1398 1399 1400 1401
        if (!region->dirty)
            continue;

        rect = sub->rects[i];
1402 1403
        rect->x = display->x_pos + offset_x;
        rect->y = display->y_pos + offset_y;
1404 1405
        rect->w = region->width;
        rect->h = region->height;
1406
        rect->nb_colors = (1 << region->depth);
1407
        rect->type      = SUBTITLE_BITMAP;
1408
        rect->pict.linesize[0] = region->width;
1409 1410

        clut = get_clut(ctx, region->clut);
1411

1412
        if (!clut)
1413
            clut = &default_clut;
1414

1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426
        switch (region->depth) {
        case 2:
            clut_table = clut->clut4;
            break;
        case 8:
            clut_table = clut->clut256;
            break;
        case 4:
        default:
            clut_table = clut->clut16;
            break;
        }
1427

1428
        rect->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
1429
        memcpy(rect->pict.data[1], clut_table, (1 << region->depth) * sizeof(uint32_t));
1430

1431 1432
        rect->pict.data[0] = av_malloc(region->buf_size);
        memcpy(rect->pict.data[0], region->pbuf, region->buf_size);
1433

1434 1435
        i++;
    }
1436

1437
    sub->num_rects = i;
1438
    }
1439
#ifdef DEBUG
1440 1441
    save_display_set(ctx);
#endif
1442

1443 1444 1445 1446 1447
    return 1;
}

static int dvbsub_decode(AVCodecContext *avctx,
                         void *data, int *data_size,
1448
                         AVPacket *avpkt)
1449
{
1450 1451
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
1452 1453
    DVBSubContext *ctx = avctx->priv_data;
    AVSubtitle *sub = data;
Michael Niedermayer's avatar
Michael Niedermayer committed
1454
    const uint8_t *p, *p_end;
1455 1456 1457 1458
    int segment_type;
    int page_id;
    int segment_length;
    int i;
1459
    int got_segment = 0;
1460

1461
    av_dlog(avctx, "DVB sub packet:\n");
1462

1463
    for (i=0; i < buf_size; i++) {
1464
        av_dlog(avctx, "%02x ", buf[i]);
1465
        if (i % 16 == 15)
1466
            av_dlog(avctx, "\n");
1467
    }
1468

1469
    if (i % 16)
1470
        av_dlog(avctx, "\n");
1471

1472 1473
    if (buf_size <= 6 || *buf != 0x0f) {
        av_dlog(avctx, "incomplete or broken packet");
1474
        return -1;
1475
    }
1476

1477 1478
    p = buf;
    p_end = buf + buf_size;
1479

1480
    while (p_end - p >= 6 && *p == 0x0f) {
1481 1482
        p += 1;
        segment_type = *p++;
1483
        page_id = AV_RB16(p);
1484
        p += 2;
1485
        segment_length = AV_RB16(p);
1486
        p += 2;
1487

1488 1489 1490 1491 1492
        if (p_end - p < segment_length) {
            av_dlog(avctx, "incomplete or broken packet");
            return -1;
        }

1493 1494
        if (page_id == ctx->composition_id || page_id == ctx->ancillary_id ||
            ctx->composition_id == -1 || ctx->ancillary_id == -1) {
1495 1496 1497
            switch (segment_type) {
            case DVBSUB_PAGE_SEGMENT:
                dvbsub_parse_page_segment(avctx, p, segment_length);
1498
                got_segment |= 1;
1499 1500 1501
                break;
            case DVBSUB_REGION_SEGMENT:
                dvbsub_parse_region_segment(avctx, p, segment_length);
1502
                got_segment |= 2;
1503 1504 1505
                break;
            case DVBSUB_CLUT_SEGMENT:
                dvbsub_parse_clut_segment(avctx, p, segment_length);
1506
                got_segment |= 4;
1507 1508 1509
                break;
            case DVBSUB_OBJECT_SEGMENT:
                dvbsub_parse_object_segment(avctx, p, segment_length);
1510
                got_segment |= 8;
1511
                break;
1512 1513
            case DVBSUB_DISPLAYDEFINITION_SEGMENT:
                dvbsub_parse_display_definition_segment(avctx, p, segment_length);
1514
                break;
1515 1516
            case DVBSUB_DISPLAY_SEGMENT:
                *data_size = dvbsub_display_end_segment(avctx, p, segment_length, sub);
1517
                got_segment |= 16;
1518 1519
                break;
            default:
1520
                av_dlog(avctx, "Subtitling segment type 0x%x, page id %d, length %d\n",
1521 1522 1523 1524 1525 1526 1527
                        segment_type, page_id, segment_length);
                break;
            }
        }

        p += segment_length;
    }
1528 1529 1530 1531
    // Some streams do not send a display segment but if we have all the other
    // segments then we need no further data.
    if (got_segment == 15 && sub)
        *data_size = dvbsub_display_end_segment(avctx, p, 0, sub);
1532

1533
    return p - buf;
1534 1535 1536
}


1537
AVCodec ff_dvbsub_decoder = {
1538 1539
    .name           = "dvbsub",
    .type           = AVMEDIA_TYPE_SUBTITLE,
1540
    .id             = AV_CODEC_ID_DVB_SUBTITLE,
1541 1542 1543 1544
    .priv_data_size = sizeof(DVBSubContext),
    .init           = dvbsub_init_decoder,
    .close          = dvbsub_close_decoder,
    .decode         = dvbsub_decode,
1545
    .long_name      = NULL_IF_CONFIG_SMALL("DVB subtitles"),
1546
};