1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2012 Clément Bœsch 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14cabdff1aSopenharmony_ci * Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci/** 22cabdff1aSopenharmony_ci * @file 23cabdff1aSopenharmony_ci * MicroDVD subtitle decoder 24cabdff1aSopenharmony_ci * 25cabdff1aSopenharmony_ci * Based on the specifications found here: 26cabdff1aSopenharmony_ci * https://trac.videolan.org/vlc/ticket/1825#comment:6 27cabdff1aSopenharmony_ci */ 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 30cabdff1aSopenharmony_ci#include "libavutil/parseutils.h" 31cabdff1aSopenharmony_ci#include "libavutil/bprint.h" 32cabdff1aSopenharmony_ci#include "avcodec.h" 33cabdff1aSopenharmony_ci#include "ass.h" 34cabdff1aSopenharmony_ci#include "codec_internal.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_cistatic int indexof(const char *s, int c) 37cabdff1aSopenharmony_ci{ 38cabdff1aSopenharmony_ci char *f = strchr(s, c); 39cabdff1aSopenharmony_ci return f ? (f - s) : -1; 40cabdff1aSopenharmony_ci} 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_cistruct microdvd_tag { 43cabdff1aSopenharmony_ci char key; 44cabdff1aSopenharmony_ci int persistent; 45cabdff1aSopenharmony_ci uint32_t data1; 46cabdff1aSopenharmony_ci uint32_t data2; 47cabdff1aSopenharmony_ci char *data_string; 48cabdff1aSopenharmony_ci int data_string_len; 49cabdff1aSopenharmony_ci}; 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_ci#define MICRODVD_PERSISTENT_OFF 0 52cabdff1aSopenharmony_ci#define MICRODVD_PERSISTENT_ON 1 53cabdff1aSopenharmony_ci#define MICRODVD_PERSISTENT_OPENED 2 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_ci// Color, Font, Size, cHarset, stYle, Position, cOordinate 56cabdff1aSopenharmony_ci#define MICRODVD_TAGS "cfshyYpo" 57cabdff1aSopenharmony_ci 58cabdff1aSopenharmony_cistatic void microdvd_set_tag(struct microdvd_tag *tags, struct microdvd_tag tag) 59cabdff1aSopenharmony_ci{ 60cabdff1aSopenharmony_ci int tag_index = indexof(MICRODVD_TAGS, tag.key); 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci if (tag_index < 0) 63cabdff1aSopenharmony_ci return; 64cabdff1aSopenharmony_ci memcpy(&tags[tag_index], &tag, sizeof(tag)); 65cabdff1aSopenharmony_ci} 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci// italic, bold, underline, strike-through 68cabdff1aSopenharmony_ci#define MICRODVD_STYLES "ibus" 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci/* some samples have lines that start with a / indicating non persistent italic 71cabdff1aSopenharmony_ci * marker */ 72cabdff1aSopenharmony_cistatic char *check_for_italic_slash_marker(struct microdvd_tag *tags, char *s) 73cabdff1aSopenharmony_ci{ 74cabdff1aSopenharmony_ci if (*s == '/') { 75cabdff1aSopenharmony_ci struct microdvd_tag tag = tags[indexof(MICRODVD_TAGS, 'y')]; 76cabdff1aSopenharmony_ci tag.key = 'y'; 77cabdff1aSopenharmony_ci tag.data1 |= 1 << 0 /* 'i' position in MICRODVD_STYLES */; 78cabdff1aSopenharmony_ci microdvd_set_tag(tags, tag); 79cabdff1aSopenharmony_ci s++; 80cabdff1aSopenharmony_ci } 81cabdff1aSopenharmony_ci return s; 82cabdff1aSopenharmony_ci} 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_cistatic char *microdvd_load_tags(struct microdvd_tag *tags, char *s) 85cabdff1aSopenharmony_ci{ 86cabdff1aSopenharmony_ci s = check_for_italic_slash_marker(tags, s); 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci while (*s == '{') { 89cabdff1aSopenharmony_ci char *start = s; 90cabdff1aSopenharmony_ci char tag_char = *(s + 1); 91cabdff1aSopenharmony_ci struct microdvd_tag tag = {0}; 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci if (!tag_char || *(s + 2) != ':') 94cabdff1aSopenharmony_ci break; 95cabdff1aSopenharmony_ci s += 3; 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci switch (tag_char) { 98cabdff1aSopenharmony_ci 99cabdff1aSopenharmony_ci /* Style */ 100cabdff1aSopenharmony_ci case 'Y': 101cabdff1aSopenharmony_ci tag.persistent = MICRODVD_PERSISTENT_ON; 102cabdff1aSopenharmony_ci case 'y': 103cabdff1aSopenharmony_ci while (*s && *s != '}' && s - start < 256) { 104cabdff1aSopenharmony_ci int style_index = indexof(MICRODVD_STYLES, *s); 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci if (style_index >= 0) 107cabdff1aSopenharmony_ci tag.data1 |= (1 << style_index); 108cabdff1aSopenharmony_ci s++; 109cabdff1aSopenharmony_ci } 110cabdff1aSopenharmony_ci if (*s != '}') 111cabdff1aSopenharmony_ci break; 112cabdff1aSopenharmony_ci /* We must distinguish persistent and non-persistent styles 113cabdff1aSopenharmony_ci * to handle this kind of style tags: {y:ib}{Y:us} */ 114cabdff1aSopenharmony_ci tag.key = tag_char; 115cabdff1aSopenharmony_ci break; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci /* Color */ 118cabdff1aSopenharmony_ci case 'C': 119cabdff1aSopenharmony_ci tag.persistent = MICRODVD_PERSISTENT_ON; 120cabdff1aSopenharmony_ci case 'c': 121cabdff1aSopenharmony_ci while (*s == '$' || *s == '#') 122cabdff1aSopenharmony_ci s++; 123cabdff1aSopenharmony_ci tag.data1 = strtol(s, &s, 16) & 0x00ffffff; 124cabdff1aSopenharmony_ci if (*s != '}') 125cabdff1aSopenharmony_ci break; 126cabdff1aSopenharmony_ci tag.key = 'c'; 127cabdff1aSopenharmony_ci break; 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_ci /* Font name */ 130cabdff1aSopenharmony_ci case 'F': 131cabdff1aSopenharmony_ci tag.persistent = MICRODVD_PERSISTENT_ON; 132cabdff1aSopenharmony_ci case 'f': { 133cabdff1aSopenharmony_ci int len = indexof(s, '}'); 134cabdff1aSopenharmony_ci if (len < 0) 135cabdff1aSopenharmony_ci break; 136cabdff1aSopenharmony_ci tag.data_string = s; 137cabdff1aSopenharmony_ci tag.data_string_len = len; 138cabdff1aSopenharmony_ci s += len; 139cabdff1aSopenharmony_ci tag.key = 'f'; 140cabdff1aSopenharmony_ci break; 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci /* Font size */ 144cabdff1aSopenharmony_ci case 'S': 145cabdff1aSopenharmony_ci tag.persistent = MICRODVD_PERSISTENT_ON; 146cabdff1aSopenharmony_ci case 's': 147cabdff1aSopenharmony_ci tag.data1 = strtol(s, &s, 10); 148cabdff1aSopenharmony_ci if (*s != '}') 149cabdff1aSopenharmony_ci break; 150cabdff1aSopenharmony_ci tag.key = 's'; 151cabdff1aSopenharmony_ci break; 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci /* Charset */ 154cabdff1aSopenharmony_ci case 'H': { 155cabdff1aSopenharmony_ci //TODO: not yet handled, just parsed. 156cabdff1aSopenharmony_ci int len = indexof(s, '}'); 157cabdff1aSopenharmony_ci if (len < 0) 158cabdff1aSopenharmony_ci break; 159cabdff1aSopenharmony_ci tag.data_string = s; 160cabdff1aSopenharmony_ci tag.data_string_len = len; 161cabdff1aSopenharmony_ci s += len; 162cabdff1aSopenharmony_ci tag.key = 'h'; 163cabdff1aSopenharmony_ci break; 164cabdff1aSopenharmony_ci } 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci /* Position */ 167cabdff1aSopenharmony_ci case 'P': 168cabdff1aSopenharmony_ci if (!*s) 169cabdff1aSopenharmony_ci break; 170cabdff1aSopenharmony_ci tag.persistent = MICRODVD_PERSISTENT_ON; 171cabdff1aSopenharmony_ci tag.data1 = (*s++ == '1'); 172cabdff1aSopenharmony_ci if (*s != '}') 173cabdff1aSopenharmony_ci break; 174cabdff1aSopenharmony_ci tag.key = 'p'; 175cabdff1aSopenharmony_ci break; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci /* Coordinates */ 178cabdff1aSopenharmony_ci case 'o': 179cabdff1aSopenharmony_ci tag.persistent = MICRODVD_PERSISTENT_ON; 180cabdff1aSopenharmony_ci tag.data1 = strtol(s, &s, 10); 181cabdff1aSopenharmony_ci if (*s != ',') 182cabdff1aSopenharmony_ci break; 183cabdff1aSopenharmony_ci s++; 184cabdff1aSopenharmony_ci tag.data2 = strtol(s, &s, 10); 185cabdff1aSopenharmony_ci if (*s != '}') 186cabdff1aSopenharmony_ci break; 187cabdff1aSopenharmony_ci tag.key = 'o'; 188cabdff1aSopenharmony_ci break; 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci default: /* Unknown tag, we consider it's text */ 191cabdff1aSopenharmony_ci break; 192cabdff1aSopenharmony_ci } 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ci if (tag.key == 0) 195cabdff1aSopenharmony_ci return start; 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ci microdvd_set_tag(tags, tag); 198cabdff1aSopenharmony_ci s++; 199cabdff1aSopenharmony_ci } 200cabdff1aSopenharmony_ci return check_for_italic_slash_marker(tags, s); 201cabdff1aSopenharmony_ci} 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_cistatic void microdvd_open_tags(AVBPrint *new_line, struct microdvd_tag *tags) 204cabdff1aSopenharmony_ci{ 205cabdff1aSopenharmony_ci int i, sidx; 206cabdff1aSopenharmony_ci for (i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) { 207cabdff1aSopenharmony_ci if (tags[i].persistent == MICRODVD_PERSISTENT_OPENED) 208cabdff1aSopenharmony_ci continue; 209cabdff1aSopenharmony_ci switch (tags[i].key) { 210cabdff1aSopenharmony_ci case 'Y': 211cabdff1aSopenharmony_ci case 'y': 212cabdff1aSopenharmony_ci for (sidx = 0; sidx < sizeof(MICRODVD_STYLES) - 1; sidx++) 213cabdff1aSopenharmony_ci if (tags[i].data1 & (1 << sidx)) 214cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\%c1}", MICRODVD_STYLES[sidx]); 215cabdff1aSopenharmony_ci break; 216cabdff1aSopenharmony_ci 217cabdff1aSopenharmony_ci case 'c': 218cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\c&H%06"PRIX32"&}", tags[i].data1); 219cabdff1aSopenharmony_ci break; 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci case 'f': 222cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\fn%.*s}", 223cabdff1aSopenharmony_ci tags[i].data_string_len, tags[i].data_string); 224cabdff1aSopenharmony_ci break; 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci case 's': 227cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\fs%"PRId32"}", tags[i].data1); 228cabdff1aSopenharmony_ci break; 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci case 'p': 231cabdff1aSopenharmony_ci if (tags[i].data1 == 0) 232cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\an8}"); 233cabdff1aSopenharmony_ci break; 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci case 'o': 236cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\pos(%"PRId32",%"PRId32")}", 237cabdff1aSopenharmony_ci tags[i].data1, tags[i].data2); 238cabdff1aSopenharmony_ci break; 239cabdff1aSopenharmony_ci } 240cabdff1aSopenharmony_ci if (tags[i].persistent == MICRODVD_PERSISTENT_ON) 241cabdff1aSopenharmony_ci tags[i].persistent = MICRODVD_PERSISTENT_OPENED; 242cabdff1aSopenharmony_ci } 243cabdff1aSopenharmony_ci} 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_cistatic void microdvd_close_no_persistent_tags(AVBPrint *new_line, 246cabdff1aSopenharmony_ci struct microdvd_tag *tags) 247cabdff1aSopenharmony_ci{ 248cabdff1aSopenharmony_ci int i, sidx; 249cabdff1aSopenharmony_ci 250cabdff1aSopenharmony_ci for (i = sizeof(MICRODVD_TAGS) - 2; i >= 0; i--) { 251cabdff1aSopenharmony_ci if (tags[i].persistent != MICRODVD_PERSISTENT_OFF) 252cabdff1aSopenharmony_ci continue; 253cabdff1aSopenharmony_ci switch (tags[i].key) { 254cabdff1aSopenharmony_ci 255cabdff1aSopenharmony_ci case 'y': 256cabdff1aSopenharmony_ci for (sidx = sizeof(MICRODVD_STYLES) - 2; sidx >= 0; sidx--) 257cabdff1aSopenharmony_ci if (tags[i].data1 & (1 << sidx)) 258cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\%c0}", MICRODVD_STYLES[sidx]); 259cabdff1aSopenharmony_ci break; 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_ci case 'c': 262cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\c}"); 263cabdff1aSopenharmony_ci break; 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci case 'f': 266cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\fn}"); 267cabdff1aSopenharmony_ci break; 268cabdff1aSopenharmony_ci 269cabdff1aSopenharmony_ci case 's': 270cabdff1aSopenharmony_ci av_bprintf(new_line, "{\\fs}"); 271cabdff1aSopenharmony_ci break; 272cabdff1aSopenharmony_ci } 273cabdff1aSopenharmony_ci tags[i].key = 0; 274cabdff1aSopenharmony_ci } 275cabdff1aSopenharmony_ci} 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_cistatic int microdvd_decode_frame(AVCodecContext *avctx, AVSubtitle *sub, 278cabdff1aSopenharmony_ci int *got_sub_ptr, const AVPacket *avpkt) 279cabdff1aSopenharmony_ci{ 280cabdff1aSopenharmony_ci AVBPrint new_line; 281cabdff1aSopenharmony_ci char *line = avpkt->data; 282cabdff1aSopenharmony_ci char *end = avpkt->data + avpkt->size; 283cabdff1aSopenharmony_ci FFASSDecoderContext *s = avctx->priv_data; 284cabdff1aSopenharmony_ci struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}}; 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_ci if (avpkt->size <= 0) 287cabdff1aSopenharmony_ci return avpkt->size; 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ci av_bprint_init(&new_line, 0, 2048); 290cabdff1aSopenharmony_ci 291cabdff1aSopenharmony_ci // subtitle content 292cabdff1aSopenharmony_ci while (line < end && *line) { 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci // parse MicroDVD tags, and open them in ASS 295cabdff1aSopenharmony_ci line = microdvd_load_tags(tags, line); 296cabdff1aSopenharmony_ci microdvd_open_tags(&new_line, tags); 297cabdff1aSopenharmony_ci 298cabdff1aSopenharmony_ci // simple copy until EOL or forced carriage return 299cabdff1aSopenharmony_ci while (line < end && *line && *line != '|') { 300cabdff1aSopenharmony_ci av_bprint_chars(&new_line, *line, 1); 301cabdff1aSopenharmony_ci line++; 302cabdff1aSopenharmony_ci } 303cabdff1aSopenharmony_ci 304cabdff1aSopenharmony_ci // line split 305cabdff1aSopenharmony_ci if (line < end && *line == '|') { 306cabdff1aSopenharmony_ci microdvd_close_no_persistent_tags(&new_line, tags); 307cabdff1aSopenharmony_ci av_bprintf(&new_line, "\\N"); 308cabdff1aSopenharmony_ci line++; 309cabdff1aSopenharmony_ci } 310cabdff1aSopenharmony_ci } 311cabdff1aSopenharmony_ci if (new_line.len) { 312cabdff1aSopenharmony_ci int ret = ff_ass_add_rect(sub, new_line.str, s->readorder++, 0, NULL, NULL); 313cabdff1aSopenharmony_ci av_bprint_finalize(&new_line, NULL); 314cabdff1aSopenharmony_ci if (ret < 0) 315cabdff1aSopenharmony_ci return ret; 316cabdff1aSopenharmony_ci } 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_ci *got_sub_ptr = sub->num_rects > 0; 319cabdff1aSopenharmony_ci return avpkt->size; 320cabdff1aSopenharmony_ci} 321cabdff1aSopenharmony_ci 322cabdff1aSopenharmony_cistatic int microdvd_init(AVCodecContext *avctx) 323cabdff1aSopenharmony_ci{ 324cabdff1aSopenharmony_ci int i, sidx; 325cabdff1aSopenharmony_ci AVBPrint font_buf; 326cabdff1aSopenharmony_ci int font_size = ASS_DEFAULT_FONT_SIZE; 327cabdff1aSopenharmony_ci int color = ASS_DEFAULT_COLOR; 328cabdff1aSopenharmony_ci int bold = ASS_DEFAULT_BOLD; 329cabdff1aSopenharmony_ci int italic = ASS_DEFAULT_ITALIC; 330cabdff1aSopenharmony_ci int underline = ASS_DEFAULT_UNDERLINE; 331cabdff1aSopenharmony_ci int alignment = ASS_DEFAULT_ALIGNMENT; 332cabdff1aSopenharmony_ci struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}}; 333cabdff1aSopenharmony_ci 334cabdff1aSopenharmony_ci av_bprint_init(&font_buf, 0, AV_BPRINT_SIZE_AUTOMATIC); 335cabdff1aSopenharmony_ci av_bprintf(&font_buf, "%s", ASS_DEFAULT_FONT); 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_ci if (avctx->extradata) { 338cabdff1aSopenharmony_ci microdvd_load_tags(tags, avctx->extradata); 339cabdff1aSopenharmony_ci for (i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) { 340cabdff1aSopenharmony_ci switch (av_tolower(tags[i].key)) { 341cabdff1aSopenharmony_ci case 'y': 342cabdff1aSopenharmony_ci for (sidx = 0; sidx < sizeof(MICRODVD_STYLES) - 1; sidx++) { 343cabdff1aSopenharmony_ci if (tags[i].data1 & (1 << sidx)) { 344cabdff1aSopenharmony_ci switch (MICRODVD_STYLES[sidx]) { 345cabdff1aSopenharmony_ci case 'i': italic = 1; break; 346cabdff1aSopenharmony_ci case 'b': bold = 1; break; 347cabdff1aSopenharmony_ci case 'u': underline = 1; break; 348cabdff1aSopenharmony_ci } 349cabdff1aSopenharmony_ci } 350cabdff1aSopenharmony_ci } 351cabdff1aSopenharmony_ci break; 352cabdff1aSopenharmony_ci 353cabdff1aSopenharmony_ci case 'c': color = tags[i].data1; break; 354cabdff1aSopenharmony_ci case 's': font_size = tags[i].data1; break; 355cabdff1aSopenharmony_ci case 'p': alignment = 8; break; 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_ci case 'f': 358cabdff1aSopenharmony_ci av_bprint_clear(&font_buf); 359cabdff1aSopenharmony_ci av_bprintf(&font_buf, "%.*s", 360cabdff1aSopenharmony_ci tags[i].data_string_len, tags[i].data_string); 361cabdff1aSopenharmony_ci break; 362cabdff1aSopenharmony_ci } 363cabdff1aSopenharmony_ci } 364cabdff1aSopenharmony_ci } 365cabdff1aSopenharmony_ci return ff_ass_subtitle_header(avctx, font_buf.str, font_size, color, 366cabdff1aSopenharmony_ci ASS_DEFAULT_BACK_COLOR, bold, italic, 367cabdff1aSopenharmony_ci underline, ASS_DEFAULT_BORDERSTYLE, 368cabdff1aSopenharmony_ci alignment); 369cabdff1aSopenharmony_ci} 370cabdff1aSopenharmony_ci 371cabdff1aSopenharmony_ciconst FFCodec ff_microdvd_decoder = { 372cabdff1aSopenharmony_ci .p.name = "microdvd", 373cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle"), 374cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_SUBTITLE, 375cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_MICRODVD, 376cabdff1aSopenharmony_ci .init = microdvd_init, 377cabdff1aSopenharmony_ci FF_CODEC_DECODE_SUB_CB(microdvd_decode_frame), 378cabdff1aSopenharmony_ci .flush = ff_ass_decoder_flush, 379cabdff1aSopenharmony_ci .priv_data_size = sizeof(FFASSDecoderContext), 380cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 381cabdff1aSopenharmony_ci}; 382