Libav 0.7.1
|
00001 /* 00002 * DVD subtitle decoding for ffmpeg 00003 * Copyright (c) 2005 Fabrice Bellard 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 #include "avcodec.h" 00022 #include "get_bits.h" 00023 #include "dsputil.h" 00024 #include "libavutil/colorspace.h" 00025 00026 //#define DEBUG 00027 00028 static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values) 00029 { 00030 uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; 00031 uint8_t r, g, b; 00032 int i, y, cb, cr; 00033 int r_add, g_add, b_add; 00034 00035 for (i = num_values; i > 0; i--) { 00036 y = *ycbcr++; 00037 cr = *ycbcr++; 00038 cb = *ycbcr++; 00039 YUV_TO_RGB1_CCIR(cb, cr); 00040 YUV_TO_RGB2_CCIR(r, g, b, y); 00041 *rgba++ = (*alpha++ << 24) | (r << 16) | (g << 8) | b; 00042 } 00043 } 00044 00045 static int decode_run_2bit(GetBitContext *gb, int *color) 00046 { 00047 unsigned int v, t; 00048 00049 v = 0; 00050 for (t = 1; v < t && t <= 0x40; t <<= 2) 00051 v = (v << 4) | get_bits(gb, 4); 00052 *color = v & 3; 00053 if (v < 4) { /* Code for fill rest of line */ 00054 return INT_MAX; 00055 } 00056 return v >> 2; 00057 } 00058 00059 static int decode_run_8bit(GetBitContext *gb, int *color) 00060 { 00061 int len; 00062 int has_run = get_bits1(gb); 00063 if (get_bits1(gb)) 00064 *color = get_bits(gb, 8); 00065 else 00066 *color = get_bits(gb, 2); 00067 if (has_run) { 00068 if (get_bits1(gb)) { 00069 len = get_bits(gb, 7); 00070 if (len == 0) 00071 len = INT_MAX; 00072 else 00073 len += 9; 00074 } else 00075 len = get_bits(gb, 3) + 2; 00076 } else 00077 len = 1; 00078 return len; 00079 } 00080 00081 static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, 00082 const uint8_t *buf, int start, int buf_size, int is_8bit) 00083 { 00084 GetBitContext gb; 00085 int bit_len; 00086 int x, y, len, color; 00087 uint8_t *d; 00088 00089 bit_len = (buf_size - start) * 8; 00090 init_get_bits(&gb, buf + start, bit_len); 00091 00092 x = 0; 00093 y = 0; 00094 d = bitmap; 00095 for(;;) { 00096 if (get_bits_count(&gb) > bit_len) 00097 return -1; 00098 if (is_8bit) 00099 len = decode_run_8bit(&gb, &color); 00100 else 00101 len = decode_run_2bit(&gb, &color); 00102 len = FFMIN(len, w - x); 00103 memset(d + x, color, len); 00104 x += len; 00105 if (x >= w) { 00106 y++; 00107 if (y >= h) 00108 break; 00109 d += linesize; 00110 x = 0; 00111 /* byte align */ 00112 align_get_bits(&gb); 00113 } 00114 } 00115 return 0; 00116 } 00117 00118 static void guess_palette(uint32_t *rgba_palette, 00119 uint8_t *colormap, 00120 uint8_t *alpha, 00121 uint32_t subtitle_color) 00122 { 00123 uint8_t color_used[16]; 00124 int nb_opaque_colors, i, level, j, r, g, b; 00125 00126 for(i = 0; i < 4; i++) 00127 rgba_palette[i] = 0; 00128 00129 memset(color_used, 0, 16); 00130 nb_opaque_colors = 0; 00131 for(i = 0; i < 4; i++) { 00132 if (alpha[i] != 0 && !color_used[colormap[i]]) { 00133 color_used[colormap[i]] = 1; 00134 nb_opaque_colors++; 00135 } 00136 } 00137 00138 if (nb_opaque_colors == 0) 00139 return; 00140 00141 j = nb_opaque_colors; 00142 memset(color_used, 0, 16); 00143 for(i = 0; i < 4; i++) { 00144 if (alpha[i] != 0) { 00145 if (!color_used[colormap[i]]) { 00146 level = (0xff * j) / nb_opaque_colors; 00147 r = (((subtitle_color >> 16) & 0xff) * level) >> 8; 00148 g = (((subtitle_color >> 8) & 0xff) * level) >> 8; 00149 b = (((subtitle_color >> 0) & 0xff) * level) >> 8; 00150 rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24); 00151 color_used[colormap[i]] = (i + 1); 00152 j--; 00153 } else { 00154 rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) | 00155 ((alpha[i] * 17) << 24); 00156 } 00157 } 00158 } 00159 } 00160 00161 #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a)) 00162 00163 static int decode_dvd_subtitles(AVSubtitle *sub_header, 00164 const uint8_t *buf, int buf_size) 00165 { 00166 int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos; 00167 int big_offsets, offset_size, is_8bit = 0; 00168 const uint8_t *yuv_palette = 0; 00169 uint8_t colormap[4], alpha[256]; 00170 int date; 00171 int i; 00172 int is_menu = 0; 00173 00174 if (buf_size < 10) 00175 return -1; 00176 memset(sub_header, 0, sizeof(*sub_header)); 00177 00178 if (AV_RB16(buf) == 0) { /* HD subpicture with 4-byte offsets */ 00179 big_offsets = 1; 00180 offset_size = 4; 00181 cmd_pos = 6; 00182 } else { 00183 big_offsets = 0; 00184 offset_size = 2; 00185 cmd_pos = 2; 00186 } 00187 00188 cmd_pos = READ_OFFSET(buf + cmd_pos); 00189 00190 while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) { 00191 date = AV_RB16(buf + cmd_pos); 00192 next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2); 00193 av_dlog(NULL, "cmd_pos=0x%04x next=0x%04x date=%d\n", 00194 cmd_pos, next_cmd_pos, date); 00195 pos = cmd_pos + 2 + offset_size; 00196 offset1 = -1; 00197 offset2 = -1; 00198 x1 = y1 = x2 = y2 = 0; 00199 while (pos < buf_size) { 00200 cmd = buf[pos++]; 00201 av_dlog(NULL, "cmd=%02x\n", cmd); 00202 switch(cmd) { 00203 case 0x00: 00204 /* menu subpicture */ 00205 is_menu = 1; 00206 break; 00207 case 0x01: 00208 /* set start date */ 00209 sub_header->start_display_time = (date << 10) / 90; 00210 break; 00211 case 0x02: 00212 /* set end date */ 00213 sub_header->end_display_time = (date << 10) / 90; 00214 break; 00215 case 0x03: 00216 /* set colormap */ 00217 if ((buf_size - pos) < 2) 00218 goto fail; 00219 colormap[3] = buf[pos] >> 4; 00220 colormap[2] = buf[pos] & 0x0f; 00221 colormap[1] = buf[pos + 1] >> 4; 00222 colormap[0] = buf[pos + 1] & 0x0f; 00223 pos += 2; 00224 break; 00225 case 0x04: 00226 /* set alpha */ 00227 if ((buf_size - pos) < 2) 00228 goto fail; 00229 alpha[3] = buf[pos] >> 4; 00230 alpha[2] = buf[pos] & 0x0f; 00231 alpha[1] = buf[pos + 1] >> 4; 00232 alpha[0] = buf[pos + 1] & 0x0f; 00233 pos += 2; 00234 av_dlog(NULL, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]); 00235 break; 00236 case 0x05: 00237 case 0x85: 00238 if ((buf_size - pos) < 6) 00239 goto fail; 00240 x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4); 00241 x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2]; 00242 y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4); 00243 y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5]; 00244 if (cmd & 0x80) 00245 is_8bit = 1; 00246 av_dlog(NULL, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2); 00247 pos += 6; 00248 break; 00249 case 0x06: 00250 if ((buf_size - pos) < 4) 00251 goto fail; 00252 offset1 = AV_RB16(buf + pos); 00253 offset2 = AV_RB16(buf + pos + 2); 00254 av_dlog(NULL, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2); 00255 pos += 4; 00256 break; 00257 case 0x86: 00258 if ((buf_size - pos) < 8) 00259 goto fail; 00260 offset1 = AV_RB32(buf + pos); 00261 offset2 = AV_RB32(buf + pos + 4); 00262 av_dlog(NULL, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2); 00263 pos += 8; 00264 break; 00265 00266 case 0x83: 00267 /* HD set palette */ 00268 if ((buf_size - pos) < 768) 00269 goto fail; 00270 yuv_palette = buf + pos; 00271 pos += 768; 00272 break; 00273 case 0x84: 00274 /* HD set contrast (alpha) */ 00275 if ((buf_size - pos) < 256) 00276 goto fail; 00277 for (i = 0; i < 256; i++) 00278 alpha[i] = 0xFF - buf[pos+i]; 00279 pos += 256; 00280 break; 00281 00282 case 0xff: 00283 goto the_end; 00284 default: 00285 av_dlog(NULL, "unrecognised subpicture command 0x%x\n", cmd); 00286 goto the_end; 00287 } 00288 } 00289 the_end: 00290 if (offset1 >= 0) { 00291 int w, h; 00292 uint8_t *bitmap; 00293 00294 /* decode the bitmap */ 00295 w = x2 - x1 + 1; 00296 if (w < 0) 00297 w = 0; 00298 h = y2 - y1; 00299 if (h < 0) 00300 h = 0; 00301 if (w > 0 && h > 0) { 00302 if (sub_header->rects != NULL) { 00303 for (i = 0; i < sub_header->num_rects; i++) { 00304 av_freep(&sub_header->rects[i]->pict.data[0]); 00305 av_freep(&sub_header->rects[i]->pict.data[1]); 00306 av_freep(&sub_header->rects[i]); 00307 } 00308 av_freep(&sub_header->rects); 00309 sub_header->num_rects = 0; 00310 } 00311 00312 bitmap = av_malloc(w * h); 00313 sub_header->rects = av_mallocz(sizeof(*sub_header->rects)); 00314 sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect)); 00315 sub_header->num_rects = 1; 00316 sub_header->rects[0]->pict.data[0] = bitmap; 00317 decode_rle(bitmap, w * 2, w, (h + 1) / 2, 00318 buf, offset1, buf_size, is_8bit); 00319 decode_rle(bitmap + w, w * 2, w, h / 2, 00320 buf, offset2, buf_size, is_8bit); 00321 sub_header->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE); 00322 if (is_8bit) { 00323 if (yuv_palette == 0) 00324 goto fail; 00325 sub_header->rects[0]->nb_colors = 256; 00326 yuv_a_to_rgba(yuv_palette, alpha, (uint32_t*)sub_header->rects[0]->pict.data[1], 256); 00327 } else { 00328 sub_header->rects[0]->nb_colors = 4; 00329 guess_palette((uint32_t*)sub_header->rects[0]->pict.data[1], 00330 colormap, alpha, 0xffff00); 00331 } 00332 sub_header->rects[0]->x = x1; 00333 sub_header->rects[0]->y = y1; 00334 sub_header->rects[0]->w = w; 00335 sub_header->rects[0]->h = h; 00336 sub_header->rects[0]->type = SUBTITLE_BITMAP; 00337 sub_header->rects[0]->pict.linesize[0] = w; 00338 } 00339 } 00340 if (next_cmd_pos == cmd_pos) 00341 break; 00342 cmd_pos = next_cmd_pos; 00343 } 00344 if (sub_header->num_rects > 0) 00345 return is_menu; 00346 fail: 00347 if (sub_header->rects != NULL) { 00348 for (i = 0; i < sub_header->num_rects; i++) { 00349 av_freep(&sub_header->rects[i]->pict.data[0]); 00350 av_freep(&sub_header->rects[i]->pict.data[1]); 00351 av_freep(&sub_header->rects[i]); 00352 } 00353 av_freep(&sub_header->rects); 00354 sub_header->num_rects = 0; 00355 } 00356 return -1; 00357 } 00358 00359 static int is_transp(const uint8_t *buf, int pitch, int n, 00360 const uint8_t *transp_color) 00361 { 00362 int i; 00363 for(i = 0; i < n; i++) { 00364 if (!transp_color[*buf]) 00365 return 0; 00366 buf += pitch; 00367 } 00368 return 1; 00369 } 00370 00371 /* return 0 if empty rectangle, 1 if non empty */ 00372 static int find_smallest_bounding_rectangle(AVSubtitle *s) 00373 { 00374 uint8_t transp_color[256]; 00375 int y1, y2, x1, x2, y, w, h, i; 00376 uint8_t *bitmap; 00377 00378 if (s->num_rects == 0 || s->rects == NULL || s->rects[0]->w <= 0 || s->rects[0]->h <= 0) 00379 return 0; 00380 00381 memset(transp_color, 0, 256); 00382 for(i = 0; i < s->rects[0]->nb_colors; i++) { 00383 if ((((uint32_t*)s->rects[0]->pict.data[1])[i] >> 24) == 0) 00384 transp_color[i] = 1; 00385 } 00386 y1 = 0; 00387 while (y1 < s->rects[0]->h && is_transp(s->rects[0]->pict.data[0] + y1 * s->rects[0]->pict.linesize[0], 00388 1, s->rects[0]->w, transp_color)) 00389 y1++; 00390 if (y1 == s->rects[0]->h) { 00391 av_freep(&s->rects[0]->pict.data[0]); 00392 s->rects[0]->w = s->rects[0]->h = 0; 00393 return 0; 00394 } 00395 00396 y2 = s->rects[0]->h - 1; 00397 while (y2 > 0 && is_transp(s->rects[0]->pict.data[0] + y2 * s->rects[0]->pict.linesize[0], 1, 00398 s->rects[0]->w, transp_color)) 00399 y2--; 00400 x1 = 0; 00401 while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->pict.data[0] + x1, s->rects[0]->pict.linesize[0], 00402 s->rects[0]->h, transp_color)) 00403 x1++; 00404 x2 = s->rects[0]->w - 1; 00405 while (x2 > 0 && is_transp(s->rects[0]->pict.data[0] + x2, s->rects[0]->pict.linesize[0], s->rects[0]->h, 00406 transp_color)) 00407 x2--; 00408 w = x2 - x1 + 1; 00409 h = y2 - y1 + 1; 00410 bitmap = av_malloc(w * h); 00411 if (!bitmap) 00412 return 1; 00413 for(y = 0; y < h; y++) { 00414 memcpy(bitmap + w * y, s->rects[0]->pict.data[0] + x1 + (y1 + y) * s->rects[0]->pict.linesize[0], w); 00415 } 00416 av_freep(&s->rects[0]->pict.data[0]); 00417 s->rects[0]->pict.data[0] = bitmap; 00418 s->rects[0]->pict.linesize[0] = w; 00419 s->rects[0]->w = w; 00420 s->rects[0]->h = h; 00421 s->rects[0]->x += x1; 00422 s->rects[0]->y += y1; 00423 return 1; 00424 } 00425 00426 #ifdef DEBUG 00427 #undef fprintf 00428 #undef perror 00429 #undef exit 00430 static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h, 00431 uint32_t *rgba_palette) 00432 { 00433 int x, y, v; 00434 FILE *f; 00435 00436 f = fopen(filename, "w"); 00437 if (!f) { 00438 perror(filename); 00439 exit(1); 00440 } 00441 fprintf(f, "P6\n" 00442 "%d %d\n" 00443 "%d\n", 00444 w, h, 255); 00445 for(y = 0; y < h; y++) { 00446 for(x = 0; x < w; x++) { 00447 v = rgba_palette[bitmap[y * w + x]]; 00448 putc((v >> 16) & 0xff, f); 00449 putc((v >> 8) & 0xff, f); 00450 putc((v >> 0) & 0xff, f); 00451 } 00452 } 00453 fclose(f); 00454 } 00455 #endif 00456 00457 static int dvdsub_decode(AVCodecContext *avctx, 00458 void *data, int *data_size, 00459 AVPacket *avpkt) 00460 { 00461 const uint8_t *buf = avpkt->data; 00462 int buf_size = avpkt->size; 00463 AVSubtitle *sub = data; 00464 int is_menu; 00465 00466 is_menu = decode_dvd_subtitles(sub, buf, buf_size); 00467 00468 if (is_menu < 0) { 00469 no_subtitle: 00470 *data_size = 0; 00471 00472 return buf_size; 00473 } 00474 if (!is_menu && find_smallest_bounding_rectangle(sub) == 0) 00475 goto no_subtitle; 00476 00477 #if defined(DEBUG) 00478 av_dlog(NULL, "start=%d ms end =%d ms\n", 00479 sub->start_display_time, 00480 sub->end_display_time); 00481 ppm_save("/tmp/a.ppm", sub->rects[0]->pict.data[0], 00482 sub->rects[0]->w, sub->rects[0]->h, sub->rects[0]->pict.data[1]); 00483 #endif 00484 00485 *data_size = 1; 00486 return buf_size; 00487 } 00488 00489 AVCodec ff_dvdsub_decoder = { 00490 "dvdsub", 00491 AVMEDIA_TYPE_SUBTITLE, 00492 CODEC_ID_DVD_SUBTITLE, 00493 0, 00494 NULL, 00495 NULL, 00496 NULL, 00497 dvdsub_decode, 00498 .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"), 00499 };