2003-06-29 14:05:49 +00:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2000-08-28 20:20:55 +00:00
# include <string.h>
# include <stdlib.h>
2002-11-14 02:49:16 +00:00
# include <signal.h>
2003-06-29 14:05:49 +00:00
# include <unistd.h>
2002-11-14 02:49:16 +00:00
# include <sys/wait.h>
2003-08-19 08:11:58 +00:00
# include <locale.h>
2002-03-30 17:06:45 +00:00
# include <gst/gst.h>
2000-01-30 10:44:33 +00:00
2003-07-01 03:45:19 +00:00
/* FIXME: This is just a temporary hack. We should have a better
* check for siginfo handling . */
# ifdef SA_SIGINFO
# define USE_SIGINFO
# endif
extern volatile gboolean glib_on_error_halt ;
static void fault_restore ( void ) ;
static void fault_spin ( void ) ;
static void sigint_restore ( void ) ;
2003-07-14 08:25:16 +00:00
static gint max_iterations = 0 ;
2001-12-24 12:30:09 +00:00
static guint64 iterations = 0 ;
static guint64 sum = 0 ;
2002-09-12 20:11:12 +00:00
static guint64 min = G_MAXINT64 ;
2001-12-24 12:30:09 +00:00
static guint64 max = 0 ;
2002-05-08 20:40:48 +00:00
static GstClock * s_clock ;
2003-07-01 03:45:19 +00:00
static GstElement * pipeline ;
gboolean caught_intr = FALSE ;
2001-12-24 12:30:09 +00:00
2001-07-23 00:57:06 +00:00
gboolean
idle_func ( gpointer data )
{
2001-12-24 12:30:09 +00:00
gboolean busy ;
2002-03-30 17:06:45 +00:00
GTimeVal tfthen , tfnow ;
GstClockTimeDiff diff ;
2001-12-24 12:30:09 +00:00
2002-05-08 20:40:48 +00:00
if ( s_clock ) {
2003-02-01 20:29:27 +00:00
//g_print ("%" G_GINT64_FORMAT "\n", gst_clock_get_time (s_clock));
2002-05-08 20:40:48 +00:00
}
2002-03-30 17:06:45 +00:00
g_get_current_time ( & tfthen ) ;
2001-12-24 12:30:09 +00:00
busy = gst_bin_iterate ( GST_BIN ( data ) ) ;
iterations + + ;
2002-03-30 17:06:45 +00:00
g_get_current_time ( & tfnow ) ;
2001-12-24 12:30:09 +00:00
2002-03-30 17:06:45 +00:00
diff = GST_TIMEVAL_TO_TIME ( tfnow ) -
GST_TIMEVAL_TO_TIME ( tfthen ) ;
2001-12-24 12:30:09 +00:00
sum + = diff ;
min = MIN ( min , diff ) ;
max = MAX ( max , diff ) ;
2003-07-14 08:25:16 +00:00
if ( ! busy | | caught_intr | | ( max_iterations > 0 & & iterations > = max_iterations ) ) {
2001-12-14 18:11:52 +00:00
gst_main_quit ( ) ;
2003-02-01 20:29:27 +00:00
g_print ( " execution ended after % " G_GUINT64_FORMAT " iterations (sum % " G_GUINT64_FORMAT " ns, average % " G_GUINT64_FORMAT " ns, min % " G_GUINT64_FORMAT " ns, max % " G_GUINT64_FORMAT " ns) \n " ,
2001-12-24 12:30:09 +00:00
iterations , sum , sum / iterations , min , max ) ;
2001-10-17 10:21:27 +00:00
}
2001-12-24 12:30:09 +00:00
return busy ;
2001-07-23 00:57:06 +00:00
}
2003-02-10 20:32:32 +00:00
# ifndef GST_DISABLE_LOADSAVE
2002-01-14 07:18:43 +00:00
static GstElement *
2002-02-06 16:35:16 +00:00
xmllaunch_parse_cmdline ( const gchar * * argv )
2002-01-14 07:18:43 +00:00
{
2002-01-15 05:57:14 +00:00
GstElement * pipeline = NULL , * e ;
2002-01-14 07:18:43 +00:00
GstXML * xml ;
gboolean err ;
2002-01-15 05:57:14 +00:00
const gchar * arg ;
gchar * element , * property , * value ;
2002-01-14 07:18:43 +00:00
GList * l ;
2002-01-15 05:57:14 +00:00
gint i = 0 ;
2002-01-14 07:18:43 +00:00
2002-01-15 05:57:14 +00:00
if ( ! ( arg = argv [ 0 ] ) ) {
2002-02-06 16:35:16 +00:00
g_print ( " usage: gst-xmllaunch <file.xml> [ element.property=value ... ] \n " ) ;
2002-01-14 07:18:43 +00:00
exit ( 1 ) ;
}
xml = gst_xml_new ( ) ;
2002-01-15 05:57:14 +00:00
err = gst_xml_parse_file ( xml , arg , NULL ) ;
2002-01-14 07:18:43 +00:00
if ( err ! = TRUE ) {
2002-01-15 05:57:14 +00:00
fprintf ( stderr , " ERROR: parse of xml file '%s' failed \n " , arg ) ;
2002-01-14 07:18:43 +00:00
exit ( 1 ) ;
}
l = gst_xml_get_topelements ( xml ) ;
2002-01-15 05:57:14 +00:00
if ( ! l ) {
fprintf ( stderr , " ERROR: no toplevel pipeline element in file '%s' \n " , arg ) ;
exit ( 1 ) ;
}
if ( l - > next )
g_warning ( " only one toplevel element is supported at this time " ) ;
pipeline = GST_ELEMENT ( l - > data ) ;
while ( ( arg = argv [ + + i ] ) ) {
element = g_strdup ( arg ) ;
property = strchr ( element , ' . ' ) ;
value = strchr ( element , ' = ' ) ;
if ( ! ( element < property & & property < value ) ) {
fprintf ( stderr , " ERROR: could not parse command line argument %d: %s " , i , element ) ;
g_free ( element ) ;
exit ( 1 ) ;
}
* property + + = ' \0 ' ;
* value + + = ' \0 ' ;
e = gst_bin_get_by_name ( GST_BIN ( pipeline ) , element ) ;
if ( ! e ) {
g_warning ( " element named '%s' not found " , element ) ;
} else {
gst_util_set_object_arg ( G_OBJECT ( e ) , property , value ) ;
}
2002-01-15 05:58:45 +00:00
g_free ( element ) ;
2002-01-15 05:57:14 +00:00
}
2002-01-14 07:18:43 +00:00
if ( ! l )
return NULL ;
else
return l - > data ;
}
2003-02-10 20:32:32 +00:00
# endif
2002-01-14 07:18:43 +00:00
2003-04-13 21:11:12 +00:00
# ifndef USE_SIGINFO
2002-12-19 20:59:48 +00:00
static void
2003-04-13 21:11:12 +00:00
fault_handler_sighandler ( int signum )
2002-11-14 02:49:16 +00:00
{
2003-04-13 21:11:12 +00:00
fault_restore ( ) ;
2002-11-14 02:49:16 +00:00
2003-08-19 05:43:55 +00:00
switch ( signum ) {
case SIGSEGV :
g_print ( " Caught SIGSEGV \n " ) ;
break ;
case SIGQUIT :
g_print ( " Caught SIGQUIT \n " ) ;
break ;
default :
g_print ( " signo: %d \n " , signum ) ;
break ;
2003-04-13 21:11:12 +00:00
}
fault_spin ( ) ;
}
# else
static void
fault_handler_sigaction ( int signum , siginfo_t * si , void * misc )
{
2002-12-19 20:59:48 +00:00
fault_restore ( ) ;
2002-11-14 02:49:16 +00:00
2003-08-19 05:43:55 +00:00
switch ( si - > si_signo ) {
case SIGSEGV :
g_print ( " Caught SIGSEGV accessing address %p \n " , si - > si_addr ) ;
break ;
case SIGQUIT :
g_print ( " Caught SIGQUIT \n " ) ;
break ;
default :
g_print ( " signo: %d \n " , si - > si_signo ) ;
g_print ( " errno: %d \n " , si - > si_errno ) ;
g_print ( " code: %d \n " , si - > si_code ) ;
break ;
2002-12-19 20:59:48 +00:00
}
2002-11-14 02:49:16 +00:00
2003-04-13 21:11:12 +00:00
fault_spin ( ) ;
}
# endif
static void
fault_spin ( void )
{
int spinning = TRUE ;
2002-12-19 20:59:48 +00:00
glib_on_error_halt = FALSE ;
g_on_error_stack_trace ( " gst-launch " ) ;
2002-11-14 02:49:16 +00:00
2002-12-19 20:59:48 +00:00
wait ( NULL ) ;
2002-11-14 02:49:16 +00:00
2002-12-19 20:59:48 +00:00
/* FIXME how do we know if we were run by libtool? */
g_print ( " Spinning. Please run 'gdb gst-launch %d' to continue debugging, "
" Ctrl-C to quit, or Ctrl- \\ to dump core. \n " ,
2003-06-29 14:05:49 +00:00
( gint ) getpid ( ) ) ;
while ( spinning ) g_usleep ( 1000000 ) ;
2002-11-14 02:49:16 +00:00
}
2002-12-19 20:59:48 +00:00
static void
fault_restore ( void )
2002-11-14 02:49:16 +00:00
{
2002-12-19 20:59:48 +00:00
struct sigaction action ;
2002-11-14 02:49:16 +00:00
2002-12-19 20:59:48 +00:00
memset ( & action , 0 , sizeof ( action ) ) ;
action . sa_handler = SIG_DFL ;
2002-11-14 02:49:16 +00:00
2003-08-19 05:43:55 +00:00
sigaction ( SIGSEGV , & action , NULL ) ;
sigaction ( SIGQUIT , & action , NULL ) ;
2002-11-14 02:49:16 +00:00
}
2002-12-19 20:59:48 +00:00
static void
fault_setup ( void )
2002-11-14 02:49:16 +00:00
{
2002-12-19 20:59:48 +00:00
struct sigaction action ;
2002-11-14 02:49:16 +00:00
2002-12-19 20:59:48 +00:00
memset ( & action , 0 , sizeof ( action ) ) ;
2003-04-13 21:11:12 +00:00
# ifdef USE_SIGINFO
action . sa_sigaction = fault_handler_sigaction ;
2002-12-19 20:59:48 +00:00
action . sa_flags = SA_SIGINFO ;
2003-04-13 21:11:12 +00:00
# else
action . sa_handler = fault_handler_sighandler ;
# endif
2002-11-14 02:49:16 +00:00
2002-12-19 20:59:48 +00:00
sigaction ( SIGSEGV , & action , NULL ) ;
sigaction ( SIGQUIT , & action , NULL ) ;
2002-11-14 02:49:16 +00:00
}
2003-11-24 02:09:23 +00:00
static void
print_tag ( const GstTagList * list , const gchar * tag , gpointer unused )
{
gint i , count ;
count = gst_tag_list_get_tag_size ( list , tag ) ;
for ( i = 0 ; i < count ; i + + ) {
2003-11-24 22:10:06 +00:00
gchar * str ;
2003-11-24 02:09:23 +00:00
2003-11-24 22:10:06 +00:00
if ( gst_tag_get_type ( tag ) = = G_TYPE_STRING ) {
g_assert ( gst_tag_list_get_string_index ( list , tag , i , & str ) ) ;
} else {
str = g_strdup_value_contents (
gst_tag_list_get_value_index ( list , tag , i ) ) ;
}
2003-11-24 02:09:23 +00:00
if ( i = = 0 ) {
g_print ( " %15s: %s \n " , gst_tag_get_nick ( tag ) , str ) ;
} else {
g_print ( " : %s \n " , str ) ;
}
g_free ( str ) ;
}
}
static void
found_tag ( GObject * pipeline , GstElement * source , GstTagList * tags )
{
g_print ( " FOUND TAG : element \" %s \" \n " , GST_STR_NULL ( GST_ELEMENT_NAME ( source ) ) ) ;
gst_tag_list_foreach ( tags , print_tag , NULL ) ;
}
2003-07-01 03:45:19 +00:00
/* we only use sighandler here because the registers are not important */
static void
sigint_handler_sighandler ( int signum )
{
g_print ( " Caught interrupt \n " ) ;
sigint_restore ( ) ;
caught_intr = TRUE ;
}
static void
sigint_setup ( void )
{
struct sigaction action ;
memset ( & action , 0 , sizeof ( action ) ) ;
action . sa_handler = sigint_handler_sighandler ;
sigaction ( SIGINT , & action , NULL ) ;
}
static void
sigint_restore ( void )
{
struct sigaction action ;
memset ( & action , 0 , sizeof ( action ) ) ;
action . sa_handler = SIG_DFL ;
2003-08-19 05:43:55 +00:00
sigaction ( SIGINT , & action , NULL ) ;
}
static void
play_handler ( int signum )
{
switch ( signum ) {
case SIGUSR1 :
g_print ( " Caught SIGUSR1 - Play request \n " ) ;
gst_element_set_state ( pipeline , GST_STATE_PLAYING ) ;
break ;
case SIGUSR2 :
g_print ( " Caught SIGUSR2 - Stop request \n " ) ;
gst_element_set_state ( pipeline , GST_STATE_NULL ) ;
break ;
}
}
static void
play_signal_setup ( void )
{
struct sigaction action ;
memset ( & action , 0 , sizeof ( action ) ) ;
action . sa_handler = play_handler ;
sigaction ( SIGUSR1 , & action , NULL ) ;
sigaction ( SIGUSR2 , & action , NULL ) ;
2003-07-01 03:45:19 +00:00
}
2001-01-21 16:06:42 +00:00
int
main ( int argc , char * argv [ ] )
{
2003-04-04 20:33:05 +00:00
gint i , j ;
2002-04-16 14:45:53 +00:00
/* options */
2003-02-03 20:30:59 +00:00
gboolean verbose = FALSE ;
2003-11-24 02:09:23 +00:00
gboolean tags = FALSE ;
2002-12-30 18:29:16 +00:00
gboolean no_fault = FALSE ;
2003-02-02 19:22:31 +00:00
gboolean trace = FALSE ;
2002-04-07 23:32:16 +00:00
gchar * savefile = NULL ;
2002-04-16 14:45:53 +00:00
gchar * exclude_args = NULL ;
2002-02-24 17:08:07 +00:00
struct poptOption options [ ] = {
2003-11-24 02:09:23 +00:00
{ " tags " , ' t ' , POPT_ARG_NONE | POPT_ARGFLAG_STRIP , & tags , 0 ,
" output tags (also known as metadata) " , NULL } ,
2003-02-03 20:30:59 +00:00
{ " verbose " , ' v ' , POPT_ARG_NONE | POPT_ARGFLAG_STRIP , & verbose , 0 ,
" output status information and property notifications " , NULL } ,
2002-04-16 14:45:53 +00:00
{ " exclude " , ' X ' , POPT_ARG_STRING | POPT_ARGFLAG_STRIP , & exclude_args , 0 ,
" do not output status information of TYPE " , " TYPE1,TYPE2,... " } ,
2003-02-10 20:32:32 +00:00
# ifndef GST_DISABLE_LOADSAVE
2002-04-07 23:32:16 +00:00
{ " output " , ' o ' , POPT_ARG_STRING | POPT_ARGFLAG_STRIP , & savefile , 0 ,
" save xml representation of pipeline to FILE and exit " , " FILE " } ,
2003-02-10 20:32:32 +00:00
# endif
2003-07-01 03:45:19 +00:00
{ " no-fault " , ' f ' , POPT_ARG_NONE | POPT_ARGFLAG_STRIP , & no_fault , 0 ,
2002-12-30 18:29:16 +00:00
" Do not install a fault handler " , NULL } ,
2003-11-24 02:09:23 +00:00
{ " trace " , ' T ' , POPT_ARG_NONE | POPT_ARGFLAG_STRIP , & trace , 0 ,
2003-02-02 19:22:31 +00:00
" print alloc trace if enabled at compile time " , NULL } ,
2003-07-14 08:25:16 +00:00
{ " iterations " , ' i ' , POPT_ARG_INT | POPT_ARGFLAG_STRIP , & max_iterations , 0 ,
" number of times to iterate pipeline " , NULL } ,
2002-02-24 17:08:07 +00:00
POPT_TABLEEND
} ;
2002-01-15 05:57:14 +00:00
gchar * * argvn ;
2002-04-07 23:32:16 +00:00
GError * error = NULL ;
2002-11-20 21:29:29 +00:00
gint res = 0 ;
2001-01-09 04:39:35 +00:00
2001-12-14 14:28:27 +00:00
free ( malloc ( 8 ) ) ; /* -lefence */
2003-08-19 08:11:58 +00:00
setlocale ( LC_ALL , " " ) ;
2003-02-02 19:22:31 +00:00
gst_alloc_trace_set_flags_all ( GST_ALLOC_TRACE_LIVE ) ;
2003-01-07 20:49:46 +00:00
gst_init_with_popt_table ( & argc , & argv , options ) ;
2003-04-04 20:33:05 +00:00
/* FIXpopt: strip short args, too. We do it ourselves for now */
j = 1 ;
for ( i = 1 ; i < argc ; i + + ) {
if ( * ( argv [ i ] ) = = ' - ' ) {
if ( strlen ( argv [ i ] ) = = 2 ) {
gchar * c = argv [ i ] ;
c + + ;
if ( * c = = ' X ' | | * c = = ' o ' ) {
i + + ;
}
}
} else {
argv [ j ] = argv [ i ] ;
j + + ;
}
}
argc = j ;
2003-01-07 20:49:46 +00:00
2002-12-30 18:29:16 +00:00
if ( ! no_fault )
fault_setup ( ) ;
2003-07-01 03:45:19 +00:00
sigint_setup ( ) ;
2003-08-19 05:43:55 +00:00
play_signal_setup ( ) ;
2002-01-14 04:09:56 +00:00
2003-02-03 20:30:59 +00:00
if ( trace ) {
if ( ! gst_alloc_trace_available ( ) ) {
g_warning ( " trace not available (recompile with trace enabled) " ) ;
}
2003-02-02 19:22:31 +00:00
gst_alloc_trace_print_all ( ) ;
2003-02-03 20:30:59 +00:00
}
2003-02-02 19:22:31 +00:00
2002-01-15 05:57:14 +00:00
/* make a null-terminated version of argv */
2002-04-07 23:32:16 +00:00
argvn = g_new0 ( char * , argc ) ;
2002-01-15 05:57:14 +00:00
memcpy ( argvn , argv + 1 , sizeof ( char * ) * ( argc - 1 ) ) ;
2003-02-10 20:32:32 +00:00
# ifndef GST_DISABLE_LOADSAVE
2002-01-14 04:09:56 +00:00
if ( strstr ( argv [ 0 ] , " gst-xmllaunch " ) ) {
2002-04-07 23:32:16 +00:00
pipeline = xmllaunch_parse_cmdline ( ( const gchar * * ) argvn ) ;
2003-02-10 20:32:32 +00:00
}
else
# endif
{
2002-04-07 23:32:16 +00:00
pipeline = ( GstElement * ) gst_parse_launchv ( ( const gchar * * ) argvn , & error ) ;
2001-06-02 18:26:25 +00:00
}
2002-09-17 21:32:26 +00:00
g_free ( argvn ) ;
2001-06-02 18:26:25 +00:00
2002-01-14 04:09:56 +00:00
if ( ! pipeline ) {
2003-04-10 01:40:03 +00:00
if ( error ) {
2002-04-07 23:32:16 +00:00
fprintf ( stderr , " ERROR: pipeline could not be constructed: %s \n " , error - > message ) ;
2003-04-10 01:40:03 +00:00
g_error_free ( error ) ;
} else {
2002-04-07 23:32:16 +00:00
fprintf ( stderr , " ERROR: pipeline could not be constructed \n " ) ;
2003-04-10 01:40:03 +00:00
}
2001-10-27 13:44:18 +00:00
exit ( 1 ) ;
2003-04-10 01:40:03 +00:00
} else if ( error ) {
fprintf ( stderr , " WARNING: erroneous pipeline: %s \n Trying to run anyway \n " , error - > message ) ;
g_error_free ( error ) ;
2001-10-27 13:44:18 +00:00
}
2002-01-14 04:09:56 +00:00
2003-02-03 20:30:59 +00:00
if ( verbose ) {
2002-04-17 00:18:04 +00:00
gchar * * exclude_list = exclude_args ? g_strsplit ( exclude_args , " , " , 0 ) : NULL ;
2002-07-30 19:25:24 +00:00
g_signal_connect ( pipeline , " deep_notify " , G_CALLBACK ( gst_element_default_deep_notify ) , exclude_list ) ;
2002-04-16 14:45:53 +00:00
}
2003-11-24 02:09:23 +00:00
if ( tags ) {
g_signal_connect ( pipeline , " found-tag " , G_CALLBACK ( found_tag ) , NULL ) ;
}
2002-07-30 19:25:24 +00:00
g_signal_connect ( pipeline , " error " , G_CALLBACK ( gst_element_default_error ) , NULL ) ;
2002-02-06 07:10:37 +00:00
2001-10-17 10:21:27 +00:00
# ifndef GST_DISABLE_LOADSAVE
2002-04-07 23:32:16 +00:00
if ( savefile ) {
2002-01-11 15:49:47 +00:00
gst_xml_write_file ( GST_ELEMENT ( pipeline ) , fopen ( savefile , " w " ) ) ;
2001-06-19 10:34:15 +00:00
}
2001-10-17 10:21:27 +00:00
# endif
2002-01-14 04:09:56 +00:00
2002-04-07 23:32:16 +00:00
if ( ! savefile ) {
2003-04-28 17:01:44 +00:00
if ( ! GST_IS_BIN ( pipeline ) ) {
GstElement * real_pipeline = gst_element_factory_make ( " pipeline " , NULL ) ;
if ( real_pipeline = = NULL ) {
fprintf ( stderr , " ERROR: The pipeline element wasn't found. \n " ) ;
exit ( 1 ) ;
}
gst_bin_add ( GST_BIN ( real_pipeline ) , pipeline ) ;
pipeline = real_pipeline ;
}
2002-07-08 19:23:59 +00:00
2001-06-19 10:34:15 +00:00
fprintf ( stderr , " RUNNING pipeline \n " ) ;
2002-12-08 20:08:39 +00:00
if ( gst_element_set_state ( pipeline , GST_STATE_PLAYING ) = = GST_STATE_FAILURE ) {
2001-12-12 18:31:25 +00:00
fprintf ( stderr , " pipeline doesn't want to play \n " ) ;
2002-11-20 21:29:29 +00:00
res = - 1 ;
goto end ;
2001-12-12 18:31:25 +00:00
}
2001-01-21 16:06:42 +00:00
2002-05-08 20:40:48 +00:00
s_clock = gst_bin_get_clock ( GST_BIN ( pipeline ) ) ;
2002-03-30 19:31:14 +00:00
if ( ! GST_FLAG_IS_SET ( GST_OBJECT ( pipeline ) , GST_BIN_SELF_SCHEDULABLE ) ) {
2002-03-18 04:41:37 +00:00
g_idle_add ( idle_func , pipeline ) ;
gst_main ( ) ;
} else {
2002-03-30 19:31:14 +00:00
g_print ( " waiting for the state change... \n " ) ;
gst_element_wait_state_change ( pipeline ) ;
2002-07-30 19:25:24 +00:00
g_print ( " got the state change... \n " ) ;
2002-03-18 04:41:37 +00:00
}
2001-01-04 10:47:39 +00:00
2001-06-19 10:34:15 +00:00
gst_element_set_state ( pipeline , GST_STATE_NULL ) ;
}
2002-11-20 21:29:29 +00:00
end :
2001-12-19 19:23:51 +00:00
gst_object_unref ( GST_OBJECT ( pipeline ) ) ;
2000-08-28 20:20:55 +00:00
2003-02-02 19:22:31 +00:00
if ( trace )
gst_alloc_trace_print_all ( ) ;
2002-11-20 21:29:29 +00:00
return res ;
2000-01-30 10:44:33 +00:00
}