xref: /third_party/ffmpeg/libavcodec/dvbsubenc.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * DVB subtitle encoding
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#include "avcodec.h"
22cabdff1aSopenharmony_ci#include "bytestream.h"
23cabdff1aSopenharmony_ci#include "codec_internal.h"
24cabdff1aSopenharmony_ci#include "libavutil/colorspace.h"
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_citypedef struct DVBSubtitleContext {
27cabdff1aSopenharmony_ci    int object_version;
28cabdff1aSopenharmony_ci} DVBSubtitleContext;
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#define PUTBITS2(val)\
31cabdff1aSopenharmony_ci{\
32cabdff1aSopenharmony_ci    bitbuf |= (val) << bitcnt;\
33cabdff1aSopenharmony_ci    bitcnt -= 2;\
34cabdff1aSopenharmony_ci    if (bitcnt < 0) {\
35cabdff1aSopenharmony_ci        bitcnt = 6;\
36cabdff1aSopenharmony_ci        *q++ = bitbuf;\
37cabdff1aSopenharmony_ci        bitbuf = 0;\
38cabdff1aSopenharmony_ci    }\
39cabdff1aSopenharmony_ci}
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_cistatic int dvb_encode_rle2(uint8_t **pq, int buf_size,
42cabdff1aSopenharmony_ci                           const uint8_t *bitmap, int linesize,
43cabdff1aSopenharmony_ci                           int w, int h)
44cabdff1aSopenharmony_ci{
45cabdff1aSopenharmony_ci    uint8_t *q, *line_begin;
46cabdff1aSopenharmony_ci    unsigned int bitbuf;
47cabdff1aSopenharmony_ci    int bitcnt;
48cabdff1aSopenharmony_ci    int x, y, len, x1, v, color;
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci    q = *pq;
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ci    for(y = 0; y < h; y++) {
53cabdff1aSopenharmony_ci        // Worst case line is 3 bits per value + 4 bytes overhead
54cabdff1aSopenharmony_ci        if (buf_size * 8 < w * 3 + 32)
55cabdff1aSopenharmony_ci            return AVERROR_BUFFER_TOO_SMALL;
56cabdff1aSopenharmony_ci        line_begin = q;
57cabdff1aSopenharmony_ci        *q++ = 0x10;
58cabdff1aSopenharmony_ci        bitbuf = 0;
59cabdff1aSopenharmony_ci        bitcnt = 6;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci        x = 0;
62cabdff1aSopenharmony_ci        while (x < w) {
63cabdff1aSopenharmony_ci            x1 = x;
64cabdff1aSopenharmony_ci            color = bitmap[x1++];
65cabdff1aSopenharmony_ci            while (x1 < w && bitmap[x1] == color)
66cabdff1aSopenharmony_ci                x1++;
67cabdff1aSopenharmony_ci            len = x1 - x;
68cabdff1aSopenharmony_ci            if (color == 0 && len == 2) {
69cabdff1aSopenharmony_ci                PUTBITS2(0);
70cabdff1aSopenharmony_ci                PUTBITS2(0);
71cabdff1aSopenharmony_ci                PUTBITS2(1);
72cabdff1aSopenharmony_ci            } else if (len >= 3 && len <= 10) {
73cabdff1aSopenharmony_ci                v = len - 3;
74cabdff1aSopenharmony_ci                PUTBITS2(0);
75cabdff1aSopenharmony_ci                PUTBITS2((v >> 2) | 2);
76cabdff1aSopenharmony_ci                PUTBITS2(v & 3);
77cabdff1aSopenharmony_ci                PUTBITS2(color);
78cabdff1aSopenharmony_ci            } else if (len >= 12 && len <= 27) {
79cabdff1aSopenharmony_ci                v = len - 12;
80cabdff1aSopenharmony_ci                PUTBITS2(0);
81cabdff1aSopenharmony_ci                PUTBITS2(0);
82cabdff1aSopenharmony_ci                PUTBITS2(2);
83cabdff1aSopenharmony_ci                PUTBITS2(v >> 2);
84cabdff1aSopenharmony_ci                PUTBITS2(v & 3);
85cabdff1aSopenharmony_ci                PUTBITS2(color);
86cabdff1aSopenharmony_ci            } else if (len >= 29) {
87cabdff1aSopenharmony_ci                /* length = 29 ... 284 */
88cabdff1aSopenharmony_ci                if (len > 284)
89cabdff1aSopenharmony_ci                    len = 284;
90cabdff1aSopenharmony_ci                v = len - 29;
91cabdff1aSopenharmony_ci                PUTBITS2(0);
92cabdff1aSopenharmony_ci                PUTBITS2(0);
93cabdff1aSopenharmony_ci                PUTBITS2(3);
94cabdff1aSopenharmony_ci                PUTBITS2((v >> 6));
95cabdff1aSopenharmony_ci                PUTBITS2((v >> 4) & 3);
96cabdff1aSopenharmony_ci                PUTBITS2((v >> 2) & 3);
97cabdff1aSopenharmony_ci                PUTBITS2(v & 3);
98cabdff1aSopenharmony_ci                PUTBITS2(color);
99cabdff1aSopenharmony_ci            } else {
100cabdff1aSopenharmony_ci                PUTBITS2(color);
101cabdff1aSopenharmony_ci                if (color == 0) {
102cabdff1aSopenharmony_ci                    PUTBITS2(1);
103cabdff1aSopenharmony_ci                }
104cabdff1aSopenharmony_ci                len = 1;
105cabdff1aSopenharmony_ci            }
106cabdff1aSopenharmony_ci            x += len;
107cabdff1aSopenharmony_ci        }
108cabdff1aSopenharmony_ci        /* end of line */
109cabdff1aSopenharmony_ci        PUTBITS2(0);
110cabdff1aSopenharmony_ci        PUTBITS2(0);
111cabdff1aSopenharmony_ci        PUTBITS2(0);
112cabdff1aSopenharmony_ci        if (bitcnt != 6) {
113cabdff1aSopenharmony_ci            *q++ = bitbuf;
114cabdff1aSopenharmony_ci        }
115cabdff1aSopenharmony_ci        *q++ = 0xf0;
116cabdff1aSopenharmony_ci        bitmap += linesize;
117cabdff1aSopenharmony_ci        buf_size -= q - line_begin;
118cabdff1aSopenharmony_ci    }
119cabdff1aSopenharmony_ci    len = q - *pq;
120cabdff1aSopenharmony_ci    *pq = q;
121cabdff1aSopenharmony_ci    return len;
122cabdff1aSopenharmony_ci}
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_ci#define PUTBITS4(val)\
125cabdff1aSopenharmony_ci{\
126cabdff1aSopenharmony_ci    bitbuf |= (val) << bitcnt;\
127cabdff1aSopenharmony_ci    bitcnt -= 4;\
128cabdff1aSopenharmony_ci    if (bitcnt < 0) {\
129cabdff1aSopenharmony_ci        bitcnt = 4;\
130cabdff1aSopenharmony_ci        *q++ = bitbuf;\
131cabdff1aSopenharmony_ci        bitbuf = 0;\
132cabdff1aSopenharmony_ci    }\
133cabdff1aSopenharmony_ci}
134cabdff1aSopenharmony_ci
135cabdff1aSopenharmony_ci/* some DVB decoders only implement 4 bits/pixel */
136cabdff1aSopenharmony_cistatic int dvb_encode_rle4(uint8_t **pq, int buf_size,
137cabdff1aSopenharmony_ci                           const uint8_t *bitmap, int linesize,
138cabdff1aSopenharmony_ci                           int w, int h)
139cabdff1aSopenharmony_ci{
140cabdff1aSopenharmony_ci    uint8_t *q, *line_begin;
141cabdff1aSopenharmony_ci    unsigned int bitbuf;
142cabdff1aSopenharmony_ci    int bitcnt;
143cabdff1aSopenharmony_ci    int x, y, len, x1, v, color;
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci    q = *pq;
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_ci    for(y = 0; y < h; y++) {
148cabdff1aSopenharmony_ci        // Worst case line is 6 bits per value, + 4 bytes overhead
149cabdff1aSopenharmony_ci        if (buf_size * 8 < w * 6 + 32)
150cabdff1aSopenharmony_ci            return AVERROR_BUFFER_TOO_SMALL;
151cabdff1aSopenharmony_ci        line_begin = q;
152cabdff1aSopenharmony_ci        *q++ = 0x11;
153cabdff1aSopenharmony_ci        bitbuf = 0;
154cabdff1aSopenharmony_ci        bitcnt = 4;
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_ci        x = 0;
157cabdff1aSopenharmony_ci        while (x < w) {
158cabdff1aSopenharmony_ci            x1 = x;
159cabdff1aSopenharmony_ci            color = bitmap[x1++];
160cabdff1aSopenharmony_ci            while (x1 < w && bitmap[x1] == color)
161cabdff1aSopenharmony_ci                x1++;
162cabdff1aSopenharmony_ci            len = x1 - x;
163cabdff1aSopenharmony_ci            if (color == 0 && len == 2) {
164cabdff1aSopenharmony_ci                PUTBITS4(0);
165cabdff1aSopenharmony_ci                PUTBITS4(0xd);
166cabdff1aSopenharmony_ci            } else if (color == 0 && (len >= 3 && len <= 9)) {
167cabdff1aSopenharmony_ci                PUTBITS4(0);
168cabdff1aSopenharmony_ci                PUTBITS4(len - 2);
169cabdff1aSopenharmony_ci            } else if (len >= 4 && len <= 7) {
170cabdff1aSopenharmony_ci                PUTBITS4(0);
171cabdff1aSopenharmony_ci                PUTBITS4(8 + len - 4);
172cabdff1aSopenharmony_ci                PUTBITS4(color);
173cabdff1aSopenharmony_ci            } else if (len >= 9 && len <= 24) {
174cabdff1aSopenharmony_ci                PUTBITS4(0);
175cabdff1aSopenharmony_ci                PUTBITS4(0xe);
176cabdff1aSopenharmony_ci                PUTBITS4(len - 9);
177cabdff1aSopenharmony_ci                PUTBITS4(color);
178cabdff1aSopenharmony_ci            } else if (len >= 25) {
179cabdff1aSopenharmony_ci                if (len > 280)
180cabdff1aSopenharmony_ci                    len = 280;
181cabdff1aSopenharmony_ci                v = len - 25;
182cabdff1aSopenharmony_ci                PUTBITS4(0);
183cabdff1aSopenharmony_ci                PUTBITS4(0xf);
184cabdff1aSopenharmony_ci                PUTBITS4(v >> 4);
185cabdff1aSopenharmony_ci                PUTBITS4(v & 0xf);
186cabdff1aSopenharmony_ci                PUTBITS4(color);
187cabdff1aSopenharmony_ci            } else {
188cabdff1aSopenharmony_ci                PUTBITS4(color);
189cabdff1aSopenharmony_ci                if (color == 0) {
190cabdff1aSopenharmony_ci                    PUTBITS4(0xc);
191cabdff1aSopenharmony_ci                }
192cabdff1aSopenharmony_ci                len = 1;
193cabdff1aSopenharmony_ci            }
194cabdff1aSopenharmony_ci            x += len;
195cabdff1aSopenharmony_ci        }
196cabdff1aSopenharmony_ci        /* end of line */
197cabdff1aSopenharmony_ci        PUTBITS4(0);
198cabdff1aSopenharmony_ci        PUTBITS4(0);
199cabdff1aSopenharmony_ci        if (bitcnt != 4) {
200cabdff1aSopenharmony_ci            *q++ = bitbuf;
201cabdff1aSopenharmony_ci        }
202cabdff1aSopenharmony_ci        *q++ = 0xf0;
203cabdff1aSopenharmony_ci        bitmap += linesize;
204cabdff1aSopenharmony_ci        buf_size -= q - line_begin;
205cabdff1aSopenharmony_ci    }
206cabdff1aSopenharmony_ci    len = q - *pq;
207cabdff1aSopenharmony_ci    *pq = q;
208cabdff1aSopenharmony_ci    return len;
209cabdff1aSopenharmony_ci}
210cabdff1aSopenharmony_ci
211cabdff1aSopenharmony_cistatic int dvb_encode_rle8(uint8_t **pq, int buf_size,
212cabdff1aSopenharmony_ci                           const uint8_t *bitmap, int linesize,
213cabdff1aSopenharmony_ci                           int w, int h)
214cabdff1aSopenharmony_ci{
215cabdff1aSopenharmony_ci    uint8_t *q, *line_begin;
216cabdff1aSopenharmony_ci    int x, y, len, x1, color;
217cabdff1aSopenharmony_ci
218cabdff1aSopenharmony_ci    q = *pq;
219cabdff1aSopenharmony_ci
220cabdff1aSopenharmony_ci    for (y = 0; y < h; y++) {
221cabdff1aSopenharmony_ci        // Worst case line is 12 bits per value, + 3 bytes overhead
222cabdff1aSopenharmony_ci        if (buf_size * 8 < w * 12 + 24)
223cabdff1aSopenharmony_ci            return AVERROR_BUFFER_TOO_SMALL;
224cabdff1aSopenharmony_ci        line_begin = q;
225cabdff1aSopenharmony_ci        *q++ = 0x12;
226cabdff1aSopenharmony_ci
227cabdff1aSopenharmony_ci        x = 0;
228cabdff1aSopenharmony_ci        while (x < w) {
229cabdff1aSopenharmony_ci            x1 = x;
230cabdff1aSopenharmony_ci            color = bitmap[x1++];
231cabdff1aSopenharmony_ci            while (x1 < w && bitmap[x1] == color)
232cabdff1aSopenharmony_ci                x1++;
233cabdff1aSopenharmony_ci            len = x1 - x;
234cabdff1aSopenharmony_ci            if (len == 1 && color) {
235cabdff1aSopenharmony_ci                // 00000001 to 11111111           1 pixel in colour x
236cabdff1aSopenharmony_ci                *q++ = color;
237cabdff1aSopenharmony_ci            } else {
238cabdff1aSopenharmony_ci                if (color == 0x00) {
239cabdff1aSopenharmony_ci                    // 00000000 0LLLLLLL          L pixels (1-127) in colour 0 (L > 0)
240cabdff1aSopenharmony_ci                    len = FFMIN(len, 127);
241cabdff1aSopenharmony_ci                    *q++ = 0x00;
242cabdff1aSopenharmony_ci                    *q++ = len;
243cabdff1aSopenharmony_ci                } else if (len > 2) {
244cabdff1aSopenharmony_ci                    // 00000000 1LLLLLLL CCCCCCCC L pixels (3-127) in colour C (L > 2)
245cabdff1aSopenharmony_ci                    len = FFMIN(len, 127);
246cabdff1aSopenharmony_ci                    *q++ = 0x00;
247cabdff1aSopenharmony_ci                    *q++ = 0x80+len;
248cabdff1aSopenharmony_ci                    *q++ = color;
249cabdff1aSopenharmony_ci                }
250cabdff1aSopenharmony_ci                else if (len == 2) {
251cabdff1aSopenharmony_ci                    *q++ = color;
252cabdff1aSopenharmony_ci                    *q++ = color;
253cabdff1aSopenharmony_ci                } else {
254cabdff1aSopenharmony_ci                    *q++ = color;
255cabdff1aSopenharmony_ci                    len = 1;
256cabdff1aSopenharmony_ci                }
257cabdff1aSopenharmony_ci            }
258cabdff1aSopenharmony_ci            x += len;
259cabdff1aSopenharmony_ci        }
260cabdff1aSopenharmony_ci        /* end of line */
261cabdff1aSopenharmony_ci        // 00000000 end of 8-bit/pixel_code_string
262cabdff1aSopenharmony_ci        *q++ = 0x00;
263cabdff1aSopenharmony_ci        *q++ = 0xf0;
264cabdff1aSopenharmony_ci        bitmap += linesize;
265cabdff1aSopenharmony_ci        buf_size -= q - line_begin;
266cabdff1aSopenharmony_ci    }
267cabdff1aSopenharmony_ci    len = q - *pq;
268cabdff1aSopenharmony_ci    *pq = q;
269cabdff1aSopenharmony_ci    return len;
270cabdff1aSopenharmony_ci}
271cabdff1aSopenharmony_ci
272cabdff1aSopenharmony_cistatic int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
273cabdff1aSopenharmony_ci                         const AVSubtitle *h)
274cabdff1aSopenharmony_ci{
275cabdff1aSopenharmony_ci    DVBSubtitleContext *s = avctx->priv_data;
276cabdff1aSopenharmony_ci    uint8_t *q, *pseg_len;
277cabdff1aSopenharmony_ci    int page_id, region_id, clut_id, object_id, i, bpp_index, page_state;
278cabdff1aSopenharmony_ci
279cabdff1aSopenharmony_ci
280cabdff1aSopenharmony_ci    q = outbuf;
281cabdff1aSopenharmony_ci
282cabdff1aSopenharmony_ci    page_id = 1;
283cabdff1aSopenharmony_ci
284cabdff1aSopenharmony_ci    if (h->num_rects && !h->rects)
285cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
286cabdff1aSopenharmony_ci
287cabdff1aSopenharmony_ci    if (avctx->width > 0 && avctx->height > 0) {
288cabdff1aSopenharmony_ci        if (buf_size < 11)
289cabdff1aSopenharmony_ci            return AVERROR_BUFFER_TOO_SMALL;
290cabdff1aSopenharmony_ci        /* display definition segment */
291cabdff1aSopenharmony_ci        *q++ = 0x0f; /* sync_byte */
292cabdff1aSopenharmony_ci        *q++ = 0x14; /* segment_type */
293cabdff1aSopenharmony_ci        bytestream_put_be16(&q, page_id);
294cabdff1aSopenharmony_ci        pseg_len = q;
295cabdff1aSopenharmony_ci        q += 2; /* segment length */
296cabdff1aSopenharmony_ci        *q++ = 0x00; /* dds version number & display window flag */
297cabdff1aSopenharmony_ci        bytestream_put_be16(&q, avctx->width - 1); /* display width */
298cabdff1aSopenharmony_ci        bytestream_put_be16(&q, avctx->height - 1); /* display height */
299cabdff1aSopenharmony_ci        bytestream_put_be16(&pseg_len, q - pseg_len - 2);
300cabdff1aSopenharmony_ci        buf_size -= 11;
301cabdff1aSopenharmony_ci    }
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_ci    /* page composition segment */
304cabdff1aSopenharmony_ci
305cabdff1aSopenharmony_ci    if (buf_size < 8 + h->num_rects * 6)
306cabdff1aSopenharmony_ci        return AVERROR_BUFFER_TOO_SMALL;
307cabdff1aSopenharmony_ci    *q++ = 0x0f; /* sync_byte */
308cabdff1aSopenharmony_ci    *q++ = 0x10; /* segment_type */
309cabdff1aSopenharmony_ci    bytestream_put_be16(&q, page_id);
310cabdff1aSopenharmony_ci    pseg_len = q;
311cabdff1aSopenharmony_ci    q += 2; /* segment length */
312cabdff1aSopenharmony_ci    *q++ = 30; /* page_timeout (seconds) */
313cabdff1aSopenharmony_ci    page_state = 2; /* mode change */
314cabdff1aSopenharmony_ci    /* page_version = 0 + page_state */
315cabdff1aSopenharmony_ci    *q++ = (s->object_version << 4) | (page_state << 2) | 3;
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_ci    for (region_id = 0; region_id < h->num_rects; region_id++) {
318cabdff1aSopenharmony_ci        *q++ = region_id;
319cabdff1aSopenharmony_ci        *q++ = 0xff; /* reserved */
320cabdff1aSopenharmony_ci        bytestream_put_be16(&q, h->rects[region_id]->x); /* left pos */
321cabdff1aSopenharmony_ci        bytestream_put_be16(&q, h->rects[region_id]->y); /* top pos */
322cabdff1aSopenharmony_ci    }
323cabdff1aSopenharmony_ci
324cabdff1aSopenharmony_ci    bytestream_put_be16(&pseg_len, q - pseg_len - 2);
325cabdff1aSopenharmony_ci    buf_size -= 8 + h->num_rects * 6;
326cabdff1aSopenharmony_ci
327cabdff1aSopenharmony_ci    if (h->num_rects) {
328cabdff1aSopenharmony_ci        for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
329cabdff1aSopenharmony_ci            if (buf_size < 6 + h->rects[clut_id]->nb_colors * 6)
330cabdff1aSopenharmony_ci                return AVERROR_BUFFER_TOO_SMALL;
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_ci            /* CLUT segment */
333cabdff1aSopenharmony_ci
334cabdff1aSopenharmony_ci            if (h->rects[clut_id]->nb_colors <= 4) {
335cabdff1aSopenharmony_ci                /* 2 bpp, some decoders do not support it correctly */
336cabdff1aSopenharmony_ci                bpp_index = 0;
337cabdff1aSopenharmony_ci            } else if (h->rects[clut_id]->nb_colors <= 16) {
338cabdff1aSopenharmony_ci                /* 4 bpp, standard encoding */
339cabdff1aSopenharmony_ci                bpp_index = 1;
340cabdff1aSopenharmony_ci            } else if (h->rects[clut_id]->nb_colors <= 256) {
341cabdff1aSopenharmony_ci                /* 8 bpp, standard encoding */
342cabdff1aSopenharmony_ci                bpp_index = 2;
343cabdff1aSopenharmony_ci            } else {
344cabdff1aSopenharmony_ci                return AVERROR(EINVAL);
345cabdff1aSopenharmony_ci            }
346cabdff1aSopenharmony_ci
347cabdff1aSopenharmony_ci
348cabdff1aSopenharmony_ci            /* CLUT segment */
349cabdff1aSopenharmony_ci            *q++ = 0x0f; /* sync byte */
350cabdff1aSopenharmony_ci            *q++ = 0x12; /* CLUT definition segment */
351cabdff1aSopenharmony_ci            bytestream_put_be16(&q, page_id);
352cabdff1aSopenharmony_ci            pseg_len = q;
353cabdff1aSopenharmony_ci            q += 2; /* segment length */
354cabdff1aSopenharmony_ci            *q++ = clut_id;
355cabdff1aSopenharmony_ci            *q++ = (0 << 4) | 0xf; /* version = 0 */
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci            for(i = 0; i < h->rects[clut_id]->nb_colors; i++) {
358cabdff1aSopenharmony_ci                *q++ = i; /* clut_entry_id */
359cabdff1aSopenharmony_ci                *q++ = (1 << (7 - bpp_index)) | (0xf << 1) | 1; /* 2 bits/pixel full range */
360cabdff1aSopenharmony_ci                {
361cabdff1aSopenharmony_ci                    int a, r, g, b;
362cabdff1aSopenharmony_ci                    uint32_t x= ((uint32_t*)h->rects[clut_id]->data[1])[i];
363cabdff1aSopenharmony_ci                    a = (x >> 24) & 0xff;
364cabdff1aSopenharmony_ci                    r = (x >> 16) & 0xff;
365cabdff1aSopenharmony_ci                    g = (x >>  8) & 0xff;
366cabdff1aSopenharmony_ci                    b = (x >>  0) & 0xff;
367cabdff1aSopenharmony_ci
368cabdff1aSopenharmony_ci                    *q++ = RGB_TO_Y_CCIR(r, g, b);
369cabdff1aSopenharmony_ci                    *q++ = RGB_TO_V_CCIR(r, g, b, 0);
370cabdff1aSopenharmony_ci                    *q++ = RGB_TO_U_CCIR(r, g, b, 0);
371cabdff1aSopenharmony_ci                    *q++ = 255 - a;
372cabdff1aSopenharmony_ci                }
373cabdff1aSopenharmony_ci            }
374cabdff1aSopenharmony_ci
375cabdff1aSopenharmony_ci            bytestream_put_be16(&pseg_len, q - pseg_len - 2);
376cabdff1aSopenharmony_ci            buf_size -= 6 + h->rects[clut_id]->nb_colors * 6;
377cabdff1aSopenharmony_ci        }
378cabdff1aSopenharmony_ci
379cabdff1aSopenharmony_ci        if (buf_size < h->num_rects * 22)
380cabdff1aSopenharmony_ci            return AVERROR_BUFFER_TOO_SMALL;
381cabdff1aSopenharmony_ci        for (region_id = 0; region_id < h->num_rects; region_id++) {
382cabdff1aSopenharmony_ci
383cabdff1aSopenharmony_ci            /* region composition segment */
384cabdff1aSopenharmony_ci
385cabdff1aSopenharmony_ci            if (h->rects[region_id]->nb_colors <= 4) {
386cabdff1aSopenharmony_ci                /* 2 bpp, some decoders do not support it correctly */
387cabdff1aSopenharmony_ci                bpp_index = 0;
388cabdff1aSopenharmony_ci            } else if (h->rects[region_id]->nb_colors <= 16) {
389cabdff1aSopenharmony_ci                /* 4 bpp, standard encoding */
390cabdff1aSopenharmony_ci                bpp_index = 1;
391cabdff1aSopenharmony_ci            } else if (h->rects[region_id]->nb_colors <= 256) {
392cabdff1aSopenharmony_ci                /* 8 bpp, standard encoding */
393cabdff1aSopenharmony_ci                bpp_index = 2;
394cabdff1aSopenharmony_ci            } else {
395cabdff1aSopenharmony_ci                return AVERROR(EINVAL);
396cabdff1aSopenharmony_ci            }
397cabdff1aSopenharmony_ci
398cabdff1aSopenharmony_ci            *q++ = 0x0f; /* sync_byte */
399cabdff1aSopenharmony_ci            *q++ = 0x11; /* segment_type */
400cabdff1aSopenharmony_ci            bytestream_put_be16(&q, page_id);
401cabdff1aSopenharmony_ci            pseg_len = q;
402cabdff1aSopenharmony_ci            q += 2; /* segment length */
403cabdff1aSopenharmony_ci            *q++ = region_id;
404cabdff1aSopenharmony_ci            *q++ = (s->object_version << 4) | (0 << 3) | 0x07; /* version , no fill */
405cabdff1aSopenharmony_ci            bytestream_put_be16(&q, h->rects[region_id]->w); /* region width */
406cabdff1aSopenharmony_ci            bytestream_put_be16(&q, h->rects[region_id]->h); /* region height */
407cabdff1aSopenharmony_ci            *q++ = ((1 + bpp_index) << 5) | ((1 + bpp_index) << 2) | 0x03;
408cabdff1aSopenharmony_ci            *q++ = region_id; /* clut_id == region_id */
409cabdff1aSopenharmony_ci            *q++ = 0; /* 8 bit fill colors */
410cabdff1aSopenharmony_ci            *q++ = 0x03; /* 4 bit and 2 bit fill colors */
411cabdff1aSopenharmony_ci
412cabdff1aSopenharmony_ci            bytestream_put_be16(&q, region_id); /* object_id == region_id */
413cabdff1aSopenharmony_ci            *q++ = (0 << 6) | (0 << 4);
414cabdff1aSopenharmony_ci            *q++ = 0;
415cabdff1aSopenharmony_ci            *q++ = 0xf0;
416cabdff1aSopenharmony_ci            *q++ = 0;
417cabdff1aSopenharmony_ci
418cabdff1aSopenharmony_ci            bytestream_put_be16(&pseg_len, q - pseg_len - 2);
419cabdff1aSopenharmony_ci        }
420cabdff1aSopenharmony_ci        buf_size -= h->num_rects * 22;
421cabdff1aSopenharmony_ci
422cabdff1aSopenharmony_ci        for (object_id = 0; object_id < h->num_rects; object_id++) {
423cabdff1aSopenharmony_ci            int (*dvb_encode_rle)(uint8_t **pq, int buf_size,
424cabdff1aSopenharmony_ci                                  const uint8_t *bitmap, int linesize,
425cabdff1aSopenharmony_ci                                  int w, int h);
426cabdff1aSopenharmony_ci
427cabdff1aSopenharmony_ci            if (buf_size < 13)
428cabdff1aSopenharmony_ci                return AVERROR_BUFFER_TOO_SMALL;
429cabdff1aSopenharmony_ci
430cabdff1aSopenharmony_ci            /* bpp_index maths */
431cabdff1aSopenharmony_ci            if (h->rects[object_id]->nb_colors <= 4) {
432cabdff1aSopenharmony_ci                /* 2 bpp, some decoders do not support it correctly */
433cabdff1aSopenharmony_ci                dvb_encode_rle = dvb_encode_rle2;
434cabdff1aSopenharmony_ci            } else if (h->rects[object_id]->nb_colors <= 16) {
435cabdff1aSopenharmony_ci                /* 4 bpp, standard encoding */
436cabdff1aSopenharmony_ci                dvb_encode_rle = dvb_encode_rle4;
437cabdff1aSopenharmony_ci            } else if (h->rects[object_id]->nb_colors <= 256) {
438cabdff1aSopenharmony_ci                /* 8 bpp, standard encoding */
439cabdff1aSopenharmony_ci                dvb_encode_rle = dvb_encode_rle8;
440cabdff1aSopenharmony_ci            } else {
441cabdff1aSopenharmony_ci                return AVERROR(EINVAL);
442cabdff1aSopenharmony_ci            }
443cabdff1aSopenharmony_ci
444cabdff1aSopenharmony_ci            /* Object Data segment */
445cabdff1aSopenharmony_ci            *q++ = 0x0f; /* sync byte */
446cabdff1aSopenharmony_ci            *q++ = 0x13;
447cabdff1aSopenharmony_ci            bytestream_put_be16(&q, page_id);
448cabdff1aSopenharmony_ci            pseg_len = q;
449cabdff1aSopenharmony_ci            q += 2; /* segment length */
450cabdff1aSopenharmony_ci
451cabdff1aSopenharmony_ci            bytestream_put_be16(&q, object_id);
452cabdff1aSopenharmony_ci            *q++ = (s->object_version << 4) | (0 << 2) | (0 << 1) | 1; /* version = 0,
453cabdff1aSopenharmony_ci                                                                       object_coding_method,
454cabdff1aSopenharmony_ci                                                                       non_modifying_color_flag */
455cabdff1aSopenharmony_ci            {
456cabdff1aSopenharmony_ci                uint8_t *ptop_field_len, *pbottom_field_len, *top_ptr, *bottom_ptr;
457cabdff1aSopenharmony_ci                int ret;
458cabdff1aSopenharmony_ci
459cabdff1aSopenharmony_ci                ptop_field_len = q;
460cabdff1aSopenharmony_ci                q += 2;
461cabdff1aSopenharmony_ci                pbottom_field_len = q;
462cabdff1aSopenharmony_ci                q += 2;
463cabdff1aSopenharmony_ci                buf_size -= 13;
464cabdff1aSopenharmony_ci
465cabdff1aSopenharmony_ci                top_ptr = q;
466cabdff1aSopenharmony_ci                ret = dvb_encode_rle(&q, buf_size,
467cabdff1aSopenharmony_ci                                     h->rects[object_id]->data[0],
468cabdff1aSopenharmony_ci                                     h->rects[object_id]->w * 2,
469cabdff1aSopenharmony_ci                                     h->rects[object_id]->w,
470cabdff1aSopenharmony_ci                                     h->rects[object_id]->h >> 1);
471cabdff1aSopenharmony_ci                if (ret < 0)
472cabdff1aSopenharmony_ci                    return ret;
473cabdff1aSopenharmony_ci                buf_size -= ret;
474cabdff1aSopenharmony_ci                bottom_ptr = q;
475cabdff1aSopenharmony_ci                ret = dvb_encode_rle(&q, buf_size,
476cabdff1aSopenharmony_ci                                     h->rects[object_id]->data[0] + h->rects[object_id]->w,
477cabdff1aSopenharmony_ci                                     h->rects[object_id]->w * 2,
478cabdff1aSopenharmony_ci                                     h->rects[object_id]->w,
479cabdff1aSopenharmony_ci                                     h->rects[object_id]->h >> 1);
480cabdff1aSopenharmony_ci                if (ret < 0)
481cabdff1aSopenharmony_ci                    return ret;
482cabdff1aSopenharmony_ci                buf_size -= ret;
483cabdff1aSopenharmony_ci
484cabdff1aSopenharmony_ci                bytestream_put_be16(&ptop_field_len, bottom_ptr - top_ptr);
485cabdff1aSopenharmony_ci                bytestream_put_be16(&pbottom_field_len, q - bottom_ptr);
486cabdff1aSopenharmony_ci            }
487cabdff1aSopenharmony_ci
488cabdff1aSopenharmony_ci            bytestream_put_be16(&pseg_len, q - pseg_len - 2);
489cabdff1aSopenharmony_ci        }
490cabdff1aSopenharmony_ci    }
491cabdff1aSopenharmony_ci
492cabdff1aSopenharmony_ci    /* end of display set segment */
493cabdff1aSopenharmony_ci
494cabdff1aSopenharmony_ci    if (buf_size < 6)
495cabdff1aSopenharmony_ci        return AVERROR_BUFFER_TOO_SMALL;
496cabdff1aSopenharmony_ci    *q++ = 0x0f; /* sync_byte */
497cabdff1aSopenharmony_ci    *q++ = 0x80; /* segment_type */
498cabdff1aSopenharmony_ci    bytestream_put_be16(&q, page_id);
499cabdff1aSopenharmony_ci    pseg_len = q;
500cabdff1aSopenharmony_ci    q += 2; /* segment length */
501cabdff1aSopenharmony_ci
502cabdff1aSopenharmony_ci    bytestream_put_be16(&pseg_len, q - pseg_len - 2);
503cabdff1aSopenharmony_ci    buf_size -= 6;
504cabdff1aSopenharmony_ci
505cabdff1aSopenharmony_ci    s->object_version = (s->object_version + 1) & 0xf;
506cabdff1aSopenharmony_ci    return q - outbuf;
507cabdff1aSopenharmony_ci}
508cabdff1aSopenharmony_ci
509cabdff1aSopenharmony_ciconst FFCodec ff_dvbsub_encoder = {
510cabdff1aSopenharmony_ci    .p.name         = "dvbsub",
511cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("DVB subtitles"),
512cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_SUBTITLE,
513cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_DVB_SUBTITLE,
514cabdff1aSopenharmony_ci    .priv_data_size = sizeof(DVBSubtitleContext),
515cabdff1aSopenharmony_ci    FF_CODEC_ENCODE_SUB_CB(dvbsub_encode),
516cabdff1aSopenharmony_ci};
517