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