Mercurial > libavcodec.hg
annotate dvdsubdec.c @ 5707:c46509aca422 libavcodec
Remove check for input buffer size as it does not guarantee that
decoder will not run out of output buffer bounds (and all suspected
decoders have their own checks now).
author | kostya |
---|---|
date | Mon, 24 Sep 2007 16:50:32 +0000 |
parents | 392483301260 |
children | d030978bcd93 |
rev | line source |
---|---|
4091 | 1 /* |
2 * DVD subtitle decoding for ffmpeg | |
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" | |
5397 | 22 #include "bitstream.h" |
23 #include "colorspace.h" | |
24 #include "dsputil.h" | |
4091 | 25 |
26 //#define DEBUG | |
27 | |
5397 | 28 static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values) |
29 { | |
30 uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; | |
31 uint8_t r, g, b; | |
32 int i, y, cb, cr; | |
33 int r_add, g_add, b_add; | |
34 | |
35 for (i = num_values; i > 0; i--) { | |
36 y = *ycbcr++; | |
37 cb = *ycbcr++; | |
38 cr = *ycbcr++; | |
39 YUV_TO_RGB1_CCIR(cb, cr); | |
40 YUV_TO_RGB2_CCIR(r, g, b, y); | |
41 *rgba++ = (*alpha++ << 24) | (r << 16) | (g << 8) | b; | |
42 } | |
43 } | |
44 | |
4091 | 45 static int dvdsub_init_decoder(AVCodecContext *avctx) |
46 { | |
47 return 0; | |
48 } | |
49 | |
5397 | 50 static int decode_run_2bit(GetBitContext *gb, int *color) |
51 { | |
52 unsigned int v, t; | |
53 | |
54 v = 0; | |
55 for (t = 1; v < t && t <= 0x40; t <<= 2) | |
56 v = (v << 4) | get_bits(gb, 4); | |
57 *color = v & 3; | |
58 if (v < 4) { /* Code for fill rest of line */ | |
59 return INT_MAX; | |
60 } | |
61 return v >> 2; | |
62 } | |
63 | |
64 static int decode_run_8bit(GetBitContext *gb, int *color) | |
4091 | 65 { |
5397 | 66 int len; |
67 int has_run = get_bits1(gb); | |
68 if (get_bits1(gb)) | |
69 *color = get_bits(gb, 8); | |
70 else | |
71 *color = get_bits(gb, 2); | |
72 if (has_run) { | |
73 if (get_bits1(gb)) { | |
74 len = get_bits(gb, 7); | |
75 if (len == 0) | |
76 len = INT_MAX; | |
77 else | |
78 len += 9; | |
79 } else | |
80 len = get_bits(gb, 3) + 2; | |
81 } else | |
82 len = 1; | |
83 return len; | |
4091 | 84 } |
85 | |
86 static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, | |
5397 | 87 const uint8_t *buf, int start, int buf_size, int is_8bit) |
4091 | 88 { |
5397 | 89 GetBitContext gb; |
90 int bit_len; | |
91 int x, y, len, color; | |
4091 | 92 uint8_t *d; |
93 | |
5397 | 94 bit_len = (buf_size - start) * 8; |
95 init_get_bits(&gb, buf + start, bit_len); | |
96 | |
4091 | 97 x = 0; |
98 y = 0; | |
99 d = bitmap; | |
100 for(;;) { | |
5397 | 101 if (get_bits_count(&gb) > bit_len) |
4091 | 102 return -1; |
5397 | 103 if (is_8bit) |
104 len = decode_run_8bit(&gb, &color); | |
105 else | |
106 len = decode_run_2bit(&gb, &color); | |
107 len = FFMIN(len, w - x); | |
4091 | 108 memset(d + x, color, len); |
109 x += len; | |
110 if (x >= w) { | |
111 y++; | |
112 if (y >= h) | |
113 break; | |
114 d += linesize; | |
115 x = 0; | |
116 /* byte align */ | |
5397 | 117 align_get_bits(&gb); |
4091 | 118 } |
119 } | |
120 return 0; | |
121 } | |
122 | |
123 static void guess_palette(uint32_t *rgba_palette, | |
5396
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
124 uint8_t *colormap, |
4091 | 125 uint8_t *alpha, |
126 uint32_t subtitle_color) | |
127 { | |
128 uint8_t color_used[16]; | |
129 int nb_opaque_colors, i, level, j, r, g, b; | |
130 | |
131 for(i = 0; i < 4; i++) | |
132 rgba_palette[i] = 0; | |
133 | |
134 memset(color_used, 0, 16); | |
135 nb_opaque_colors = 0; | |
136 for(i = 0; i < 4; i++) { | |
5396
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
137 if (alpha[i] != 0 && !color_used[colormap[i]]) { |
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
138 color_used[colormap[i]] = 1; |
4091 | 139 nb_opaque_colors++; |
140 } | |
141 } | |
142 | |
143 if (nb_opaque_colors == 0) | |
144 return; | |
145 | |
146 j = nb_opaque_colors; | |
147 memset(color_used, 0, 16); | |
148 for(i = 0; i < 4; i++) { | |
149 if (alpha[i] != 0) { | |
5396
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
150 if (!color_used[colormap[i]]) { |
4091 | 151 level = (0xff * j) / nb_opaque_colors; |
152 r = (((subtitle_color >> 16) & 0xff) * level) >> 8; | |
153 g = (((subtitle_color >> 8) & 0xff) * level) >> 8; | |
154 b = (((subtitle_color >> 0) & 0xff) * level) >> 8; | |
155 rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24); | |
5396
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
156 color_used[colormap[i]] = (i + 1); |
4091 | 157 j--; |
158 } else { | |
5396
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
159 rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) | |
4091 | 160 ((alpha[i] * 17) << 24); |
161 } | |
162 } | |
163 } | |
164 } | |
165 | |
5397 | 166 #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a)) |
167 | |
4091 | 168 static int decode_dvd_subtitles(AVSubtitle *sub_header, |
169 const uint8_t *buf, int buf_size) | |
170 { | |
171 int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos; | |
5397 | 172 int big_offsets, offset_size, is_8bit = 0; |
173 const uint8_t *yuv_palette = 0; | |
174 uint8_t colormap[4], alpha[256]; | |
4091 | 175 int date; |
176 int i; | |
177 int is_menu = 0; | |
178 | |
5397 | 179 if (buf_size < 10) |
4091 | 180 return -1; |
181 sub_header->rects = NULL; | |
182 sub_header->num_rects = 0; | |
183 sub_header->start_display_time = 0; | |
184 sub_header->end_display_time = 0; | |
185 | |
5397 | 186 if (AV_RB16(buf) == 0) { /* HD subpicture with 4-byte offsets */ |
187 big_offsets = 1; | |
188 offset_size = 4; | |
189 cmd_pos = 6; | |
190 } else { | |
191 big_offsets = 0; | |
192 offset_size = 2; | |
193 cmd_pos = 2; | |
194 } | |
195 | |
196 cmd_pos = READ_OFFSET(buf + cmd_pos); | |
197 | |
198 while ((cmd_pos + 2 + offset_size) < buf_size) { | |
4438
fe3179006730
Remove the getbe16 functions and use the AV_RB16 macro instead. Patch by Ian
takis
parents:
4437
diff
changeset
|
199 date = AV_RB16(buf + cmd_pos); |
5397 | 200 next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2); |
4091 | 201 #ifdef DEBUG |
202 av_log(NULL, AV_LOG_INFO, "cmd_pos=0x%04x next=0x%04x date=%d\n", | |
203 cmd_pos, next_cmd_pos, date); | |
204 #endif | |
5397 | 205 pos = cmd_pos + 2 + offset_size; |
4091 | 206 offset1 = -1; |
207 offset2 = -1; | |
208 x1 = y1 = x2 = y2 = 0; | |
209 while (pos < buf_size) { | |
210 cmd = buf[pos++]; | |
211 #ifdef DEBUG | |
212 av_log(NULL, AV_LOG_INFO, "cmd=%02x\n", cmd); | |
213 #endif | |
214 switch(cmd) { | |
215 case 0x00: | |
216 /* menu subpicture */ | |
217 is_menu = 1; | |
218 break; | |
219 case 0x01: | |
220 /* set start date */ | |
221 sub_header->start_display_time = (date << 10) / 90; | |
222 break; | |
223 case 0x02: | |
224 /* set end date */ | |
225 sub_header->end_display_time = (date << 10) / 90; | |
226 break; | |
227 case 0x03: | |
5396
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
228 /* set colormap */ |
4091 | 229 if ((buf_size - pos) < 2) |
230 goto fail; | |
5396
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
231 colormap[3] = buf[pos] >> 4; |
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
232 colormap[2] = buf[pos] & 0x0f; |
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
233 colormap[1] = buf[pos + 1] >> 4; |
9f0f022ca8e7
Rename "palette" to "colormap" when it's referring to the mapping from a 2-bit
takis
parents:
4924
diff
changeset
|
234 colormap[0] = buf[pos + 1] & 0x0f; |
4091 | 235 pos += 2; |
236 break; | |
237 case 0x04: | |
238 /* set alpha */ | |
239 if ((buf_size - pos) < 2) | |
240 goto fail; | |
241 alpha[3] = buf[pos] >> 4; | |
242 alpha[2] = buf[pos] & 0x0f; | |
243 alpha[1] = buf[pos + 1] >> 4; | |
244 alpha[0] = buf[pos + 1] & 0x0f; | |
245 pos += 2; | |
246 #ifdef DEBUG | |
247 av_log(NULL, AV_LOG_INFO, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]); | |
248 #endif | |
249 break; | |
250 case 0x05: | |
5397 | 251 case 0x85: |
4091 | 252 if ((buf_size - pos) < 6) |
253 goto fail; | |
254 x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4); | |
255 x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2]; | |
256 y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4); | |
257 y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5]; | |
5397 | 258 if (cmd & 0x80) |
259 is_8bit = 1; | |
4091 | 260 #ifdef DEBUG |
261 av_log(NULL, AV_LOG_INFO, "x1=%d x2=%d y1=%d y2=%d\n", | |
262 x1, x2, y1, y2); | |
263 #endif | |
264 pos += 6; | |
265 break; | |
266 case 0x06: | |
267 if ((buf_size - pos) < 4) | |
268 goto fail; | |
4438
fe3179006730
Remove the getbe16 functions and use the AV_RB16 macro instead. Patch by Ian
takis
parents:
4437
diff
changeset
|
269 offset1 = AV_RB16(buf + pos); |
fe3179006730
Remove the getbe16 functions and use the AV_RB16 macro instead. Patch by Ian
takis
parents:
4437
diff
changeset
|
270 offset2 = AV_RB16(buf + pos + 2); |
4091 | 271 #ifdef DEBUG |
272 av_log(NULL, AV_LOG_INFO, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2); | |
273 #endif | |
274 pos += 4; | |
275 break; | |
5397 | 276 case 0x86: |
277 if ((buf_size - pos) < 8) | |
278 goto fail; | |
279 offset1 = AV_RB32(buf + pos); | |
280 offset2 = AV_RB32(buf + pos + 4); | |
281 #ifdef DEBUG | |
282 av_log(NULL, AV_LOG_INFO, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2); | |
283 #endif | |
284 pos += 8; | |
285 break; | |
286 | |
287 case 0x83: | |
288 /* HD set palette */ | |
289 if ((buf_size - pos) < 768) | |
290 goto fail; | |
291 yuv_palette = buf + pos; | |
292 pos += 768; | |
293 break; | |
294 case 0x84: | |
295 /* HD set contrast (alpha) */ | |
296 if ((buf_size - pos) < 256) | |
297 goto fail; | |
298 for (i = 0; i < 256; i++) | |
299 alpha[i] = 0xFF - buf[pos+i]; | |
300 pos += 256; | |
301 break; | |
302 | |
4091 | 303 case 0xff: |
5397 | 304 goto the_end; |
4091 | 305 default: |
5397 | 306 #ifdef DEBUG |
307 av_log(NULL, AV_LOG_INFO, "unrecognised subpicture command 0x%x\n", cmd); | |
308 #endif | |
4091 | 309 goto the_end; |
310 } | |
311 } | |
312 the_end: | |
313 if (offset1 >= 0) { | |
314 int w, h; | |
315 uint8_t *bitmap; | |
316 | |
317 /* decode the bitmap */ | |
318 w = x2 - x1 + 1; | |
319 if (w < 0) | |
320 w = 0; | |
321 h = y2 - y1; | |
322 if (h < 0) | |
323 h = 0; | |
324 if (w > 0 && h > 0) { | |
325 if (sub_header->rects != NULL) { | |
326 for (i = 0; i < sub_header->num_rects; i++) { | |
327 av_free(sub_header->rects[i].bitmap); | |
328 av_free(sub_header->rects[i].rgba_palette); | |
329 } | |
330 av_freep(&sub_header->rects); | |
331 sub_header->num_rects = 0; | |
332 } | |
333 | |
334 bitmap = av_malloc(w * h); | |
335 sub_header->rects = av_mallocz(sizeof(AVSubtitleRect)); | |
336 sub_header->num_rects = 1; | |
5397 | 337 sub_header->rects[0].bitmap = bitmap; |
4437
42ad7d63fb5d
Fix a bug in the DVD subtitle decoder where subtitles with odd heights would not
takis
parents:
4091
diff
changeset
|
338 decode_rle(bitmap, w * 2, w, (h + 1) / 2, |
5397 | 339 buf, offset1, buf_size, is_8bit); |
4091 | 340 decode_rle(bitmap + w, w * 2, w, h / 2, |
5397 | 341 buf, offset2, buf_size, is_8bit); |
342 if (is_8bit) { | |
343 if (yuv_palette == 0) | |
344 goto fail; | |
345 sub_header->rects[0].rgba_palette = av_malloc(256 * 4); | |
346 sub_header->rects[0].nb_colors = 256; | |
347 yuv_a_to_rgba(yuv_palette, alpha, sub_header->rects[0].rgba_palette, 256); | |
348 } else { | |
349 sub_header->rects[0].rgba_palette = av_malloc(4 * 4); | |
350 sub_header->rects[0].nb_colors = 4; | |
5398 | 351 guess_palette(sub_header->rects[0].rgba_palette, |
352 colormap, alpha, 0xffff00); | |
5397 | 353 } |
4091 | 354 sub_header->rects[0].x = x1; |
355 sub_header->rects[0].y = y1; | |
356 sub_header->rects[0].w = w; | |
357 sub_header->rects[0].h = h; | |
358 sub_header->rects[0].linesize = w; | |
359 } | |
360 } | |
361 if (next_cmd_pos == cmd_pos) | |
362 break; | |
363 cmd_pos = next_cmd_pos; | |
364 } | |
365 if (sub_header->num_rects > 0) | |
366 return is_menu; | |
367 fail: | |
5397 | 368 if (sub_header->rects != NULL) { |
369 for (i = 0; i < sub_header->num_rects; i++) { | |
370 av_free(sub_header->rects[i].bitmap); | |
371 av_free(sub_header->rects[i].rgba_palette); | |
372 } | |
373 av_freep(&sub_header->rects); | |
374 sub_header->num_rects = 0; | |
375 } | |
4091 | 376 return -1; |
377 } | |
378 | |
379 static int is_transp(const uint8_t *buf, int pitch, int n, | |
380 const uint8_t *transp_color) | |
381 { | |
382 int i; | |
383 for(i = 0; i < n; i++) { | |
384 if (!transp_color[*buf]) | |
385 return 0; | |
386 buf += pitch; | |
387 } | |
388 return 1; | |
389 } | |
390 | |
391 /* return 0 if empty rectangle, 1 if non empty */ | |
392 static int find_smallest_bounding_rectangle(AVSubtitle *s) | |
393 { | |
394 uint8_t transp_color[256]; | |
395 int y1, y2, x1, x2, y, w, h, i; | |
396 uint8_t *bitmap; | |
397 | |
398 if (s->num_rects == 0 || s->rects == NULL || s->rects[0].w <= 0 || s->rects[0].h <= 0) | |
399 return 0; | |
400 | |
401 memset(transp_color, 0, 256); | |
402 for(i = 0; i < s->rects[0].nb_colors; i++) { | |
403 if ((s->rects[0].rgba_palette[i] >> 24) == 0) | |
404 transp_color[i] = 1; | |
405 } | |
406 y1 = 0; | |
407 while (y1 < s->rects[0].h && is_transp(s->rects[0].bitmap + y1 * s->rects[0].linesize, | |
408 1, s->rects[0].w, transp_color)) | |
409 y1++; | |
410 if (y1 == s->rects[0].h) { | |
411 av_freep(&s->rects[0].bitmap); | |
412 s->rects[0].w = s->rects[0].h = 0; | |
413 return 0; | |
414 } | |
415 | |
416 y2 = s->rects[0].h - 1; | |
417 while (y2 > 0 && is_transp(s->rects[0].bitmap + y2 * s->rects[0].linesize, 1, | |
418 s->rects[0].w, transp_color)) | |
419 y2--; | |
420 x1 = 0; | |
421 while (x1 < (s->rects[0].w - 1) && is_transp(s->rects[0].bitmap + x1, s->rects[0].linesize, | |
422 s->rects[0].h, transp_color)) | |
423 x1++; | |
424 x2 = s->rects[0].w - 1; | |
425 while (x2 > 0 && is_transp(s->rects[0].bitmap + x2, s->rects[0].linesize, s->rects[0].h, | |
426 transp_color)) | |
427 x2--; | |
428 w = x2 - x1 + 1; | |
429 h = y2 - y1 + 1; | |
430 bitmap = av_malloc(w * h); | |
431 if (!bitmap) | |
432 return 1; | |
433 for(y = 0; y < h; y++) { | |
434 memcpy(bitmap + w * y, s->rects[0].bitmap + x1 + (y1 + y) * s->rects[0].linesize, w); | |
435 } | |
436 av_freep(&s->rects[0].bitmap); | |
437 s->rects[0].bitmap = bitmap; | |
438 s->rects[0].linesize = w; | |
439 s->rects[0].w = w; | |
440 s->rects[0].h = h; | |
441 s->rects[0].x += x1; | |
442 s->rects[0].y += y1; | |
443 return 1; | |
444 } | |
445 | |
446 static int dvdsub_close_decoder(AVCodecContext *avctx) | |
447 { | |
448 return 0; | |
449 } | |
450 | |
451 #ifdef DEBUG | |
452 #undef fprintf | |
453 static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h, | |
454 uint32_t *rgba_palette) | |
455 { | |
456 int x, y, v; | |
457 FILE *f; | |
458 | |
459 f = fopen(filename, "w"); | |
460 if (!f) { | |
461 perror(filename); | |
462 exit(1); | |
463 } | |
464 fprintf(f, "P6\n" | |
465 "%d %d\n" | |
466 "%d\n", | |
467 w, h, 255); | |
468 for(y = 0; y < h; y++) { | |
469 for(x = 0; x < w; x++) { | |
470 v = rgba_palette[bitmap[y * w + x]]; | |
471 putc((v >> 16) & 0xff, f); | |
472 putc((v >> 8) & 0xff, f); | |
473 putc((v >> 0) & 0xff, f); | |
474 } | |
475 } | |
476 fclose(f); | |
477 } | |
478 #endif | |
479 | |
480 static int dvdsub_decode(AVCodecContext *avctx, | |
481 void *data, int *data_size, | |
482 uint8_t *buf, int buf_size) | |
483 { | |
484 AVSubtitle *sub = (void *)data; | |
485 int is_menu; | |
486 | |
487 is_menu = decode_dvd_subtitles(sub, buf, buf_size); | |
488 | |
489 if (is_menu < 0) { | |
490 no_subtitle: | |
491 *data_size = 0; | |
492 | |
493 return buf_size; | |
494 } | |
495 if (!is_menu && find_smallest_bounding_rectangle(sub) == 0) | |
496 goto no_subtitle; | |
497 | |
498 #if defined(DEBUG) | |
499 av_log(NULL, AV_LOG_INFO, "start=%d ms end =%d ms\n", | |
500 sub->start_display_time, | |
501 sub->end_display_time); | |
502 ppm_save("/tmp/a.ppm", sub->rects[0].bitmap, | |
503 sub->rects[0].w, sub->rects[0].h, sub->rects[0].rgba_palette); | |
504 #endif | |
505 | |
506 *data_size = 1; | |
507 return buf_size; | |
508 } | |
509 | |
510 AVCodec dvdsub_decoder = { | |
511 "dvdsub", | |
512 CODEC_TYPE_SUBTITLE, | |
513 CODEC_ID_DVD_SUBTITLE, | |
514 0, | |
515 dvdsub_init_decoder, | |
516 NULL, | |
517 dvdsub_close_decoder, | |
518 dvdsub_decode, | |
519 }; |