]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/dvdsub.c
10l
[ffmpeg] / libavcodec / dvdsub.c
index 3300d0d62964ccc05deeda5e9a8460e12af2216d..2ed015a99a9b779422fd5e37a11be228fbcd746a 100644 (file)
@@ -2,19 +2,21 @@
  * DVD subtitle decoding for ffmpeg
  * Copyright (c) 2005 Fabrice Bellard.
  *
- * This library is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include "avcodec.h"
 
@@ -28,17 +30,17 @@ static int dvdsub_init_decoder(AVCodecContext *avctx)
     return 0;
 }
 
-uint16_t getbe16(const uint8_t *p)
+static uint16_t getbe16(const uint8_t *p)
 {
     return (p[0] << 8) | p[1];
 }
 
-int get_nibble(const uint8_t *buf, int nibble_offset)
+static int get_nibble(const uint8_t *buf, int nibble_offset)
 {
     return (buf[nibble_offset >> 1] >> ((1 - (nibble_offset & 1)) << 2)) & 0xf;
 }
 
-static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, 
+static int decode_rle(uint8_t *bitmap, int linesize, int w, int h,
                       const uint8_t *buf, int nibble_offset, int buf_size)
 {
     unsigned int v;
@@ -91,7 +93,7 @@ static void guess_palette(uint32_t *rgba_palette,
 {
     uint8_t color_used[16];
     int nb_opaque_colors, i, level, j, r, g, b;
-    
+
     for(i = 0; i < 4; i++)
         rgba_palette[i] = 0;
 
@@ -103,37 +105,39 @@ static void guess_palette(uint32_t *rgba_palette,
             nb_opaque_colors++;
         }
     }
-    
+
     if (nb_opaque_colors == 0)
         return;
-    
-    j = 0;
+
+    j = nb_opaque_colors;
     memset(color_used, 0, 16);
     for(i = 0; i < 4; i++) {
         if (alpha[i] != 0) {
             if (!color_used[palette[i]])  {
-                level = (0xff * (j + 1)) / nb_opaque_colors;
+                level = (0xff * j) / nb_opaque_colors;
                 r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
                 g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
                 b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
-                rgba_palette[i] = b | (g << 8) | (r << 16) | (0xff << 24);
+                rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24);
                 color_used[palette[i]] = (i + 1);
-                j++;
+                j--;
             } else {
-                rgba_palette[i] = rgba_palette[color_used[palette[i]] - 1];
+                rgba_palette[i] = (rgba_palette[color_used[palette[i]] - 1] & 0x00ffffff) |
+                                    ((alpha[i] * 17) << 24);
             }
         }
     }
 }
 
-static int decode_dvd_subtitles(AVSubtitle *sub_header, 
+static int decode_dvd_subtitles(AVSubtitle *sub_header,
                                 const uint8_t *buf, int buf_size)
 {
     int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos;
     uint8_t palette[4], alpha[4];
     int date;
     int i;
-    
+    int is_menu = 0;
+
     if (buf_size < 4)
         return -1;
     sub_header->rects = NULL;
@@ -146,7 +150,7 @@ static int decode_dvd_subtitles(AVSubtitle *sub_header,
         date = getbe16(buf + cmd_pos);
         next_cmd_pos = getbe16(buf + cmd_pos + 2);
 #ifdef DEBUG
-        av_log(NULL, AV_LOG_INFO, "cmd_pos=0x%04x next=0x%04x date=%d\n", 
+        av_log(NULL, AV_LOG_INFO, "cmd_pos=0x%04x next=0x%04x date=%d\n",
                cmd_pos, next_cmd_pos, date);
 #endif
         pos = cmd_pos + 4;
@@ -160,35 +164,39 @@ static int decode_dvd_subtitles(AVSubtitle *sub_header,
 #endif
             switch(cmd) {
             case 0x00:
-                /* force display */
+                /* menu subpicture */
+                is_menu = 1;
                 break;
             case 0x01:
                 /* set start date */
-                sub_header->start_display_time = date * 10;
+                sub_header->start_display_time = (date << 10) / 90;
                 break;
             case 0x02:
                 /* set end date */
-                sub_header->end_display_time = date * 10;
+                sub_header->end_display_time = (date << 10) / 90;
                 break;
             case 0x03:
                 /* set palette */
                 if ((buf_size - pos) < 2)
                     goto fail;
-                palette[0] = buf[pos] >> 4;
-                palette[1] = buf[pos] & 0x0f;
-                palette[2] = buf[pos + 1] >> 4;
-                palette[3] = buf[pos + 1] & 0x0f;
+                palette[3] = buf[pos] >> 4;
+                palette[2] = buf[pos] & 0x0f;
+                palette[1] = buf[pos + 1] >> 4;
+                palette[0] = buf[pos + 1] & 0x0f;
                 pos += 2;
                 break;
             case 0x04:
                 /* set alpha */
                 if ((buf_size - pos) < 2)
                     goto fail;
-                alpha[0] = buf[pos] >> 4;
-                alpha[1] = buf[pos] & 0x0f;
-                alpha[2] = buf[pos + 1] >> 4;
-                alpha[3] = buf[pos + 1] & 0x0f;
+                alpha[3] = buf[pos] >> 4;
+                alpha[2] = buf[pos] & 0x0f;
+                alpha[1] = buf[pos + 1] >> 4;
+                alpha[0] = buf[pos + 1] & 0x0f;
                 pos += 2;
+#ifdef DEBUG
+            av_log(NULL, AV_LOG_INFO, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
+#endif
                 break;
             case 0x05:
                 if ((buf_size - pos) < 6)
@@ -222,7 +230,7 @@ static int decode_dvd_subtitles(AVSubtitle *sub_header,
         if (offset1 >= 0) {
             int w, h;
             uint8_t *bitmap;
-            
+
             /* decode the bitmap */
             w = x2 - x1 + 1;
             if (w < 0)
@@ -264,12 +272,12 @@ static int decode_dvd_subtitles(AVSubtitle *sub_header,
         cmd_pos = next_cmd_pos;
     }
     if (sub_header->num_rects > 0)
-        return 0;
+        return is_menu;
  fail:
     return -1;
 }
 
-static int is_transp(const uint8_t *buf, int pitch, int n, 
+static int is_transp(const uint8_t *buf, int pitch, int n,
                      const uint8_t *transp_color)
 {
     int i;
@@ -282,7 +290,7 @@ static int is_transp(const uint8_t *buf, int pitch, int n,
 }
 
 /* return 0 if empty rectangle, 1 if non empty */
-static int find_smallest_bouding_rectangle(AVSubtitle *s)
+static int find_smallest_bounding_rectangle(AVSubtitle *s)
 {
     uint8_t transp_color[256];
     int y1, y2, x1, x2, y, w, h, i;
@@ -375,18 +383,21 @@ static int dvdsub_decode(AVCodecContext *avctx,
                          uint8_t *buf, int buf_size)
 {
     AVSubtitle *sub = (void *)data;
+    int is_menu;
 
-    if (decode_dvd_subtitles(sub, buf, buf_size) < 0) {
+    is_menu = decode_dvd_subtitles(sub, buf, buf_size);
+
+    if (is_menu < 0) {
     no_subtitle:
         *data_size = 0;
 
         return buf_size;
     }
-    if (find_smallest_bouding_rectangle(sub) == 0)
+    if (!is_menu && find_smallest_bounding_rectangle(sub) == 0)
         goto no_subtitle;
 
 #if defined(DEBUG)
-    av_log(NULL, AV_LOG_INFO, "start=%d ms end =%d ms\n", 
+    av_log(NULL, AV_LOG_INFO, "start=%d ms end =%d ms\n",
            sub->start_display_time,
            sub->end_display_time);
     ppm_save("/tmp/a.ppm", sub->rects[0].bitmap,
@@ -422,11 +433,11 @@ static int dvdsub_parse_init(AVCodecParserContext *s)
 
 static int dvdsub_parse(AVCodecParserContext *s,
                         AVCodecContext *avctx,
-                        uint8_t **poutbuf, int *poutbuf_size, 
+                        uint8_t **poutbuf, int *poutbuf_size,
                         const uint8_t *buf, int buf_size)
 {
     DVDSubParseContext *pc = s->priv_data;
-    
+
     if (pc->packet_index == 0) {
         if (buf_size < 2)
             return 0;