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