* It includes functions allowing to open a new thread, send pictures to a
* thread, and destroy a previously oppened video output thread.
*****************************************************************************
- * Copyright (C) 2000-2004 the VideoLAN team
+ * Copyright (C) 2000-2007 the VideoLAN team
* $Id$
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
/*****************************************************************************
* Preamble
*****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include <vlc/vlc.h>
#include <stdlib.h> /* free() */
* helpers */
#include "input/input_internal.h"
+#include "modules/modules.h"
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int BinaryLog ( uint32_t );
static void MaskToShift ( int *, int *, uint32_t );
+static void vout_Destructor ( vlc_object_t * p_this );
+
/* Object variables callbacks */
static int DeinterlaceCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static int ParseVideoFilter2Chain( vout_thread_t *, char * );
static void RemoveVideoFilters2( vout_thread_t *p_vout );
+/* Display media title in OSD */
+static void DisplayTitleOnOSD( vout_thread_t *p_vout );
+
/*****************************************************************************
* Video Filter2 functions
*****************************************************************************/
/* Reattach video output to playlist before bailing out */
if( p_vout )
{
- playlist_t *p_playlist = pl_Yield( p_this );
spu_Attach( p_vout->p_spu, p_this, VLC_FALSE );
vlc_object_detach( p_vout );
- vlc_object_attach( p_vout, p_playlist );
- pl_Release( p_this );
+ vlc_object_attach( p_vout, p_this->p_libvlc );
}
return NULL;
}
if( !p_vout )
{
- playlist_t *p_playlist = pl_Yield( p_this );
- vlc_mutex_lock( &p_playlist->gc_lock );
- p_vout = vlc_object_find( p_playlist,
+ p_vout = vlc_object_find( p_this->p_libvlc,
VLC_OBJECT_VOUT, FIND_CHILD );
/* only first children of p_input for unused vout */
- if( p_vout && p_vout->p_parent != (vlc_object_t *)p_playlist )
+ if( p_vout && p_vout->p_parent != VLC_OBJECT(p_this->p_libvlc) )
{
vlc_object_release( p_vout );
p_vout = NULL;
}
- vlc_mutex_unlock( &p_playlist->gc_lock );
- pl_Release( p_this );
+ if( p_vout )
+ vlc_object_detach( p_vout ); /* Remove it from the GC */
}
}
p_vout->b_filter_change = VLC_FALSE;
}
- if( psz_filter_chain ) free( psz_filter_chain );
+ free( psz_filter_chain );
}
if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
- ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) ||
( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
p_vout->b_filter_change )
{
/* We are not interested in this format, close this vout */
- vlc_object_detach( p_vout );
vlc_object_release( p_vout );
vout_Destroy( p_vout );
p_vout = NULL;
else
{
/* This video output is cool! Hijack it. */
- vlc_object_detach( p_vout );
spu_Attach( p_vout->p_spu, p_this, VLC_TRUE );
vlc_object_attach( p_vout, p_this );
+ if( p_vout->b_title_show )
+ DisplayTitleOnOSD( p_vout );
vlc_object_release( p_vout );
}
}
vout_thread_t * p_vout; /* thread descriptor */
input_thread_t * p_input_thread;
int i_index; /* loop variable */
- char * psz_plugin;
vlc_value_t val, text;
unsigned int i_width = p_fmt->i_width;
vlc_fourcc_t i_chroma = p_fmt->i_chroma;
unsigned int i_aspect = p_fmt->i_aspect;
+ config_chain_t *p_cfg;
+ char *psz_parser;
+ char *psz_name;
+
/* Allocate descriptor */
p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
if( p_vout == NULL )
/* Initialize locks */
vlc_mutex_init( p_vout, &p_vout->picture_lock );
vlc_mutex_init( p_vout, &p_vout->change_lock );
+ vlc_mutex_init( p_vout, &p_vout->vfilter_lock );
/* Mouse coordinates */
var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
else
{
/* continue the parent's filter chain */
- char *psz_end;
+ char *psz_tmp;
- psz_end = strchr( ((vout_thread_t *)p_parent)->psz_filter_chain, ':' );
- if( psz_end && *(psz_end+1) )
- p_vout->psz_filter_chain = strdup( psz_end+1 );
- else p_vout->psz_filter_chain = NULL;
+ /* Ugly hack to jump to our configuration chain */
+ p_vout->psz_filter_chain
+ = ((vout_thread_t *)p_parent)->psz_filter_chain;
+ p_vout->psz_filter_chain
+ = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain );
+ config_ChainDestroy( p_cfg );
+ free( psz_tmp );
/* Create a video filter2 var ... but don't inherit values */
var_Create( p_vout, "video-filter", VLC_VAR_STRING );
{
var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Get( p_vout, "vout", &val );
- psz_plugin = val.psz_string;
+ psz_parser = val.psz_string;
}
else
{
- /* the filter chain is a string list of filters separated by double
- * colons */
- char *psz_end;
-
- psz_end = strchr( p_vout->psz_filter_chain, ':' );
- if( psz_end )
- psz_plugin = strndup( p_vout->psz_filter_chain,
- psz_end - p_vout->psz_filter_chain );
- else psz_plugin = strdup( p_vout->psz_filter_chain );
+ psz_parser = strdup( p_vout->psz_filter_chain );
}
/* Create the vout thread */
+ config_ChainCreate( &psz_name, &p_cfg, psz_parser );
+ free( psz_parser );
+ p_vout->p_cfg = p_cfg;
p_vout->p_module = module_Need( p_vout,
( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
- "video filter" : "video output", psz_plugin, 0 );
+ "video filter" : "video output", psz_name, p_vout->psz_filter_chain && *p_vout->psz_filter_chain );
+ free( psz_name );
- if( psz_plugin ) free( psz_plugin );
if( p_vout->p_module == NULL )
{
msg_Err( p_vout, "no suitable vout module" );
vlc_object_detach( p_vout );
- vlc_object_destroy( p_vout );
+ vlc_object_release( p_vout );
return NULL;
}
var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
text.psz_string = _("Deinterlace");
var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
- val.psz_string = ""; text.psz_string = _("Disable");
+ val.psz_string = (char *)""; text.psz_string = _("Disable");
var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
- val.psz_string = "discard"; text.psz_string = _("Discard");
+ val.psz_string = (char *)"discard"; text.psz_string = _("Discard");
var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
- val.psz_string = "blend"; text.psz_string = _("Blend");
+ val.psz_string = (char *)"blend"; text.psz_string = _("Blend");
var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
- val.psz_string = "mean"; text.psz_string = _("Mean");
+ val.psz_string = (char *)"mean"; text.psz_string = _("Mean");
var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
- val.psz_string = "bob"; text.psz_string = _("Bob");
+ val.psz_string = (char *)"bob"; text.psz_string = _("Bob");
var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
- val.psz_string = "linear"; text.psz_string = _("Linear");
+ val.psz_string = (char *)"linear"; text.psz_string = _("Linear");
var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
- val.psz_string = "x"; text.psz_string = "X";
+ val.psz_string = (char *)"x"; text.psz_string = (char *)"X";
var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
{
var_Set( p_vout, "deinterlace", val );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
}
var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
-
var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
text.psz_string = _("Filters");
var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
{
msg_Err( p_vout, "out of memory" );
module_Unneed( p_vout, p_vout->p_module );
- vlc_object_detach( p_vout );
- vlc_object_destroy( p_vout );
+ vlc_object_release( p_vout );
return NULL;
}
msg_Err( p_vout, "video output creation failed" );
/* Make sure the thread is destroyed */
- p_vout->b_die = VLC_TRUE;
-
- vlc_thread_join( p_vout );
-
- vlc_object_detach( p_vout );
- vlc_object_destroy( p_vout );
+ vlc_object_release( p_vout );
return NULL;
}
+ vlc_object_set_destructor( p_vout, vout_Destructor );
+
return p_vout;
}
*****************************************************************************/
void vout_Destroy( vout_thread_t *p_vout )
{
- vout_thread_t *p_another_vout;
- playlist_t *p_playlist = pl_Yield( p_vout );
+ /* XXX: should go in the destructor */
+ var_Destroy( p_vout, "intf-change" );
- /* Request thread destruction */
- p_vout->b_die = VLC_TRUE;
- vlc_thread_join( p_vout );
+ vlc_object_release( p_vout );
+}
- var_Destroy( p_vout, "intf-change" );
+static void vout_Destructor( vlc_object_t * p_this )
+{
+ vout_thread_t *p_vout = (vout_thread_t *)p_this;
- if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );
+ free( p_vout->psz_filter_chain );
+
+ config_ChainDestroy( p_vout->p_cfg );
- /* Free structure */
- vlc_object_destroy( p_vout );
#ifndef __APPLE__
+ vout_thread_t *p_another_vout;
+ playlist_t *p_playlist = pl_Yield( p_vout );
+
/* This is a dirty hack for mostly Linux, where there is no way to get the GUI
back if you closed it while playing video. This is solved in Mac OS X,
where we have this novelty called menubar, that will always allow you access
to the applications main functionality. They should try that on linux sometime */
- p_another_vout = vlc_object_find( p_playlist,
+ p_another_vout = vlc_object_find( p_this->p_libvlc,
VLC_OBJECT_VOUT, FIND_ANYWHERE );
if( p_another_vout == NULL )
{
{
vlc_object_release( p_another_vout );
}
-#endif
vlc_object_release( p_playlist );
+#endif
}
/*****************************************************************************
return;
}
+ if( p_vout->b_title_show )
+ DisplayTitleOnOSD( p_vout );
+
/*
* Main loop - it is not executed if an error occurred during
* initialization
}
i_loops++;
- if( i_loops % 20 == 0 )
- {
if( !p_input )
{
p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
i_displayed = i_lost = 0;
vlc_mutex_unlock( &p_input->p->counters.counters_lock );
}
- }
#if 0
p_vout->c_loops++;
if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
if( p_vout->b_vfilter_change == VLC_TRUE )
{
int i;
+ vlc_mutex_lock( &p_vout->vfilter_lock );
RemoveVideoFilters2( p_vout );
for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
{
p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
- p_vout->psz_vfilters[i], 0 );
+ p_vout->psz_vfilters[i],
+ VLC_TRUE );
if( p_vfilter->p_module )
{
msg_Err( p_vout, "no video filter found (%s)",
p_vout->psz_vfilters[i] );
vlc_object_detach( p_vfilter );
- vlc_object_destroy( p_vfilter );
+ vlc_object_release( p_vfilter );
}
}
p_vout->b_vfilter_change = VLC_FALSE;
+ vlc_mutex_unlock( &p_vout->vfilter_lock );
}
if( p_picture )
/* Destroy the locks */
vlc_mutex_destroy( &p_vout->picture_lock );
vlc_mutex_destroy( &p_vout->change_lock );
+ vlc_mutex_destroy( &p_vout->vfilter_lock );
/* Release the module */
if( p_vout && p_vout->p_module )
* vout_VarCallback: generic callback for intf variables
*****************************************************************************/
int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
- vlc_value_t old_value, vlc_value_t new_value,
- void * unused )
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
vlc_value_t val;
+ (void)psz_variable; (void)newval; (void)oldval; (void)p_data;
val.b_bool = VLC_TRUE;
var_Set( p_vout, "intf-change", val );
return VLC_SUCCESS;
vlc_object_release( p_this->p_input );
-#ifdef WIN32
- CloseHandle( p_this->thread_id );
-#endif
-
- vlc_object_destroy( p_this );
+ vlc_object_release( p_this );
}
/*****************************************************************************
char *psz_mode = newval.psz_string;
char *psz_filter, *psz_deinterlace = NULL;
+ (void)psz_cmd; (void)oldval; (void)p_data;
var_Get( p_vout, "vout-filter", &val );
psz_filter = val.psz_string;
val.psz_string = psz_filter;
var_Set( p_vout, "vout-filter", val );
- if( psz_filter ) free( psz_filter );
+ free( psz_filter );
return VLC_SUCCESS;
}
vout_thread_t *p_vout = (vout_thread_t *)p_this;
input_thread_t *p_input;
vlc_value_t val;
+ (void)psz_cmd; (void)oldval; (void)p_data;
p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
FIND_PARENT );
p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
config_ChainDestroy( p_cfg );
free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
+ p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL;
}
p_vout->i_vfilters_cfg = 0;
if( psz_vfilters && *psz_vfilters )
msg_Dbg( p_vout, "adding vfilter: %s",
p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
p_vout->i_vfilters_cfg++;
- if( psz_parser && psz_parser )
+ if( psz_parser && *psz_parser )
{
if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
{
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
+ (void)psz_cmd; (void)oldval; (void)p_data;
+ vlc_mutex_lock( &p_vout->vfilter_lock );
ParseVideoFilter2Chain( p_vout, newval.psz_string );
p_vout->b_vfilter_change = VLC_TRUE;
+ vlc_mutex_unlock( &p_vout->vfilter_lock );
return VLC_SUCCESS;
}
}
free( p_vout->pp_vfilters[i]->p_owner );
- vlc_object_destroy( p_vout->pp_vfilters[i] );
+ vlc_object_release( p_vout->pp_vfilters[i] );
}
p_vout->i_vfilters = 0;
}
+
+static void DisplayTitleOnOSD( vout_thread_t *p_vout )
+{
+ input_thread_t *p_input;
+ mtime_t i_now, i_stop;
+
+ p_input = (input_thread_t *)vlc_object_find( p_vout,
+ VLC_OBJECT_INPUT, FIND_ANYWHERE );
+ if( p_input )
+ {
+ i_now = mdate();
+ i_stop = i_now + (mtime_t)(p_vout->i_title_timeout * 1000);
+ char *psz_nowplaying =
+ input_item_GetNowPlaying( input_GetItem( p_input ) );
+ char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) );
+ char *psz_name = input_item_GetTitle( input_GetItem( p_input ) );
+ if( EMPTY_STR( psz_name ) )
+ {
+ free( psz_name );
+ psz_name = input_item_GetName( input_GetItem( p_input ) );
+ }
+ if( !EMPTY_STR( psz_nowplaying ) )
+ {
+ vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
+ psz_nowplaying, NULL,
+ p_vout->i_title_position,
+ 30 + p_vout->fmt_in.i_width
+ - p_vout->fmt_in.i_visible_width
+ - p_vout->fmt_in.i_x_offset,
+ 20 + p_vout->fmt_in.i_y_offset,
+ i_now, i_stop );
+ }
+ else if( !EMPTY_STR( psz_artist ) )
+ {
+ char *psz_string = NULL;
+ if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) != -1 )
+ {
+ vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
+ psz_string, NULL,
+ p_vout->i_title_position,
+ 30 + p_vout->fmt_in.i_width
+ - p_vout->fmt_in.i_visible_width
+ - p_vout->fmt_in.i_x_offset,
+ 20 + p_vout->fmt_in.i_y_offset,
+ i_now, i_stop );
+ free( psz_string );
+ }
+ }
+ else
+ {
+ vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
+ psz_name, NULL,
+ p_vout->i_title_position,
+ 30 + p_vout->fmt_in.i_width
+ - p_vout->fmt_in.i_visible_width
+ - p_vout->fmt_in.i_x_offset,
+ 20 + p_vout->fmt_in.i_y_offset,
+ i_now, i_stop );
+ }
+ vlc_object_release( p_input );
+ free( psz_artist );
+ free( psz_name );
+ free( psz_nowplaying );
+ }
+}
+