Commit | Line | Data |
---|---|---|
c6ec28b1 MN |
1 | /* |
2 | * DVB subtitle decoding for ffmpeg | |
3 | * Copyright (c) 2005 Ian Caulfield. | |
4 | * | |
b78e7197 DB |
5 | * This file is part of FFmpeg. |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
c6ec28b1 MN |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either | |
b78e7197 | 10 | * version 2.1 of the License, or (at your option) any later version. |
c6ec28b1 | 11 | * |
b78e7197 | 12 | * FFmpeg is distributed in the hope that it will be useful, |
c6ec28b1 MN |
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 | |
b78e7197 | 18 | * License along with FFmpeg; if not, write to the Free Software |
5509bffa | 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
c6ec28b1 MN |
20 | */ |
21 | #include "avcodec.h" | |
22 | #include "dsputil.h" | |
23 | #include "bitstream.h" | |
04d2e45f | 24 | #include "colorspace.h" |
c6ec28b1 MN |
25 | |
26 | //#define DEBUG | |
27 | //#define DEBUG_PACKET_CONTENTS | |
28 | //#define DEBUG_SAVE_IMAGES | |
29 | ||
30 | #define DVBSUB_PAGE_SEGMENT 0x10 | |
31 | #define DVBSUB_REGION_SEGMENT 0x11 | |
32 | #define DVBSUB_CLUT_SEGMENT 0x12 | |
33 | #define DVBSUB_OBJECT_SEGMENT 0x13 | |
34 | #define DVBSUB_DISPLAY_SEGMENT 0x80 | |
35 | ||
0c3c674c | 36 | #define cm (ff_cropTbl + MAX_NEG_CROP) |
c6ec28b1 MN |
37 | |
38 | #ifdef DEBUG_SAVE_IMAGES | |
39 | #undef fprintf | |
40 | #if 0 | |
41 | static void png_save(const char *filename, uint8_t *bitmap, int w, int h, | |
42 | uint32_t *rgba_palette) | |
43 | { | |
44 | int x, y, v; | |
45 | FILE *f; | |
46 | char fname[40], fname2[40]; | |
47 | char command[1024]; | |
115329f1 | 48 | |
c6ec28b1 MN |
49 | snprintf(fname, 40, "%s.ppm", filename); |
50 | ||
51 | f = fopen(fname, "w"); | |
52 | if (!f) { | |
53 | perror(fname); | |
54 | exit(1); | |
55 | } | |
56 | fprintf(f, "P6\n" | |
57 | "%d %d\n" | |
58 | "%d\n", | |
59 | w, h, 255); | |
60 | for(y = 0; y < h; y++) { | |
61 | for(x = 0; x < w; x++) { | |
62 | v = rgba_palette[bitmap[y * w + x]]; | |
63 | putc((v >> 16) & 0xff, f); | |
64 | putc((v >> 8) & 0xff, f); | |
65 | putc((v >> 0) & 0xff, f); | |
66 | } | |
67 | } | |
68 | fclose(f); | |
115329f1 DB |
69 | |
70 | ||
c6ec28b1 MN |
71 | snprintf(fname2, 40, "%s-a.pgm", filename); |
72 | ||
73 | f = fopen(fname2, "w"); | |
74 | if (!f) { | |
75 | perror(fname2); | |
76 | exit(1); | |
77 | } | |
78 | fprintf(f, "P5\n" | |
79 | "%d %d\n" | |
80 | "%d\n", | |
81 | w, h, 255); | |
82 | for(y = 0; y < h; y++) { | |
83 | for(x = 0; x < w; x++) { | |
84 | v = rgba_palette[bitmap[y * w + x]]; | |
85 | putc((v >> 24) & 0xff, f); | |
86 | } | |
87 | } | |
88 | fclose(f); | |
115329f1 | 89 | |
c6ec28b1 MN |
90 | snprintf(command, 1024, "pnmtopng -alpha %s %s > %s.png 2> /dev/null", fname2, fname, filename); |
91 | system(command); | |
115329f1 | 92 | |
c6ec28b1 MN |
93 | snprintf(command, 1024, "rm %s %s", fname, fname2); |
94 | system(command); | |
95 | } | |
96 | #endif | |
97 | ||
98 | static void png_save2(const char *filename, uint32_t *bitmap, int w, int h) | |
99 | { | |
100 | int x, y, v; | |
101 | FILE *f; | |
102 | char fname[40], fname2[40]; | |
103 | char command[1024]; | |
115329f1 | 104 | |
e1c48b7a | 105 | snprintf(fname, sizeof(fname), "%s.ppm", filename); |
c6ec28b1 MN |
106 | |
107 | f = fopen(fname, "w"); | |
108 | if (!f) { | |
109 | perror(fname); | |
110 | exit(1); | |
111 | } | |
112 | fprintf(f, "P6\n" | |
113 | "%d %d\n" | |
114 | "%d\n", | |
115 | w, h, 255); | |
116 | for(y = 0; y < h; y++) { | |
117 | for(x = 0; x < w; x++) { | |
118 | v = bitmap[y * w + x]; | |
119 | putc((v >> 16) & 0xff, f); | |
120 | putc((v >> 8) & 0xff, f); | |
121 | putc((v >> 0) & 0xff, f); | |
122 | } | |
123 | } | |
124 | fclose(f); | |
115329f1 DB |
125 | |
126 | ||
e1c48b7a | 127 | snprintf(fname2, sizeof(fname2), "%s-a.pgm", filename); |
c6ec28b1 MN |
128 | |
129 | f = fopen(fname2, "w"); | |
130 | if (!f) { | |
131 | perror(fname2); | |
132 | exit(1); | |
133 | } | |
134 | fprintf(f, "P5\n" | |
135 | "%d %d\n" | |
136 | "%d\n", | |
137 | w, h, 255); | |
138 | for(y = 0; y < h; y++) { | |
139 | for(x = 0; x < w; x++) { | |
140 | v = bitmap[y * w + x]; | |
141 | putc((v >> 24) & 0xff, f); | |
142 | } | |
143 | } | |
144 | fclose(f); | |
115329f1 | 145 | |
e1c48b7a | 146 | snprintf(command, sizeof(command), "pnmtopng -alpha %s %s > %s.png 2> /dev/null", fname2, fname, filename); |
c6ec28b1 | 147 | system(command); |
115329f1 | 148 | |
e1c48b7a | 149 | snprintf(command, sizeof(command), "rm %s %s", fname, fname2); |
c6ec28b1 MN |
150 | system(command); |
151 | } | |
152 | #endif | |
153 | ||
154 | #define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) | |
155 | ||
156 | typedef struct DVBSubCLUT { | |
157 | int id; | |
158 | ||
159 | uint32_t clut4[4]; | |
160 | uint32_t clut16[16]; | |
161 | uint32_t clut256[256]; | |
115329f1 | 162 | |
c6ec28b1 MN |
163 | struct DVBSubCLUT *next; |
164 | } DVBSubCLUT; | |
165 | ||
166 | static DVBSubCLUT default_clut; | |
167 | ||
168 | typedef struct DVBSubObjectDisplay { | |
169 | int object_id; | |
170 | int region_id; | |
171 | ||
172 | int x_pos; | |
173 | int y_pos; | |
174 | ||
175 | int fgcolour; | |
176 | int bgcolour; | |
115329f1 | 177 | |
c6ec28b1 | 178 | struct DVBSubObjectDisplay *region_list_next; |
115329f1 | 179 | struct DVBSubObjectDisplay *object_list_next; |
c6ec28b1 MN |
180 | } DVBSubObjectDisplay; |
181 | ||
182 | typedef struct DVBSubObject { | |
183 | int id; | |
184 | ||
185 | int type; | |
115329f1 DB |
186 | |
187 | DVBSubObjectDisplay *display_list; | |
188 | ||
c6ec28b1 MN |
189 | struct DVBSubObject *next; |
190 | } DVBSubObject; | |
191 | ||
192 | typedef struct DVBSubRegionDisplay { | |
193 | int region_id; | |
194 | ||
195 | int x_pos; | |
196 | int y_pos; | |
197 | ||
198 | struct DVBSubRegionDisplay *next; | |
199 | } DVBSubRegionDisplay; | |
200 | ||
201 | typedef struct DVBSubRegion { | |
202 | int id; | |
203 | ||
204 | int width; | |
205 | int height; | |
206 | int depth; | |
115329f1 | 207 | |
c6ec28b1 MN |
208 | int clut; |
209 | int bgcolour; | |
115329f1 | 210 | |
c6ec28b1 MN |
211 | uint8_t *pbuf; |
212 | int buf_size; | |
213 | ||
214 | DVBSubObjectDisplay *display_list; | |
115329f1 | 215 | |
c6ec28b1 MN |
216 | struct DVBSubRegion *next; |
217 | } DVBSubRegion; | |
218 | ||
219 | typedef struct DVBSubContext { | |
220 | int composition_id; | |
221 | int ancillary_id; | |
222 | ||
223 | int time_out; | |
224 | DVBSubRegion *region_list; | |
225 | DVBSubCLUT *clut_list; | |
226 | DVBSubObject *object_list; | |
115329f1 | 227 | |
c6ec28b1 MN |
228 | int display_list_size; |
229 | DVBSubRegionDisplay *display_list; | |
230 | } DVBSubContext; | |
231 | ||
232 | ||
233 | static DVBSubObject* get_object(DVBSubContext *ctx, int object_id) | |
234 | { | |
235 | DVBSubObject *ptr = ctx->object_list; | |
236 | ||
237 | while (ptr != NULL && ptr->id != object_id) { | |
238 | ptr = ptr->next; | |
239 | } | |
115329f1 | 240 | |
c6ec28b1 MN |
241 | return ptr; |
242 | } | |
243 | ||
244 | static DVBSubCLUT* get_clut(DVBSubContext *ctx, int clut_id) | |
245 | { | |
246 | DVBSubCLUT *ptr = ctx->clut_list; | |
247 | ||
248 | while (ptr != NULL && ptr->id != clut_id) { | |
249 | ptr = ptr->next; | |
250 | } | |
115329f1 | 251 | |
c6ec28b1 MN |
252 | return ptr; |
253 | } | |
254 | ||
255 | static DVBSubRegion* get_region(DVBSubContext *ctx, int region_id) | |
256 | { | |
257 | DVBSubRegion *ptr = ctx->region_list; | |
258 | ||
259 | while (ptr != NULL && ptr->id != region_id) { | |
260 | ptr = ptr->next; | |
261 | } | |
115329f1 | 262 | |
c6ec28b1 MN |
263 | return ptr; |
264 | } | |
265 | ||
266 | static void delete_region_display_list(DVBSubContext *ctx, DVBSubRegion *region) | |
267 | { | |
268 | DVBSubObject *object, *obj2, **obj2_ptr; | |
269 | DVBSubObjectDisplay *display, *obj_disp, **obj_disp_ptr; | |
270 | ||
271 | while (region->display_list != NULL) { | |
272 | display = region->display_list; | |
115329f1 | 273 | |
c6ec28b1 | 274 | object = get_object(ctx, display->object_id); |
115329f1 | 275 | |
c6ec28b1 MN |
276 | if (object != NULL) { |
277 | obj_disp = object->display_list; | |
278 | obj_disp_ptr = &object->display_list; | |
115329f1 | 279 | |
c6ec28b1 MN |
280 | while (obj_disp != NULL && obj_disp != display) { |
281 | obj_disp_ptr = &obj_disp->object_list_next; | |
282 | obj_disp = obj_disp->object_list_next; | |
283 | } | |
115329f1 | 284 | |
c6ec28b1 MN |
285 | if (obj_disp) { |
286 | *obj_disp_ptr = obj_disp->object_list_next; | |
115329f1 | 287 | |
c6ec28b1 MN |
288 | if (object->display_list == NULL) { |
289 | obj2 = ctx->object_list; | |
290 | obj2_ptr = &ctx->object_list; | |
291 | ||
292 | while (obj2 != NULL && obj2 != object) { | |
293 | obj2_ptr = &obj2->next; | |
294 | obj2 = obj2->next; | |
295 | } | |
115329f1 | 296 | |
c6ec28b1 | 297 | *obj2_ptr = obj2->next; |
115329f1 | 298 | |
c6ec28b1 MN |
299 | av_free(obj2); |
300 | } | |
301 | } | |
302 | } | |
115329f1 | 303 | |
c6ec28b1 | 304 | region->display_list = display->region_list_next; |
115329f1 | 305 | |
c6ec28b1 MN |
306 | av_free(display); |
307 | } | |
115329f1 | 308 | |
c6ec28b1 MN |
309 | } |
310 | ||
311 | static void delete_state(DVBSubContext *ctx) | |
312 | { | |
313 | DVBSubRegion *region; | |
314 | DVBSubCLUT *clut; | |
115329f1 | 315 | |
c6ec28b1 MN |
316 | while (ctx->region_list != NULL) |
317 | { | |
318 | region = ctx->region_list; | |
319 | ||
320 | ctx->region_list = region->next; | |
321 | ||
322 | delete_region_display_list(ctx, region); | |
323 | if (region->pbuf != NULL) | |
324 | av_free(region->pbuf); | |
325 | ||
326 | av_free(region); | |
327 | } | |
328 | ||
329 | while (ctx->clut_list != NULL) | |
330 | { | |
331 | clut = ctx->clut_list; | |
332 | ||
333 | ctx->clut_list = clut->next; | |
334 | ||
335 | av_free(clut); | |
336 | } | |
337 | ||
338 | /* Should already be null */ | |
339 | if (ctx->object_list != NULL) | |
340 | av_log(0, AV_LOG_ERROR, "Memory deallocation error!\n"); | |
341 | } | |
342 | ||
343 | static int dvbsub_init_decoder(AVCodecContext *avctx) | |
344 | { | |
345 | int i, r, g, b, a = 0; | |
346 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
347 | ||
c6ec28b1 | 348 | memset(avctx->priv_data, 0, sizeof(DVBSubContext)); |
115329f1 | 349 | |
c6ec28b1 MN |
350 | ctx->composition_id = avctx->sub_id & 0xffff; |
351 | ctx->ancillary_id = avctx->sub_id >> 16; | |
352 | ||
353 | default_clut.id = -1; | |
354 | default_clut.next = NULL; | |
355 | ||
356 | default_clut.clut4[0] = RGBA( 0, 0, 0, 0); | |
357 | default_clut.clut4[1] = RGBA(255, 255, 255, 255); | |
358 | default_clut.clut4[2] = RGBA( 0, 0, 0, 255); | |
359 | default_clut.clut4[3] = RGBA(127, 127, 127, 255); | |
360 | ||
361 | default_clut.clut16[0] = RGBA( 0, 0, 0, 0); | |
362 | for (i = 1; i < 16; i++) { | |
363 | if (i < 8) { | |
364 | r = (i & 1) ? 255 : 0; | |
365 | g = (i & 2) ? 255 : 0; | |
366 | b = (i & 4) ? 255 : 0; | |
367 | } else { | |
368 | r = (i & 1) ? 127 : 0; | |
369 | g = (i & 2) ? 127 : 0; | |
370 | b = (i & 4) ? 127 : 0; | |
115329f1 | 371 | } |
c6ec28b1 MN |
372 | default_clut.clut16[i] = RGBA(r, g, b, 255); |
373 | } | |
374 | ||
375 | default_clut.clut256[0] = RGBA( 0, 0, 0, 0); | |
376 | for (i = 1; i < 256; i++) { | |
377 | if (i < 8) { | |
378 | r = (i & 1) ? 255 : 0; | |
379 | g = (i & 2) ? 255 : 0; | |
380 | b = (i & 4) ? 255 : 0; | |
381 | a = 63; | |
382 | } else { | |
383 | switch (i & 0x88) { | |
384 | case 0x00: | |
385 | r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0); | |
386 | g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0); | |
387 | b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0); | |
388 | a = 255; | |
389 | break; | |
390 | case 0x08: | |
391 | r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0); | |
392 | g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0); | |
393 | b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0); | |
394 | a = 127; | |
395 | break; | |
396 | case 0x80: | |
397 | r = 127 + ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0); | |
398 | g = 127 + ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0); | |
399 | b = 127 + ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0); | |
400 | a = 255; | |
401 | break; | |
402 | case 0x88: | |
403 | r = ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0); | |
404 | g = ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0); | |
405 | b = ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0); | |
406 | a = 255; | |
407 | break; | |
408 | } | |
115329f1 | 409 | } |
c6ec28b1 MN |
410 | default_clut.clut256[i] = RGBA(r, g, b, a); |
411 | } | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
416 | static int dvbsub_close_decoder(AVCodecContext *avctx) | |
417 | { | |
418 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
419 | DVBSubRegionDisplay *display; | |
420 | ||
421 | delete_state(ctx); | |
115329f1 | 422 | |
c6ec28b1 MN |
423 | while (ctx->display_list != NULL) |
424 | { | |
425 | display = ctx->display_list; | |
426 | ctx->display_list = display->next; | |
115329f1 | 427 | |
c6ec28b1 MN |
428 | av_free(display); |
429 | } | |
430 | ||
431 | return 0; | |
432 | } | |
433 | ||
115329f1 DB |
434 | static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len, |
435 | uint8_t **srcbuf, int buf_size, | |
c6ec28b1 MN |
436 | int non_mod, uint8_t *map_table) |
437 | { | |
438 | GetBitContext gb; | |
115329f1 | 439 | |
c6ec28b1 MN |
440 | int bits; |
441 | int run_length; | |
442 | int pixels_read = 0; | |
115329f1 | 443 | |
c6ec28b1 | 444 | init_get_bits(&gb, *srcbuf, buf_size << 8); |
115329f1 | 445 | |
c6ec28b1 MN |
446 | while (get_bits_count(&gb) < (buf_size << 8) && pixels_read < dbuf_len) { |
447 | bits = get_bits(&gb, 2); | |
448 | ||
449 | if (bits != 0) { | |
450 | if (non_mod != 1 || bits != 1) { | |
451 | if (map_table != NULL) | |
452 | *destbuf++ = map_table[bits]; | |
453 | else | |
454 | *destbuf++ = bits; | |
455 | } | |
456 | pixels_read++; | |
457 | } else { | |
5fc32c27 | 458 | bits = get_bits1(&gb); |
c6ec28b1 MN |
459 | if (bits == 1) { |
460 | run_length = get_bits(&gb, 3) + 3; | |
461 | bits = get_bits(&gb, 2); | |
115329f1 | 462 | |
c6ec28b1 MN |
463 | if (non_mod == 1 && bits == 1) |
464 | pixels_read += run_length; | |
465 | else { | |
466 | if (map_table != NULL) | |
467 | bits = map_table[bits]; | |
468 | while (run_length-- > 0 && pixels_read < dbuf_len) { | |
469 | *destbuf++ = bits; | |
470 | pixels_read++; | |
471 | } | |
472 | } | |
473 | } else { | |
5fc32c27 | 474 | bits = get_bits1(&gb); |
c6ec28b1 MN |
475 | if (bits == 0) { |
476 | bits = get_bits(&gb, 2); | |
477 | if (bits == 2) { | |
478 | run_length = get_bits(&gb, 4) + 12; | |
479 | bits = get_bits(&gb, 2); | |
480 | ||
481 | if (non_mod == 1 && bits == 1) | |
482 | pixels_read += run_length; | |
483 | else { | |
484 | if (map_table != NULL) | |
485 | bits = map_table[bits]; | |
486 | while (run_length-- > 0 && pixels_read < dbuf_len) { | |
487 | *destbuf++ = bits; | |
488 | pixels_read++; | |
489 | } | |
490 | } | |
491 | } else if (bits == 3) { | |
492 | run_length = get_bits(&gb, 8) + 29; | |
493 | bits = get_bits(&gb, 2); | |
494 | ||
495 | if (non_mod == 1 && bits == 1) | |
496 | pixels_read += run_length; | |
497 | else { | |
498 | if (map_table != NULL) | |
499 | bits = map_table[bits]; | |
500 | while (run_length-- > 0 && pixels_read < dbuf_len) { | |
501 | *destbuf++ = bits; | |
502 | pixels_read++; | |
503 | } | |
504 | } | |
505 | } else if (bits == 1) { | |
506 | pixels_read += 2; | |
507 | if (map_table != NULL) | |
508 | bits = map_table[0]; | |
509 | else | |
510 | bits = 0; | |
511 | if (pixels_read <= dbuf_len) { | |
512 | *destbuf++ = bits; | |
513 | *destbuf++ = bits; | |
514 | } | |
515 | } else { | |
516 | (*srcbuf) += (get_bits_count(&gb) + 7) >> 3; | |
517 | return pixels_read; | |
518 | } | |
519 | } else { | |
520 | if (map_table != NULL) | |
521 | bits = map_table[0]; | |
522 | else | |
523 | bits = 0; | |
524 | *destbuf++ = bits; | |
525 | pixels_read++; | |
526 | } | |
527 | } | |
528 | } | |
529 | } | |
115329f1 | 530 | |
c6ec28b1 MN |
531 | if (get_bits(&gb, 6) != 0) |
532 | av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n"); | |
533 | ||
534 | (*srcbuf) += (get_bits_count(&gb) + 7) >> 3; | |
535 | ||
536 | return pixels_read; | |
537 | } | |
115329f1 DB |
538 | |
539 | static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len, | |
540 | uint8_t **srcbuf, int buf_size, | |
c6ec28b1 MN |
541 | int non_mod, uint8_t *map_table) |
542 | { | |
543 | GetBitContext gb; | |
115329f1 | 544 | |
c6ec28b1 MN |
545 | int bits; |
546 | int run_length; | |
547 | int pixels_read = 0; | |
115329f1 DB |
548 | |
549 | init_get_bits(&gb, *srcbuf, buf_size << 8); | |
550 | ||
c6ec28b1 MN |
551 | while (get_bits_count(&gb) < (buf_size << 8) && pixels_read < dbuf_len) { |
552 | bits = get_bits(&gb, 4); | |
553 | ||
554 | if (bits != 0) { | |
555 | if (non_mod != 1 || bits != 1) { | |
556 | if (map_table != NULL) | |
557 | *destbuf++ = map_table[bits]; | |
558 | else | |
559 | *destbuf++ = bits; | |
560 | } | |
561 | pixels_read++; | |
562 | } else { | |
5fc32c27 | 563 | bits = get_bits1(&gb); |
c6ec28b1 MN |
564 | if (bits == 0) { |
565 | run_length = get_bits(&gb, 3); | |
115329f1 | 566 | |
c6ec28b1 MN |
567 | if (run_length == 0) { |
568 | (*srcbuf) += (get_bits_count(&gb) + 7) >> 3; | |
569 | return pixels_read; | |
570 | } | |
115329f1 | 571 | |
c6ec28b1 | 572 | run_length += 2; |
115329f1 | 573 | |
c6ec28b1 MN |
574 | if (map_table != NULL) |
575 | bits = map_table[0]; | |
576 | else | |
577 | bits = 0; | |
115329f1 | 578 | |
c6ec28b1 MN |
579 | while (run_length-- > 0 && pixels_read < dbuf_len) { |
580 | *destbuf++ = bits; | |
581 | pixels_read++; | |
582 | } | |
583 | } else { | |
5fc32c27 | 584 | bits = get_bits1(&gb); |
c6ec28b1 MN |
585 | if (bits == 0) { |
586 | run_length = get_bits(&gb, 2) + 4; | |
587 | bits = get_bits(&gb, 4); | |
588 | ||
589 | if (non_mod == 1 && bits == 1) | |
590 | pixels_read += run_length; | |
591 | else { | |
592 | if (map_table != NULL) | |
593 | bits = map_table[bits]; | |
594 | while (run_length-- > 0 && pixels_read < dbuf_len) { | |
595 | *destbuf++ = bits; | |
596 | pixels_read++; | |
597 | } | |
598 | } | |
599 | } else { | |
600 | bits = get_bits(&gb, 2); | |
601 | if (bits == 2) { | |
602 | run_length = get_bits(&gb, 4) + 9; | |
603 | bits = get_bits(&gb, 4); | |
115329f1 | 604 | |
c6ec28b1 MN |
605 | if (non_mod == 1 && bits == 1) |
606 | pixels_read += run_length; | |
607 | else { | |
608 | if (map_table != NULL) | |
609 | bits = map_table[bits]; | |
610 | while (run_length-- > 0 && pixels_read < dbuf_len) { | |
611 | *destbuf++ = bits; | |
612 | pixels_read++; | |
613 | } | |
614 | } | |
615 | } else if (bits == 3) { | |
616 | run_length = get_bits(&gb, 8) + 25; | |
617 | bits = get_bits(&gb, 4); | |
618 | ||
619 | if (non_mod == 1 && bits == 1) | |
620 | pixels_read += run_length; | |
621 | else { | |
622 | if (map_table != NULL) | |
623 | bits = map_table[bits]; | |
624 | while (run_length-- > 0 && pixels_read < dbuf_len) { | |
625 | *destbuf++ = bits; | |
626 | pixels_read++; | |
627 | } | |
628 | } | |
629 | } else if (bits == 1) { | |
630 | pixels_read += 2; | |
631 | if (map_table != NULL) | |
632 | bits = map_table[0]; | |
633 | else | |
634 | bits = 0; | |
635 | if (pixels_read <= dbuf_len) { | |
636 | *destbuf++ = bits; | |
637 | *destbuf++ = bits; | |
638 | } | |
639 | } else { | |
640 | if (map_table != NULL) | |
641 | bits = map_table[0]; | |
642 | else | |
643 | bits = 0; | |
644 | *destbuf++ = bits; | |
645 | pixels_read ++; | |
646 | } | |
647 | } | |
648 | } | |
649 | } | |
650 | } | |
115329f1 | 651 | |
c6ec28b1 MN |
652 | if (get_bits(&gb, 8) != 0) |
653 | av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n"); | |
115329f1 | 654 | |
c6ec28b1 MN |
655 | (*srcbuf) += (get_bits_count(&gb) + 7) >> 3; |
656 | ||
657 | return pixels_read; | |
658 | } | |
115329f1 DB |
659 | |
660 | static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len, | |
661 | uint8_t **srcbuf, int buf_size, | |
c6ec28b1 MN |
662 | int non_mod, uint8_t *map_table) |
663 | { | |
664 | uint8_t *sbuf_end = (*srcbuf) + buf_size; | |
665 | int bits; | |
666 | int run_length; | |
667 | int pixels_read = 0; | |
115329f1 | 668 | |
c6ec28b1 MN |
669 | while (*srcbuf < sbuf_end && pixels_read < dbuf_len) { |
670 | bits = *(*srcbuf)++; | |
115329f1 | 671 | |
c6ec28b1 MN |
672 | if (bits != 0) { |
673 | if (non_mod != 1 || bits != 1) { | |
674 | if (map_table != NULL) | |
675 | *destbuf++ = map_table[bits]; | |
676 | else | |
677 | *destbuf++ = bits; | |
678 | } | |
679 | pixels_read++; | |
680 | } else { | |
681 | bits = *(*srcbuf)++; | |
682 | run_length = bits & 0x7f; | |
683 | if ((bits & 0x80) == 0) { | |
684 | if (run_length == 0) { | |
685 | return pixels_read; | |
686 | } | |
115329f1 | 687 | |
c6ec28b1 MN |
688 | if (map_table != NULL) |
689 | bits = map_table[0]; | |
690 | else | |
691 | bits = 0; | |
692 | while (run_length-- > 0 && pixels_read < dbuf_len) { | |
693 | *destbuf++ = bits; | |
694 | pixels_read++; | |
695 | } | |
696 | } else { | |
697 | bits = *(*srcbuf)++; | |
698 | ||
699 | if (non_mod == 1 && bits == 1) | |
700 | pixels_read += run_length; | |
701 | if (map_table != NULL) | |
702 | bits = map_table[bits]; | |
703 | else while (run_length-- > 0 && pixels_read < dbuf_len) { | |
704 | *destbuf++ = bits; | |
705 | pixels_read++; | |
706 | } | |
707 | } | |
708 | } | |
709 | } | |
115329f1 | 710 | |
c6ec28b1 MN |
711 | if (*(*srcbuf)++ != 0) |
712 | av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n"); | |
115329f1 | 713 | |
c6ec28b1 MN |
714 | return pixels_read; |
715 | } | |
115329f1 | 716 | |
c6ec28b1 MN |
717 | |
718 | ||
719 | static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDisplay *display, | |
720 | uint8_t *buf, int buf_size, int top_bottom, int non_mod) | |
721 | { | |
722 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
723 | ||
724 | DVBSubRegion *region = get_region(ctx, display->region_id); | |
725 | uint8_t *buf_end = buf + buf_size; | |
726 | uint8_t *pbuf; | |
727 | int x_pos, y_pos; | |
728 | int i; | |
115329f1 | 729 | |
c6ec28b1 MN |
730 | uint8_t map2to4[] = { 0x0, 0x7, 0x8, 0xf}; |
731 | uint8_t map2to8[] = {0x00, 0x77, 0x88, 0xff}; | |
115329f1 | 732 | uint8_t map4to8[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, |
c6ec28b1 MN |
733 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; |
734 | uint8_t *map_table; | |
115329f1 | 735 | |
c6ec28b1 MN |
736 | #ifdef DEBUG |
737 | av_log(avctx, AV_LOG_INFO, "DVB pixel block size %d, %s field:\n", buf_size, | |
738 | top_bottom ? "bottom" : "top"); | |
739 | #endif | |
740 | ||
741 | #ifdef DEBUG_PACKET_CONTENTS | |
742 | for (i = 0; i < buf_size; i++) | |
743 | { | |
744 | if (i % 16 == 0) | |
745 | av_log(avctx, AV_LOG_INFO, "0x%08p: ", buf+i); | |
746 | ||
747 | av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); | |
748 | if (i % 16 == 15) | |
749 | av_log(avctx, AV_LOG_INFO, "\n"); | |
750 | } | |
115329f1 | 751 | |
c6ec28b1 MN |
752 | if (i % 16 != 0) |
753 | av_log(avctx, AV_LOG_INFO, "\n"); | |
754 | ||
755 | #endif | |
756 | ||
757 | if (region == 0) | |
758 | return; | |
115329f1 | 759 | |
c6ec28b1 | 760 | pbuf = region->pbuf; |
115329f1 | 761 | |
c6ec28b1 MN |
762 | x_pos = display->x_pos; |
763 | y_pos = display->y_pos; | |
115329f1 | 764 | |
c6ec28b1 MN |
765 | if ((y_pos & 1) != top_bottom) |
766 | y_pos++; | |
767 | ||
768 | while (buf < buf_end) { | |
769 | if (x_pos > region->width || y_pos > region->height) { | |
770 | av_log(avctx, AV_LOG_ERROR, "Invalid object location!\n"); | |
771 | return; | |
772 | } | |
115329f1 | 773 | |
c6ec28b1 MN |
774 | switch (*buf++) { |
775 | case 0x10: | |
776 | if (region->depth == 8) | |
777 | map_table = map2to8; | |
778 | else if (region->depth == 4) | |
779 | map_table = map2to4; | |
780 | else | |
781 | map_table = NULL; | |
115329f1 DB |
782 | |
783 | x_pos += dvbsub_read_2bit_string(pbuf + (y_pos * region->width) + x_pos, | |
784 | region->width - x_pos, &buf, buf_size, | |
c6ec28b1 MN |
785 | non_mod, map_table); |
786 | break; | |
787 | case 0x11: | |
788 | if (region->depth < 4) { | |
789 | av_log(avctx, AV_LOG_ERROR, "4-bit pixel string in %d-bit region!\n", region->depth); | |
790 | return; | |
791 | } | |
115329f1 | 792 | |
c6ec28b1 MN |
793 | if (region->depth == 8) |
794 | map_table = map4to8; | |
795 | else | |
796 | map_table = NULL; | |
115329f1 DB |
797 | |
798 | x_pos += dvbsub_read_4bit_string(pbuf + (y_pos * region->width) + x_pos, | |
799 | region->width - x_pos, &buf, buf_size, | |
c6ec28b1 MN |
800 | non_mod, map_table); |
801 | break; | |
802 | case 0x12: | |
803 | if (region->depth < 8) { | |
804 | av_log(avctx, AV_LOG_ERROR, "8-bit pixel string in %d-bit region!\n", region->depth); | |
805 | return; | |
806 | } | |
115329f1 DB |
807 | |
808 | x_pos += dvbsub_read_8bit_string(pbuf + (y_pos * region->width) + x_pos, | |
809 | region->width - x_pos, &buf, buf_size, | |
c6ec28b1 MN |
810 | non_mod, NULL); |
811 | break; | |
115329f1 | 812 | |
c6ec28b1 MN |
813 | case 0x20: |
814 | map2to4[0] = (*buf) >> 4; | |
815 | map2to4[1] = (*buf++) & 0xf; | |
816 | map2to4[2] = (*buf) >> 4; | |
817 | map2to4[3] = (*buf++) & 0xf; | |
818 | break; | |
819 | case 0x21: | |
820 | for (i = 0; i < 4; i++) | |
821 | map2to8[i] = *buf++; | |
822 | break; | |
823 | case 0x22: | |
824 | for (i = 0; i < 16; i++) | |
825 | map4to8[i] = *buf++; | |
826 | break; | |
115329f1 | 827 | |
c6ec28b1 MN |
828 | case 0xf0: |
829 | x_pos = display->x_pos; | |
830 | y_pos += 2; | |
831 | break; | |
832 | default: | |
833 | av_log(avctx, AV_LOG_INFO, "Unknown/unsupported pixel block 0x%x\n", *(buf-1)); | |
834 | } | |
835 | } | |
115329f1 | 836 | |
c6ec28b1 MN |
837 | } |
838 | ||
839 | static void dvbsub_parse_object_segment(AVCodecContext *avctx, | |
840 | uint8_t *buf, int buf_size) | |
841 | { | |
842 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
115329f1 | 843 | |
c6ec28b1 MN |
844 | uint8_t *buf_end = buf + buf_size; |
845 | uint8_t *block; | |
846 | int object_id; | |
847 | DVBSubObject *object; | |
848 | DVBSubObjectDisplay *display; | |
849 | int top_field_len, bottom_field_len; | |
115329f1 | 850 | |
c6ec28b1 | 851 | int coding_method, non_modifying_colour; |
115329f1 | 852 | |
fead30d4 | 853 | object_id = AV_RB16(buf); |
c6ec28b1 | 854 | buf += 2; |
115329f1 | 855 | |
c6ec28b1 MN |
856 | object = get_object(ctx, object_id); |
857 | ||
115329f1 DB |
858 | if (!object) |
859 | return; | |
860 | ||
c6ec28b1 MN |
861 | coding_method = ((*buf) >> 2) & 3; |
862 | non_modifying_colour = ((*buf++) >> 1) & 1; | |
115329f1 | 863 | |
c6ec28b1 | 864 | if (coding_method == 0) { |
fead30d4 | 865 | top_field_len = AV_RB16(buf); |
c6ec28b1 | 866 | buf += 2; |
fead30d4 | 867 | bottom_field_len = AV_RB16(buf); |
c6ec28b1 | 868 | buf += 2; |
115329f1 | 869 | |
c6ec28b1 MN |
870 | if (buf + top_field_len + bottom_field_len > buf_end) { |
871 | av_log(avctx, AV_LOG_ERROR, "Field data size too large\n"); | |
872 | return; | |
115329f1 DB |
873 | } |
874 | ||
c6ec28b1 MN |
875 | for (display = object->display_list; display != 0; display = display->object_list_next) { |
876 | block = buf; | |
877 | ||
878 | dvbsub_parse_pixel_data_block(avctx, display, block, top_field_len, 0, | |
879 | non_modifying_colour); | |
880 | ||
881 | if (bottom_field_len > 0) | |
882 | block = buf + top_field_len; | |
883 | else | |
884 | bottom_field_len = top_field_len; | |
885 | ||
886 | dvbsub_parse_pixel_data_block(avctx, display, block, bottom_field_len, 1, | |
887 | non_modifying_colour); | |
888 | } | |
115329f1 | 889 | |
c6ec28b1 | 890 | /* } else if (coding_method == 1) {*/ |
115329f1 | 891 | |
c6ec28b1 MN |
892 | } else { |
893 | av_log(avctx, AV_LOG_ERROR, "Unknown object coding %d\n", coding_method); | |
894 | } | |
115329f1 | 895 | |
c6ec28b1 MN |
896 | } |
897 | ||
c6ec28b1 MN |
898 | static void dvbsub_parse_clut_segment(AVCodecContext *avctx, |
899 | uint8_t *buf, int buf_size) | |
900 | { | |
901 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
115329f1 | 902 | |
c6ec28b1 MN |
903 | uint8_t *buf_end = buf + buf_size; |
904 | int clut_id; | |
905 | DVBSubCLUT *clut; | |
906 | int entry_id, depth , full_range; | |
907 | int y, cr, cb, alpha; | |
908 | int r, g, b, r_add, g_add, b_add; | |
909 | ||
910 | #ifdef DEBUG_PACKET_CONTENTS | |
911 | int i; | |
912 | ||
913 | av_log(avctx, AV_LOG_INFO, "DVB clut packet:\n"); | |
914 | ||
915 | for (i=0; i < buf_size; i++) | |
916 | { | |
917 | av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); | |
918 | if (i % 16 == 15) | |
919 | av_log(avctx, AV_LOG_INFO, "\n"); | |
920 | } | |
115329f1 | 921 | |
c6ec28b1 MN |
922 | if (i % 16 != 0) |
923 | av_log(avctx, AV_LOG_INFO, "\n"); | |
924 | ||
925 | #endif | |
926 | ||
927 | clut_id = *buf++; | |
928 | buf += 1; | |
115329f1 | 929 | |
c6ec28b1 | 930 | clut = get_clut(ctx, clut_id); |
115329f1 | 931 | |
c6ec28b1 MN |
932 | if (clut == NULL) { |
933 | clut = av_malloc(sizeof(DVBSubCLUT)); | |
115329f1 | 934 | |
c6ec28b1 MN |
935 | memcpy(clut, &default_clut, sizeof(DVBSubCLUT)); |
936 | ||
937 | clut->id = clut_id; | |
115329f1 DB |
938 | |
939 | clut->next = ctx->clut_list; | |
c6ec28b1 MN |
940 | ctx->clut_list = clut; |
941 | } | |
115329f1 | 942 | |
c6ec28b1 MN |
943 | while (buf + 4 < buf_end) |
944 | { | |
945 | entry_id = *buf++; | |
115329f1 | 946 | |
c6ec28b1 | 947 | depth = (*buf) & 0xe0; |
115329f1 | 948 | |
c6ec28b1 MN |
949 | if (depth == 0) { |
950 | av_log(avctx, AV_LOG_ERROR, "Invalid clut depth 0x%x!\n", *buf); | |
951 | return; | |
952 | } | |
115329f1 | 953 | |
c6ec28b1 | 954 | full_range = (*buf++) & 1; |
115329f1 | 955 | |
c6ec28b1 MN |
956 | if (full_range) { |
957 | y = *buf++; | |
958 | cr = *buf++; | |
959 | cb = *buf++; | |
960 | alpha = *buf++; | |
961 | } else { | |
962 | y = buf[0] & 0xfc; | |
963 | cr = (((buf[0] & 3) << 2) | ((buf[1] >> 6) & 3)) << 4; | |
964 | cb = (buf[1] << 2) & 0xf0; | |
965 | alpha = (buf[1] << 6) & 0xc0; | |
115329f1 | 966 | |
c6ec28b1 MN |
967 | buf += 2; |
968 | } | |
115329f1 | 969 | |
c6ec28b1 MN |
970 | if (y == 0) |
971 | alpha = 0xff; | |
115329f1 | 972 | |
c6ec28b1 MN |
973 | YUV_TO_RGB1_CCIR(cb, cr); |
974 | YUV_TO_RGB2_CCIR(r, g, b, y); | |
115329f1 | 975 | |
c6ec28b1 MN |
976 | #ifdef DEBUG |
977 | av_log(avctx, AV_LOG_INFO, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha); | |
978 | #endif | |
115329f1 | 979 | |
c6ec28b1 MN |
980 | if (depth & 0x80) |
981 | clut->clut4[entry_id] = RGBA(r,g,b,255 - alpha); | |
982 | if (depth & 0x40) | |
983 | clut->clut16[entry_id] = RGBA(r,g,b,255 - alpha); | |
984 | if (depth & 0x20) | |
985 | clut->clut256[entry_id] = RGBA(r,g,b,255 - alpha); | |
986 | } | |
987 | } | |
988 | ||
989 | ||
990 | static void dvbsub_parse_region_segment(AVCodecContext *avctx, | |
991 | uint8_t *buf, int buf_size) | |
992 | { | |
993 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
115329f1 | 994 | |
c6ec28b1 MN |
995 | uint8_t *buf_end = buf + buf_size; |
996 | int region_id, object_id; | |
997 | DVBSubRegion *region; | |
998 | DVBSubObject *object; | |
999 | DVBSubObjectDisplay *display; | |
1000 | int fill; | |
115329f1 | 1001 | |
c6ec28b1 MN |
1002 | if (buf_size < 10) |
1003 | return; | |
115329f1 | 1004 | |
c6ec28b1 | 1005 | region_id = *buf++; |
115329f1 | 1006 | |
c6ec28b1 | 1007 | region = get_region(ctx, region_id); |
115329f1 | 1008 | |
c6ec28b1 MN |
1009 | if (region == NULL) |
1010 | { | |
1011 | region = av_mallocz(sizeof(DVBSubRegion)); | |
115329f1 | 1012 | |
c6ec28b1 | 1013 | region->id = region_id; |
115329f1 | 1014 | |
c6ec28b1 MN |
1015 | region->next = ctx->region_list; |
1016 | ctx->region_list = region; | |
1017 | } | |
115329f1 | 1018 | |
c6ec28b1 | 1019 | fill = ((*buf++) >> 3) & 1; |
115329f1 | 1020 | |
fead30d4 | 1021 | region->width = AV_RB16(buf); |
c6ec28b1 | 1022 | buf += 2; |
fead30d4 | 1023 | region->height = AV_RB16(buf); |
c6ec28b1 | 1024 | buf += 2; |
115329f1 | 1025 | |
c6ec28b1 MN |
1026 | if (region->width * region->height != region->buf_size) { |
1027 | if (region->pbuf != 0) | |
1028 | av_free(region->pbuf); | |
115329f1 | 1029 | |
c6ec28b1 | 1030 | region->buf_size = region->width * region->height; |
115329f1 | 1031 | |
c6ec28b1 | 1032 | region->pbuf = av_malloc(region->buf_size); |
115329f1 | 1033 | |
c6ec28b1 MN |
1034 | fill = 1; |
1035 | } | |
115329f1 | 1036 | |
c6ec28b1 | 1037 | region->depth = 1 << (((*buf++) >> 2) & 7); |
2867ed9b MN |
1038 | if(region->depth<2 || region->depth>8){ |
1039 | av_log(avctx, AV_LOG_ERROR, "region depth %d is invalid\n", region->depth); | |
1040 | region->depth= 4; | |
1041 | } | |
c6ec28b1 | 1042 | region->clut = *buf++; |
115329f1 | 1043 | |
c6ec28b1 MN |
1044 | if (region->depth == 8) |
1045 | region->bgcolour = *buf++; | |
1046 | else { | |
1047 | buf += 1; | |
115329f1 | 1048 | |
c6ec28b1 MN |
1049 | if (region->depth == 4) |
1050 | region->bgcolour = (((*buf++) >> 4) & 15); | |
1051 | else | |
1052 | region->bgcolour = (((*buf++) >> 2) & 3); | |
1053 | } | |
1054 | ||
1055 | #ifdef DEBUG | |
1056 | av_log(avctx, AV_LOG_INFO, "Region %d, (%dx%d)\n", region_id, region->width, region->height); | |
1057 | #endif | |
1058 | ||
1059 | if (fill) { | |
1060 | memset(region->pbuf, region->bgcolour, region->buf_size); | |
1061 | #ifdef DEBUG | |
1062 | av_log(avctx, AV_LOG_INFO, "Fill region (%d)\n", region->bgcolour); | |
1063 | #endif | |
1064 | } | |
1065 | ||
1066 | delete_region_display_list(ctx, region); | |
1067 | ||
1068 | while (buf + 5 < buf_end) { | |
fead30d4 | 1069 | object_id = AV_RB16(buf); |
c6ec28b1 | 1070 | buf += 2; |
115329f1 | 1071 | |
c6ec28b1 MN |
1072 | object = get_object(ctx, object_id); |
1073 | ||
1074 | if (object == NULL) { | |
1075 | object = av_mallocz(sizeof(DVBSubObject)); | |
115329f1 | 1076 | |
c6ec28b1 MN |
1077 | object->id = object_id; |
1078 | object->next = ctx->object_list; | |
1079 | ctx->object_list = object; | |
1080 | } | |
115329f1 | 1081 | |
c6ec28b1 | 1082 | object->type = (*buf) >> 6; |
115329f1 | 1083 | |
c6ec28b1 | 1084 | display = av_mallocz(sizeof(DVBSubObjectDisplay)); |
115329f1 | 1085 | |
c6ec28b1 MN |
1086 | display->object_id = object_id; |
1087 | display->region_id = region_id; | |
115329f1 | 1088 | |
fead30d4 | 1089 | display->x_pos = AV_RB16(buf) & 0xfff; |
c6ec28b1 | 1090 | buf += 2; |
fead30d4 | 1091 | display->y_pos = AV_RB16(buf) & 0xfff; |
c6ec28b1 | 1092 | buf += 2; |
115329f1 | 1093 | |
c6ec28b1 MN |
1094 | if ((object->type == 1 || object->type == 2) && buf+1 < buf_end) { |
1095 | display->fgcolour = *buf++; | |
1096 | display->bgcolour = *buf++; | |
1097 | } | |
115329f1 | 1098 | |
c6ec28b1 MN |
1099 | display->region_list_next = region->display_list; |
1100 | region->display_list = display; | |
115329f1 | 1101 | |
c6ec28b1 MN |
1102 | display->object_list_next = object->display_list; |
1103 | object->display_list = display; | |
1104 | } | |
1105 | } | |
1106 | ||
1107 | static void dvbsub_parse_page_segment(AVCodecContext *avctx, | |
1108 | uint8_t *buf, int buf_size) | |
1109 | { | |
1110 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
1111 | DVBSubRegionDisplay *display; | |
1112 | DVBSubRegionDisplay *tmp_display_list, **tmp_ptr; | |
115329f1 | 1113 | |
c6ec28b1 MN |
1114 | uint8_t *buf_end = buf + buf_size; |
1115 | int region_id; | |
1116 | int page_state; | |
115329f1 | 1117 | |
c6ec28b1 MN |
1118 | if (buf_size < 1) |
1119 | return; | |
115329f1 | 1120 | |
c6ec28b1 MN |
1121 | ctx->time_out = *buf++; |
1122 | page_state = ((*buf++) >> 2) & 3; | |
115329f1 | 1123 | |
c6ec28b1 MN |
1124 | #ifdef DEBUG |
1125 | av_log(avctx, AV_LOG_INFO, "Page time out %ds, state %d\n", ctx->time_out, page_state); | |
1126 | #endif | |
1127 | ||
1128 | if (page_state == 2) | |
1129 | { | |
1130 | delete_state(ctx); | |
1131 | } | |
115329f1 | 1132 | |
c6ec28b1 MN |
1133 | tmp_display_list = ctx->display_list; |
1134 | ctx->display_list = NULL; | |
1135 | ctx->display_list_size = 0; | |
115329f1 | 1136 | |
c6ec28b1 MN |
1137 | while (buf + 5 < buf_end) { |
1138 | region_id = *buf++; | |
1139 | buf += 1; | |
115329f1 | 1140 | |
c6ec28b1 MN |
1141 | display = tmp_display_list; |
1142 | tmp_ptr = &tmp_display_list; | |
115329f1 | 1143 | |
c6ec28b1 MN |
1144 | while (display != NULL && display->region_id != region_id) { |
1145 | tmp_ptr = &display->next; | |
1146 | display = display->next; | |
1147 | } | |
115329f1 | 1148 | |
c6ec28b1 MN |
1149 | if (display == NULL) |
1150 | display = av_mallocz(sizeof(DVBSubRegionDisplay)); | |
115329f1 | 1151 | |
c6ec28b1 | 1152 | display->region_id = region_id; |
115329f1 | 1153 | |
fead30d4 | 1154 | display->x_pos = AV_RB16(buf); |
c6ec28b1 | 1155 | buf += 2; |
fead30d4 | 1156 | display->y_pos = AV_RB16(buf); |
c6ec28b1 | 1157 | buf += 2; |
115329f1 | 1158 | |
c6ec28b1 | 1159 | *tmp_ptr = display->next; |
115329f1 | 1160 | |
c6ec28b1 MN |
1161 | display->next = ctx->display_list; |
1162 | ctx->display_list = display; | |
1163 | ctx->display_list_size++; | |
115329f1 | 1164 | |
c6ec28b1 MN |
1165 | #ifdef DEBUG |
1166 | av_log(avctx, AV_LOG_INFO, "Region %d, (%d,%d)\n", region_id, display->x_pos, display->y_pos); | |
1167 | #endif | |
1168 | } | |
115329f1 | 1169 | |
c6ec28b1 MN |
1170 | while (tmp_display_list != 0) { |
1171 | display = tmp_display_list; | |
115329f1 | 1172 | |
c6ec28b1 | 1173 | tmp_display_list = display->next; |
115329f1 | 1174 | |
c6ec28b1 MN |
1175 | av_free(display); |
1176 | } | |
115329f1 | 1177 | |
c6ec28b1 MN |
1178 | } |
1179 | ||
1180 | ||
1181 | #ifdef DEBUG_SAVE_IMAGES | |
1182 | static void save_display_set(DVBSubContext *ctx) | |
1183 | { | |
1184 | DVBSubRegion *region; | |
1185 | DVBSubRegionDisplay *display; | |
1186 | DVBSubCLUT *clut; | |
1187 | uint32_t *clut_table; | |
1188 | int x_pos, y_pos, width, height; | |
1189 | int x, y, y_off, x_off; | |
1190 | uint32_t *pbuf; | |
1191 | char filename[32]; | |
1192 | static int fileno_index = 0; | |
1193 | ||
1194 | x_pos = -1; | |
1195 | y_pos = -1; | |
1196 | width = 0; | |
1197 | height = 0; | |
115329f1 | 1198 | |
c6ec28b1 MN |
1199 | for (display = ctx->display_list; display != NULL; display = display->next) { |
1200 | region = get_region(ctx, display->region_id); | |
115329f1 | 1201 | |
c6ec28b1 MN |
1202 | if (x_pos == -1) { |
1203 | x_pos = display->x_pos; | |
1204 | y_pos = display->y_pos; | |
1205 | width = region->width; | |
1206 | height = region->height; | |
1207 | } else { | |
1208 | if (display->x_pos < x_pos) { | |
1209 | width += (x_pos - display->x_pos); | |
1210 | x_pos = display->x_pos; | |
1211 | } | |
115329f1 | 1212 | |
c6ec28b1 MN |
1213 | if (display->y_pos < y_pos) { |
1214 | height += (y_pos - display->y_pos); | |
1215 | y_pos = display->y_pos; | |
1216 | } | |
115329f1 | 1217 | |
c6ec28b1 MN |
1218 | if (display->x_pos + region->width > x_pos + width) { |
1219 | width = display->x_pos + region->width - x_pos; | |
1220 | } | |
115329f1 | 1221 | |
c6ec28b1 MN |
1222 | if (display->y_pos + region->height > y_pos + height) { |
1223 | height = display->y_pos + region->height - y_pos; | |
1224 | } | |
1225 | } | |
1226 | } | |
115329f1 | 1227 | |
c6ec28b1 | 1228 | if (x_pos >= 0) { |
115329f1 | 1229 | |
c6ec28b1 MN |
1230 | pbuf = av_malloc(width * height * 4); |
1231 | ||
1232 | for (display = ctx->display_list; display != NULL; display = display->next) { | |
1233 | region = get_region(ctx, display->region_id); | |
1234 | ||
1235 | x_off = display->x_pos - x_pos; | |
1236 | y_off = display->y_pos - y_pos; | |
1237 | ||
1238 | clut = get_clut(ctx, region->clut); | |
1239 | ||
1240 | if (clut == 0) | |
1241 | clut = &default_clut; | |
1242 | ||
1243 | switch (region->depth) { | |
1244 | case 2: | |
1245 | clut_table = clut->clut4; | |
1246 | break; | |
1247 | case 8: | |
1248 | clut_table = clut->clut256; | |
1249 | break; | |
1250 | case 4: | |
1251 | default: | |
1252 | clut_table = clut->clut16; | |
1253 | break; | |
1254 | } | |
115329f1 | 1255 | |
c6ec28b1 MN |
1256 | for (y = 0; y < region->height; y++) { |
1257 | for (x = 0; x < region->width; x++) { | |
115329f1 | 1258 | pbuf[((y + y_off) * width) + x_off + x] = |
c6ec28b1 MN |
1259 | clut_table[region->pbuf[y * region->width + x]]; |
1260 | } | |
1261 | } | |
1262 | ||
115329f1 | 1263 | } |
c6ec28b1 | 1264 | |
e1c48b7a | 1265 | snprintf(filename, sizeof(filename), "dvbs.%d", fileno_index); |
c6ec28b1 MN |
1266 | |
1267 | png_save2(filename, pbuf, width, height); | |
1268 | ||
1269 | av_free(pbuf); | |
1270 | } | |
115329f1 | 1271 | |
c6ec28b1 MN |
1272 | fileno_index++; |
1273 | } | |
1274 | #endif | |
1275 | ||
115329f1 | 1276 | static int dvbsub_display_end_segment(AVCodecContext *avctx, uint8_t *buf, |
c6ec28b1 MN |
1277 | int buf_size, AVSubtitle *sub) |
1278 | { | |
1279 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
1280 | ||
1281 | DVBSubRegion *region; | |
1282 | DVBSubRegionDisplay *display; | |
1283 | AVSubtitleRect *rect; | |
1284 | DVBSubCLUT *clut; | |
1285 | uint32_t *clut_table; | |
1286 | int i; | |
115329f1 | 1287 | |
c6ec28b1 MN |
1288 | sub->rects = NULL; |
1289 | sub->start_display_time = 0; | |
1290 | sub->end_display_time = ctx->time_out * 1000; | |
1291 | sub->format = 0; | |
1292 | ||
1293 | sub->num_rects = ctx->display_list_size; | |
115329f1 | 1294 | |
bf01fb69 IC |
1295 | if (sub->num_rects > 0) |
1296 | sub->rects = av_mallocz(sizeof(AVSubtitleRect) * sub->num_rects); | |
c6ec28b1 MN |
1297 | |
1298 | i = 0; | |
1299 | ||
1300 | for (display = ctx->display_list; display != NULL; display = display->next) { | |
1301 | region = get_region(ctx, display->region_id); | |
1302 | rect = &sub->rects[i]; | |
115329f1 | 1303 | |
c6ec28b1 MN |
1304 | if (region == NULL) |
1305 | continue; | |
115329f1 | 1306 | |
c6ec28b1 MN |
1307 | rect->x = display->x_pos; |
1308 | rect->y = display->y_pos; | |
1309 | rect->w = region->width; | |
1310 | rect->h = region->height; | |
1311 | rect->nb_colors = 16; | |
1312 | rect->linesize = region->width; | |
1313 | ||
1314 | clut = get_clut(ctx, region->clut); | |
115329f1 | 1315 | |
c6ec28b1 MN |
1316 | if (clut == NULL) |
1317 | clut = &default_clut; | |
115329f1 | 1318 | |
c6ec28b1 MN |
1319 | switch (region->depth) { |
1320 | case 2: | |
1321 | clut_table = clut->clut4; | |
1322 | break; | |
1323 | case 8: | |
1324 | clut_table = clut->clut256; | |
1325 | break; | |
1326 | case 4: | |
1327 | default: | |
1328 | clut_table = clut->clut16; | |
1329 | break; | |
1330 | } | |
115329f1 | 1331 | |
c6ec28b1 MN |
1332 | rect->rgba_palette = av_malloc((1 << region->depth) * sizeof(uint32_t)); |
1333 | memcpy(rect->rgba_palette, clut_table, (1 << region->depth) * sizeof(uint32_t)); | |
115329f1 | 1334 | |
c6ec28b1 MN |
1335 | rect->bitmap = av_malloc(region->buf_size); |
1336 | memcpy(rect->bitmap, region->pbuf, region->buf_size); | |
115329f1 | 1337 | |
c6ec28b1 MN |
1338 | i++; |
1339 | } | |
115329f1 | 1340 | |
c6ec28b1 | 1341 | sub->num_rects = i; |
115329f1 | 1342 | |
c6ec28b1 MN |
1343 | #ifdef DEBUG_SAVE_IMAGES |
1344 | save_display_set(ctx); | |
1345 | #endif | |
115329f1 | 1346 | |
c6ec28b1 MN |
1347 | return 1; |
1348 | } | |
1349 | ||
1350 | static int dvbsub_decode(AVCodecContext *avctx, | |
1351 | void *data, int *data_size, | |
1352 | uint8_t *buf, int buf_size) | |
1353 | { | |
1354 | DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; | |
1355 | AVSubtitle *sub = (AVSubtitle*) data; | |
1356 | uint8_t *p, *p_end; | |
1357 | int segment_type; | |
1358 | int page_id; | |
1359 | int segment_length; | |
115329f1 | 1360 | |
c6ec28b1 MN |
1361 | #ifdef DEBUG_PACKET_CONTENTS |
1362 | int i; | |
1363 | ||
1364 | av_log(avctx, AV_LOG_INFO, "DVB sub packet:\n"); | |
1365 | ||
1366 | for (i=0; i < buf_size; i++) | |
1367 | { | |
1368 | av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); | |
1369 | if (i % 16 == 15) | |
1370 | av_log(avctx, AV_LOG_INFO, "\n"); | |
1371 | } | |
115329f1 | 1372 | |
c6ec28b1 MN |
1373 | if (i % 16 != 0) |
1374 | av_log(avctx, AV_LOG_INFO, "\n"); | |
1375 | ||
1376 | #endif | |
1377 | ||
1378 | if (buf_size <= 2) | |
1379 | return -1; | |
115329f1 | 1380 | |
c6ec28b1 MN |
1381 | p = buf; |
1382 | p_end = buf + buf_size; | |
115329f1 | 1383 | |
c6ec28b1 MN |
1384 | while (p < p_end && *p == 0x0f) |
1385 | { | |
1386 | p += 1; | |
1387 | segment_type = *p++; | |
fead30d4 | 1388 | page_id = AV_RB16(p); |
c6ec28b1 | 1389 | p += 2; |
fead30d4 | 1390 | segment_length = AV_RB16(p); |
c6ec28b1 | 1391 | p += 2; |
115329f1 | 1392 | |
c6ec28b1 MN |
1393 | if (page_id == ctx->composition_id || page_id == ctx->ancillary_id) { |
1394 | switch (segment_type) { | |
1395 | case DVBSUB_PAGE_SEGMENT: | |
1396 | dvbsub_parse_page_segment(avctx, p, segment_length); | |
1397 | break; | |
1398 | case DVBSUB_REGION_SEGMENT: | |
1399 | dvbsub_parse_region_segment(avctx, p, segment_length); | |
1400 | break; | |
1401 | case DVBSUB_CLUT_SEGMENT: | |
1402 | dvbsub_parse_clut_segment(avctx, p, segment_length); | |
1403 | break; | |
1404 | case DVBSUB_OBJECT_SEGMENT: | |
1405 | dvbsub_parse_object_segment(avctx, p, segment_length); | |
1406 | break; | |
1407 | case DVBSUB_DISPLAY_SEGMENT: | |
1408 | *data_size = dvbsub_display_end_segment(avctx, p, segment_length, sub); | |
1409 | break; | |
1410 | default: | |
1411 | #ifdef DEBUG | |
115329f1 | 1412 | av_log(avctx, AV_LOG_INFO, "Subtitling segment type 0x%x, page id %d, length %d\n", |
c6ec28b1 MN |
1413 | segment_type, page_id, segment_length); |
1414 | #endif | |
1415 | break; | |
1416 | } | |
1417 | } | |
1418 | ||
1419 | p += segment_length; | |
1420 | } | |
115329f1 | 1421 | |
c6ec28b1 MN |
1422 | if (p != p_end) |
1423 | { | |
1424 | #ifdef DEBUG | |
1425 | av_log(avctx, AV_LOG_INFO, "Junk at end of packet\n"); | |
1426 | #endif | |
1427 | return -1; | |
1428 | } | |
1429 | ||
bf01fb69 | 1430 | return buf_size; |
c6ec28b1 MN |
1431 | } |
1432 | ||
1433 | ||
1434 | AVCodec dvbsub_decoder = { | |
1435 | "dvbsub", | |
1436 | CODEC_TYPE_SUBTITLE, | |
1437 | CODEC_ID_DVB_SUBTITLE, | |
1438 | sizeof(DVBSubContext), | |
1439 | dvbsub_init_decoder, | |
1440 | NULL, | |
1441 | dvbsub_close_decoder, | |
1442 | dvbsub_decode, | |
1443 | }; |