9 changed files with 854 additions and 288 deletions
@ -0,0 +1,285 @@ |
|||
/*****************************************************************************
|
|||
* Common SVCD and VCD subtitle routines. |
|||
***************************************************************************** |
|||
* Copyright (C) 2003 VideoLAN |
|||
* $Id: common.c,v 1.1 2003/12/28 04:51:52 rocky Exp $ |
|||
* |
|||
* Author: Rocky Bernstein |
|||
* based on code from: |
|||
* Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
|
|||
* Samuel Hocevar <sam@zoy.org> |
|||
* Laurent Aimar <fenrir@via.ecp.fr> |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program 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 General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. |
|||
*****************************************************************************/ |
|||
|
|||
/*****************************************************************************
|
|||
* Preamble |
|||
*****************************************************************************/ |
|||
#include <vlc/vlc.h> |
|||
#include <vlc/vout.h> |
|||
#include <vlc/decoder.h> |
|||
|
|||
#include "subtitle.h" |
|||
#include "common.h" |
|||
|
|||
/*****************************************************************************
|
|||
Free Resources associated with subtitle packet. |
|||
*****************************************************************************/ |
|||
void VCDSubClose( vlc_object_t *p_this ) |
|||
{ |
|||
decoder_t *p_dec = (decoder_t*)p_this; |
|||
decoder_sys_t *p_sys = p_dec->p_sys; |
|||
|
|||
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , ""); |
|||
|
|||
if( !p_sys->b_packetizer ) |
|||
{ |
|||
/* FIXME check if it's ok to not lock vout */ |
|||
if( p_sys->p_vout != NULL && p_sys->p_vout->p_subpicture != NULL ) |
|||
{ |
|||
subpicture_t * p_subpic; |
|||
int i_subpic; |
|||
|
|||
for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) |
|||
{ |
|||
p_subpic = &p_sys->p_vout->p_subpicture[i_subpic]; |
|||
|
|||
if( p_subpic != NULL && |
|||
( ( p_subpic->i_status == RESERVED_SUBPICTURE ) || |
|||
( p_subpic->i_status == READY_SUBPICTURE ) ) ) |
|||
{ |
|||
vout_DestroySubPicture( p_sys->p_vout, p_subpic ); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if( p_sys->p_block ) |
|||
{ |
|||
block_ChainRelease( p_sys->p_block ); |
|||
} |
|||
|
|||
free( p_sys ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
|
|||
Initialize so the next packet will start off a new one. |
|||
|
|||
*****************************************************************************/ |
|||
void |
|||
VCDSubInitSubtitleBlock( decoder_sys_t * p_sys ) |
|||
{ |
|||
p_sys->i_spu_size = 0; |
|||
p_sys->state = SUBTITLE_BLOCK_EMPTY; |
|||
p_sys->i_spu = 0; |
|||
p_sys->p_block = NULL; |
|||
p_sys->subtitle_data_pos = 0; |
|||
|
|||
} |
|||
|
|||
void |
|||
VCDSubInitSubtitleData(decoder_sys_t *p_sys) |
|||
{ |
|||
if ( p_sys->subtitle_data ) { |
|||
if ( p_sys->subtitle_data_size < p_sys->i_spu_size ) { |
|||
p_sys->subtitle_data = realloc(p_sys->subtitle_data, |
|||
p_sys->i_spu_size); |
|||
p_sys->subtitle_data_size = p_sys->i_spu_size; |
|||
} |
|||
} else { |
|||
p_sys->subtitle_data = malloc(p_sys->i_spu_size); |
|||
p_sys->subtitle_data_size = p_sys->i_spu_size; |
|||
/* FIXME: wrong place to get p_sys */ |
|||
p_sys->i_image = 0; |
|||
} |
|||
p_sys->subtitle_data_pos = 0; |
|||
} |
|||
|
|||
void |
|||
VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len ) |
|||
{ |
|||
decoder_sys_t *p_sys = p_dec->p_sys; |
|||
int chunk_length = buf_len; |
|||
|
|||
if ( chunk_length > p_sys->i_spu_size - p_sys->subtitle_data_pos ) { |
|||
msg_Warn( p_dec, "too much data (%d) expecting at most %u", |
|||
chunk_length, p_sys->i_spu_size - p_sys->subtitle_data_pos ); |
|||
|
|||
chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos; |
|||
} |
|||
|
|||
if ( chunk_length > 0 ) { |
|||
memcpy(p_sys->subtitle_data + p_sys->subtitle_data_pos, |
|||
buffer, chunk_length); |
|||
p_sys->subtitle_data_pos += chunk_length; |
|||
dbg_print(DECODE_DBG_PACKET, "%d bytes appended, pointer now %d", |
|||
chunk_length, p_sys->subtitle_data_pos); |
|||
} |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* FindVout: Find a vout or wait for one to be created. |
|||
*****************************************************************************/ |
|||
vout_thread_t *VCDSubFindVout( decoder_t *p_dec ) |
|||
{ |
|||
vout_thread_t *p_vout = NULL; |
|||
|
|||
/* Find an available video output */ |
|||
do |
|||
{ |
|||
if( p_dec->b_die || p_dec->b_error ) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); |
|||
if( p_vout ) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
msleep( VOUT_OUTMEM_SLEEP ); |
|||
} |
|||
while( 1 ); |
|||
|
|||
return p_vout; |
|||
} |
|||
|
|||
|
|||
/* Scales down (reduces size) of p_dest in the x direction as
|
|||
determined through aspect ratio x_scale by y_scale. Scaling |
|||
is done in place. p_spu->i_width, is updated to new width |
|||
|
|||
The aspect ratio is assumed to be between 1/2 and 1. |
|||
*/ |
|||
void |
|||
VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu, |
|||
unsigned int i_scale_x, unsigned int i_scale_y ) |
|||
{ |
|||
int i_row, i_col; |
|||
|
|||
decoder_sys_t *p_sys = p_dec->p_sys; |
|||
uint8_t *p_src1 = p_spu->p_sys->p_data; |
|||
uint8_t *p_src2 = p_src1 + PIXEL_SIZE; |
|||
uint8_t *p_dst = p_src1; |
|||
unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ; |
|||
unsigned int used=0; /* Number of bytes used up in p_src1. */ |
|||
|
|||
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) , |
|||
"Old width: %d, new width: %d", |
|||
p_spu->i_width, i_new_width); |
|||
|
|||
for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) { |
|||
|
|||
if (used != 0) { |
|||
/* Discard the remaining piece of the column of the previous line*/ |
|||
used=0; |
|||
p_src1 = p_src2; |
|||
p_src2 += PIXEL_SIZE; |
|||
} |
|||
|
|||
for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) { |
|||
unsigned int i; |
|||
unsigned int w1= i_scale_x - used; |
|||
unsigned int w2= i_scale_y - w1; |
|||
|
|||
used = w2; |
|||
for (i = 0; i < PIXEL_SIZE; i++ ) { |
|||
*p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y; |
|||
p_src1++; p_src2++; p_dst++; |
|||
} |
|||
|
|||
if (i_scale_x == used) { |
|||
/* End of last pixel was end of p_src2. */ |
|||
p_src1 = p_src2; |
|||
p_src2 += PIXEL_SIZE; |
|||
i_col++; |
|||
used = 0; |
|||
} |
|||
} |
|||
} |
|||
p_spu->i_width = i_new_width; |
|||
|
|||
if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM ) |
|||
{ |
|||
ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data; |
|||
for ( i_row=0; i_row < p_spu->i_height - 1; i_row++ ) { |
|||
for ( i_col=0; i_col < p_spu->i_width - 1; i_col++ ) { |
|||
printf("%1x", p_source->s.t); |
|||
p_source++; |
|||
} |
|||
printf("\n"); |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* DestroySPU: subpicture destructor |
|||
*****************************************************************************/ |
|||
void VCDSubDestroySPU( subpicture_t *p_spu ) |
|||
{ |
|||
if( p_spu->p_sys->p_input ) |
|||
{ |
|||
/* Detach from our input thread */ |
|||
vlc_object_release( p_spu->p_sys->p_input ); |
|||
} |
|||
|
|||
vlc_mutex_destroy( &p_spu->p_sys->lock ); |
|||
free( p_spu->p_sys ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
This callback is called from the input thread when we need cropping |
|||
*****************************************************************************/ |
|||
int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var, |
|||
vlc_value_t oldval, vlc_value_t newval, void *p_data ) |
|||
{ |
|||
VCDSubUpdateSPU( (subpicture_t *)p_data, p_object ); |
|||
|
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
update subpicture settings |
|||
***************************************************************************** |
|||
This function is called from CropCallback and at initialization time, to |
|||
retrieve crop information from the input. |
|||
*****************************************************************************/ |
|||
void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object ) |
|||
{ |
|||
vlc_value_t val; |
|||
|
|||
p_spu->p_sys->b_crop = val.b_bool; |
|||
if( !p_spu->p_sys->b_crop ) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var_Get( p_object, "x-start", &val ); |
|||
p_spu->p_sys->i_x_start = val.i_int; |
|||
var_Get( p_object, "y-start", &val ); |
|||
p_spu->p_sys->i_y_start = val.i_int; |
|||
var_Get( p_object, "x-end", &val ); |
|||
p_spu->p_sys->i_x_end = val.i_int; |
|||
var_Get( p_object, "y-end", &val ); |
|||
p_spu->p_sys->i_y_end = val.i_int; |
|||
|
|||
} |
|||
|
|||
@ -0,0 +1,39 @@ |
|||
/*****************************************************************************
|
|||
* Header for Common SVCD and VCD subtitle routines. |
|||
***************************************************************************** |
|||
* Copyright (C) 2003 VideoLAN |
|||
* $Id: common.h,v 1.1 2003/12/28 04:51:52 rocky Exp $ |
|||
* |
|||
* Author: Rocky Bernstein |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program 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 General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. |
|||
*****************************************************************************/ |
|||
|
|||
void VCDSubClose ( vlc_object_t * ); |
|||
void VCDSubInitSubtitleBlock( decoder_sys_t * p_sys ); |
|||
void VCDSubInitSubtitleData(decoder_sys_t *p_sys); |
|||
void VCDSubAppendData( decoder_t *p_dec, uint8_t *buffer, |
|||
uint32_t buf_len ); |
|||
vout_thread_t *VCDSubFindVout( decoder_t *p_dec ); |
|||
|
|||
void VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu, |
|||
unsigned int i_scale_x, unsigned int i_scale_y ); |
|||
void VCDSubDestroySPU( subpicture_t *p_spu ); |
|||
int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var, |
|||
vlc_value_t oldval, vlc_value_t newval, |
|||
void *p_data ); |
|||
void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object ); |
|||
|
|||
|
|||
@ -0,0 +1,307 @@ |
|||
/*****************************************************************************
|
|||
* cvd.c : CVD Subtitle decoder thread |
|||
***************************************************************************** |
|||
* Copyright (C) 2003 VideoLAN |
|||
* $Id: cvd.c,v 1.1 2003/12/28 04:51:52 rocky Exp $ |
|||
* |
|||
* Authors: Rocky Bernstein |
|||
* based on code from: |
|||
* Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
|
|||
* Samuel Hocevar <sam@zoy.org> |
|||
* Laurent Aimar <fenrir@via.ecp.fr> |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program 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 General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. |
|||
*****************************************************************************/ |
|||
|
|||
/*****************************************************************************
|
|||
* Preamble |
|||
*****************************************************************************/ |
|||
#include <vlc/vlc.h> |
|||
#include <vlc/vout.h> |
|||
#include <vlc/decoder.h> |
|||
|
|||
#include "subtitle.h" |
|||
#include "cvd.h" |
|||
#include "common.h" |
|||
|
|||
#define DEBUG_LONGTEXT N_( \ |
|||
"This integer when viewed in binary is a debugging mask\n" \ |
|||
"external call 1\n" \ |
|||
"all calls 2\n" \ |
|||
"packet assembly info 4\n" \ |
|||
"image bitmaps 8\n" \ |
|||
"image transformations 16\n" \ |
|||
"misc info 32\n" ) |
|||
|
|||
/*****************************************************************************
|
|||
* Module descriptor. |
|||
*****************************************************************************/ |
|||
static int DecoderOpen ( vlc_object_t * ); |
|||
static int PacketizerOpen( vlc_object_t * ); |
|||
|
|||
vlc_module_begin(); |
|||
set_description( _("CVD subtitle decoder") ); |
|||
set_capability( "decoder", 50 ); |
|||
set_callbacks( DecoderOpen, VCDSubClose ); |
|||
|
|||
add_integer ( MODULE_STRING "-debug", 0, NULL, |
|||
N_("set debug mask for additional debugging."), |
|||
N_(DEBUG_LONGTEXT), VLC_TRUE ); |
|||
|
|||
add_submodule(); |
|||
set_description( _("Chaoji VCD subtitle packetizer") ); |
|||
set_capability( "packetizer", 50 ); |
|||
set_callbacks( PacketizerOpen, VCDSubClose ); |
|||
vlc_module_end(); |
|||
|
|||
/*****************************************************************************
|
|||
* Local prototypes |
|||
*****************************************************************************/ |
|||
|
|||
static block_t *Reassemble( decoder_t *, block_t ** ); |
|||
static void Decode ( decoder_t *, block_t ** ); |
|||
static block_t *Packetize( decoder_t *, block_t ** ); |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* DecoderOpen |
|||
***************************************************************************** |
|||
* Tries to launch a decoder and return score so that the interface is able |
|||
* to chose. |
|||
*****************************************************************************/ |
|||
static int |
|||
DecoderOpen( vlc_object_t *p_this ) |
|||
{ |
|||
decoder_t *p_dec = (decoder_t*)p_this; |
|||
decoder_sys_t *p_sys; |
|||
|
|||
if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'c','v','d',' ' ) ) |
|||
{ |
|||
return VLC_EGENERIC; |
|||
} |
|||
|
|||
|
|||
p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); |
|||
|
|||
p_sys->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" ); |
|||
p_sys->b_packetizer = VLC_FALSE; |
|||
p_sys->p_vout = NULL; |
|||
p_sys->i_image = -1; |
|||
p_sys->subtitle_data = NULL; |
|||
|
|||
VCDSubInitSubtitleBlock( p_sys ); |
|||
|
|||
es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'c','v','d',' ' ) ); |
|||
|
|||
|
|||
p_dec->pf_decode_sub = Decode; |
|||
p_dec->pf_packetize = Packetize; |
|||
|
|||
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , ""); |
|||
|
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* PacketizerOpen |
|||
***************************************************************************** |
|||
* Tries to launch a decoder and return score so that the interface is able |
|||
* to chose. |
|||
*****************************************************************************/ |
|||
static int PacketizerOpen( vlc_object_t *p_this ) |
|||
{ |
|||
decoder_t *p_dec = (decoder_t*)p_this; |
|||
|
|||
if( DecoderOpen( p_this ) ) |
|||
{ |
|||
return VLC_EGENERIC; |
|||
} |
|||
p_dec->p_sys->b_packetizer = VLC_TRUE; |
|||
|
|||
return VLC_SUCCESS; |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Decode: |
|||
*****************************************************************************/ |
|||
static void |
|||
Decode ( decoder_t *p_dec, block_t **pp_block ) |
|||
{ |
|||
decoder_sys_t *p_sys = p_dec->p_sys; |
|||
block_t *p_spu = Reassemble( p_dec, pp_block ); |
|||
|
|||
dbg_print( (DECODE_DBG_CALL) , ""); |
|||
|
|||
if( p_spu ) |
|||
{ |
|||
p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 ); |
|||
p_sys->i_pts = p_spu->i_pts; |
|||
block_ChainRelease( p_spu ); |
|||
|
|||
if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) ) |
|||
{ |
|||
/* Parse and decode */ |
|||
E_(ParsePacket)( p_dec ); |
|||
|
|||
vlc_object_release( p_sys->p_vout ); |
|||
} |
|||
|
|||
VCDSubInitSubtitleBlock ( p_sys ); |
|||
} |
|||
|
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Packetize: |
|||
*****************************************************************************/ |
|||
static block_t * |
|||
Packetize( decoder_t *p_dec, block_t **pp_block ) |
|||
{ |
|||
decoder_sys_t *p_sys = p_dec->p_sys; |
|||
block_t *p_spu = Reassemble( p_dec, pp_block ); |
|||
|
|||
if( p_spu ) |
|||
{ |
|||
p_spu->i_dts = p_spu->i_pts; |
|||
p_spu->i_length = 0; |
|||
|
|||
VCDSubInitSubtitleBlock( p_sys ); |
|||
|
|||
return block_ChainGather( p_spu ); |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
/* following functions are local */ |
|||
|
|||
#define SPU_HEADER_LEN 5 |
|||
|
|||
/*****************************************************************************
|
|||
Reassemble: |
|||
|
|||
The data for single screen subtitle may come in one of many |
|||
non-contiguous packets of a stream. This routine is called when the |
|||
next packet in the stream comes in. The job of this routine is to |
|||
parse the header, if this is the beginning, and combine the packets |
|||
into one complete subtitle unit. |
|||
|
|||
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 ) |
|||
{ |
|||
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 ) |
|||
{ |
|||
return NULL; |
|||
} |
|||
p_block = *pp_block; |
|||
*pp_block = NULL; |
|||
|
|||
if( p_block->i_buffer < SPU_HEADER_LEN ) |
|||
{ |
|||
msg_Dbg( p_dec, "invalid packet header (size %d < %d)" , |
|||
p_block->i_buffer, SPU_HEADER_LEN ); |
|||
block_Release( p_block ); |
|||
return NULL; |
|||
} |
|||
|
|||
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", |
|||
p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4], |
|||
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 ); |
|||
} |
|||
|
|||
if ( i_packet != i_expected_packet ) { |
|||
msg_Warn( p_dec, "expecting subtitle image packet %u but found %u", |
|||
i_expected_packet, i_packet); |
|||
} |
|||
|
|||
p_sys->i_packet = i_packet; |
|||
|
|||
if ( p_sys->i_packet == 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 ); |
|||
|
|||
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 ); |
|||
} |
|||
|
|||
dbg_print( (DECODE_DBG_PACKET), |
|||
"subtitle packet complete, size=%d", p_sys->i_spu ); |
|||
|
|||
return p_sys->p_block; |
|||
} |
|||
return NULL; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/*****************************************************************************
|
|||
* cvd.h : CVD subtitles decoder thread interface |
|||
***************************************************************************** |
|||
* Copyright (C) 2003 VideoLAN |
|||
* $Id: cvd.h,v 1.1 2003/12/28 04:51:52 rocky Exp $ |
|||
* |
|||
* Author: Rocky Bernstein |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program 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 General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. |
|||
*****************************************************************************/ |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* Prototypes |
|||
*****************************************************************************/ |
|||
void E_(ParseHeader)( decoder_t *, uint8_t *, block_t * ); |
|||
void E_(ParsePacket)( decoder_t * ); |
|||
|
|||
@ -0,0 +1,172 @@ |
|||
/*****************************************************************************
|
|||
* 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 $ |
|||
* |
|||
* Authors: Rocky Bernstein |
|||
* based on code from: |
|||
* Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
|
|||
* Sam Hocevar <sam@zoy.org> |
|||
* Laurent Aimar <fenrir@via.ecp.fr> |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program 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 General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. |
|||
*****************************************************************************/ |
|||
|
|||
/*****************************************************************************
|
|||
* Preamble |
|||
*****************************************************************************/ |
|||
#include <vlc/vlc.h> |
|||
#include <vlc/vout.h> |
|||
#include <vlc/decoder.h> |
|||
|
|||
#include "subtitle.h" |
|||
#include "render.h" |
|||
#include "cvd.h" |
|||
|
|||
/* An image color is a two-bit palette entry: 0..3 */ |
|||
typedef uint8_t ogt_color_t; |
|||
|
|||
/*****************************************************************************
|
|||
* Local prototypes. |
|||
*****************************************************************************/ |
|||
static int ParseImage ( decoder_t *, subpicture_t * ); |
|||
|
|||
/*
|
|||
* We do not have information on the subtitle format used on CVD's |
|||
* except the submux sample code and a couple of samples of dubious |
|||
* origin. Thus, this is the result of reading some code whose |
|||
* correctness is not known and some experimentation. |
|||
* |
|||
* CVD subtitles present several differences compared to SVCD OGT |
|||
* subtitles. Firstly, the image comes first and the metadata is at |
|||
* the end. So that the metadata can be found easily, the subtitle |
|||
* begins with two two-byte (everything is big-endian again) that |
|||
* describe, the total size of the subtitle data and the offset to the |
|||
* metadata (size of the image data plus the four bytes at the |
|||
* beginning. |
|||
* |
|||
* Image data comes interlaced and uses RLE. Coding is based in |
|||
* four-bit nibbles that are further subdivided in a two-bit repeat |
|||
* count and a two-bit color number so that up to three pixels can be |
|||
* describe with a total of four bits. The function of a 0 repeat |
|||
* count is unknown. It might be used for RLE extension. There is a |
|||
* special case, though. When the full nibble is zero, the rest of |
|||
* the line is filled with the color value in the next nibble. It is |
|||
* unknown what happens if the color value is greater than three. The |
|||
* rest seems to use a 4-entries palette. It is not impossible that |
|||
* the fill-line complete case above is not as described and the zero |
|||
* repeat count means fill line. The sample code never produces this, |
|||
* so it may be untested. |
|||
* |
|||
* The metadata section does not follow a fixed pattern, every |
|||
* metadata item consists of a tag byte followed by parameters. In all |
|||
* cases known, the block (including the tag byte) is exactly four |
|||
* bytes in length. Read the code for the rest. |
|||
*/ |
|||
|
|||
/* FIXME: do we really need p_buffer and p?
|
|||
Can't all of thes _offset's and _lengths's get removed? |
|||
*/ |
|||
void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block ) |
|||
{ |
|||
decoder_sys_t *p_sys = p_dec->p_sys; |
|||
|
|||
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , ""); |
|||
|
|||
/* To be finished...*/ |
|||
return; |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* ParsePacket: parse an SPU packet and send it to the video output |
|||
***************************************************************************** |
|||
* This function parses the SPU packet and, if valid, sends it to the |
|||
* video output. |
|||
*****************************************************************************/ |
|||
void |
|||
E_(ParsePacket)( decoder_t *p_dec) |
|||
{ |
|||
decoder_sys_t *p_sys = p_dec->p_sys; |
|||
|
|||
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , ""); |
|||
|
|||
/* To be completed... */ |
|||
return; |
|||
|
|||
} |
|||
|
|||
/* Advance pointer to image pointer, update internal i_remaining counter
|
|||
and check that we haven't goine too far in the image data. */ |
|||
#define advance_color_pointer_byte \ |
|||
p++; \ |
|||
i_remaining=4; \ |
|||
if (p >= maxp) { \ |
|||
msg_Warn( p_dec, \ |
|||
"broken subtitle - tried to access beyond end " \ |
|||
"in image extraction"); \ |
|||
return VLC_EGENERIC; \ |
|||
} \ |
|||
|
|||
#define advance_color_pointer \ |
|||
i_remaining--; \ |
|||
if ( i_remaining == 0 ) { \ |
|||
advance_color_pointer_byte; \ |
|||
} |
|||
|
|||
/* Get the next field - either a palette index or a RLE count for
|
|||
color 0. To do this we use byte image pointer p, and i_remaining |
|||
which indicates where we are in the byte. |
|||
*/ |
|||
static inline ogt_color_t |
|||
ExtractField(uint8_t *p, unsigned int i_remaining) |
|||
{ |
|||
return ( ( *p >> 2*(i_remaining-1) ) & 0x3 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* ParseImage: parse the image part of the subtitle |
|||
***************************************************************************** |
|||
This part parses the subtitle graphical data and stores it in a more |
|||
convenient structure for later rendering. |
|||
|
|||
The image is encoded using two bits per pixel that select a palette |
|||
entry except that value 0 starts a limited run-length encoding for |
|||
color 0. When 0 is seen, the next two bits encode one less than the |
|||
number of pixels, so we can encode run lengths from 1 to 4. These get |
|||
filled with the color in palette entry 0. |
|||
|
|||
The encoding of each line is padded to a whole number of bytes. The |
|||
first field is padded to an even byte length and the complete subtitle |
|||
is padded to a 4-byte multiple that always include one zero byte at |
|||
the end. |
|||
|
|||
However we'll transform this so that that the RLE is expanded and |
|||
interlacing will also be removed. On output each pixel entry will by |
|||
an 8-bit alpha, y, u, and v entry. |
|||
|
|||
*****************************************************************************/ |
|||
static int |
|||
ParseImage( decoder_t *p_dec, subpicture_t * p_spu ) |
|||
{ |
|||
decoder_sys_t *p_sys = p_dec->p_sys; |
|||
|
|||
dbg_print( (DECODE_DBG_CALL) , ""); |
|||
/* To be finished...*/ |
|||
return VLC_EGENERIC; |
|||
|
|||
} |
|||
|
|||
Loading…
Reference in new issue