* subsdec.c : text subtitles decoder
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: subsdec.c,v 1.4 2003/11/05 00:17:50 hartman Exp $
+ * $Id$
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Samuel Hocevar <sam@zoy.org>
/*****************************************************************************
* Preamble
*****************************************************************************/
-#include <stdlib.h> /* malloc(), free() */
-#include <string.h> /* memcpy(), memset() */
-
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>
+
#include <osd.h>
-#include <codecs.h>
#if defined(HAVE_ICONV)
#include <iconv.h>
* Local prototypes
*****************************************************************************/
static int OpenDecoder ( vlc_object_t * );
+static void CloseDecoder ( vlc_object_t * );
-static int InitDecoder ( decoder_t * );
-static int RunDecoder ( decoder_t *, block_t * );
-static int EndDecoder ( decoder_t * );
+static void DecodeBlock ( decoder_t *, block_t ** );
static void ParseText ( decoder_t *, block_t *, vout_thread_t * );
+static void StripTags ( char * );
#define DEFAULT_NAME "System Default"
"C99", "JAVA", "UCS-2", "UCS-2BE", "UCS-2LE", "UCS-4", "UCS-4BE", "UCS-4LE", "",
"HZ", "GBK", "GB18030", "JOHAB", "ARMSCII-8",
"Georgian-Academy", "Georgian-PS", "TIS-620", "MuleLao-1", "VISCII", "TCVN",
- "HPROMAN8", "NEXTSTEP", NULL };
+ "HPROMAN8", "NEXTSTEP" };
#endif
+static int pi_justification[] = { 0, 1, 2 };
+static char *ppsz_justification_text[] = {N_("Center"),N_("Left"),N_("Right")};
+
#define ENCODING_TEXT N_("Subtitles text encoding")
-#define ENCODING_LONGTEXT N_("Change the encoding used in text subtitles")
+#define ENCODING_LONGTEXT N_("Set the encoding used in text subtitles")
#define ALIGN_TEXT N_("Subtitles justification")
-#define ALIGN_LONGTEXT N_("Change the justification of substitles (0=center, 1=left, 2=right)")
+#define ALIGN_LONGTEXT N_("Set the justification of subtitles")
vlc_module_begin();
set_description( _("text subtitles decoder") );
set_capability( "decoder", 50 );
- set_callbacks( OpenDecoder, NULL );
+ set_callbacks( OpenDecoder, CloseDecoder );
- add_category_hint( N_("Subtitles"), NULL, VLC_FALSE );
- add_integer( "subsdec-align", 0, NULL, ALIGN_TEXT, ALIGN_LONGTEXT, VLC_TRUE );
+ add_integer( "subsdec-align", 0, NULL, ALIGN_TEXT, ALIGN_LONGTEXT,
+ VLC_TRUE );
+ change_integer_list( pi_justification, ppsz_justification_text, 0 );
#if defined(HAVE_ICONV)
- add_string_from_list( "subsdec-encoding", DEFAULT_NAME, ppsz_encodings, NULL, ENCODING_TEXT, ENCODING_LONGTEXT, VLC_FALSE );
+ add_string( "subsdec-encoding", DEFAULT_NAME, NULL,
+ ENCODING_TEXT, ENCODING_LONGTEXT, VLC_FALSE );
+ change_string_list( ppsz_encodings, 0, 0 );
#endif
vlc_module_end();
*****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
- decoder_t *p_dec = (decoder_t*)p_this;
+ decoder_t *p_dec = (decoder_t*)p_this;
+ decoder_sys_t *p_sys;
+ vlc_value_t val;
- if( p_dec->p_fifo->i_fourcc != VLC_FOURCC('s','u','b','t') &&
- p_dec->p_fifo->i_fourcc != VLC_FOURCC('s','s','a',' ') )
+ if( p_dec->fmt_in.i_codec != VLC_FOURCC('s','u','b','t') &&
+ p_dec->fmt_in.i_codec != VLC_FOURCC('s','s','a',' ') )
{
return VLC_EGENERIC;
}
- p_dec->pf_init = InitDecoder;
- p_dec->pf_decode = RunDecoder;
- p_dec->pf_end = EndDecoder;
+ p_dec->pf_decode_sub = DecodeBlock;
/* Allocate the memory needed to store the decoder's structure */
- if( ( p_dec->p_sys =
+ if( ( p_dec->p_sys = p_sys =
(decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
{
msg_Err( p_dec, "out of memory" );
return VLC_EGENERIC;
}
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * InitDecoder: Initalize the decoder
- *****************************************************************************/
-static int InitDecoder( decoder_t *p_dec )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- subtitle_data_t *p_demux_data = (subtitle_data_t *)p_dec->p_fifo->p_demux_data;
- vlc_value_t val;
-
var_Create( p_dec, "subsdec-align", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Get( p_dec, "subsdec-align", &val );
p_sys->i_align = val.i_int;
#if defined(HAVE_ICONV)
- var_Create( p_dec, "subsdec-encoding",
- VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Get( p_dec, "subsdec-encoding", &val );
- if( !strcmp( val.psz_string, DEFAULT_NAME ) )
+ if( p_dec->fmt_in.subs.psz_encoding && *p_dec->fmt_in.subs.psz_encoding )
{
- char *psz_charset =(char*)malloc( 100 );
- vlc_current_charset( &psz_charset );
- p_sys->iconv_handle = iconv_open( "UTF-8", psz_charset );
- free( psz_charset );
+ msg_Dbg( p_dec, "using character encoding: %s",
+ p_dec->fmt_in.subs.psz_encoding );
+ p_sys->iconv_handle = iconv_open( "UTF-8",
+ p_dec->fmt_in.subs.psz_encoding );
}
else
{
- p_sys->iconv_handle = iconv_open( "UTF-8", val.psz_string );
- }
+ var_Create( p_dec, "subsdec-encoding",
+ VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+ var_Get( p_dec, "subsdec-encoding", &val );
+ if( !strcmp( val.psz_string, DEFAULT_NAME ) )
+ {
+ char *psz_charset =(char*)malloc( 100 );
+ vlc_current_charset( &psz_charset );
+ p_sys->iconv_handle = iconv_open( "UTF-8", psz_charset );
+ msg_Dbg( p_dec, "using character encoding: %s", psz_charset );
+ free( psz_charset );
+ }
+ else if( val.psz_string )
+ {
+ msg_Dbg( p_dec, "using character encoding: %s", val.psz_string );
+ p_sys->iconv_handle = iconv_open( "UTF-8", val.psz_string );
+ }
- if( p_sys->iconv_handle == (iconv_t)-1 )
- {
- msg_Warn( p_dec, "Unable to do requested conversion" );
- }
+ if( p_sys->iconv_handle == (iconv_t)-1 )
+ {
+ msg_Warn( p_dec, "unable to do requested conversion" );
+ }
- if( val.psz_string ) free( val.psz_string );
+ if( val.psz_string ) free( val.psz_string );
+ }
#else
- msg_Dbg( p_dec, "No iconv support available" );
-#endif
-#if 1
- if( p_demux_data )
- msg_Dbg( p_dec, p_demux_data->psz_header );
+ msg_Dbg( p_dec, "no iconv support available" );
#endif
return VLC_SUCCESS;
}
/****************************************************************************
- * RunDecoder: the whole thing
+ * DecodeBlock: the whole thing
****************************************************************************
* This function must be fed with complete subtitles units.
****************************************************************************/
-static int RunDecoder( decoder_t *p_dec, block_t *p_block )
+static void DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
vout_thread_t *p_vout;
+ if( !pp_block || *pp_block == NULL )
+ {
+ return;
+ }
+
/* Here we are dealing with text subtitles */
p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
- if( !p_vout )
+ if( p_vout )
+ {
+ ParseText( p_dec, *pp_block, p_vout );
+ vlc_object_release( p_vout );
+ }
+ else
{
msg_Warn( p_dec, "couldn't find a video output, trashing subtitle" );
- return VLC_SUCCESS;
}
- ParseText( p_dec, p_block, p_vout );
- vlc_object_release( p_vout );
-
- return VLC_SUCCESS;
+ block_Release( *pp_block );
+ *pp_block = NULL;
}
/*****************************************************************************
- * EndDecoder: clean up the decoder
+ * CloseDecoder: clean up the decoder
*****************************************************************************/
-static int EndDecoder( decoder_t *p_dec )
+static void CloseDecoder( vlc_object_t *p_this )
{
+ decoder_t *p_dec = (decoder_t *)p_this;
decoder_sys_t *p_sys = p_dec->p_sys;
vout_thread_t *p_vout;
#endif
free( p_sys );
-
- return VLC_SUCCESS;
}
/*****************************************************************************
msg_Warn( p_dec, "subtitle without a date" );
return;
}
-
+
/* Check validity of packet data */
if( p_block->i_buffer <= 1 || p_block->p_buffer[0] == '\0' )
{
{
char *psz_new_subtitle;
char *psz_convert_buffer_out;
- const char *psz_convert_buffer_in;
+ char *psz_convert_buffer_in;
size_t ret, inbytes_left, outbytes_left;
psz_new_subtitle = malloc( 6 * strlen( psz_subtitle ) );
if( inbytes_left )
{
- msg_Warn( p_dec, "Something fishy happened during conversion" );
+ msg_Warn( p_dec, "Failed to convert subtitle encoding, dropping subtitle.\nTry setting a different character-encoding for the subtitle." );
+ free( psz_subtitle );
+ return;
}
else
{
}
#endif
- if( p_dec->p_fifo->i_fourcc == VLC_FOURCC('s','s','a',' ') )
+ if( p_dec->fmt_in.i_codec == VLC_FOURCC('s','s','a',' ') )
{
/* Decode SSA strings */
/* We expect: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
break;
}
}
-
- vout_ShowTextAbsolute( p_vout, psz_subtitle, NULL,
- OSD_ALIGN_BOTTOM | p_sys->i_align,
- i_align_h, i_align_v,
- p_block->i_pts, p_block->i_dts );
+ StripTags( psz_subtitle );
+ vout_ShowTextAbsolute( p_vout, SUBT1_CHAN, psz_subtitle, NULL,
+ OSD_ALIGN_BOTTOM | p_sys->i_align, i_align_h,
+ i_align_v, p_block->i_pts,
+ p_block->i_length ? p_block->i_pts + p_block->i_length : 0 );
free( psz_subtitle );
}
+
+static void StripTags( char *psz_text )
+{
+ int i_left_moves = 0;
+ vlc_bool_t b_inside_tag = VLC_FALSE;
+ int i = 0;
+ int i_tag_start = -1;
+ while( psz_text[ i ] )
+ {
+ if( !b_inside_tag )
+ {
+ if( psz_text[ i ] == '<' )
+ {
+ b_inside_tag = VLC_TRUE;
+ i_tag_start = i;
+ }
+ psz_text[ i - i_left_moves ] = psz_text[ i ];
+ }
+ else
+ {
+ if( ( psz_text[ i ] == ' ' ) ||
+ ( psz_text[ i ] == '\t' ) ||
+ ( psz_text[ i ] == '\n' ) ||
+ ( psz_text[ i ] == '\r' ) )
+ {
+ b_inside_tag = VLC_FALSE;
+ i_tag_start = -1;
+ }
+ else if( psz_text[ i ] == '>' )
+ {
+ i_left_moves += i - i_tag_start + 1;
+ i_tag_start = -1;
+ b_inside_tag = VLC_FALSE;
+ }
+ else
+ {
+ psz_text[ i - i_left_moves ] = psz_text[ i ];
+ }
+ }
+ i++;
+ }
+ psz_text[ i - i_left_moves ] = '\0';
+}
+