First cut at CVD subtitle unit assembly and initial parsing.
authorRocky Bernstein <rocky@videolan.org>
Sun, 28 Dec 2003 11:26:52 +0000 (11:26 +0000)
committerRocky Bernstein <rocky@videolan.org>
Sun, 28 Dec 2003 11:26:52 +0000 (11:26 +0000)
modules/codec/ogt/cvd.c
modules/codec/ogt/cvd_parse.c
modules/codec/ogt/ogt_parse.c
modules/codec/ogt/subtitle.h

index e48d813..8f008ae 100644 (file)
@@ -2,7 +2,7 @@
  * cvd.c : CVD Subtitle decoder thread
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
  * cvd.c : CVD Subtitle decoder thread
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
- * $Id: cvd.c,v 1.1 2003/12/28 04:51:52 rocky Exp $
+ * $Id: cvd.c,v 1.2 2003/12/28 11:26:52 rocky Exp $
  *
  * Authors: Rocky Bernstein
  *   based on code from:
  *
  * Authors: Rocky Bernstein
  *   based on code from:
@@ -186,7 +186,7 @@ Packetize( decoder_t *p_dec, block_t **pp_block )
 
 /* following functions are local */
 
 
 /* following functions are local */
 
-#define SPU_HEADER_LEN 5
+#define SPU_HEADER_LEN 1
 
 /*****************************************************************************
  Reassemble:
 
 /*****************************************************************************
  Reassemble:
@@ -200,16 +200,6 @@ Packetize( decoder_t *p_dec, block_t **pp_block )
  If everything is complete, we will return a block. Otherwise return
  NULL.
 
  If everything is complete, we will return a block. Otherwise return
  NULL.
 
-
- The format of the beginning of the subtitle packet that is used here.
-
-   size    description
-   -------------------------------------------
-   byte    subtitle channel (0..7) in bits 0-3
-   byte    subtitle packet number of this subtitle image 0-N,
-           if the subtitle packet is complete, the top bit of the byte is 1.
-   uint16  subtitle image number
-
  *****************************************************************************/
 static block_t *
 Reassemble( decoder_t *p_dec, block_t **pp_block )
  *****************************************************************************/
 static block_t *
 Reassemble( decoder_t *p_dec, block_t **pp_block )
@@ -217,8 +207,6 @@ Reassemble( decoder_t *p_dec, block_t **pp_block )
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_block;
     uint8_t *p_buffer;
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_block;
     uint8_t *p_buffer;
-    uint16_t i_expected_image;
-    uint8_t  i_packet, i_expected_packet;
 
     if( pp_block == NULL || *pp_block == NULL )
     {
 
     if( pp_block == NULL || *pp_block == NULL )
     {
@@ -238,70 +226,187 @@ Reassemble( decoder_t *p_dec, block_t **pp_block )
     p_buffer = p_block->p_buffer;
 
     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
     p_buffer = p_block->p_buffer;
 
     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
-              "header: 0x%02x 0x%02x 0x%02x 0x%02x, size: %i",
+              "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
               p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
               p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
+              p_buffer[5], p_buffer[6],
               p_block->i_buffer);
 
               p_block->i_buffer);
 
-    if( config_GetInt( p_dec, "spu-channel" ) != p_buffer[1] )
-      return NULL;
-
-    if ( p_sys->state == SUBTITLE_BLOCK_EMPTY ) {
-      i_expected_image  = p_sys->i_image+1;
-      i_expected_packet = 0;
-    } else {
-      i_expected_image  = p_sys->i_image;
-      i_expected_packet = p_sys->i_packet+1;
-    }
-
-    p_buffer += 2;
-
-    if ( *p_buffer & 0x80 ) {
-      p_sys->state = SUBTITLE_BLOCK_COMPLETE;
-      i_packet     = ( *p_buffer++ & 0x7F );
-    } else {
-      p_sys->state = SUBTITLE_BLOCK_PARTIAL;
-      i_packet     = *p_buffer++;
-    }
-
-    p_sys->i_image = GETINT16(p_buffer);
-
-    if ( p_sys->i_image != i_expected_image ) {
-      msg_Warn( p_dec, "expecting subtitle image %u but found %u",
-                i_expected_image, p_sys->i_image );
-    }
+    /* There is little data on the format, but it does not seem to have a
+       good way to detect the first packet in the subtitle.  It seems,
+       however, that it has a valid pts while later packets for the same
+       image don't */
 
 
-    if ( i_packet != i_expected_packet ) {
-      msg_Warn( p_dec, "expecting subtitle image packet %u but found %u",
-                i_expected_packet, i_packet);
+    if ( p_sys->state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 ) {
+      msg_Warn( p_dec, 
+               "first packet expected but no PTS present -- skipped\n");
+      return NULL;
     }
 
     }
 
-    p_sys->i_packet = i_packet;
-
-    if ( p_sys->i_packet == 0 ) {
+    if ( p_sys->subtitle_data_pos == 0 ) {
       /* First packet in the subtitle block */
       E_(ParseHeader)( p_dec, p_buffer, p_block );
       VCDSubInitSubtitleData(p_sys);
     }
 
     /* FIXME - remove append_data and use chainappend */
       /* First packet in the subtitle block */
       E_(ParseHeader)( p_dec, p_buffer, p_block );
       VCDSubInitSubtitleData(p_sys);
     }
 
     /* FIXME - remove append_data and use chainappend */
-    VCDSubAppendData( p_dec, p_buffer, p_block->i_buffer - 5 );
+    VCDSubAppendData( p_dec, p_buffer, p_block->i_buffer - 1 );
 
     block_ChainAppend( &p_sys->p_block, p_block );
 
     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
 
 
     block_ChainAppend( &p_sys->p_block, p_block );
 
     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
 
-    if (p_sys->state == SUBTITLE_BLOCK_COMPLETE)
-    {
-      if( p_sys->i_spu != p_sys->i_spu_size )
-        {
-          msg_Warn( p_dec, "SPU packets size=%d should be %d",
-                   p_sys->i_spu, p_sys->i_spu_size );
-        }
+    if ( p_sys->subtitle_data_pos == p_sys->i_spu_size ) {
+      /* last packet in subtitle block. */
+
+      uint8_t *p     = p_sys->subtitle_data + p_sys->metadata_offset+1;
+      uint8_t *p_end = p + p_sys->metadata_length;
 
       dbg_print( (DECODE_DBG_PACKET),
                  "subtitle packet complete, size=%d", p_sys->i_spu );
 
 
       dbg_print( (DECODE_DBG_PACKET),
                  "subtitle packet complete, size=%d", p_sys->i_spu );
 
+      p_sys->state = SUBTITLE_BLOCK_COMPLETE;
+      p_sys->i_image++;
+
+
+      for ( ; p < p_end; p += 4 ) {
+
+       switch ( p[0] ) {
+         
+       case 0x04:      /* Display duration in 1/90000ths of a second */
+
+         p_sys->i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
+         
+         dbg_print( DECODE_DBG_PACKET, 
+                    "subtitle display duration %u", p_sys->i_duration);
+         break;
+         
+       case 0x0c:      /* Unknown */
+         dbg_print( DECODE_DBG_PACKET, 
+                    "subtitle command unknown 0x%0x 0x%0x 0x%0x 0x%0x\n",
+                   p[0], p[1], p[2], p[3]);
+         break;
+         
+       case 0x17:      /* Position */
+         p_sys->i_x_start = ((p[1]&0x0f)<<6) + (p[2]>>2);
+         p_sys->i_y_start = ((p[2]&0x03)<<8) + p[3];
+         dbg_print( DECODE_DBG_PACKET, 
+                    "start position (%d,%d): %.2x %.2x %.2x", 
+                    p_sys->i_x_start, p_sys->i_y_start,
+                    p[1], p[2], p[3] );
+         break;
+         
+       case 0x1f:      /* Coordinates of the image bottom right */
+         {
+           int lastx = ((p[1]&0x0f)<<6) + (p[2]>>2);
+           int lasty = ((p[2]&0x03)<<8) + p[3];
+           p_sys->i_width  = lastx - p_sys->i_x_start + 1;
+           p_sys->i_height = lasty - p_sys->i_y_start + 1;
+           dbg_print( DECODE_DBG_PACKET, 
+                      "end position: (%d,%d): %.2x %.2x %.2x, w x h: %d x %d",
+                      lastx, lasty, p[1], p[2], p[3], 
+                      p_sys->i_width, p_sys->i_height );
+           break;
+         }
+         
+         
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27: 
+         {
+           uint8_t v = p[0]-0x24;
+           
+           /* Primary Palette */
+           dbg_print( DECODE_DBG_PACKET,
+                      "primary palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
+                      v, p[1], p[2], p[3]);
+           
+           p_sys->pi_palette[v].s.y = p[1];
+           p_sys->pi_palette[v].s.u = p[2];
+           p_sys->pi_palette[v].s.v = p[3];
+           break;
+         }
+         
+         
+       case 0x2c:
+       case 0x2d:
+       case 0x2e:
+       case 0x2f:
+         {
+           uint8_t v = p[0]-0x2c;
+           
+           dbg_print( DECODE_DBG_PACKET,
+                      "highlight palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
+                      v, p[1], p[2], p[3]);
+           
+           /* Highlight Palette */
+           p_sys->pi_palette_highlight[v].s.y = p[1];
+           p_sys->pi_palette_highlight[v].s.u = p[2];
+           p_sys->pi_palette_highlight[v].s.v = p[3];
+           break;
+         }
+
+       case 0x37:
+         /* transparency for primary palette */
+         p_sys->pi_palette[0].s.t = p[3] & 0x0f;
+         p_sys->pi_palette[1].s.t = p[3] >> 4;
+         p_sys->pi_palette[2].s.t = p[2] & 0x0f;
+         p_sys->pi_palette[3].s.t = p[2] >> 4;
+
+         dbg_print( DECODE_DBG_PACKET,
+                    "transparancy for primary palette (y,u,v): "
+                    "0x%0x 0x%0x 0x%0x",
+                    p[1], p[2], p[3]);
+
+         break;
+
+       case 0x3f:
+         /* transparency for highlight palette */
+         p_sys->pi_palette_highlight[0].s.t = p[2] & 0x0f;
+         p_sys->pi_palette_highlight[1].s.t = p[2] >> 4;
+         p_sys->pi_palette_highlight[2].s.t = p[1] & 0x0f;
+         p_sys->pi_palette_highlight[3].s.t = p[1] >> 4;
+
+         dbg_print( DECODE_DBG_PACKET,
+                    "transparancy for highlight palette (y,u,v): "
+                    "0x%0x 0x%0x 0x%0x",
+                    p[1], p[2], p[3]);
+
+         break;
+         
+       case 0x47:
+         /* offset to first field data, we correct to make it relative
+            to comp_image_offset (usually 4) */
+         p_sys->first_field_offset =
+           (p[2] << 8) + p[3] - p_sys->comp_image_offset;
+         dbg_print( DECODE_DBG_PACKET, 
+                    "first_field_offset %d", p_sys->first_field_offset);
+         break;
+         
+       case 0x4f:
+         /* offset to second field data, we correct to make it relative to
+            comp_image_offset (usually 4) */
+         p_sys->second_field_offset =
+           (p[2] << 8) + p[3] - p_sys->comp_image_offset;
+         dbg_print( DECODE_DBG_PACKET, 
+                    "second_field_offset %d", p_sys->second_field_offset);
+         break;
+         
+       default:
+         msg_Warn( p_dec, 
+                   "unknown sequence in control header " 
+                   "0x%0x 0x%0x 0x%0x 0x%0x",
+                   p[0], p[1], p[2], p[3]);
+         
+         p_sys->subtitle_data_pos = 0;
+       }
+      }
       return p_sys->p_block;
       return p_sys->p_block;
+    } else {
+      /* Not last block in subtitle, so wait for another. */
+      p_sys->state = SUBTITLE_BLOCK_PARTIAL;
     }
     }
+
+    
     return NULL;
 }
     return NULL;
 }
index ed427b8..4dde2e9 100644 (file)
@@ -2,7 +2,7 @@
  * parse.c: Philips OGT (SVCD subtitle) packet parser
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
  * parse.c: Philips OGT (SVCD subtitle) packet parser
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
- * $Id: cvd_parse.c,v 1.1 2003/12/28 04:51:52 rocky Exp $
+ * $Id: cvd_parse.c,v 1.2 2003/12/28 11:26:52 rocky Exp $
  *
  * Authors: Rocky Bernstein 
  *   based on code from: 
  *
  * Authors: Rocky Bernstein 
  *   based on code from: 
@@ -35,6 +35,7 @@
 #include "subtitle.h"
 #include "render.h"
 #include "cvd.h"
 #include "subtitle.h"
 #include "render.h"
 #include "cvd.h"
+#include "common.h"
 
 /* An image color is a two-bit palette entry: 0..3 */ 
 typedef uint8_t ogt_color_t;
 
 /* An image color is a two-bit palette entry: 0..3 */ 
 typedef uint8_t ogt_color_t;
@@ -83,11 +84,29 @@ static int  ParseImage         ( decoder_t *, subpicture_t * );
 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
 {
   decoder_sys_t *p_sys = p_dec->p_sys;
 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
 {
   decoder_sys_t *p_sys = p_dec->p_sys;
-
+  u_int8_t *p = p_buffer+1;
+
+  dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
+            "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
+            p_buffer[0], p_buffer[1], p_buffer[2], p_buffer[3],
+            p_buffer[4], p_buffer[5],
+            p_block->i_buffer);
+  
   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
 
   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
 
-  /* To be finished...*/
-  return;
+  p_sys->i_pts    = p_block->i_pts;
+  p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
+
+  /* FIXME: check data sanity */
+  p_sys->metadata_offset = GETINT16(p);
+  p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
+
+  p_sys->comp_image_offset = 4;
+  p_sys->comp_image_length = p_sys->metadata_offset - p_sys->comp_image_offset;
+  
+  dbg_print(DECODE_DBG_PACKET, "total size: %d  image size: %d\n",
+           p_sys->i_spu_size, p_sys->comp_image_length);
+
 }
 
 
 }
 
 
@@ -102,10 +121,63 @@ E_(ParsePacket)( decoder_t *p_dec)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
+    subpicture_t  *p_spu;
+
     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
 
     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
 
-    /* To be completed... */
-    return;
+    /* Allocate the subpicture internal data. */
+    p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
+    if( p_spu == NULL )
+    {
+        return;
+    }
+
+    /* In ParseImage we expand the run-length encoded color 0's; also
+       we expand pixels and remove the color palette. This should
+       facilitate scaling and antialiasing and speed up rendering.
+    */
+    p_spu->p_sys = malloc( sizeof( subpicture_sys_t ) 
+                          + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
+
+    /* Fill the p_spu structure */
+    vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
+
+    p_spu->pf_render  = VCDSubRender;
+    p_spu->pf_destroy = VCDSubDestroySPU;
+    p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
+
+    p_spu->p_sys->i_x_end        = p_sys->i_x_start + p_sys->i_width - 1;
+    p_spu->p_sys->i_y_end        = p_sys->i_y_start + p_sys->i_height - 1;
+
+    /* FIXME: use aspect ratio for x? */
+    p_spu->i_x        = p_sys->i_x_start * 3 / 4; 
+    p_spu->i_y        = p_sys->i_y_start;
+    p_spu->i_width    = p_sys->i_width;
+    p_spu->i_height   = p_sys->i_height;
+
+    p_spu->i_start    = p_sys->i_pts;
+    p_spu->i_stop     = p_sys->i_pts + (p_sys->i_duration * 10);
+    
+    p_spu->p_sys->b_crop  = VLC_FALSE;
+    p_spu->p_sys->i_debug = p_sys->i_debug;
+
+    /* Get display time now. If we do it later, we may miss the PTS. */
+    p_spu->p_sys->i_pts = p_sys->i_pts;
+
+    /* Attach to our input thread */
+    p_spu->p_sys->p_input = vlc_object_find( p_dec,
+                                             VLC_OBJECT_INPUT, FIND_PARENT );
+
+    /* We try to display it */
+    if( ParseImage( p_dec, p_spu ) )
+    {
+        /* There was a parse error, delete the subpicture */
+        vout_DestroySubPicture( p_sys->p_vout, p_spu );
+        return;
+    }
+
+    /* SPU is finished - we can ask the video output to display it */
+    vout_DisplaySubPicture( p_sys->p_vout, p_spu );
 
 }
 
 
 }
 
index b3375a7..d12af15 100644 (file)
@@ -2,7 +2,7 @@
  * Philips OGT (SVCD subtitle) packet parser
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
  * Philips OGT (SVCD subtitle) packet parser
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
- * $Id: ogt_parse.c,v 1.1 2003/12/28 04:51:52 rocky Exp $
+ * $Id: ogt_parse.c,v 1.2 2003/12/28 11:26:52 rocky Exp $
  *
  * Author: Rocky Bernstein 
  *   based on code from: 
  *
  * Author: Rocky Bernstein 
  *   based on code from: 
@@ -85,6 +85,8 @@ void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
   u_int8_t *p = p_buffer;
   int i;
   
   u_int8_t *p = p_buffer;
   int i;
   
+  dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
+
   p_sys->i_pts    = p_block->i_pts;
   p_sys->i_spu_size = GETINT16(p);
   p_sys->i_options  = *p++;
   p_sys->i_pts    = p_block->i_pts;
   p_sys->i_spu_size = GETINT16(p);
   p_sys->i_options  = *p++;
index ede45c5..a7bc788 100644 (file)
@@ -2,7 +2,7 @@
  * subtitle.h : Common SVCD and CVD subtitles header
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
  * subtitle.h : Common SVCD and CVD subtitles header
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
- * $Id: subtitle.h,v 1.1 2003/12/28 02:01:11 rocky Exp $
+ * $Id: subtitle.h,v 1.2 2003/12/28 11:26:52 rocky Exp $
  *
  * Author: Rocky Bernstein
  *   based on code from:
  *
  * Author: Rocky Bernstein
  *   based on code from:
@@ -44,7 +44,7 @@
 #define LOG_ERR(args...)  msg_Err( p_input, args )
 #define LOG_WARN(args...) msg_Warn( p_input, args )
 
 #define LOG_ERR(args...)  msg_Err( p_input, args )
 #define LOG_WARN(args...) msg_Warn( p_input, args )
 
-#define GETINT16(p) ( (p[0] <<  8) +  p[1] ); p +=2;
+#define GETINT16(p) ( (p[0] <<  8) +   p[1] )  ; p +=2;
 
 #define GETINT32(p) ( (p[0] << 24) +  (p[1] << 16) +    \
                       (p[2] <<  8) +  (p[3]) ) ; p += 4;
 
 #define GETINT32(p) ( (p[0] << 24) +  (p[1] << 16) +    \
                       (p[2] <<  8) +  (p[3]) ) ; p += 4;
@@ -108,6 +108,9 @@ struct decoder_sys_t
   uint16_t comp_image_offset;  /* offset from subtitle_data to compressed
                                   image data */
   int comp_image_length;       /* size of the compressed image data */
   uint16_t comp_image_offset;  /* offset from subtitle_data to compressed
                                   image data */
   int comp_image_length;       /* size of the compressed image data */
+  int first_field_offset;       /* offset of even raster lines. Used
+                                  only for CVD.
+                                */
   int second_field_offset;      /* offset of odd raster lines */
   int metadata_offset;          /* offset to data describing the image */
   int metadata_length;          /* length of metadata */
   int second_field_offset;      /* offset of odd raster lines */
   int metadata_offset;          /* offset to data describing the image */
   int metadata_length;          /* length of metadata */
@@ -121,7 +124,12 @@ struct decoder_sys_t
                                     image when displayed */
   uint16_t i_width, i_height;  /* dimensions in pixels of image */
 
                                     image when displayed */
   uint16_t i_width, i_height;  /* dimensions in pixels of image */
 
-  ogt_yuvt_t pi_palette[NUM_SUBTITLE_COLORS];
+  ogt_yuvt_t pi_palette[NUM_SUBTITLE_COLORS];  /* Palette of colors used
+                                                 in subtitle */
+
+
+  ogt_yuvt_t pi_palette_highlight[NUM_SUBTITLE_COLORS]; /* Only used
+                                                          for CVD */
 
   uint8_t i_options;
   uint8_t i_options2;
 
   uint8_t i_options;
   uint8_t i_options2;