Only one format of text subtitles is supported right now but we should be able
to expand this by modifying modules/codec/spudec/text.c.
Most of this work comes from by Andrew Flintham ( thanks a bunch Andrew :).
* share/font-eutopiabold36.rle: new font for the text subtitler, courtesy of
Andrew Flintham.
* AUTHORS: added Andrew Flintham to the authors file.
* modules/demux/ogg.c: modified the ogg demuxer to handle subtitles.
* modules/codec/ffmpeg/*: modified the ffmpeg decoder to always keep the last decoded
frame linked.
D: Win32 interface
S: France
+N: Andrew Flintham
+E: amf@cus.org.uk
+D: text subtitler and font scripts
+S: United Kingdom
* video.c: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: video.c,v 1.2 2002/11/05 10:07:56 gbazin Exp $
+ * $Id: video.c,v 1.3 2002/11/06 21:48:24 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
+ p_vdec->p_lastpic = NULL;
+ p_vdec->p_secondlastpic = NULL;
p_vdec->b_direct_rendering = 0;
#if LIBAVCODEC_BUILD > 4615
if( (p_vdec->p_codec->capabilities & CODEC_CAP_DR1)
*****************************************************************************/
void E_( EndThread_Video )( vdec_thread_t *p_vdec )
{
+ if( p_vdec->p_secondlastpic )
+ vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_secondlastpic );
+ if( p_vdec->p_lastpic )
+ vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_lastpic );
+
if( p_vdec->p_pp )
{
/* release postprocessing module */
msleep( VOUT_OUTMEM_SLEEP );
}
- /* FIXME: we may have to use link/unlinkPicture to fully support streams
- * with B FRAMES */
+ /* FIXME: We keep the last picture linked until the current one is decoded,
+ * this trick won't work with streams with B frames though. */
+ vout_LinkPicture( p_vdec->p_vout, p_pic );
+ if( p_vdec->p_secondlastpic )
+ vout_UnlinkPicture( p_vdec->p_vout, p_vdec->p_secondlastpic );
+ p_vdec->p_secondlastpic = p_vdec->p_lastpic;
+ p_vdec->p_lastpic = p_pic;
avctx->draw_horiz_band= NULL;
avctx->dr_buffer[0]= p_pic->p[0].p_pixels;
* video.h: video decoder using ffmpeg library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: video.h,v 1.2 2002/11/05 10:07:56 gbazin Exp $
+ * $Id: video.h,v 1.3 2002/11/06 21:48:24 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
/* for direct rendering */
int b_direct_rendering;
-
+ picture_t *p_lastpic;
+ picture_t *p_secondlastpic;
} vdec_thread_t;
SOURCES_spudec = \
modules/codec/spudec/spudec.c \
modules/codec/spudec/parse.c \
- modules/codec/spudec/render.c
+ modules/codec/spudec/render.c \
+ modules/codec/spudec/text.c \
+ modules/codec/spudec/subtitler.c
noinst_HEADERS += \
modules/codec/spudec/spudec.h
* parse.c: SPU parser
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: parse.c,v 1.4 2002/11/06 18:07:57 sam Exp $
+ * $Id: parse.c,v 1.5 2002/11/06 21:48:24 gbazin Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
#include <vlc/vout.h>
#include <vlc/decoder.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h> /* getpid() */
-#endif
-
-#ifdef WIN32 /* getpid() for win32 is located in process.h */
-# include <process.h>
-#endif
-
#include "spudec.h"
/*****************************************************************************
* render.c : SPU renderer
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: render.c,v 1.3 2002/11/06 18:07:57 sam Exp $
+ * $Id: render.c,v 1.4 2002/11/06 21:48:24 gbazin Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Rudolf Cornelissen <rag.cornelissen@inter.nl.net>
#include <vlc/vout.h>
#include <vlc/decoder.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h> /* getpid() */
-#endif
-
-#ifdef WIN32 /* getpid() for win32 is located in process.h */
-# include <process.h>
-#endif
-
#include "spudec.h"
/*****************************************************************************
* spudec.c : SPU decoder thread
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: spudec.c,v 1.7 2002/11/06 18:07:57 sam Exp $
+ * $Id: spudec.c,v 1.8 2002/11/06 21:48:24 gbazin Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
#include <vlc/vout.h>
#include <vlc/decoder.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h> /* getpid() */
-#endif
-
-#ifdef WIN32 /* getpid() for win32 is located in process.h */
-# include <process.h>
-#endif
-
#include "spudec.h"
/*****************************************************************************
/*****************************************************************************
* Module descriptor.
*****************************************************************************/
+#define FONT_TEXT N_("Font used by the text subtitler")
+#define FONT_LONGTEXT N_(\
+ "When the subtitles are coded in text form then, you can choose " \
+ "which font will be used to display them.")
+
vlc_module_begin();
- set_description( _("DVD subtitles decoder module") );
+ add_category_hint( N_("subtitles"), NULL );
+ add_file( "spudec-font", "./share/font-eutopiabold36.rle", NULL,
+ FONT_TEXT, FONT_LONGTEXT );
+ set_description( _("subtitles decoder module") );
set_capability( "decoder", 50 );
set_callbacks( OpenDecoder, NULL );
vlc_module_end();
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
if( p_fifo->i_fourcc != VLC_FOURCC('s','p','u',' ')
- && p_fifo->i_fourcc != VLC_FOURCC('s','p','u','b') )
- {
+ && p_fifo->i_fourcc != VLC_FOURCC('s','p','u','b')
+ && p_fifo->i_fourcc != VLC_FOURCC('s','u','b','t') )
+ {
return VLC_EGENERIC;
}
-
+
p_fifo->pf_run = RunDecoder;
return VLC_SUCCESS;
static int RunDecoder( decoder_fifo_t * p_fifo )
{
spudec_thread_t * p_spudec;
+ subtitler_font_t * p_font;
+ char * psz_font;
/* Allocate the memory needed to store the thread's structure */
p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) );
*/
p_spudec->p_vout = NULL;
p_spudec->p_fifo = p_fifo;
-
+
/*
* Initialize thread and free configuration
*/
* Main loop - it is not executed if an error occured during
* initialization
*/
- while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
+ if( p_fifo->i_fourcc == VLC_FOURCC('s','u','b','t') )
{
- if( E_(SyncPacket)( p_spudec ) )
+ /* Here we are dealing with text subtitles */
+
+ if( (psz_font = config_GetPsz( p_fifo, "spudec-font" )) == NULL )
+ {
+ msg_Err( p_fifo, "no default font selected" );
+ p_font = NULL;
+ p_spudec->p_fifo->b_error;
+ }
+ else
{
- continue;
+ p_font = subtitler_LoadFont( p_spudec->p_vout, psz_font );
+ if ( p_font == NULL )
+ {
+ msg_Err( p_fifo, "unable to load font: %s", psz_font );
+ p_spudec->p_fifo->b_error;
+ }
}
+ if( psz_font ) free( psz_font );
- E_(ParsePacket)( p_spudec );
+ while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
+ {
+ E_(ParseText)( p_spudec, p_font );
+ }
+
+ if( p_font ) subtitler_UnloadFont( p_spudec->p_vout, p_font );
+
+ }
+ else
+ {
+ /* Here we are dealing with sub-pictures subtitles*/
+
+ while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
+ {
+ if( E_(SyncPacket)( p_spudec ) )
+ {
+ continue;
+ }
+
+ E_(ParsePacket)( p_spudec );
+ }
}
/*
{
if( p_spudec->p_fifo->b_die || p_spudec->p_fifo->b_error )
{
- /* Call InitBitstream anyway so p_spudec is in a known state
- * before calling CloseBitstream */
+ /* Call InitBitstream anyway so p_spudec->bit_stream is in a known
+ * state before calling CloseBitstream */
InitBitstream( &p_spudec->bit_stream, p_spudec->p_fifo,
NULL, NULL );
return -1;
CloseBitstream( &p_spudec->bit_stream );
free( p_spudec );
}
-
* spudec.h : sub picture unit decoder thread interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: spudec.h,v 1.3 2002/11/06 18:07:57 sam Exp $
+ * $Id: spudec.h,v 1.4 2002/11/06 21:48:24 gbazin Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
int i_x_start, i_y_start, i_x_end, i_y_end;
};
+/*****************************************************************************
+ * subtitler_font_t : proportional font
+ *****************************************************************************/
+typedef struct subtitler_font_s
+{
+ int i_height; /* character height in pixels */
+ int i_width[256]; /* character widths in pixels */
+ int i_memory[256]; /* amount of memory used by character */
+ int * p_length[256]; /* line byte widths */
+ u16 ** p_offset[256]; /* pointer to RLE data */
+} subtitler_font_t;
+
/*****************************************************************************
* spudec_thread_t : sub picture unit decoder thread descriptor
*****************************************************************************/
void E_(RenderSPU) ( vout_thread_t *, picture_t *,
const subpicture_t * );
+void E_(ParseText) ( spudec_thread_t *, subtitler_font_t * );
+
+subtitler_font_t *E_(subtitler_LoadFont) ( vout_thread_t *, const char * );
+void E_(subtitler_UnloadFont) ( vout_thread_t *, subtitler_font_t * );
+void E_(subtitler_PlotSubtitle) ( vout_thread_t *, char *, subtitler_font_t *,
+ mtime_t, mtime_t );
--- /dev/null
+/*****************************************************************************
+ * subtitler.c : subtitler font routines
+ *****************************************************************************
+ * Copyright (C) 1999, 2000 VideoLAN
+ *
+ * Authors: Andrew Flintham <amf@cus.org.uk>
+ *
+ * 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 <stdlib.h> /* malloc(), free() */
+#include <string.h> /* memcpy(), memset() */
+#include <errno.h> /* errno */
+#include <fcntl.h> /* open() */
+#include <ctype.h> /* toascii() */
+
+#include <vlc/vlc.h>
+#include <vlc/vout.h>
+#include <vlc/decoder.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* read(), close() */
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "spudec.h"
+
+/*****************************************************************************
+ * subtitler_line : internal structure for an individual line in a subtitle
+ *****************************************************************************/
+typedef struct subtitler_line_s
+{
+ struct subtitler_line_s * p_next;
+ char * p_text;
+} subtitler_line_t;
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static uint16_t *PlotSubtitleLine( char *, subtitler_font_t *, int,
+ uint16_t * );
+static void DestroySPU ( subpicture_t * );
+
+/*****************************************************************************
+ * subtitler_LoadFont: load a run-length encoded font file into memory
+ *****************************************************************************
+ * RLE font files have the following format:
+ *
+ * 2 bytes : magic number: 0x36 0x05
+ * 1 byte : font height in rows
+ *
+ * then, per character:
+ * 1 byte : character
+ * 1 byte : character width in pixels
+ *
+ * then, per row:
+ * 1 byte : length of row, in entries
+ *
+ * then, per entry
+ * 1 byte : colour
+ * 1 byte : number of pixels of that colour
+ *
+ * to end:
+ * 1 byte : 0xff
+ *****************************************************************************/
+subtitler_font_t* subtitler_LoadFont( vout_thread_t * p_vout,
+ const char * psz_name )
+{
+ subtitler_font_t * p_font;
+
+ int i;
+ int i_file;
+ int i_char;
+ int i_length;
+ int i_line;
+ int i_total_length;
+
+ byte_t pi_buffer[512]; /* file buffer */
+
+ msg_Dbg( p_vout, "loading font '%s'", psz_name );
+
+ i_file = open( psz_name, O_RDONLY );
+
+ if( i_file == -1 )
+ {
+ msg_Err( p_vout, "can't open font file '%s' (%s)", psz_name,
+ strerror(errno) );
+ return( NULL );
+ }
+
+ /* Read magick number */
+ if( read( i_file, pi_buffer, 2 ) != 2 )
+ {
+ msg_Err( p_vout, "unexpected end of font file '%s'", psz_name );
+ close( i_file );
+ return( NULL );
+ }
+ if( pi_buffer[0] != 0x36 || pi_buffer[1] != 0x05 )
+ {
+ msg_Err( p_vout, "file '%s' is not a font file", psz_name );
+ close( i_file );
+ return( NULL );
+ }
+
+ p_font = malloc( sizeof( subtitler_font_t ) );
+
+ if( p_font == NULL )
+ {
+ msg_Err( p_vout, "out of memory" );
+ close( i_file );
+ return NULL;
+ }
+
+ /* Read font height */
+ if( read( i_file, pi_buffer, 1 ) != 1 )
+ {
+ msg_Err( p_vout, "unexpected end of font file '%s'", psz_name );
+ free( p_font );
+ close( i_file );
+ return( NULL );
+ }
+ p_font->i_height = pi_buffer[0];
+
+ /* Initialise font character data */
+ for( i = 0; i < 256; i++ )
+ {
+ p_font->i_width[i] = 0;
+ p_font->i_memory[i] = 0;
+ p_font->p_offset[i] = NULL;
+ p_font->p_length[i] = NULL;
+ }
+
+ while(1)
+ {
+ /* Read character number */
+ if( read( i_file, pi_buffer, 1 ) != 1)
+ {
+ msg_Err( p_vout, "unexpected end of font file '%s'", psz_name );
+ close( i_file );
+ subtitler_UnloadFont( p_vout, p_font );
+ return( NULL );
+ }
+ i_char = pi_buffer[0];
+
+ /* Character 255 signals the end of the font file */
+ if(i_char == 255)
+ {
+ break;
+ }
+
+ /* Read character width */
+ if( read( i_file, pi_buffer, 1 ) != 1 )
+ {
+ msg_Err( p_vout, "unexpected end of font file '%s'", psz_name );
+ close( i_file );
+ subtitler_UnloadFont( p_vout, p_font );
+ return( NULL );
+ }
+ p_font->i_width[ i_char ] = pi_buffer[0];
+
+ p_font->p_length[ i_char ] = (int *) malloc(
+ sizeof(int) * p_font->i_height );
+ p_font->p_offset[ i_char ] = (uint16_t **) malloc(
+ sizeof(uint16_t *) * p_font->i_height);
+
+ if( p_font->p_length[ i_char] == NULL ||
+ p_font->p_offset[ i_char ] == NULL )
+ {
+ msg_Err( p_vout, "out of memory" );
+ close( i_file );
+ subtitler_UnloadFont( p_vout, p_font );
+ return NULL;
+ }
+ for( i_line=0; i_line < p_font->i_height; i_line ++ )
+ {
+ p_font->p_offset[ i_char ][ i_line ] = NULL;
+ }
+
+ i_total_length=0;
+ for( i_line = 0; i_line < p_font->i_height; i_line ++ )
+ {
+ /* Read line length */
+ if( read( i_file, pi_buffer, 1 ) != 1)
+ {
+ msg_Err( p_vout, "unexpected end of font file '%s'", psz_name);
+ subtitler_UnloadFont( p_vout, p_font );
+ close( i_file );
+ return( NULL );
+ }
+ i_length = pi_buffer[0];
+ p_font->p_length[ i_char ][ i_line ] = i_length;
+
+ i_total_length += i_length;
+
+ /* Read line RLE data */
+ if( read( i_file, pi_buffer, i_length*2 ) != i_length*2)
+ {
+ msg_Err( p_vout, "unexpected end of font file '%s'", psz_name);
+ subtitler_UnloadFont( p_vout, p_font );
+ close( i_file );
+ return( NULL );
+ }
+ p_font->p_offset[ i_char ][ i_line ] =
+ (uint16_t *) malloc( sizeof( uint16_t ) * i_length );
+ if( p_font->p_offset[ i_char ][ i_line ] == NULL )
+ {
+ msg_Err( p_vout, "out of memory" );
+ close( i_file );
+ subtitler_UnloadFont( p_vout, p_font );
+ return NULL;
+ }
+ for( i = 0; i < i_length; i++ )
+ {
+ *( p_font->p_offset[ i_char ][ i_line ] + i ) =
+ (uint16_t) ( pi_buffer[ i * 2 ] +
+ ( pi_buffer[ i * 2 + 1 ] << 2 ) );
+ }
+
+ }
+
+ /* Set total memory size of character */
+ p_font->i_memory[ i_char ] = i_total_length;
+
+ }
+
+ close(i_file);
+
+ return p_font;
+}
+
+/*****************************************************************************
+ * subtitler_UnloadFont: unload a run-length encoded font file from memory
+ *****************************************************************************/
+void subtitler_UnloadFont( vout_thread_t * p_vout, subtitler_font_t * p_font )
+{
+ int i_char;
+ int i_line;
+
+ msg_Dbg( p_vout, "unloading font" );
+
+ if( p_font == NULL )
+ {
+ return;
+ }
+
+ for( i_char = 0; i_char < 256; i_char ++ )
+ {
+ if( p_font->p_offset[ i_char ] != NULL )
+ {
+ for( i_line = 0; i_line < p_font->i_height; i_line++ )
+ {
+ if( p_font->p_offset[ i_char ][ i_line ] != NULL )
+ {
+ free( p_font->p_offset[ i_char ][ i_line ] );
+ }
+ }
+ free( p_font->p_offset[ i_char ] );
+ }
+ if( p_font->p_length[ i_char ] != NULL )
+ {
+ free( p_font->p_length[ i_char ] );
+ }
+ }
+
+ free( p_font );
+}
+
+/*****************************************************************************
+ * subtitler_PlotSubtitle: create a subpicture containing the subtitle
+ *****************************************************************************/
+void subtitler_PlotSubtitle ( vout_thread_t *p_vout , char *psz_subtitle,
+ subtitler_font_t *p_font, mtime_t i_start,
+ mtime_t i_stop )
+{
+ subpicture_t * p_spu;
+
+ int i_x;
+ int i_width;
+ int i_lines;
+ int i_longest_width;
+ int i_total_length;
+ int i_char;
+
+ uint16_t * p_data;
+
+ char * p_line_start;
+ char * p_word_start;
+ char * p_char;
+
+ subtitler_line_t * p_first_line;
+ subtitler_line_t * p_previous_line;
+ subtitler_line_t * p_line;
+
+ if( p_font == NULL )
+ {
+ msg_Err( p_vout, "attempt to use NULL font in subtitle" );
+ return;
+ }
+
+ p_first_line = NULL;
+ p_previous_line = NULL;
+
+ p_line_start = psz_subtitle;
+
+ while( *p_line_start != 0 )
+ {
+ i_width = 0;
+ p_word_start = p_line_start;
+ p_char = p_line_start;
+
+ while( *p_char != '\n' && *p_char != 0 )
+ {
+ i_width += p_font->i_width[ toascii( *p_char ) ];
+
+ if( i_width > p_vout->output.i_width )
+ {
+ /* If the line has more than one word, break at the end of
+ the previous one. If the line is one very long word,
+ display as much as we can of it */
+ if( p_word_start != p_line_start )
+ {
+ p_char=p_word_start;
+ }
+ break;
+ }
+
+ if( *p_char == ' ' )
+ {
+ p_word_start = p_char+1;
+ }
+
+ p_char++;
+ }
+
+ p_line = malloc(sizeof(subtitler_line_t));
+
+ if( p_line == NULL )
+ {
+ msg_Err( p_vout, "out of memory" );
+ return;
+ }
+
+ if( p_first_line == NULL )
+ {
+ p_first_line = p_line;
+ }
+
+ if( p_previous_line != NULL )
+ {
+ p_previous_line->p_next = p_line;
+ }
+
+ p_previous_line = p_line;
+
+ p_line->p_next = NULL;
+
+ p_line->p_text = malloc(( p_char - p_line_start ) +1 );
+
+ if( p_line == NULL )
+ {
+ msg_Err( p_vout, "out of memory" );
+ return;
+ }
+
+ /* Copy only the part of the text that is in this line */
+ strncpy( p_line->p_text , p_line_start , p_char - p_line_start );
+ *( p_line->p_text + ( p_char - p_line_start )) = 0;
+
+ /* If we had to break a line because it was too long, ensure that
+ no characters are lost */
+ if( *p_char != '\n' && *p_char != 0 )
+ {
+ p_char--;
+ }
+
+ p_line_start = p_char;
+ if( *p_line_start != 0 )
+ {
+ p_line_start ++;
+ }
+ }
+
+ i_lines = 0;
+ i_longest_width = 0;
+ i_total_length = 0;
+ p_line = p_first_line;
+
+ /* Find the width of the longest line, count the total number of lines,
+ and calculate the amount of memory we need to allocate for the RLE
+ data */
+ while( p_line != NULL )
+ {
+ i_lines++;
+ i_width = 0;
+ for( i_x = 0; i_x < strlen( p_line->p_text ); i_x++ )
+ {
+ i_char = toascii(*(( p_line->p_text )+ i_x ));
+ i_width += p_font->i_width[ i_char ];
+ i_total_length += p_font->i_memory[ i_char ];
+ }
+ if(i_width > i_longest_width)
+ {
+ i_longest_width = i_width;
+ }
+ p_line = p_line->p_next;
+ }
+
+ /* Allow space for the padding bytes at either edge */
+ i_total_length += p_font->i_height * 2 * i_lines;
+
+ /* Allocate the subpicture internal data. */
+ p_spu = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
+ if( p_spu == NULL )
+ {
+ return;
+ }
+
+ /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
+ * expand the RLE stuff so that we won't need to read nibbles later
+ * on. This will speed things up a lot. Plus, we'll only need to do
+ * this stupid interlacing stuff once. */
+ p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
+ + i_total_length * sizeof(uint16_t) );
+ if( p_spu->p_sys == NULL )
+ {
+ vout_DestroySubPicture( p_vout, p_spu );
+ return;
+ }
+
+ /* Fill the p_spu structure */
+ p_spu->pf_render = E_(RenderSPU);
+ p_spu->pf_destroy = DestroySPU;
+ p_spu->p_sys->p_data = (uint8_t *)p_spu->p_sys + sizeof(subpicture_sys_t);
+
+ p_spu->i_start = i_start;
+ p_spu->i_stop = i_stop;
+
+ p_spu->b_ephemer = i_stop ? VLC_FALSE : VLC_TRUE;
+
+ /* FIXME: Do we need these two? */
+ p_spu->p_sys->pi_offset[0] = 0;
+ p_spu->p_sys->pi_offset[1] = 0;
+
+ p_spu->p_sys->b_palette = 1;
+
+ /* Colour 0 is transparent */
+ p_spu->p_sys->pi_yuv[0][0] = 0xff;
+ p_spu->p_sys->pi_yuv[0][1] = 0x80;
+ p_spu->p_sys->pi_yuv[0][2] = 0x80;
+ p_spu->p_sys->pi_yuv[0][3] = 0x80;
+ p_spu->p_sys->pi_alpha[0] = 0x0;
+
+ /* Colour 1 is grey */
+ p_spu->p_sys->pi_yuv[1][0] = 0x80;
+ p_spu->p_sys->pi_yuv[1][1] = 0x80;
+ p_spu->p_sys->pi_yuv[1][2] = 0x80;
+ p_spu->p_sys->pi_yuv[1][3] = 0x80;
+ p_spu->p_sys->pi_alpha[1] = 0xf;
+
+ /* Colour 2 is white */
+ p_spu->p_sys->pi_yuv[2][0] = 0xff;
+ p_spu->p_sys->pi_yuv[2][1] = 0xff;
+ p_spu->p_sys->pi_yuv[2][2] = 0xff;
+ p_spu->p_sys->pi_yuv[2][3] = 0xff;
+ p_spu->p_sys->pi_alpha[2] = 0xf;
+
+ /* Colour 3 is black */
+ p_spu->p_sys->pi_yuv[3][0] = 0x00;
+ p_spu->p_sys->pi_yuv[3][1] = 0x00;
+ p_spu->p_sys->pi_yuv[3][2] = 0x00;
+ p_spu->p_sys->pi_yuv[3][3] = 0x00;
+ p_spu->p_sys->pi_alpha[3] = 0xf;
+
+ p_spu->p_sys->b_crop = VLC_FALSE;
+
+ p_spu->i_x = (p_vout->output.i_width - i_longest_width) / 2;
+ p_spu->i_y = p_vout->output.i_height - (p_font->i_height * i_lines);
+ p_spu->i_width = i_longest_width;
+ p_spu->i_height = p_font->i_height*i_lines;
+
+ p_data = (uint16_t *)(p_spu->p_sys->p_data);
+
+ p_line = p_first_line;
+ while( p_line != NULL )
+ {
+ p_data = PlotSubtitleLine( p_line->p_text,
+ p_font, i_longest_width, p_data );
+ p_previous_line = p_line;
+ p_line = p_line->p_next;
+ free( p_previous_line->p_text );
+ free( p_previous_line );
+ }
+
+ /* SPU is finished - we can ask the video output to display it */
+ vout_DisplaySubPicture( p_vout, p_spu );
+
+}
+
+/*****************************************************************************
+ * PlotSubtitleLine: plot a single line of a subtitle
+ *****************************************************************************/
+static uint16_t * PlotSubtitleLine ( char *psz_line, subtitler_font_t *p_font,
+ int i_total_width, uint16_t *p_data )
+{
+ int i_x;
+ int i_y;
+ int i_length;
+ int i_line_width;
+ int i_char;
+
+ uint16_t * p_rle;
+
+ i_line_width = 0;
+ for( i_x = 0; i_x< strlen( psz_line ); i_x++ )
+ {
+ i_line_width += p_font->i_width[ toascii( *( psz_line+i_x ) ) ]; }
+
+ for( i_y = 0; i_y < p_font->i_height; i_y++ )
+ {
+ /* Pad line to fit box */
+ if( i_line_width < i_total_width )
+ {
+ *p_data++ = ((( i_total_width - i_line_width)/2) << 2 );
+ }
+
+ for(i_x = 0; i_x < strlen(psz_line); i_x ++)
+ {
+ i_char = toascii( *(psz_line + i_x) );
+
+ if( p_font->i_width[ i_char ] != 0 )
+ {
+ p_rle = p_font->p_offset[ i_char ][ i_y ];
+ i_length = p_font->p_length[ i_char ][ i_y ];
+
+ if(p_rle != NULL )
+ {
+ memcpy(p_data, p_rle, i_length * sizeof(uint16_t) );
+ p_data+=i_length;
+ }
+ }
+ }
+
+ /* Pad line to fit box */
+ if( i_line_width < i_total_width )
+ {
+ *p_data++ = ((( i_total_width - i_line_width)
+ - (( i_total_width - i_line_width)/2)) << 2 );
+ }
+ }
+
+ return p_data;
+}
+
+/*****************************************************************************
+ * DestroySPU: subpicture destructor
+ *****************************************************************************/
+static void DestroySPU( subpicture_t *p_spu )
+{
+ free( p_spu->p_sys );
+}
--- /dev/null
+/*****************************************************************************
+ * text.c: text subtitles parser
+ *****************************************************************************
+ * Copyright (C) 2000-2001 VideoLAN
+ * $Id: text.c,v 1.1 2002/11/06 21:48:24 gbazin Exp $
+ *
+ * Authors: Gildas Bazin <gbazin@netcourrier.com>
+ *
+ * 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 <stdlib.h> /* malloc(), free() */
+#include <string.h> /* memcpy(), memset() */
+
+#include <vlc/vlc.h>
+#include <vlc/vout.h>
+#include <vlc/decoder.h>
+
+#include "spudec.h"
+
+/*****************************************************************************
+ * Local prototypes.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * ParseText: parse an text subtitle packet and send it to the video output
+ *****************************************************************************/
+void E_(ParseText)( spudec_thread_t *p_spudec, subtitler_font_t *p_font )
+{
+ char * psz_subtitle;
+ mtime_t i_pts;
+
+ /* We cannot display a subpicture with no date */
+ i_pts = p_spudec->bit_stream.p_pes->i_pts;
+ if( i_pts == 0 )
+ {
+ /* Dump the packet */
+ NextDataPacket( p_spudec->p_fifo, &p_spudec->bit_stream );
+ msg_Warn( p_spudec->p_fifo, "subtitle without a date" );
+ return;
+ }
+ else
+
+ /* Check validity of packet data */
+ if( (p_spudec->bit_stream.p_data->p_payload_end
+ - p_spudec->bit_stream.p_data->p_payload_start) <= 0
+ || (strlen(p_spudec->bit_stream.p_data->p_payload_start)
+ > p_spudec->bit_stream.p_data->p_payload_end
+ - p_spudec->bit_stream.p_data->p_payload_start) )
+ {
+ /* Dump the packet */
+ NextDataPacket( p_spudec->p_fifo, &p_spudec->bit_stream );
+ msg_Warn( p_spudec->p_fifo, "invalid subtitle" );
+ return;
+ }
+ psz_subtitle = p_spudec->bit_stream.p_data->p_payload_start;
+
+ if( psz_subtitle[0] != '\0' )
+ {
+ subtitler_PlotSubtitle( p_spudec->p_vout,
+ psz_subtitle, p_font,
+ i_pts,
+ 0 );
+ }
+
+ /* Prepare for next time. No need to check that
+ * p_spudec->bit_stream->p_data is valid since we check later on
+ * for b_die and b_error */
+ NextDataPacket( p_spudec->p_fifo, &p_spudec->bit_stream );
+}
* ogg.c : ogg stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: ogg.c,v 1.7 2002/11/05 21:57:41 gbazin Exp $
+ * $Id: ogg.c,v 1.8 2002/11/06 21:48:23 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
/* current audio and video es */
logical_stream_t *p_stream_video;
logical_stream_t *p_stream_audio;
+ logical_stream_t *p_stream_spu;
/* stream we use as a time reference for demux reading speed */
logical_stream_t *p_stream_timeref;
/* Stream managment */
static int Ogg_StreamStart ( input_thread_t *, demux_sys_t *, int );
-static int Ogg_StreamSeek ( input_thread_t *, demux_sys_t *, int, mtime_t );
static void Ogg_StreamStop ( input_thread_t *, demux_sys_t *, int );
/* Bitstream manipulation */
}
}
- //Ogg_StreamSeek( p_input, p_ogg, i_stream, p_ogg->i_time );
-
return( p_stream->i_activated );
#undef p_stream
}
#undef p_stream
}
-static int Ogg_StreamSeek( input_thread_t *p_input, demux_sys_t *p_ogg,
- int i_stream, mtime_t i_date )
-{
-#define p_stream p_ogg->pp_stream[i_stream]
-
- /* FIXME: todo */
-
- return 1;
-#undef p_stream
-}
-
/****************************************************************************
* Ogg_Check: Check we are dealing with an ogg stream.
****************************************************************************/
}
/* Convert the pcr into a pts */
- p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
- input_ClockGetTS( p_input, p_input->stream.p_selected_program,
- p_stream->i_pcr );
+ if( p_stream->i_cat != SPU_ES )
+ {
+ p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
+ input_ClockGetTS( p_input, p_input->stream.p_selected_program,
+ p_stream->i_pcr );
+ }
+ else
+ {
+ /* Of course subtitles had to be different! */
+ p_pes->i_pts = ( p_oggpacket->granulepos < 0 ) ? 0 :
+ input_ClockGetTS( p_input, p_input->stream.p_selected_program,
+ p_oggpacket->granulepos * 90000 /
+ p_stream->i_rate );
+ }
/* Convert the next granule into a pcr */
if( p_oggpacket->granulepos < 0 )
p_oggpacket->bytes - i_header_len );
p_data->p_payload_end = p_data->p_payload_start + p_pes->i_pes_size;
+ p_data->b_discard_payload = 0;
input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
}
/* Check for text (subtitles) header */
else if( !strncmp(st->streamtype, "text", 4) )
{
+ /* We need to get rid of the header packet */
+ ogg_stream_packetout( &p_stream->os, &oggpacket );
+
msg_Dbg( p_input, "found text subtitles header" );
p_stream->i_cat = SPU_ES;
p_stream->i_fourcc =
VLC_FOURCC( 's', 'u', 'b', 't' );
+ p_stream->i_rate = 1000; /* granulepos is in milisec */
}
else
{
p_ogg->i_streams + 1, 0 );
p_input->stream.i_mux_rate += (p_stream->i_bitrate / ( 8 * 50 ));
vlc_mutex_unlock( &p_input->stream.stream_lock );
- p_stream->p_es->i_stream_id = i_stream;
+ p_stream->p_es->i_stream_id = p_stream->p_es->i_id = i_stream;
p_stream->p_es->i_fourcc = p_stream->i_fourcc;
p_stream->p_es->i_cat = p_stream->i_cat;
p_stream->p_es->p_demux_data = p_stream->p_bih ?
switch( p_stream->p_es->i_cat )
{
case( VIDEO_ES ):
-
if( (p_ogg->p_stream_video == NULL) )
{
p_ogg->p_stream_video = p_stream;
case( AUDIO_ES ):
if( (p_ogg->p_stream_audio == NULL) )
{
- p_ogg->p_stream_audio = p_stream;
- p_ogg->p_stream_timeref = p_stream;
- Ogg_StreamStart( p_input, p_ogg, i_stream );
+ int i_audio = config_GetInt( p_input, "audio-channel" );
+ if( i_audio == i_stream || i_audio <= 0 ||
+ i_audio >= p_ogg->i_streams ||
+ p_ogg->pp_stream[i_audio]->p_es->i_cat != AUDIO_ES )
+ {
+ p_ogg->p_stream_audio = p_stream;
+ p_ogg->p_stream_timeref = p_stream;
+ Ogg_StreamStart( p_input, p_ogg, i_stream );
+ }
+ }
+ break;
+
+ case( SPU_ES ):
+ if( (p_ogg->p_stream_spu == NULL) )
+ {
+ /* for spu, default is none */
+ int i_spu = config_GetInt( p_input, "spu-channel" );
+ if( i_spu < 0 || i_spu >= p_ogg->i_streams ||
+ p_ogg->pp_stream[i_spu]->p_es->i_cat != SPU_ES )
+ {
+ break;
+ }
+ else if( i_spu == i_stream )
+ {
+ p_ogg->p_stream_spu = p_stream;
+ Ogg_StreamStart( p_input, p_ogg, i_stream );
+ }
}
break;