Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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]->pict.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]->pict.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]->pict.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 | }; |