Commit bea939bb authored by Rocky Bernstein's avatar Rocky Bernstein

First cut at CVD subtitle unit assembly and initial parsing.

parent f5d08737
......@@ -2,7 +2,7 @@
* 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:
......@@ -186,7 +186,7 @@ Packetize( decoder_t *p_dec, block_t **pp_block )
/* following functions are local */
#define SPU_HEADER_LEN 5
#define SPU_HEADER_LEN 1
/*****************************************************************************
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.
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 )
......@@ -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;
uint16_t i_expected_image;
uint8_t i_packet, i_expected_packet;
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),
"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[5], p_buffer[6],
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 */
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;
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 );
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;
} else {
/* Not last block in subtitle, so wait for another. */
p_sys->state = SUBTITLE_BLOCK_PARTIAL;
}
return NULL;
}
......@@ -2,7 +2,7 @@
* 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:
......@@ -35,6 +35,7 @@
#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;
......@@ -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;
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) , "");
/* 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;
subpicture_t *p_spu;
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 );
}
......
......@@ -2,7 +2,7 @@
* 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:
......@@ -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;
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++;
......
......@@ -2,7 +2,7 @@
* 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:
......@@ -44,7 +44,7 @@
#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;
......@@ -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 */
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 */
......@@ -121,7 +124,12 @@ struct decoder_sys_t
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment