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