blob: 3cdbade99c429ee231b830b0034fbbeb9108e6a2
1 | /* |
2 | * DVB subtitle encoding |
3 | * Copyright (c) 2005 Fabrice Bellard |
4 | * |
5 | * This file is part of FFmpeg. |
6 | * |
7 | * FFmpeg is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * FFmpeg is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with FFmpeg; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ |
21 | #include "avcodec.h" |
22 | #include "bytestream.h" |
23 | #include "libavutil/colorspace.h" |
24 | |
25 | typedef struct DVBSubtitleContext { |
26 | int object_version; |
27 | } DVBSubtitleContext; |
28 | |
29 | #define PUTBITS2(val)\ |
30 | {\ |
31 | bitbuf |= (val) << bitcnt;\ |
32 | bitcnt -= 2;\ |
33 | if (bitcnt < 0) {\ |
34 | bitcnt = 6;\ |
35 | *q++ = bitbuf;\ |
36 | bitbuf = 0;\ |
37 | }\ |
38 | } |
39 | |
40 | static void dvb_encode_rle2(uint8_t **pq, |
41 | const uint8_t *bitmap, int linesize, |
42 | int w, int h) |
43 | { |
44 | uint8_t *q; |
45 | unsigned int bitbuf; |
46 | int bitcnt; |
47 | int x, y, len, x1, v, color; |
48 | |
49 | q = *pq; |
50 | |
51 | for(y = 0; y < h; y++) { |
52 | *q++ = 0x10; |
53 | bitbuf = 0; |
54 | bitcnt = 6; |
55 | |
56 | x = 0; |
57 | while (x < w) { |
58 | x1 = x; |
59 | color = bitmap[x1++]; |
60 | while (x1 < w && bitmap[x1] == color) |
61 | x1++; |
62 | len = x1 - x; |
63 | if (color == 0 && len == 2) { |
64 | PUTBITS2(0); |
65 | PUTBITS2(0); |
66 | PUTBITS2(1); |
67 | } else if (len >= 3 && len <= 10) { |
68 | v = len - 3; |
69 | PUTBITS2(0); |
70 | PUTBITS2((v >> 2) | 2); |
71 | PUTBITS2(v & 3); |
72 | PUTBITS2(color); |
73 | } else if (len >= 12 && len <= 27) { |
74 | v = len - 12; |
75 | PUTBITS2(0); |
76 | PUTBITS2(0); |
77 | PUTBITS2(2); |
78 | PUTBITS2(v >> 2); |
79 | PUTBITS2(v & 3); |
80 | PUTBITS2(color); |
81 | } else if (len >= 29) { |
82 | /* length = 29 ... 284 */ |
83 | if (len > 284) |
84 | len = 284; |
85 | v = len - 29; |
86 | PUTBITS2(0); |
87 | PUTBITS2(0); |
88 | PUTBITS2(3); |
89 | PUTBITS2((v >> 6)); |
90 | PUTBITS2((v >> 4) & 3); |
91 | PUTBITS2((v >> 2) & 3); |
92 | PUTBITS2(v & 3); |
93 | PUTBITS2(color); |
94 | } else { |
95 | PUTBITS2(color); |
96 | if (color == 0) { |
97 | PUTBITS2(1); |
98 | } |
99 | len = 1; |
100 | } |
101 | x += len; |
102 | } |
103 | /* end of line */ |
104 | PUTBITS2(0); |
105 | PUTBITS2(0); |
106 | PUTBITS2(0); |
107 | if (bitcnt != 6) { |
108 | *q++ = bitbuf; |
109 | } |
110 | *q++ = 0xf0; |
111 | bitmap += linesize; |
112 | } |
113 | *pq = q; |
114 | } |
115 | |
116 | #define PUTBITS4(val)\ |
117 | {\ |
118 | bitbuf |= (val) << bitcnt;\ |
119 | bitcnt -= 4;\ |
120 | if (bitcnt < 0) {\ |
121 | bitcnt = 4;\ |
122 | *q++ = bitbuf;\ |
123 | bitbuf = 0;\ |
124 | }\ |
125 | } |
126 | |
127 | /* some DVB decoders only implement 4 bits/pixel */ |
128 | static void dvb_encode_rle4(uint8_t **pq, |
129 | const uint8_t *bitmap, int linesize, |
130 | int w, int h) |
131 | { |
132 | uint8_t *q; |
133 | unsigned int bitbuf; |
134 | int bitcnt; |
135 | int x, y, len, x1, v, color; |
136 | |
137 | q = *pq; |
138 | |
139 | for(y = 0; y < h; y++) { |
140 | *q++ = 0x11; |
141 | bitbuf = 0; |
142 | bitcnt = 4; |
143 | |
144 | x = 0; |
145 | while (x < w) { |
146 | x1 = x; |
147 | color = bitmap[x1++]; |
148 | while (x1 < w && bitmap[x1] == color) |
149 | x1++; |
150 | len = x1 - x; |
151 | if (color == 0 && len == 2) { |
152 | PUTBITS4(0); |
153 | PUTBITS4(0xd); |
154 | } else if (color == 0 && (len >= 3 && len <= 9)) { |
155 | PUTBITS4(0); |
156 | PUTBITS4(len - 2); |
157 | } else if (len >= 4 && len <= 7) { |
158 | PUTBITS4(0); |
159 | PUTBITS4(8 + len - 4); |
160 | PUTBITS4(color); |
161 | } else if (len >= 9 && len <= 24) { |
162 | PUTBITS4(0); |
163 | PUTBITS4(0xe); |
164 | PUTBITS4(len - 9); |
165 | PUTBITS4(color); |
166 | } else if (len >= 25) { |
167 | if (len > 280) |
168 | len = 280; |
169 | v = len - 25; |
170 | PUTBITS4(0); |
171 | PUTBITS4(0xf); |
172 | PUTBITS4(v >> 4); |
173 | PUTBITS4(v & 0xf); |
174 | PUTBITS4(color); |
175 | } else { |
176 | PUTBITS4(color); |
177 | if (color == 0) { |
178 | PUTBITS4(0xc); |
179 | } |
180 | len = 1; |
181 | } |
182 | x += len; |
183 | } |
184 | /* end of line */ |
185 | PUTBITS4(0); |
186 | PUTBITS4(0); |
187 | if (bitcnt != 4) { |
188 | *q++ = bitbuf; |
189 | } |
190 | *q++ = 0xf0; |
191 | bitmap += linesize; |
192 | } |
193 | *pq = q; |
194 | } |
195 | |
196 | static void dvb_encode_rle8(uint8_t **pq, |
197 | const uint8_t *bitmap, int linesize, |
198 | int w, int h) |
199 | { |
200 | uint8_t *q; |
201 | int x, y, len, x1, color; |
202 | |
203 | q = *pq; |
204 | |
205 | for (y = 0; y < h; y++) { |
206 | *q++ = 0x12; |
207 | |
208 | x = 0; |
209 | while (x < w) { |
210 | x1 = x; |
211 | color = bitmap[x1++]; |
212 | while (x1 < w && bitmap[x1] == color) |
213 | x1++; |
214 | len = x1 - x; |
215 | if (len == 1 && color) { |
216 | // 00000001 to 11111111 1 pixel in colour x |
217 | *q++ = color; |
218 | } else { |
219 | if (color == 0x00) { |
220 | // 00000000 0LLLLLLL L pixels (1-127) in colour 0 (L > 0) |
221 | len = FFMIN(len, 127); |
222 | *q++ = 0x00; |
223 | *q++ = len; |
224 | } else if (len > 2) { |
225 | // 00000000 1LLLLLLL CCCCCCCC L pixels (3-127) in colour C (L > 2) |
226 | len = FFMIN(len, 127); |
227 | *q++ = 0x00; |
228 | *q++ = 0x80+len; |
229 | *q++ = color; |
230 | } |
231 | else if (len == 2) { |
232 | *q++ = color; |
233 | *q++ = color; |
234 | } else { |
235 | *q++ = color; |
236 | len = 1; |
237 | } |
238 | } |
239 | x += len; |
240 | } |
241 | /* end of line */ |
242 | // 00000000 00000000 end of 8-bit/pixel_code_string |
243 | *q++ = 0x00; |
244 | *q++ = 0x00; |
245 | bitmap += linesize; |
246 | } |
247 | *pq = q; |
248 | } |
249 | |
250 | static int encode_dvb_subtitles(DVBSubtitleContext *s, |
251 | uint8_t *outbuf, const AVSubtitle *h) |
252 | { |
253 | uint8_t *q, *pseg_len; |
254 | int page_id, region_id, clut_id, object_id, i, bpp_index, page_state; |
255 | |
256 | |
257 | q = outbuf; |
258 | |
259 | page_id = 1; |
260 | |
261 | if (h->num_rects && !h->rects) |
262 | return -1; |
263 | |
264 | /* page composition segment */ |
265 | |
266 | *q++ = 0x0f; /* sync_byte */ |
267 | *q++ = 0x10; /* segment_type */ |
268 | bytestream_put_be16(&q, page_id); |
269 | pseg_len = q; |
270 | q += 2; /* segment length */ |
271 | *q++ = 30; /* page_timeout (seconds) */ |
272 | page_state = 2; /* mode change */ |
273 | /* page_version = 0 + page_state */ |
274 | *q++ = (s->object_version << 4) | (page_state << 2) | 3; |
275 | |
276 | for (region_id = 0; region_id < h->num_rects; region_id++) { |
277 | *q++ = region_id; |
278 | *q++ = 0xff; /* reserved */ |
279 | bytestream_put_be16(&q, h->rects[region_id]->x); /* left pos */ |
280 | bytestream_put_be16(&q, h->rects[region_id]->y); /* top pos */ |
281 | } |
282 | |
283 | bytestream_put_be16(&pseg_len, q - pseg_len - 2); |
284 | |
285 | if (h->num_rects) { |
286 | for (clut_id = 0; clut_id < h->num_rects; clut_id++) { |
287 | |
288 | /* CLUT segment */ |
289 | |
290 | if (h->rects[clut_id]->nb_colors <= 4) { |
291 | /* 2 bpp, some decoders do not support it correctly */ |
292 | bpp_index = 0; |
293 | } else if (h->rects[clut_id]->nb_colors <= 16) { |
294 | /* 4 bpp, standard encoding */ |
295 | bpp_index = 1; |
296 | } else if (h->rects[clut_id]->nb_colors <= 256) { |
297 | /* 8 bpp, standard encoding */ |
298 | bpp_index = 2; |
299 | } else { |
300 | return -1; |
301 | } |
302 | |
303 | |
304 | /* CLUT segment */ |
305 | *q++ = 0x0f; /* sync byte */ |
306 | *q++ = 0x12; /* CLUT definition segment */ |
307 | bytestream_put_be16(&q, page_id); |
308 | pseg_len = q; |
309 | q += 2; /* segment length */ |
310 | *q++ = clut_id; |
311 | *q++ = (0 << 4) | 0xf; /* version = 0 */ |
312 | |
313 | for(i = 0; i < h->rects[clut_id]->nb_colors; i++) { |
314 | *q++ = i; /* clut_entry_id */ |
315 | *q++ = (1 << (7 - bpp_index)) | (0xf << 1) | 1; /* 2 bits/pixel full range */ |
316 | { |
317 | int a, r, g, b; |
318 | uint32_t x= ((uint32_t*)h->rects[clut_id]->data[1])[i]; |
319 | a = (x >> 24) & 0xff; |
320 | r = (x >> 16) & 0xff; |
321 | g = (x >> 8) & 0xff; |
322 | b = (x >> 0) & 0xff; |
323 | |
324 | *q++ = RGB_TO_Y_CCIR(r, g, b); |
325 | *q++ = RGB_TO_V_CCIR(r, g, b, 0); |
326 | *q++ = RGB_TO_U_CCIR(r, g, b, 0); |
327 | *q++ = 255 - a; |
328 | } |
329 | } |
330 | |
331 | bytestream_put_be16(&pseg_len, q - pseg_len - 2); |
332 | } |
333 | } |
334 | |
335 | for (region_id = 0; region_id < h->num_rects; region_id++) { |
336 | |
337 | /* region composition segment */ |
338 | |
339 | if (h->rects[region_id]->nb_colors <= 4) { |
340 | /* 2 bpp, some decoders do not support it correctly */ |
341 | bpp_index = 0; |
342 | } else if (h->rects[region_id]->nb_colors <= 16) { |
343 | /* 4 bpp, standard encoding */ |
344 | bpp_index = 1; |
345 | } else { |
346 | return -1; |
347 | } |
348 | |
349 | *q++ = 0x0f; /* sync_byte */ |
350 | *q++ = 0x11; /* segment_type */ |
351 | bytestream_put_be16(&q, page_id); |
352 | pseg_len = q; |
353 | q += 2; /* segment length */ |
354 | *q++ = region_id; |
355 | *q++ = (s->object_version << 4) | (0 << 3) | 0x07; /* version , no fill */ |
356 | bytestream_put_be16(&q, h->rects[region_id]->w); /* region width */ |
357 | bytestream_put_be16(&q, h->rects[region_id]->h); /* region height */ |
358 | *q++ = ((1 + bpp_index) << 5) | ((1 + bpp_index) << 2) | 0x03; |
359 | *q++ = region_id; /* clut_id == region_id */ |
360 | *q++ = 0; /* 8 bit fill colors */ |
361 | *q++ = 0x03; /* 4 bit and 2 bit fill colors */ |
362 | |
363 | bytestream_put_be16(&q, region_id); /* object_id == region_id */ |
364 | *q++ = (0 << 6) | (0 << 4); |
365 | *q++ = 0; |
366 | *q++ = 0xf0; |
367 | *q++ = 0; |
368 | |
369 | bytestream_put_be16(&pseg_len, q - pseg_len - 2); |
370 | } |
371 | |
372 | if (h->num_rects) { |
373 | |
374 | for (object_id = 0; object_id < h->num_rects; object_id++) { |
375 | void (*dvb_encode_rle)(uint8_t **pq, |
376 | const uint8_t *bitmap, int linesize, |
377 | int w, int h); |
378 | |
379 | /* bpp_index maths */ |
380 | if (h->rects[object_id]->nb_colors <= 4) { |
381 | /* 2 bpp, some decoders do not support it correctly */ |
382 | dvb_encode_rle = dvb_encode_rle2; |
383 | } else if (h->rects[object_id]->nb_colors <= 16) { |
384 | /* 4 bpp, standard encoding */ |
385 | dvb_encode_rle = dvb_encode_rle4; |
386 | } else if (h->rects[object_id]->nb_colors <= 256) { |
387 | /* 8 bpp, standard encoding */ |
388 | dvb_encode_rle = dvb_encode_rle8; |
389 | } else { |
390 | return -1; |
391 | } |
392 | |
393 | /* Object Data segment */ |
394 | *q++ = 0x0f; /* sync byte */ |
395 | *q++ = 0x13; |
396 | bytestream_put_be16(&q, page_id); |
397 | pseg_len = q; |
398 | q += 2; /* segment length */ |
399 | |
400 | bytestream_put_be16(&q, object_id); |
401 | *q++ = (s->object_version << 4) | (0 << 2) | (0 << 1) | 1; /* version = 0, |
402 | onject_coding_method, |
403 | non_modifying_color_flag */ |
404 | { |
405 | uint8_t *ptop_field_len, *pbottom_field_len, *top_ptr, *bottom_ptr; |
406 | |
407 | ptop_field_len = q; |
408 | q += 2; |
409 | pbottom_field_len = q; |
410 | q += 2; |
411 | |
412 | top_ptr = q; |
413 | dvb_encode_rle(&q, h->rects[object_id]->data[0], h->rects[object_id]->w * 2, |
414 | h->rects[object_id]->w, h->rects[object_id]->h >> 1); |
415 | bottom_ptr = q; |
416 | dvb_encode_rle(&q, h->rects[object_id]->data[0] + h->rects[object_id]->w, |
417 | h->rects[object_id]->w * 2, h->rects[object_id]->w, |
418 | h->rects[object_id]->h >> 1); |
419 | |
420 | bytestream_put_be16(&ptop_field_len, bottom_ptr - top_ptr); |
421 | bytestream_put_be16(&pbottom_field_len, q - bottom_ptr); |
422 | } |
423 | |
424 | bytestream_put_be16(&pseg_len, q - pseg_len - 2); |
425 | } |
426 | } |
427 | |
428 | /* end of display set segment */ |
429 | |
430 | *q++ = 0x0f; /* sync_byte */ |
431 | *q++ = 0x80; /* segment_type */ |
432 | bytestream_put_be16(&q, page_id); |
433 | pseg_len = q; |
434 | q += 2; /* segment length */ |
435 | |
436 | bytestream_put_be16(&pseg_len, q - pseg_len - 2); |
437 | |
438 | s->object_version = (s->object_version + 1) & 0xf; |
439 | return q - outbuf; |
440 | } |
441 | |
442 | static int dvbsub_encode(AVCodecContext *avctx, |
443 | unsigned char *buf, int buf_size, |
444 | const AVSubtitle *sub) |
445 | { |
446 | DVBSubtitleContext *s = avctx->priv_data; |
447 | int ret; |
448 | |
449 | ret = encode_dvb_subtitles(s, buf, sub); |
450 | return ret; |
451 | } |
452 | |
453 | AVCodec ff_dvbsub_encoder = { |
454 | .name = "dvbsub", |
455 | .long_name = NULL_IF_CONFIG_SMALL("DVB subtitles"), |
456 | .type = AVMEDIA_TYPE_SUBTITLE, |
457 | .id = AV_CODEC_ID_DVB_SUBTITLE, |
458 | .priv_data_size = sizeof(DVBSubtitleContext), |
459 | .encode_sub = dvbsub_encode, |
460 | }; |
461 |