dvdsub.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:14k
源码类别:

Windows CE

开发平台:

C/C++

  1. /*
  2.  * DVD subtitle decoding for ffmpeg
  3.  * Copyright (c) 2005 Fabrice Bellard.
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Lesser General Public
  7.  * License as published by the Free Software Foundation; either
  8.  * version 2 of the License, or (at your option) any later version.
  9.  *
  10.  * This library is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * Lesser General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU Lesser General Public
  16.  * License along with this library; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. #include "avcodec.h"
  20. //#define DEBUG
  21. typedef struct DVDSubContext {
  22. } DVDSubContext;
  23. static int dvdsub_init_decoder(AVCodecContext *avctx)
  24. {
  25.     return 0;
  26. }
  27. uint16_t getbe16(const uint8_t *p)
  28. {
  29.     return (p[0] << 8) | p[1];
  30. }
  31. int get_nibble(const uint8_t *buf, int nibble_offset)
  32. {
  33.     return (buf[nibble_offset >> 1] >> ((1 - (nibble_offset & 1)) << 2)) & 0xf;
  34. }
  35. static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, 
  36.                       const uint8_t *buf, int nibble_offset, int buf_size)
  37. {
  38.     unsigned int v;
  39.     int x, y, len, color, nibble_end;
  40.     uint8_t *d;
  41.     nibble_end = buf_size * 2;
  42.     x = 0;
  43.     y = 0;
  44.     d = bitmap;
  45.     for(;;) {
  46.         if (nibble_offset >= nibble_end)
  47.             return -1;
  48.         v = get_nibble(buf, nibble_offset++);
  49.         if (v < 0x4) {
  50.             v = (v << 4) | get_nibble(buf, nibble_offset++);
  51.             if (v < 0x10) {
  52.                 v = (v << 4) | get_nibble(buf, nibble_offset++);
  53.                 if (v < 0x040) {
  54.                     v = (v << 4) | get_nibble(buf, nibble_offset++);
  55.                     if (v < 4) {
  56.                         v |= (w - x) << 2;
  57.                     }
  58.                 }
  59.             }
  60.         }
  61.         len = v >> 2;
  62.         if (len > (w - x))
  63.             len = (w - x);
  64.         color = v & 0x03;
  65.         memset(d + x, color, len);
  66.         x += len;
  67.         if (x >= w) {
  68.             y++;
  69.             if (y >= h)
  70.                 break;
  71.             d += linesize;
  72.             x = 0;
  73.             /* byte align */
  74.             nibble_offset += (nibble_offset & 1);
  75.         }
  76.     }
  77.     return 0;
  78. }
  79. static void guess_palette(uint32_t *rgba_palette,
  80.                           uint8_t *palette,
  81.                           uint8_t *alpha,
  82.                           uint32_t subtitle_color)
  83. {
  84.     uint8_t color_used[16];
  85.     int nb_opaque_colors, i, level, j, r, g, b;
  86.     
  87.     for(i = 0; i < 4; i++)
  88.         rgba_palette[i] = 0;
  89.     memset(color_used, 0, 16);
  90.     nb_opaque_colors = 0;
  91.     for(i = 0; i < 4; i++) {
  92.         if (alpha[i] != 0 && !color_used[palette[i]]) {
  93.             color_used[palette[i]] = 1;
  94.             nb_opaque_colors++;
  95.         }
  96.     }
  97.     
  98.     if (nb_opaque_colors == 0)
  99.         return;
  100.     
  101.     j = nb_opaque_colors;
  102.     memset(color_used, 0, 16);
  103.     for(i = 0; i < 4; i++) {
  104.         if (alpha[i] != 0) {
  105.             if (!color_used[palette[i]])  {
  106.                 level = (0xff * j) / nb_opaque_colors;
  107.                 r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
  108.                 g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
  109.                 b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
  110.                 rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24);
  111.                 color_used[palette[i]] = (i + 1);
  112.                 j--;
  113.             } else {
  114.                 rgba_palette[i] = (rgba_palette[color_used[palette[i]] - 1] & 0x00ffffff) |
  115.                                     ((alpha[i] * 17) << 24);
  116.             }
  117.         }
  118.     }
  119. }
  120. static int decode_dvd_subtitles(AVSubtitle *sub_header, 
  121.                                 const uint8_t *buf, int buf_size)
  122. {
  123.     int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos;
  124.     uint8_t palette[4], alpha[4];
  125.     int date;
  126.     int i;
  127.     int is_menu = 0;
  128.     
  129.     if (buf_size < 4)
  130.         return -1;
  131.     sub_header->rects = NULL;
  132.     sub_header->num_rects = 0;
  133.     sub_header->start_display_time = 0;
  134.     sub_header->end_display_time = 0;
  135.     cmd_pos = getbe16(buf + 2);
  136.     while ((cmd_pos + 4) < buf_size) {
  137.         date = getbe16(buf + cmd_pos);
  138.         next_cmd_pos = getbe16(buf + cmd_pos + 2);
  139. #ifdef DEBUG
  140.         av_log(NULL, AV_LOG_INFO, "cmd_pos=0x%04x next=0x%04x date=%dn", 
  141.                cmd_pos, next_cmd_pos, date);
  142. #endif
  143.         pos = cmd_pos + 4;
  144.         offset1 = -1;
  145.         offset2 = -1;
  146.         x1 = y1 = x2 = y2 = 0;
  147.         while (pos < buf_size) {
  148.             cmd = buf[pos++];
  149. #ifdef DEBUG
  150.             av_log(NULL, AV_LOG_INFO, "cmd=%02xn", cmd);
  151. #endif
  152.             switch(cmd) {
  153.             case 0x00:
  154.                 /* menu subpicture */
  155.                 is_menu = 1;
  156.                 break;
  157.             case 0x01:
  158.                 /* set start date */
  159.                 sub_header->start_display_time = (date << 10) / 90;
  160.                 break;
  161.             case 0x02:
  162.                 /* set end date */
  163.                 sub_header->end_display_time = (date << 10) / 90;
  164.                 break;
  165.             case 0x03:
  166.                 /* set palette */
  167.                 if ((buf_size - pos) < 2)
  168.                     goto fail;
  169.                 palette[3] = buf[pos] >> 4;
  170.                 palette[2] = buf[pos] & 0x0f;
  171.                 palette[1] = buf[pos + 1] >> 4;
  172.                 palette[0] = buf[pos + 1] & 0x0f;
  173.                 pos += 2;
  174.                 break;
  175.             case 0x04:
  176.                 /* set alpha */
  177.                 if ((buf_size - pos) < 2)
  178.                     goto fail;
  179.                 alpha[3] = buf[pos] >> 4;
  180.                 alpha[2] = buf[pos] & 0x0f;
  181.                 alpha[1] = buf[pos + 1] >> 4;
  182.                 alpha[0] = buf[pos + 1] & 0x0f;
  183.                 pos += 2;
  184. #ifdef DEBUG
  185.             av_log(NULL, AV_LOG_INFO, "alpha=%x%x%x%xn", alpha[0],alpha[1],alpha[2],alpha[3]);
  186. #endif
  187.                 break;
  188.             case 0x05:
  189.                 if ((buf_size - pos) < 6)
  190.                     goto fail;
  191.                 x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4);
  192.                 x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2];
  193.                 y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4);
  194.                 y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5];
  195. #ifdef DEBUG
  196.                 av_log(NULL, AV_LOG_INFO, "x1=%d x2=%d y1=%d y2=%dn",
  197.                        x1, x2, y1, y2);
  198. #endif
  199.                 pos += 6;
  200.                 break;
  201.             case 0x06:
  202.                 if ((buf_size - pos) < 4)
  203.                     goto fail;
  204.                 offset1 = getbe16(buf + pos);
  205.                 offset2 = getbe16(buf + pos + 2);
  206. #ifdef DEBUG
  207.                 av_log(NULL, AV_LOG_INFO, "offset1=0x%04x offset2=0x%04xn", offset1, offset2);
  208. #endif
  209.                 pos += 4;
  210.                 break;
  211.             case 0xff:
  212.             default:
  213.                 goto the_end;
  214.             }
  215.         }
  216.     the_end:
  217.         if (offset1 >= 0) {
  218.             int w, h;
  219.             uint8_t *bitmap;
  220.             
  221.             /* decode the bitmap */
  222.             w = x2 - x1 + 1;
  223.             if (w < 0)
  224.                 w = 0;
  225.             h = y2 - y1;
  226.             if (h < 0)
  227.                 h = 0;
  228.             if (w > 0 && h > 0) {
  229.                 if (sub_header->rects != NULL) {
  230.                     for (i = 0; i < sub_header->num_rects; i++) {
  231.                         av_free(sub_header->rects[i].bitmap);
  232.                         av_free(sub_header->rects[i].rgba_palette);
  233.                     }
  234.                     av_freep(&sub_header->rects);
  235.                     sub_header->num_rects = 0;
  236.                 }
  237.                 bitmap = av_malloc(w * h);
  238.                 sub_header->rects = av_mallocz(sizeof(AVSubtitleRect));
  239.                 sub_header->num_rects = 1;
  240.                 sub_header->rects[0].rgba_palette = av_malloc(4 * 4);
  241.                 decode_rle(bitmap, w * 2, w, h / 2,
  242.                            buf, offset1 * 2, buf_size);
  243.                 decode_rle(bitmap + w, w * 2, w, h / 2,
  244.                            buf, offset2 * 2, buf_size);
  245.                 guess_palette(sub_header->rects[0].rgba_palette,
  246.                               palette, alpha, 0xffff00);
  247.                 sub_header->rects[0].x = x1;
  248.                 sub_header->rects[0].y = y1;
  249.                 sub_header->rects[0].w = w;
  250.                 sub_header->rects[0].h = h;
  251.                 sub_header->rects[0].nb_colors = 4;
  252.                 sub_header->rects[0].linesize = w;
  253.                 sub_header->rects[0].bitmap = bitmap;
  254.             }
  255.         }
  256.         if (next_cmd_pos == cmd_pos)
  257.             break;
  258.         cmd_pos = next_cmd_pos;
  259.     }
  260.     if (sub_header->num_rects > 0)
  261.         return is_menu;
  262.  fail:
  263.     return -1;
  264. }
  265. static int is_transp(const uint8_t *buf, int pitch, int n, 
  266.                      const uint8_t *transp_color)
  267. {
  268.     int i;
  269.     for(i = 0; i < n; i++) {
  270.         if (!transp_color[*buf])
  271.             return 0;
  272.         buf += pitch;
  273.     }
  274.     return 1;
  275. }
  276. /* return 0 if empty rectangle, 1 if non empty */
  277. static int find_smallest_bounding_rectangle(AVSubtitle *s)
  278. {
  279.     uint8_t transp_color[256];
  280.     int y1, y2, x1, x2, y, w, h, i;
  281.     uint8_t *bitmap;
  282.     if (s->num_rects == 0 || s->rects == NULL || s->rects[0].w <= 0 || s->rects[0].h <= 0)
  283.         return 0;
  284.     memset(transp_color, 0, 256);
  285.     for(i = 0; i < s->rects[0].nb_colors; i++) {
  286.         if ((s->rects[0].rgba_palette[i] >> 24) == 0)
  287.             transp_color[i] = 1;
  288.     }
  289.     y1 = 0;
  290.     while (y1 < s->rects[0].h && is_transp(s->rects[0].bitmap + y1 * s->rects[0].linesize,
  291.                                   1, s->rects[0].w, transp_color))
  292.         y1++;
  293.     if (y1 == s->rects[0].h) {
  294.         av_freep(&s->rects[0].bitmap);
  295.         s->rects[0].w = s->rects[0].h = 0;
  296.         return 0;
  297.     }
  298.     y2 = s->rects[0].h - 1;
  299.     while (y2 > 0 && is_transp(s->rects[0].bitmap + y2 * s->rects[0].linesize, 1,
  300.                                s->rects[0].w, transp_color))
  301.         y2--;
  302.     x1 = 0;
  303.     while (x1 < (s->rects[0].w - 1) && is_transp(s->rects[0].bitmap + x1, s->rects[0].linesize,
  304.                                         s->rects[0].h, transp_color))
  305.         x1++;
  306.     x2 = s->rects[0].w - 1;
  307.     while (x2 > 0 && is_transp(s->rects[0].bitmap + x2, s->rects[0].linesize, s->rects[0].h,
  308.                                   transp_color))
  309.         x2--;
  310.     w = x2 - x1 + 1;
  311.     h = y2 - y1 + 1;
  312.     bitmap = av_malloc(w * h);
  313.     if (!bitmap)
  314.         return 1;
  315.     for(y = 0; y < h; y++) {
  316.         memcpy(bitmap + w * y, s->rects[0].bitmap + x1 + (y1 + y) * s->rects[0].linesize, w);
  317.     }
  318.     av_freep(&s->rects[0].bitmap);
  319.     s->rects[0].bitmap = bitmap;
  320.     s->rects[0].linesize = w;
  321.     s->rects[0].w = w;
  322.     s->rects[0].h = h;
  323.     s->rects[0].x += x1;
  324.     s->rects[0].y += y1;
  325.     return 1;
  326. }
  327. static int dvdsub_close_decoder(AVCodecContext *avctx)
  328. {
  329.     return 0;
  330. }
  331. #ifdef DEBUG
  332. #undef fprintf
  333. static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
  334.                      uint32_t *rgba_palette)
  335. {
  336.     int x, y, v;
  337.     FILE *f;
  338.     f = fopen(filename, "w");
  339.     if (!f) {
  340.         perror(filename);
  341.         exit(1);
  342.     }
  343.     fprintf(f, "P6n"
  344.             "%d %dn"
  345.             "%dn",
  346.             w, h, 255);
  347.     for(y = 0; y < h; y++) {
  348.         for(x = 0; x < w; x++) {
  349.             v = rgba_palette[bitmap[y * w + x]];
  350.             putc((v >> 16) & 0xff, f);
  351.             putc((v >> 8) & 0xff, f);
  352.             putc((v >> 0) & 0xff, f);
  353.         }
  354.     }
  355.     fclose(f);
  356. }
  357. #endif
  358. static int dvdsub_decode(AVCodecContext *avctx,
  359.                          void *data, int *data_size,
  360.                          uint8_t *buf, int buf_size)
  361. {
  362.     AVSubtitle *sub = (void *)data;
  363.     int is_menu;
  364.     is_menu = decode_dvd_subtitles(sub, buf, buf_size);
  365.     if (is_menu < 0) {
  366.     no_subtitle:
  367.         *data_size = 0;
  368.         return buf_size;
  369.     }
  370.     if (!is_menu && find_smallest_bounding_rectangle(sub) == 0)
  371.         goto no_subtitle;
  372. #if defined(DEBUG)
  373.     av_log(NULL, AV_LOG_INFO, "start=%d ms end =%d msn", 
  374.            sub->start_display_time,
  375.            sub->end_display_time);
  376.     ppm_save("/tmp/a.ppm", sub->rects[0].bitmap,
  377.              sub->rects[0].w, sub->rects[0].h, sub->rects[0].rgba_palette);
  378. #endif
  379.     *data_size = 1;
  380.     return buf_size;
  381. }
  382. AVCodec dvdsub_decoder = {
  383.     "dvdsub",
  384.     CODEC_TYPE_SUBTITLE,
  385.     CODEC_ID_DVD_SUBTITLE,
  386.     sizeof(DVDSubContext),
  387.     dvdsub_init_decoder,
  388.     NULL,
  389.     dvdsub_close_decoder,
  390.     dvdsub_decode,
  391. };
  392. /* parser definition */
  393. typedef struct DVDSubParseContext {
  394.     uint8_t *packet;
  395.     int packet_len;
  396.     int packet_index;
  397. } DVDSubParseContext;
  398. static int dvdsub_parse_init(AVCodecParserContext *s)
  399. {
  400.     return 0;
  401. }
  402. static int dvdsub_parse(AVCodecParserContext *s,
  403.                         AVCodecContext *avctx,
  404.                         uint8_t **poutbuf, int *poutbuf_size, 
  405.                         const uint8_t *buf, int buf_size)
  406. {
  407.     DVDSubParseContext *pc = s->priv_data;
  408.     
  409.     if (pc->packet_index == 0) {
  410.         if (buf_size < 2)
  411.             return 0;
  412.         pc->packet_len = (buf[0] << 8) | buf[1];
  413.         av_freep(&pc->packet);
  414.         pc->packet = av_malloc(pc->packet_len);
  415.     }
  416.     if (pc->packet) {
  417.         if (pc->packet_index + buf_size <= pc->packet_len) {
  418.             memcpy(pc->packet + pc->packet_index, buf, buf_size);
  419.             pc->packet_index += buf_size;
  420.             if (pc->packet_index >= pc->packet_len) {
  421.                 *poutbuf = pc->packet;
  422.                 *poutbuf_size = pc->packet_len;
  423.                 pc->packet_index = 0;
  424.                 return buf_size;
  425.             }
  426.         } else {
  427.             /* erroneous size */
  428.             pc->packet_index = 0;
  429.         }
  430.     }
  431.     *poutbuf = NULL;
  432.     *poutbuf_size = 0;
  433.     return buf_size;
  434. }
  435. static void dvdsub_parse_close(AVCodecParserContext *s)
  436. {
  437.     DVDSubParseContext *pc = s->priv_data;
  438.     av_freep(&pc->packet);
  439. }
  440. AVCodecParser dvdsub_parser = {
  441.     { CODEC_ID_DVD_SUBTITLE },
  442.     sizeof(DVDSubParseContext),
  443.     dvdsub_parse_init,
  444.     dvdsub_parse,
  445.     dvdsub_parse_close,
  446. };