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