All: My shot at improving subtitle rendering in vlc. Now each vout uses a...

All: My shot at improving subtitle rendering in vlc. Now each vout uses a "text renderer" module to render text on the video when needed. I decieded to make this a module type, because other api's (win32 and macosx) is supposed to do better than freetype under some circumstances.

include/video_output.h: added some members needed by text renderer modules
src/video_output/video_output.c: load and unload text renderer module when needed
src/video_output/video_text.c: implemented some functions to show text on the video
include/osd.h: exported the functions to show text
modules/misc/Modules.am, module/misc/freetype.c: new text renderer module, largly based on the old osdtext module.
modules/video_filter/Modules.am, modules/video_filter/osd_text.c: removed the osdtext module
configure.ac: changes "osdtext" to "freetype" some places
modules/codec/spudec/*: when iconv is available, use it to convert textual subtitles from the encoding given by --sub-encoding to utf8. Use new code to render subtitles
modules/control/lirc/lirc.c: use new code to give feedback on buttons pressed. untested.
modules/demux/util/sub.c: remove all traces of the ugly old osdtext module
modules/misc/dummy/*: added a "text renderer" submodule in the dummy module
src/misc/modules.c: included osd.h as it seems to be needed to export symbols


final notes: you need to give a proper value to --freetype-font. This should be the path to a font file freetype2 can handle (almost any format afaik) with a unicode translation table in it. Windows ttf files will do. In linux at least openoffice distributes some fonts that work. I think macosx and beos also has useable fonts.
parent 371148d3
dnl Autoconf settings for vlc
dnl $Id: configure.ac,v 1.29 2003/07/14 16:10:20 gbazin Exp $
dnl $Id: configure.ac,v 1.30 2003/07/14 21:32:58 sigmunau Exp $
AC_INIT(vlc,0.6.0)
......@@ -2129,9 +2129,9 @@ then
if test "${FREETYPE_CONFIG}" != "no"
then
AX_ADD_PLUGINS([osdtext])
AX_ADD_CFLAGS([osdtext],[`${FREETYPE_CONFIG} --cflags`])
AX_ADD_LDFLAGS([osdtext],[`${FREETYPE_CONFIG} --libs`])
AX_ADD_PLUGINS([freetype])
AX_ADD_CFLAGS([freetype],[`${FREETYPE_CONFIG} --cflags`])
AX_ADD_LDFLAGS([freetype],[`${FREETYPE_CONFIG} --libs`])
CPPFLAGS="${CPPFLAGS_save} ${CFLAGS_freetype}"
elif test "${enable_freetype}" = "yes"
then
......
......@@ -2,7 +2,7 @@
* osd.h : Constants for use with osd modules
*****************************************************************************
* Copyright (C) 2003 VideoLAN
* $Id: osd.h,v 1.1 2003/03/23 16:38:40 sigmunau Exp $
* $Id: osd.h,v 1.2 2003/07/14 21:32:58 sigmunau Exp $
*
* Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
*
......@@ -25,3 +25,15 @@
#define OSD_ALIGN_RIGHT 0x1
#define OSD_ALIGN_TOP 0
#define OSD_ALIGN_BOTTOM 0x2
struct text_style_t
{
int i_size;
uint32_t i_color;
vlc_bool_t b_italic;
vlc_bool_t b_bold;
vlc_bool_t b_underline;
};
static const text_style_t default_text_style = { 22, 0xffffff, VLC_FALSE, VLC_FALSE, VLC_FALSE };
VLC_EXPORT( void, vout_ShowTextRelative, ( vout_thread_t *, char *, text_style_t *, int, int, int, mtime_t ) );
VLC_EXPORT( void, vout_ShowTextAbsolute, ( vout_thread_t *, char *, text_style_t *, int, int, int, mtime_t, mtime_t ) );
......@@ -5,7 +5,7 @@
* thread, and destroy a previously opened video output thread.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video_output.h,v 1.95 2003/06/09 00:33:34 massiot Exp $
* $Id: video_output.h,v 1.96 2003/07/14 21:32:58 sigmunau Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
......@@ -50,76 +50,91 @@ typedef struct vout_chroma_t
} vout_chroma_t;
/*****************************************************************************
* vout_thread_t: video output thread descriptor
*****************************************************************************
/**
* \brief video output thread descriptor
*
* Any independant video output device, such as an X11 window or a GGI device,
* is represented by a video output thread, and described using the following
* structure.
*****************************************************************************/
*/
struct vout_thread_t
{
VLC_COMMON_MEMBERS
/* Thread properties and lock */
vlc_mutex_t picture_lock; /* picture heap lock */
vlc_mutex_t subpicture_lock; /* subpicture heap lock */
vlc_mutex_t change_lock; /* thread change lock */
vout_sys_t * p_sys; /* system output method */
/* Current display properties */
uint16_t i_changes; /* changes made to the thread */
float f_gamma; /* gamma */
vlc_bool_t b_grayscale; /* color or grayscale display */
vlc_bool_t b_info; /* print additional information */
vlc_bool_t b_interface; /* render interface */
vlc_bool_t b_scale; /* allow picture scaling */
vlc_bool_t b_fullscreen; /* toogle fullscreen display */
vlc_bool_t b_override_aspect; /* aspect ratio overriden */
mtime_t render_time; /* last picture render time */
unsigned int i_window_width; /* video window width */
unsigned int i_window_height; /* video window height */
/* Plugin used and shortcuts to access its capabilities */
/** \name Thread properties and locks */
/**@{*/
vlc_mutex_t picture_lock; /**< picture heap lock */
vlc_mutex_t subpicture_lock; /**< subpicture heap lock */
vlc_mutex_t change_lock; /**< thread change lock */
vout_sys_t * p_sys; /**< system output method */
/**@}*/
/** \name Current display properties */
/**@{*/
uint16_t i_changes; /**< changes made to the thread */
float f_gamma; /**< gamma */
vlc_bool_t b_grayscale; /**< color or grayscale display */
vlc_bool_t b_info; /**< print additional information */
vlc_bool_t b_interface; /**< render interface */
vlc_bool_t b_scale; /**< allow picture scaling */
vlc_bool_t b_fullscreen; /**< toogle fullscreen display */
vlc_bool_t b_override_aspect; /**< aspect ratio overriden */
mtime_t render_time; /**< last picture render time */
unsigned int i_window_width; /**< video window width */
unsigned int i_window_height; /**< video window height */
/**@}*/
/** \name Plugin used and shortcuts to access its capabilities */
/**@{*/
module_t * p_module;
int ( *pf_init ) ( vout_thread_t * );
void ( *pf_end ) ( vout_thread_t * );
int ( *pf_manage ) ( vout_thread_t * );
void ( *pf_render ) ( vout_thread_t *, picture_t * );
void ( *pf_display ) ( vout_thread_t *, picture_t * );
/**@}*/
/* Statistics - these numbers are not supposed to be accurate, but are a
/** \name Statistics
* These numbers are not supposed to be accurate, but are a
* good indication of the thread status */
count_t c_fps_samples; /* picture counts */
mtime_t p_fps_sample[VOUT_FPS_SAMPLES]; /* FPS samples dates */
/* Video heap and translation tables */
int i_heap_size; /* heap size */
picture_heap_t render; /* rendered pictures */
picture_heap_t output; /* direct buffers */
vlc_bool_t b_direct; /* rendered are like direct ? */
vout_chroma_t chroma; /* translation tables */
/**@{*/
count_t c_fps_samples; /**< picture counts */
mtime_t p_fps_sample[VOUT_FPS_SAMPLES]; /**< FPS samples dates */
/**@}*/
/** \name Video heap and translation tables */
/**@{*/
int i_heap_size; /**< heap size */
picture_heap_t render; /**< rendered pictures */
picture_heap_t output; /**< direct buffers */
vlc_bool_t b_direct; /**< rendered are like direct ? */
vout_chroma_t chroma; /**< translation tables */
/**@}*/
/* Picture and subpicture heaps */
picture_t p_picture[2*VOUT_MAX_PICTURES]; /* pictures */
subpicture_t p_subpicture[VOUT_MAX_PICTURES]; /* subpictures */
/* Bitmap fonts */
vout_font_t * p_default_font; /* default font */
vout_font_t * p_large_font; /* large font */
picture_t p_picture[2*VOUT_MAX_PICTURES]; /**< pictures */
subpicture_t p_subpicture[VOUT_MAX_PICTURES]; /**< subpictures */
/* Statistics */
count_t c_loops;
count_t c_pictures, c_late_pictures;
mtime_t display_jitter; /* average deviation from the PTS */
count_t c_jitter_samples; /* number of samples used for the *
* calculation of the jitter */
/* delay created by internal caching */
count_t c_loops;
count_t c_pictures, c_late_pictures;
mtime_t display_jitter; /**< average deviation from the PTS */
count_t c_jitter_samples; /**< number of samples used
for the calculation of the
jitter */
/** delay created by internal caching */
int i_pts_delay;
/* Filter chain */
char *psz_filter_chain;
vlc_bool_t b_filter_change;
/* text renderer data */
text_renderer_sys_t * p_text_renderer_data; /**< private data for
the text renderer */
module_t * p_text_renderer_module; /**< text renderer module */
int ( *pf_add_string ) ( vout_thread_t *, char *, text_style_t *, int,
int, int, mtime_t, mtime_t ); /**< callback used when a new string needs to be shown on the vout */
};
#define I_OUTPUTPICTURES p_vout->output.i_pictures
......
......@@ -2,7 +2,7 @@
* spudec.c : SPU decoder thread
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: spudec.c,v 1.19 2003/06/12 22:27:35 massiot Exp $
* $Id: spudec.c,v 1.20 2003/07/14 21:32:58 sigmunau Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -52,6 +52,9 @@ static vout_thread_t *FindVout( spudec_thread_t * );
#define DEFAULT_FONT "font-eutopiabold21.rle"
#define ENCODING_TEXT N_("subtitle text encoding")
#define ENCODING_LONGTEXT N_("change the encoding used in text subtitles")
vlc_module_begin();
add_category_hint( N_("subtitles"), NULL, VLC_TRUE );
#if defined(SYS_DARWIN) || defined(SYS_BEOS) \
......@@ -61,6 +64,10 @@ vlc_module_begin();
#else
add_file( "spudec-font", "share/" DEFAULT_FONT, NULL,
FONT_TEXT, FONT_LONGTEXT, VLC_TRUE );
#endif
#if defined(HAVE_ICONV)
add_string( "spudec-encoding", "ISO-8859-1", NULL, ENCODING_TEXT,
ENCODING_LONGTEXT, VLC_FALSE );
#endif
set_description( _("subtitles decoder") );
set_capability( "decoder", 50 );
......@@ -151,7 +158,13 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
p_spudec->p_fifo->b_error = VLC_TRUE;
}
#endif
#if defined(HAVE_ICONV)
p_spudec->iconv_handle = iconv_open( "UTF-8", config_GetPsz( p_spudec->p_fifo, "spudec-encoding" ) );
if( p_spudec->iconv_handle == (iconv_t)-1 )
{
msg_Warn( p_spudec->p_fifo, "Unable to do requested conversion" );
}
#endif
while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
{
/* Find/Wait for a video output */
......@@ -324,7 +337,12 @@ static void EndThread( spudec_thread_t *p_spudec )
}
}
}
#if defined(HAVE_ICONV)
if( p_spudec->iconv_handle != (iconv_t)-1 )
{
iconv_close( p_spudec->iconv_handle );
}
#endif
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.5 2002/12/06 16:34:05 sam Exp $
* $Id: spudec.h,v 1.6 2003/07/14 21:32:58 sigmunau Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -21,6 +22,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#if defined(HAVE_ICONV)
#include <iconv.h>
#endif
typedef struct spudec_thread_t spudec_thread_t;
struct subpicture_sys_t
......@@ -83,6 +89,9 @@ struct spudec_thread_t
*/
unsigned int i_spu_size; /* size of current SPU packet */
unsigned int i_rle_size; /* size of the RLE part */
#if defined(HAVE_ICONV)
iconv_t iconv_handle; /* handle to iconv instance */
#endif
};
/*****************************************************************************
......
......@@ -2,7 +2,7 @@
* text.c: text subtitles parser
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: text.c,v 1.5 2003/05/11 14:33:32 sigmunau Exp $
* $Id: text.c,v 1.6 2003/07/14 21:32:58 sigmunau Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
......@@ -21,7 +21,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/* define USE_FREETYPE here to disable the old style subtitles */
/*****************************************************************************
* Preamble
......@@ -32,6 +31,7 @@
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>
#include <osd.h>
#include "spudec.h"
......@@ -44,7 +44,6 @@
*****************************************************************************/
void E_(ParseText)( spudec_thread_t *p_spudec, subtitler_font_t *p_font )
{
#if !defined(USE_FREETYPE)
char * psz_subtitle;
mtime_t i_pts, i_dts;
/* We cannot display a subpicture with no date */
......@@ -74,17 +73,43 @@ void E_(ParseText)( spudec_thread_t *p_spudec, subtitler_font_t *p_font )
if( psz_subtitle[0] != '\0' )
{
#if defined(HAVE_ICONV)
char *psz_new_subtitle, *psz_convert_buffer_out, *psz_convert_buffer_in;
size_t ret, inbytes_left, outbytes_left;
psz_new_subtitle = malloc( 6 * strlen( psz_subtitle ) * sizeof(char) );
psz_convert_buffer_out = psz_new_subtitle;
psz_convert_buffer_in = psz_subtitle;
inbytes_left = strlen( psz_subtitle );
outbytes_left = 6 * inbytes_left;
ret = iconv( p_spudec->iconv_handle, &psz_convert_buffer_in, &inbytes_left, &psz_convert_buffer_out, &outbytes_left );
*psz_convert_buffer_out = '\0';
if( inbytes_left )
{
msg_Warn( p_spudec->p_fifo, "Something fishy happened during conversion" );
}
else
{
msg_Dbg( p_spudec->p_fifo, "reencoded \"%s\" into \"%s\"", psz_subtitle, psz_new_subtitle );
vout_ShowTextAbsolute( p_spudec->p_vout, psz_new_subtitle, NULL,
OSD_ALIGN_BOTTOM|OSD_ALIGN_LEFT, 20, 20,
i_pts, i_dts );
}
free( psz_new_subtitle );
#else
vout_ShowTextAbsolute( p_spudec->p_vout, psz_subtitle, NULL,
OSD_ALIGN_BOTTOM|OSD_ALIGN_LEFT, 20, 20,
i_pts, i_dts );
#endif
#if 0
subtitler_PlotSubtitle( p_spudec->p_vout,
psz_subtitle, p_font,
i_pts,
i_dts );
#endif
}
/* 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 );
#else
msleep(10);
#endif
}
......@@ -2,7 +2,7 @@
* lirc.c : lirc plugin for vlc
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: lirc.c,v 1.6 2003/03/30 18:14:37 gbazin Exp $
* $Id: lirc.c,v 1.7 2003/07/14 21:32:59 sigmunau Exp $
*
* Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
*
......@@ -370,25 +370,9 @@ static void Run( intf_thread_t *p_intf )
static void Feedback( intf_thread_t *p_intf, char *psz_string )
{
vlc_value_t val, lockval;
if ( p_intf->p_sys->p_vout
&& var_Get( p_intf->p_sys->p_vout, "lock", &lockval ) == VLC_SUCCESS )
if ( p_intf->p_sys->p_vout )
{
vlc_mutex_lock( lockval.p_address );
val.i_int = OSD_ALIGN_RIGHT|OSD_ALIGN_BOTTOM;
var_Set( p_intf->p_sys->p_vout, "flags", val );
val.i_int = 400000;
var_Set( p_intf->p_sys->p_vout, "duration", val );
val.i_int = 30;
var_Set( p_intf->p_sys->p_vout, "x-margin", val );
val.i_int = 20;
var_Set( p_intf->p_sys->p_vout, "y-margin", val );
val.psz_string = psz_string;
var_Set( p_intf->p_sys->p_vout, "string", val );
vlc_mutex_unlock( lockval.p_address );
}
else
{
msg_Dbg( p_intf, psz_string );
vout_ShowTextRelative( p_intf->p_sys->p_vout, psz_string, NULL,
OSD_ALIGN_TOP|OSD_ALIGN_RIGHT, 30,20,400000 );
}
}
......@@ -2,7 +2,7 @@
* sub.c
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: sub.c,v 1.16 2003/06/26 18:14:56 sam Exp $
* $Id: sub.c,v 1.17 2003/07/14 21:32:59 sigmunau Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -21,8 +21,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/* define USE_FREETYPE to use freetype for subtitles */
/*****************************************************************************
* Preamble
*****************************************************************************/
......@@ -33,9 +31,6 @@
#include <vlc/vlc.h>
#include <vlc/input.h>
#if defined(USE_FREETYPE)
#include <osd.h>
#endif
#include "vlc_video.h"
#include "sub.h"
......@@ -447,9 +442,6 @@ static int sub_open ( subtitle_demux_t *p_sub,
*****************************************************************************/
static int sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate )
{
#if defined(USE_FREETYPE)
vlc_object_t *p_vout = NULL;
#endif
if( p_sub->p_es->p_decoder_fifo && !p_sub->i_previously_selected )
{
p_sub->i_previously_selected = 1;
......@@ -469,9 +461,6 @@ static int sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate )
data_packet_t *p_data;
int i_len;
#if defined(USE_FREETYPE)
p_vout = vlc_object_find( p_sub, VLC_OBJECT_VOUT, FIND_ANYWHERE );
#endif
i_len = strlen( p_sub->subtitle[p_sub->i_subtitle].psz_text ) + 1;
......@@ -514,35 +503,7 @@ static int sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate )
{
p_pes->i_dts = 0;
}
#if defined(USE_FREETYPE)
if( p_vout )
{
vlc_value_t val, lockval;
if( var_Get( p_vout, "lock", &lockval ) == VLC_SUCCESS )
{
int64_t i_tmp;
vlc_mutex_lock( lockval.p_address );
msg_Dbg( p_sub, "pts "I64Fd" dts " I64Fd, p_pes->i_pts,
p_pes->i_dts );
i_tmp = p_pes->i_dts - p_pes->i_pts;
val.i_int = OSD_ALIGN_LEFT|OSD_ALIGN_BOTTOM;
var_Set( p_vout, "flags", val );
val.time.i_low = (int)(p_pes->i_pts+p_sub->p_input->i_pts_delay);
val.time.i_high = (int)( p_pes->i_pts >> 32 );
var_Set( p_vout, "start-date", val );
val.time.i_low = (int)(p_pes->i_dts + p_sub->p_input->i_pts_delay);
val.time.i_high = (int)( p_pes->i_dts >> 32 );
var_Set( p_vout, "stop-date", val );
val.i_int = 20;
var_Set( p_vout, "x-margin", val );
val.i_int = 20;
var_Set( p_vout, "y-margin", val );
val.psz_string = p_sub->subtitle[p_sub->i_subtitle].psz_text;
var_Set( p_vout, "string", val );
vlc_mutex_unlock( lockval.p_address );
}
}
#endif
p_pes->i_nb_data = 1;
p_pes->p_first =
p_pes->p_last = p_data;
......@@ -563,12 +524,6 @@ static int sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate )
p_sub->i_subtitle++;
}
#if defined(USE_FREETYPE)
if ( p_vout )
{
vlc_object_release( p_vout );
}
#endif
return( 0 );
}
......
......@@ -5,4 +5,5 @@ SOURCES_gnome2_main = gtk_main.c
SOURCES_sap = sap.c
SOURCES_screensaver = screensaver.c
SOURCES_qte_main = qte_main.cpp
SOURCES_freetype = freetype.c
SOURCES_httpd = httpd.c
......@@ -6,5 +6,6 @@ SOURCES_dummy = \
interface.c \
input.c \
decoder.c \
renderer.c \
$(NULL)
......@@ -2,7 +2,7 @@
* dummy.c : dummy plugin for vlc
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
* $Id: dummy.c,v 1.8 2003/06/17 16:09:16 gbazin Exp $
* $Id: dummy.c,v 1.9 2003/07/14 21:32:59 sigmunau Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -80,5 +80,9 @@ vlc_module_begin();
set_callbacks( E_(OpenVideo), NULL );
add_category_hint( N_("Video"), NULL, VLC_FALSE );
add_string( "dummy-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, VLC_FALSE );
add_submodule();
set_description( _("dummy font renderer function") );
set_capability( "text renderer", 1 );
set_callbacks( E_(OpenRenderer), NULL );
vlc_module_end();
......@@ -2,7 +2,7 @@
* dummy.h : dummy plugin for vlc
*****************************************************************************
* Copyright (C) 2000, 2001, 2002 VideoLAN
* $Id: dummy.h,v 1.1 2002/08/04 17:23:43 sam Exp $
* $Id: dummy.h,v 1.2 2003/07/14 21:32:59 sigmunau Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -37,3 +37,4 @@ int E_(OpenAudio) ( vlc_object_t * );
int E_(OpenVideo) ( vlc_object_t * );
int E_(OpenRenderer) ( vlc_object_t * );
/*****************************************************************************
* osd_text.c : Filter to put text on the video, using freetype2
* freetype.c : Put text on the video, using freetype2
*****************************************************************************
* Copyright (C) 2002, 2003 VideoLAN
* $Id: osd_text.c,v 1.5 2003/06/11 20:36:22 gbazin Exp $
* $Id: freetype.c,v 1.1 2003/07/14 21:32:59 sigmunau Exp $
*
* Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
*
......@@ -32,8 +32,6 @@
#include <osd.h>
#include <math.h>
#include "filter_common.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
......@@ -46,17 +44,11 @@
static int Create ( vlc_object_t * );
static void Destroy ( vlc_object_t * );
static int Init ( vout_thread_t * );
static void End ( vout_thread_t * );
static void Render ( vout_thread_t *, picture_t * );
static int SendEvents( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static int SetMargin ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static int AddText ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static void Render ( vout_thread_t *, picture_t *,
const subpicture_t * );
static int AddText ( vout_thread_t *, byte_t *, text_style_t *, int,
int, int, mtime_t, mtime_t );
static int GetUnicodeCharFromUTF8( byte_t ** );
/*****************************************************************************
* Module descriptor
......@@ -67,11 +59,11 @@ static int AddText ( vlc_object_t *, char const *,
#define FONTSIZE_LONGTEXT N_("The size of the fonts used by the osd module" )
vlc_module_begin();
add_category_hint( N_("OSD"), NULL, VLC_FALSE );
add_file( "osd-font", "", NULL, FONT_TEXT, FONT_LONGTEXT, VLC_FALSE );
add_integer( "osd-fontsize", 16, NULL, FONTSIZE_TEXT, FONTSIZE_LONGTEXT, VLC_FALSE );
set_description( _("osd text filter") );
set_capability( "video filter", 0 );
add_category_hint( N_("Fonts"), NULL, VLC_FALSE );
add_file( "freetype-font", "", NULL, FONT_TEXT, FONT_LONGTEXT, VLC_FALSE );
add_integer( "freetype-fontsize", 16, NULL, FONTSIZE_TEXT, FONTSIZE_LONGTEXT, VLC_FALSE );
set_description( _("freetype2 font renderer") );
set_capability( "text renderer", 100 );
add_shortcut( "text" );
set_callbacks( Create, Destroy );
vlc_module_end();
......@@ -80,19 +72,18 @@ vlc_module_end();
Describes a string to be displayed on the video, or a linked list of
such
*/
typedef struct string_info_s string_info_t;
struct string_info_s
struct subpicture_sys_t
{
string_info_t *p_next;
int i_x_margin;
int i_y_margin;
int i_width;
int i_height;
int i_flags;
mtime_t i_start_date;
mtime_t i_end_date;
char *psz_text;
/** The string associated with this subpicture */
byte_t *psz_text;
/** NULL-terminated list of glyphs making the string */
FT_Glyph *pp_glyphs;
/** list of relative positions for the glyphs */
FT_Vector *p_glyph_pos;
};
......@@ -102,26 +93,17 @@ struct string_info_s
* This structure is part of the video output thread descriptor.
* It describes the osd-text specific properties of an output thread.
*****************************************************************************/
struct vout_sys_t
struct text_renderer_sys_t
{
int i_clones;
vout_thread_t *p_vout;
FT_Library p_library; /* handle to library */
FT_Face p_face; /* handle to face object */
string_info_t *p_strings;
int i_x_margin;
int i_y_margin;
int i_flags;
int i_duration;
mtime_t i_start_date;
mtime_t i_end_date;
vlc_mutex_t *lock;
vlc_bool_t i_use_kerning;
uint8_t pi_gamma[256];
};
/* more prototypes */
static void ComputeBoundingBox( string_info_t * );
static void FreeString( string_info_t * );
//static void ComputeBoundingBox( subpicture_sys_t * );
static void FreeString( subpicture_t * );
/*****************************************************************************
* Create: allocates osd-text video thread output method
......@@ -134,424 +116,253 @@ static int Create( vlc_object_t *p_this )
vout_thread_t *p_vout = (vout_thread_t *)p_this;
char *psz_fontfile;
int i, i_error;
vlc_value_t val;
double gamma_inv = 1.0f / gamma_value;
/* Allocate structure */
p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
if( p_vout->p_sys == NULL )
{
msg_Err( p_vout, "out of memory" );
return VLC_ENOMEM;
}
p_vout->p_sys->p_strings = NULL;
p_vout->p_sys->i_x_margin = 50;
p_vout->p_sys->i_y_margin = 50;
p_vout->p_sys->i_flags = 0;
p_vout->p_sys->i_duration = 2000000;
p_vout->p_sys->i_start_date = 0;
p_vout->p_sys->i_end_date = 0;
p_vout->p_sys->lock = malloc( sizeof(vlc_mutex_t));
if( p_vout->p_sys->lock == NULL )
p_vout->p_text_renderer_data = malloc( sizeof( text_renderer_sys_t ) );
if( p_vout->p_text_renderer_data == NULL )
{
msg_Err( p_vout, "out of memory" );
return VLC_ENOMEM;
}
vlc_mutex_init( p_vout, p_vout->p_sys->lock);
for (i = 0; i < 256; i++) {
p_vout->p_sys->pi_gamma[i] =
p_vout->p_text_renderer_data->pi_gamma[i] =
(uint8_t)( pow( (double)i / 255.0f, gamma_inv) * 255.0f );
msg_Dbg( p_vout, "%d", p_vout->p_sys->pi_gamma[i]);
//msg_Dbg( p_vout, "%d", p_vout->p_text_renderer_data->pi_gamma[i]);
}
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = NULL;
p_vout->pf_render = Render;
p_vout->pf_display = NULL;
/* Look what method was requested */
psz_fontfile = config_GetPsz( p_vout, "osd-font" );
i_error = FT_Init_FreeType( &p_vout->p_sys->p_library );
psz_fontfile = config_GetPsz( p_vout, "freetype-font" );
i_error = FT_Init_FreeType( &p_vout->p_text_renderer_data->p_library );
if( i_error )
{
msg_Err( p_vout, "couldn't initialize freetype" );
free( p_vout->p_sys );
free( p_vout->p_text_renderer_data );
return VLC_EGENERIC;
}
i_error = FT_New_Face( p_vout->p_sys->p_library, psz_fontfile, 0,
&p_vout->p_sys->p_face );
i_error = FT_New_Face( p_vout->p_text_renderer_data->p_library,
psz_fontfile, 0,
&p_vout->p_text_renderer_data->p_face );
if( i_error == FT_Err_Unknown_File_Format )
{
msg_Err( p_vout, "file %s have unknown format", psz_fontfile );
free( p_vout->p_sys );
FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
free( p_vout->p_text_renderer_data );
return VLC_EGENERIC;
}
else if( i_error )
{
msg_Err( p_vout, "failed to load font file" );
free( p_vout->p_sys );
FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
free( p_vout->p_text_renderer_data );
return VLC_EGENERIC;
}
p_vout->p_sys->i_use_kerning = FT_HAS_KERNING(p_vout->p_sys->p_face);
i_error = FT_Select_Charmap( p_vout->p_text_renderer_data->p_face,
FT_ENCODING_UNICODE );
if ( i_error )
{
msg_Err( p_vout, "Font has no unicode translation table" );
FT_Done_Face( p_vout->p_text_renderer_data->p_face );
FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
free( p_vout->p_text_renderer_data );
return VLC_EGENERIC;
}
p_vout->p_text_renderer_data->i_use_kerning = FT_HAS_KERNING(p_vout->p_text_renderer_data->p_face);
i_error = FT_Set_Pixel_Sizes( p_vout->p_sys->p_face, 0, config_GetInt( p_vout, "osd-fontsize" ) );
i_error = FT_Set_Pixel_Sizes( p_vout->p_text_renderer_data->p_face, 0,
config_GetInt( p_vout, "freetype-fontsize" ) );
if( i_error )
{
msg_Err( p_vout, "couldn't set font size to %d",
config_GetInt( p_vout, "osd-fontsize" ) );
free( p_vout->p_sys );
return VLC_EGENERIC;
}
var_Create( p_vout, "lock", VLC_VAR_MUTEX );
var_Create( p_vout, "flags", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
var_AddCallback( p_vout, "flags", SetMargin, NULL );
var_Create( p_vout, "x-margin", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
var_AddCallback( p_vout, "x-margin", SetMargin, NULL );
var_Create( p_vout, "y-margin", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
var_AddCallback( p_vout, "y-margin", SetMargin, NULL );
var_Create( p_vout, "duration", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
var_AddCallback( p_vout, "duration", SetMargin, NULL );
var_Create( p_vout, "start-date", VLC_VAR_TIME | VLC_VAR_ISCOMMAND );
var_AddCallback( p_vout, "start-date", SetMargin, NULL );
var_Create( p_vout, "end-date", VLC_VAR_TIME | VLC_VAR_ISCOMMAND );
var_AddCallback( p_vout, "end-date", SetMargin, NULL );
var_Create( p_vout, "string", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
var_AddCallback( p_vout, "string", AddText, NULL );
val.psz_string = "Videolan";
// var_Set( p_vout, "string", val );
// p_vout->p_sys->p_strings->i_end_date = 0xFFFFFFFFFFFFFFF;
return VLC_SUCCESS;
}
/*****************************************************************************
* Init: initialize the video thread output method
*****************************************************************************/
static int Init( vout_thread_t *p_vout )
{
int i_index;
picture_t *p_pic;
I_OUTPUTPICTURES = 0;
/* Initialize the output structure */
p_vout->output.i_chroma = p_vout->render.i_chroma;
p_vout->output.i_width = p_vout->render.i_width;
p_vout->output.i_height = p_vout->render.i_height;
p_vout->output.i_aspect = p_vout->render.i_aspect;
/* Try to open the real video output */
msg_Dbg( p_vout, "spawning the real video output" );
p_vout->p_sys->p_vout = vout_Create( p_vout,
p_vout->render.i_width, p_vout->render.i_height,
p_vout->render.i_chroma, p_vout->render.i_aspect );
if( p_vout->p_sys->p_vout == NULL )
{
msg_Err( p_vout, "failed to start vout" );
free( p_vout->p_text_renderer_data );
return VLC_EGENERIC;
}
ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
p_vout->pf_add_string = AddText;
return VLC_SUCCESS;
}
/*****************************************************************************
* End: terminate Clone video thread output method
*****************************************************************************/
static void End( vout_thread_t *p_vout )
{
int i_index;
/* Free the fake output buffers we allocated */
for( i_index = I_OUTPUTPICTURES ; i_index ; )
{
i_index--;
free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
}
}
/*****************************************************************************
* Destroy: destroy Clone video thread output method
*****************************************************************************
* Terminate an output method created by CloneCreateOutputMethod
* Clean up all data and library connections
*****************************************************************************/
static void Destroy( vlc_object_t *p_this )
{
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
string_info_t *p_string1, *p_string2;
DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
vlc_object_detach( p_vout->p_sys->p_vout );
vout_Destroy( p_vout->p_sys->p_vout );
vlc_mutex_destroy( p_vout->p_sys->lock );
p_string1 = p_vout->p_sys->p_strings;
while( p_string1 )
{
p_string2 = p_string1->p_next;
FreeString( p_string1 );
p_string1 = p_string2;
}
FT_Done_Face( p_vout->p_sys->p_face );
FT_Done_FreeType( p_vout->p_sys->p_library );
free( p_vout->p_sys );
FT_Done_Face( p_vout->p_text_renderer_data->p_face );
FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
free( p_vout->p_text_renderer_data );
}
/*****************************************************************************
* SendEvents: forward mouse and keyboard events to the parent p_vout
*****************************************************************************/
static int SendEvents( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
var_Set( (vlc_object_t *)p_data, psz_var, newval );
return VLC_SUCCESS;
}
/*****************************************************************************
* Render: displays previously rendered output
* Render: place string in picture
*****************************************************************************
* This function send the currently rendered image to Clone image, waits
* until it is displayed and switch the two rendering buffers, preparing next
* frame.
* This function merges the previously rendered freetype glyphs into a picture
*****************************************************************************/
static void Render( vout_thread_t *p_vout, picture_t *p_pic )
static void Render( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_subpic )
{
picture_t *p_outpic = NULL;
subpicture_sys_t *p_string = p_subpic->p_sys;
int i_plane, i_error,x,y,pen_x, pen_y;
unsigned int i;
string_info_t *p_string;
mtime_t date;
while( ( p_outpic =
vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 )
) == NULL )
{
if( p_vout->b_die || p_vout->b_error )
{
vout_DestroyPicture(
p_vout->p_sys->p_vout, p_outpic );
return;
}
msleep( VOUT_OUTMEM_SLEEP );
}
vout_DatePicture( p_vout->p_sys->p_vout,
p_outpic, p_pic->date );
if( p_vout->i_changes )
{
p_vout->p_sys->p_vout->i_changes = p_vout->i_changes;
p_vout->i_changes = 0;
}
date = mdate();
/* trash old strings */
while( p_vout->p_sys->p_strings &&
p_vout->p_sys->p_strings->i_end_date < date )
{
p_string = p_vout->p_sys->p_strings;
p_vout->p_sys->p_strings = p_string->p_next;
msg_Dbg( p_vout, "trashing string "I64Fd" < "I64Fd, p_string->i_end_date, date );
FreeString( p_string );
}
vlc_mutex_lock( p_vout->p_sys->lock );
for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
{
uint8_t *p_in, *p_in_end, *p_out;
int i_in_pitch = p_pic->p[i_plane].i_pitch;
const int i_out_pitch = p_outpic->p[i_plane].i_pitch;
const int i_copy_pitch = p_outpic->p[i_plane].i_visible_pitch;
uint8_t *p_in;
int i_pitch = p_pic->p[i_plane].i_pitch;
p_in = p_pic->p[i_plane].p_pixels;
p_out = p_outpic->p[i_plane].p_pixels;
if( i_in_pitch == i_copy_pitch
&& i_out_pitch == i_copy_pitch )
{
p_vout->p_vlc->pf_memcpy( p_out, p_in, i_in_pitch
* p_outpic->p[i_plane].i_lines );
}
else
{
p_in_end = p_in + i_in_pitch * p_outpic->p[i_plane].i_lines;
while( p_in < p_in_end )
{
p_vout->p_vlc->pf_memcpy( p_out, p_in, i_copy_pitch );
p_in += i_in_pitch;
p_out += i_out_pitch;
}
}
/* pen_x = 20;
pen_y = 100;*/
if ( i_plane == 0 )
{
for( p_string = p_vout->p_sys->p_strings; p_string != NULL;
p_string = p_string->p_next )
{
if( p_string->i_start_date > date )
{
continue;
}
if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
{
pen_y = p_outpic->p[i_plane].i_lines - p_string->i_height -
p_string->i_y_margin;
}
else
{
pen_y = p_string->i_y_margin;
}
if ( p_string->i_flags & OSD_ALIGN_RIGHT )
{
pen_x = i_out_pitch - p_string->i_width
- p_string->i_x_margin;
}
else
{
pen_x = p_string->i_x_margin;
}
for( i = 0; i < strlen( p_string->psz_text ); i++ )
{
if( p_string->pp_glyphs[i] )
{
FT_Glyph p_glyph = p_string->pp_glyphs[i];
FT_BitmapGlyph p_image;
i_error = FT_Glyph_To_Bitmap( &p_glyph,
FT_RENDER_MODE_NORMAL,
&p_string->p_glyph_pos[i],
0 );
if ( i_error ) continue;
p_image = (FT_BitmapGlyph)p_glyph;
#define alpha p_vout->p_sys->pi_gamma[p_image->bitmap.buffer[x+ y*p_image->bitmap.width]]
#define pixel p_out[(p_string->p_glyph_pos[i].y + pen_y + y - p_image->top)*i_out_pitch+x+pen_x+p_string->p_glyph_pos[i].x+p_image->left]
for(y = 0; y < p_image->bitmap.rows; y++ )
{
for( x = 0; x < p_image->bitmap.width; x++ )
{
// pixel = alpha;
// pixel = (pixel^alpha)^pixel;
pixel = ((pixel*(255-alpha))>>8) + (255*alpha>>8);
}
}
FT_Done_Glyph( p_glyph );
}
}
}
}
{
if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
{
pen_y = p_pic->p[i_plane].i_lines - p_string->i_height -
p_string->i_y_margin;
}
else
{
pen_y = p_string->i_y_margin;
}
if ( p_string->i_flags & OSD_ALIGN_RIGHT )
{
pen_x = i_pitch - p_string->i_width
- p_string->i_x_margin;
}
else
{
pen_x = p_string->i_x_margin;
}
for( i = 0; p_string->pp_glyphs[i] != NULL; i++ )
{
if( p_string->pp_glyphs[i] )
{
FT_Glyph p_glyph = p_string->pp_glyphs[i];
FT_BitmapGlyph p_image;
i_error = FT_Glyph_To_Bitmap( &p_glyph,
FT_RENDER_MODE_NORMAL,
&p_string->p_glyph_pos[i],
0 );
if ( i_error ) continue;
p_image = (FT_BitmapGlyph)p_glyph;
#define alpha p_vout->p_text_renderer_data->pi_gamma[p_image->bitmap.buffer[x+ y*p_image->bitmap.width]]
#define pixel p_in[(p_string->p_glyph_pos[i].y + pen_y + y - p_image->top)*i_pitch+x+pen_x+p_string->p_glyph_pos[i].x+p_image->left]
for(y = 0; y < p_image->bitmap.rows; y++ )
{
for( x = 0; x < p_image->bitmap.width; x++ )
{
// pixel = alpha;
// pixel = (pixel^alpha)^pixel;
pixel = ((pixel*(255-alpha))>>8) + (255*alpha>>8);
}
}
FT_Done_Glyph( p_glyph );
}
}
}
}
vlc_mutex_unlock( p_vout->p_sys->lock );
vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
}
static int SetMargin ( vlc_object_t *p_this, char const *psz_command,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
/**
* This function receives a string and creates a subpicture for it. It
* also calculates the size needed for this string, and renders the
* needed glyphs into memory. It is used as pf_add_string callback in
* the vout method by this module
*/
static int AddText ( vout_thread_t *p_vout, byte_t *psz_string,
text_style_t *p_style, int i_flags, int i_hmargin,
int i_vmargin, mtime_t i_start, mtime_t i_stop )
{
vout_thread_t *p_vout = (vout_thread_t*)p_this;
if( !strcmp( psz_command, "x-margin" ) )
{
p_vout->p_sys->i_x_margin = newval.i_int;
}
else if( !strcmp( psz_command, "y-margin" ) )
{
p_vout->p_sys->i_y_margin = newval.i_int;
}
else if( !strcmp( psz_command, "duration" ) )
{
p_vout->p_sys->i_duration = newval.i_int;
msg_Dbg( p_vout, "setting duration %d", p_vout->p_sys->i_duration );
}
else if( !strcmp( psz_command, "start-date" ) )
{
p_vout->p_sys->i_start_date = ( (mtime_t) newval.time.i_high << 32 )
+ newval.time.i_low;
}
else if( !strcmp( psz_command, "end-date" ) )
subpicture_sys_t *p_string;
int i, i_pen_y, i_pen_x, i_error, i_glyph_index, i_previous, i_char;
subpicture_t *p_subpic;
FT_BBox line;
FT_BBox glyph_size;
FT_Vector result;
result.x = 0;
result.y = 0;
line.xMin = 0;
line.xMax = 0;
line.yMin = 0;
line.yMax = 0;
/* Create and initialize a subpicture */
p_subpic = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
if ( p_subpic == NULL )
{
p_vout->p_sys->i_end_date = ( (mtime_t) newval.time.i_high << 32 )
+ newval.time.i_low;
return VLC_EGENERIC;
}
else if( !strcmp( psz_command, "flags" ) )
p_subpic->pf_render = Render;
p_subpic->pf_destroy = FreeString;
p_subpic->i_start = i_start;
p_subpic->i_stop = i_stop;
if( i_stop == 0 )
{
p_vout->p_sys->i_flags = newval.i_int;
p_subpic->b_ephemer = VLC_TRUE;
}
else
{
msg_Err( p_vout, "Invalid command" );
return VLC_EGENERIC;
p_subpic->b_ephemer = VLC_FALSE;
}
return VLC_SUCCESS;
}
static int AddText ( vlc_object_t *p_this, char const *psz_command,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
vout_thread_t *p_vout = (vout_thread_t*)p_this;
string_info_t **pp_string;
string_info_t *p_string;
char *psz_string;
int i, i_pen_x, i_error, i_glyph_index, i_previous;
p_string = malloc( sizeof(string_info_t) );
p_string->i_flags = p_vout->p_sys->i_flags;
p_string->i_x_margin = p_vout->p_sys->i_x_margin;
p_string->i_y_margin = p_vout->p_sys->i_y_margin;
if( p_vout->p_sys->i_start_date && p_vout->p_sys->i_end_date )
/* Create and initialize private data for the subpicture */
p_string = malloc( sizeof(subpicture_sys_t) );
if ( p_string == NULL )
{
p_string->i_end_date = p_vout->p_sys->i_end_date;
p_string->i_start_date = p_vout->p_sys->i_start_date;
vout_DestroySubPicture( p_vout, p_subpic );
return VLC_ENOMEM;
}
else
{
p_string->i_end_date = mdate() + p_vout->p_sys->i_duration;
p_string->i_start_date = 0;
}
p_vout->p_sys->i_end_date = 0;
p_vout->p_sys->i_start_date = 0;
p_string->psz_text = strdup( newval.psz_string );
p_subpic->p_sys = p_string;
p_string->i_flags = i_flags;
p_string->i_x_margin = i_hmargin;
p_string->i_y_margin = i_vmargin;
p_string->psz_text = strdup( psz_string );
p_string->pp_glyphs = malloc( sizeof(FT_GlyphSlot)
* strlen( p_string->psz_text ) );
* ( strlen( p_string->psz_text ) + 1 ) );
if( p_string->pp_glyphs == NULL )
{
msg_Err( p_this, "Out of memory" );
msg_Err( p_vout, "Out of memory" );
return VLC_ENOMEM;
}
p_string->p_glyph_pos = malloc( sizeof( FT_Vector )
* strlen( p_string->psz_text ) );
if( p_string->p_glyph_pos == NULL )
{
msg_Err( p_this, "Out of memory" );
msg_Err( p_vout, "Out of memory" );
return VLC_ENOMEM;
}
/* Calculate relative glyph positions and a bounding box for the
* entire string */
i_pen_x = 0;
i_pen_y = 0;
i_previous = 0;
psz_string = p_string->psz_text;
for( i = 0; *psz_string; i++, psz_string++ )
i = 0;
while( *psz_string )
{
#define face p_vout->p_sys->p_face
i_char = GetUnicodeCharFromUTF8( &psz_string );
#define face p_vout->p_text_renderer_data->p_face
#define glyph face->glyph
if ( *psz_string == '\n' )
if ( i_char == '\n' )
{
i_pen_x = 0;
p_string->pp_glyphs[ i ] = NULL;
result.x = __MAX( result.x, line.xMax );
result.y += line.yMax - line.yMin;
line.xMin = 0;
line.xMax = 0;
line.yMin = 0;
line.yMax = 0;
i_pen_y = result.y + 1;
continue;
}
i_glyph_index = FT_Get_Char_Index( face, *psz_string);
if ( p_vout->p_sys->i_use_kerning && i_glyph_index
i_glyph_index = FT_Get_Char_Index( face, i_char );
if ( p_vout->p_text_renderer_data->i_use_kerning && i_glyph_index
&& i_previous )
{
FT_Vector delta;
......@@ -561,107 +372,50 @@ static int AddText ( vlc_object_t *p_this, char const *psz_command,
}
p_string->p_glyph_pos[ i ].x = i_pen_x;
p_string->p_glyph_pos[ i ].y = 0;
p_string->p_glyph_pos[ i ].y = i_pen_y;
i_error = FT_Load_Glyph( face, i_glyph_index, FT_LOAD_DEFAULT );
if ( i_error )
{
msg_Err( p_this, "FT_Load_Glyph returned %d", i_error );
msg_Err( p_vout, "FT_Load_Glyph returned %d", i_error );
return VLC_EGENERIC;
}
i_error = FT_Get_Glyph( glyph, &p_string->pp_glyphs[ i ] );
if ( i_error )
{
msg_Err( p_this, "FT_Get_Glyph returned %d", i_error );
msg_Err( p_vout, "FT_Get_Glyph returned %d", i_error );
return VLC_EGENERIC;
}
i_previous = i_glyph_index;
i_pen_x += glyph->advance.x >> 6;
}
ComputeBoundingBox( p_string );
msg_Dbg( p_this, "string height is %d width is %d", p_string->i_height, p_string->i_width );
p_string->p_next = NULL;
msg_Dbg( p_this, "adding string \"%s\" at (%d,%d) start_date "I64Fd
" end_date" I64Fd, p_string->psz_text, p_string->i_x_margin,
p_string->i_y_margin, p_string->i_start_date,
p_string->i_end_date );
vlc_mutex_lock( p_vout->p_sys->lock );
pp_string = &p_vout->p_sys->p_strings;
while( *pp_string && (*pp_string)->i_end_date < p_string->i_end_date )
{
pp_string = &(*pp_string)->p_next;
}
p_string->p_next = (*pp_string);
*pp_string = p_string;
vlc_mutex_unlock( p_vout->p_sys->lock );
return VLC_SUCCESS;
}
static void ComputeBoundingBox( string_info_t *p_string )
{
unsigned int i;
int i_pen_y = 0;
int i_firstline_height = 0;
FT_Vector result;
FT_BBox line;
FT_BBox glyph_size;
result.x = 0;
result.y = 0;
line.xMin = 0;
line.xMax = 0;
line.yMin = 0;
line.yMax = 0;
for ( i = 0; i < strlen( p_string->psz_text ); i++ )
{
if ( p_string->psz_text[i] == '\n' )
{
result.x = __MAX( result.x, line.xMax );
result.y += line.yMax - line.yMin;
if ( !i_firstline_height )
{
i_firstline_height = result.y;
}
line.xMin = 0;
line.xMax = 0;
line.yMin = 0;
line.yMax = 0;
i_pen_y = result.y + 1;
continue;
}
p_string->p_glyph_pos[ i ].y = i_pen_y;
FT_Glyph_Get_CBox( p_string->pp_glyphs[i],
ft_glyph_bbox_pixels, &glyph_size );
/* Do rest */
line.xMax = p_string->p_glyph_pos[i].x + glyph_size.xMax - glyph_size.xMin;
line.yMax = __MAX( line.yMax, glyph_size.yMax );
line.yMin = __MIN( line.yMin, glyph_size.yMin );
i_previous = i_glyph_index;
i_pen_x += glyph->advance.x >> 6;
i++;
}
p_string->pp_glyphs[i] = NULL;
result.x = __MAX( result.x, line.xMax );
result.y += line.yMax - line.yMin;
p_string->i_height = result.y;
p_string->i_width = result.x;
if ( !i_firstline_height )
{
i_firstline_height = result.y;
}
for ( i = 0; i < strlen( p_string->psz_text ); i++ )
{
p_string->p_glyph_pos[ i ].y += i_firstline_height;
}
return;
msg_Dbg( p_vout, "string height is %d, width is %d", p_string->i_height, p_string->i_width );
msg_Dbg( p_vout, "adding string \"%s\" at (%d,%d) start_date "I64Fd
" end_date" I64Fd, p_string->psz_text, p_string->i_x_margin,
p_string->i_y_margin, i_start, i_stop );
vout_DisplaySubPicture( p_vout, p_subpic );
return VLC_SUCCESS;
}
static void FreeString( string_info_t *p_string )
static void FreeString( subpicture_t *p_subpic )
{
unsigned int i;
for ( i = 0; i < strlen( p_string->psz_text ); i++ )
subpicture_sys_t *p_string = p_subpic->p_sys;
for ( i = 0; p_string->pp_glyphs[ i ] != NULL; i++ )
{
if ( p_string->pp_glyphs[ i ] )
{
FT_Done_Glyph( p_string->pp_glyphs[ i ] );
}
FT_Done_Glyph( p_string->pp_glyphs[ i ] );
}
free( p_string->psz_text );
free( p_string->p_glyph_pos );
......@@ -669,3 +423,46 @@ static void FreeString( string_info_t *p_string )
free( p_string );
}
/* convert one or more utf8 bytes into a unicode character */
static int GetUnicodeCharFromUTF8( byte_t **ppsz_utf8_string )
{
int i_remaining_bytes, i_char = 0;
if( ( **ppsz_utf8_string & 0xFC ) == 0xFC )
{
i_char = **ppsz_utf8_string & 1;
i_remaining_bytes = 5;
}
else if( ( **ppsz_utf8_string & 0xF8 ) == 0xF8 )
{
i_char = **ppsz_utf8_string & 3;
i_remaining_bytes = 4;
}
else if( ( **ppsz_utf8_string & 0xF0 ) == 0xF0 )
{
i_char = **ppsz_utf8_string & 7;
i_remaining_bytes = 3;
}
else if( ( **ppsz_utf8_string & 0xE0 ) == 0xE0 )
{
i_char = **ppsz_utf8_string & 15;
i_remaining_bytes = 2;
}
else if( ( **ppsz_utf8_string & 0xC0 ) == 0xC0 )
{
i_char = **ppsz_utf8_string & 31;
i_remaining_bytes = 1;
}
else
{
i_char = **ppsz_utf8_string;
i_remaining_bytes = 0;
}
while( i_remaining_bytes )
{
(*ppsz_utf8_string)++;
i_remaining_bytes--;
i_char = ( i_char << 6 ) + ( **ppsz_utf8_string & 0x3F );
}
(*ppsz_utf8_string)++;
return i_char;
}
......@@ -6,6 +6,5 @@ SOURCES_wall = wall.c
SOURCES_clone = clone.c
SOURCES_crop = crop.c
SOURCES_motionblur = motionblur.c
SOURCES_osdtext = osd_text.c
SOURCES_logo = logo.c
noinst_HEADERS += filter_common.h
......@@ -2,7 +2,7 @@
* modules.c : Builtin and plugin modules management functions
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: modules.c,v 1.124 2003/07/01 12:56:47 sam Exp $
* $Id: modules.c,v 1.125 2003/07/14 21:32:59 sigmunau Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Ethan C. Baldridge <BaldridgeE@cadmus.com>
......@@ -87,6 +87,7 @@
#include "stream_output.h"
#include "announce.h"
#include "osd.h"
#include "iso_lang.h"
......
......@@ -5,7 +5,7 @@
* thread, and destroy a previously oppened video output thread.
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: video_output.c,v 1.228 2003/06/28 21:18:58 fenrir Exp $
* $Id: video_output.c,v 1.229 2003/07/14 21:32:59 sigmunau Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
......@@ -382,7 +382,13 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent,
vlc_object_destroy( p_vout );
return NULL;
}
p_vout->p_text_renderer_module = module_Need( p_vout, "text renderer",
NULL );
if( p_vout->p_text_renderer_module == NULL )
{
msg_Warn( p_vout, "no suitable text renderer module" );
p_vout->pf_add_string = NULL;
}
/* Create a few object variables for interface interaction */
var_Create( p_vout, "fullscreen", VLC_VAR_BOOL );
text.psz_string = _("Fullscreen");
......@@ -1010,7 +1016,7 @@ static void EndThread( vout_thread_t *p_vout )
{
module_Unneed( p_vout, p_vout->chroma.p_module );
}
/* Destroy all remaining pictures */
for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES; i_index++ )
{
......@@ -1030,6 +1036,8 @@ static void EndThread( vout_thread_t *p_vout )
}
}
module_Unneed( p_vout, p_vout->p_text_renderer_module );
/* Destroy translation tables */
p_vout->pf_end( p_vout );
......
......@@ -2,7 +2,7 @@
* video_text.c : text manipulation functions
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: video_text.c,v 1.43 2003/06/26 12:19:59 sam Exp $
* $Id: video_text.c,v 1.44 2003/07/14 21:32:59 sigmunau Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
......@@ -21,6 +21,66 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#include <vlc/vout.h>
/**
* \brief Show text on the video for some time
* \param p_vout pointer to the vout the text is to be showed on
* \param psz_string The text to be shown
* \param p_style Pointer to a struct with text style info
* \param i_flags flags for alignment and such
* \param i_hmargin horizontal margin in pixels
* \param i_vmargin vertical margin in pixels
* \param i_duration Amount of time the text is to be shown.
*/
void vout_ShowTextRelative( vout_thread_t *p_vout, char *psz_string,
text_style_t *p_style, int i_flags,
int i_hmargin, int i_vmargin,
mtime_t i_duration )
{
mtime_t i_now = mdate();
if ( p_vout->pf_add_string )
{
p_vout->pf_add_string( p_vout, psz_string, p_style, i_flags, i_hmargin,
i_vmargin, i_now, i_now + i_duration );
}
else
{
msg_Warn( p_vout, "No text renderer found" );
}
}
/**
* \brief Show text on the video from a given start date to a given end date
* \param p_vout pointer to the vout the text is to be showed on
* \param psz_string The text to be shown
* \param p_style Pointer to a struct with text style info
* \param i_flags flags for alignment and such
* \param i_hmargin horizontal margin in pixels
* \param i_vmargin vertical margin in pixels
* \param i_start the time when this string is to appear on the video
* \param i_stop the time when this string should stop to be displayed
* if this is 0 the string will be shown untill the next string
* is about to be shown
*/
void vout_ShowTextAbsolute( vout_thread_t *p_vout, char *psz_string,
text_style_t *p_style, int i_flags,
int i_hmargin, int i_vmargin, mtime_t i_start,
mtime_t i_stop )
{
if ( p_vout->pf_add_string )
{
p_vout->pf_add_string( p_vout, psz_string, p_style, i_flags, i_hmargin,
i_vmargin, i_start, i_stop );
}
else
{
msg_Warn( p_vout, "No text renderer found" );
}
}
/* XXX: unused */
#if 0
......
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