From: Clément Stenac Date: Wed, 9 Nov 2005 13:44:49 +0000 (+0000) Subject: Add a input_Read function that reads a stream in blocking or non-blocking mode and... X-Git-Tag: 0.9.0-test0~13357 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=cbc8fb034c62aa70c72277298357d701a5456604;p=vlc Add a input_Read function that reads a stream in blocking or non-blocking mode and cleans-up (Closes:#244) Still needs to be exported, but needs some thinking for pause/stop handling --- diff --git a/include/vlc_input.h b/include/vlc_input.h index 09f2218553..8901de1dca 100644 --- a/include/vlc_input.h +++ b/include/vlc_input.h @@ -411,6 +411,9 @@ struct input_thread_t VLC_EXPORT( input_thread_t *, __input_CreateThread, ( vlc_object_t *, input_item_t * ) ); #define input_Preparse(a,b) __input_Preparse(VLC_OBJECT(a),b) VLC_EXPORT( int, __input_Preparse, ( vlc_object_t *, input_item_t * ) ); + +#define input_Read(a,b,c) __input_Read(VLC_OBJECT(a),b, c) +VLC_EXPORT( void, __input_Read, ( vlc_object_t *, input_item_t *, vlc_bool_t ) ); VLC_EXPORT( void, input_StopThread, ( input_thread_t * ) ); VLC_EXPORT( void, input_DestroyThread, ( input_thread_t * ) ); diff --git a/include/vlc_symbols.h b/include/vlc_symbols.h index 0ab41c3881..7e95f60501 100644 --- a/include/vlc_symbols.h +++ b/include/vlc_symbols.h @@ -263,6 +263,7 @@ int net_Printf (vlc_object_t *p_this, int fd, v_socket_t *, const char *psz_fmt, int __vlc_thread_set_priority (vlc_object_t *, char *, int, int); int ACL_LoadFile (vlc_acl_t *p_acl, const char *path); void input_StopThread (input_thread_t *); +void __input_Read (vlc_object_t *, input_item_t *, vlc_bool_t); intf_thread_t * __intf_Create (vlc_object_t *, const char *); void aout_ChannelReorder (uint8_t *, int, int, const int *, int); int __var_DelCallback (vlc_object_t *, const char *, vlc_callback_t, void *); @@ -847,6 +848,7 @@ struct module_symbols_t int (*osd_ShowTextAbsolute_inner) (spu_t *, int, char *, text_style_t *, int, int, int, mtime_t, mtime_t); char * (*config_GetUserDir_inner) (void); char * (*FromUTF32_inner) (const wchar_t *); + void (*__input_Read_inner) (vlc_object_t *, input_item_t *, vlc_bool_t); }; # if defined (__PLUGIN__) # define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner @@ -1256,6 +1258,7 @@ struct module_symbols_t # define osd_ShowTextAbsolute (p_symbols)->osd_ShowTextAbsolute_inner # define config_GetUserDir (p_symbols)->config_GetUserDir_inner # define FromUTF32 (p_symbols)->FromUTF32_inner +# define __input_Read (p_symbols)->__input_Read_inner # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__) /****************************************************************** * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access. @@ -1668,6 +1671,7 @@ struct module_symbols_t ((p_symbols)->osd_ShowTextAbsolute_inner) = osd_ShowTextAbsolute; \ ((p_symbols)->config_GetUserDir_inner) = config_GetUserDir; \ ((p_symbols)->FromUTF32_inner) = FromUTF32; \ + ((p_symbols)->__input_Read_inner) = __input_Read; \ (p_symbols)->net_ConvertIPv4_deprecated = NULL; \ # endif /* __PLUGIN__ */ diff --git a/src/input/input.c b/src/input/input.c index 1c3001d098..2eb982744b 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -43,10 +43,13 @@ * Local prototypes *****************************************************************************/ static int Run ( input_thread_t *p_input ); +static int RunAndClean ( input_thread_t *p_input ); -static int Init ( input_thread_t *p_input, vlc_bool_t b_quick ); -static void Error( input_thread_t *p_input ); -static void End ( input_thread_t *p_input ); +static input_thread_t * Create ( vlc_object_t *, input_item_t *, vlc_bool_t ); +static int Init ( input_thread_t *p_input, vlc_bool_t b_quick ); +static void Error ( input_thread_t *p_input ); +static void End ( input_thread_t *p_input ); +static void MainLoop( input_thread_t *p_input ); static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * ); static void ControlReduce( input_thread_t * ); @@ -76,8 +79,6 @@ static void SlaveSeek( input_thread_t *p_input ); static vlc_meta_t *InputMetaUser( input_thread_t *p_input ); /***************************************************************************** - * input_CreateThread: creates a new input thread - ***************************************************************************** * This function creates a new input, and returns a pointer * to its description. On error, it returns NULL. * @@ -101,9 +102,8 @@ static vlc_meta_t *InputMetaUser( input_thread_t *p_input ); * TODO explain when Callback is called * TODO complete this list (?) *****************************************************************************/ -input_thread_t *__input_CreateThread( vlc_object_t *p_parent, - input_item_t *p_item ) - +static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, + vlc_bool_t b_quick ) { input_thread_t *p_input; /* thread descriptor */ vlc_value_t val; @@ -172,62 +172,81 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, input_ControlVarInit( p_input ); p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" ); - /* TODO */ - var_Get( p_input, "bookmarks", &val ); - if( val.psz_string ) - { - /* FIXME: have a common cfg parsing routine used by sout and others */ - char *psz_parser, *psz_start, *psz_end; - psz_parser = val.psz_string; - while( (psz_start = strchr( psz_parser, '{' ) ) ) - { - seekpoint_t *p_seekpoint = vlc_seekpoint_New(); - char backup; - psz_start++; - psz_end = strchr( psz_start, '}' ); - if( !psz_end ) break; - psz_parser = psz_end + 1; - backup = *psz_parser; - *psz_parser = 0; - *psz_end = ','; - - while( (psz_end = strchr( psz_start, ',' ) ) ) + if( !b_quick ) + { + var_Get( p_input, "bookmarks", &val ); + if( val.psz_string ) + { + /* FIXME: have a common cfg parsing routine used by sout and others */ + char *psz_parser, *psz_start, *psz_end; + psz_parser = val.psz_string; + while( (psz_start = strchr( psz_parser, '{' ) ) ) { - *psz_end = 0; - if( !strncmp( psz_start, "name=", 5 ) ) - { - p_seekpoint->psz_name = psz_start + 5; - } - else if( !strncmp( psz_start, "bytes=", 6 ) ) - { - p_seekpoint->i_byte_offset = atoll(psz_start + 6); + seekpoint_t *p_seekpoint = vlc_seekpoint_New(); + char backup; + psz_start++; + psz_end = strchr( psz_start, '}' ); + if( !psz_end ) break; + psz_parser = psz_end + 1; + backup = *psz_parser; + *psz_parser = 0; + *psz_end = ','; + while( (psz_end = strchr( psz_start, ',' ) ) ) + { + *psz_end = 0; + if( !strncmp( psz_start, "name=", 5 ) ) + { + p_seekpoint->psz_name = psz_start + 5; + } + else if( !strncmp( psz_start, "bytes=", 6 ) ) + { + p_seekpoint->i_byte_offset = atoll(psz_start + 6); + } + else if( !strncmp( psz_start, "time=", 5 ) ) + { + p_seekpoint->i_time_offset = atoll(psz_start + 5) * 1000000; + } + psz_start = psz_end + 1; } - else if( !strncmp( psz_start, "time=", 5 ) ) - { - p_seekpoint->i_time_offset = atoll(psz_start + 5) * 1000000; - } - psz_start = psz_end + 1; + msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd, + p_seekpoint->psz_name, p_seekpoint->i_byte_offset, + p_seekpoint->i_time_offset ); + input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint ); + vlc_seekpoint_Delete( p_seekpoint ); + *psz_parser = backup; } - msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd, - p_seekpoint->psz_name, p_seekpoint->i_byte_offset, - p_seekpoint->i_time_offset ); - input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint ); - vlc_seekpoint_Delete( p_seekpoint ); - *psz_parser = backup; + free( val.psz_string ); } - free( val.psz_string ); } /* Remove 'Now playing' info as it is probably outdated */ input_Control( p_input, INPUT_DEL_INFO, _("Meta-information"), - VLC_META_NOW_PLAYING ); + VLC_META_NOW_PLAYING ); + return p_input; +} + +/** + * Initialize an input thread and run it. You will need to monitor the thread to clean + * up after it is done + * + * \param p_parent a vlc_object + * \param p_item an input item + * \return a pointer to the spawned input thread + */ +input_thread_t *__input_CreateThread( vlc_object_t *p_parent, + input_item_t *p_item ) + +{ + input_thread_t *p_input; /* thread descriptor */ + + p_input = Create( p_parent, p_item, VLC_FALSE ); /* Now we can attach our new input */ vlc_object_attach( p_input, p_parent ); /* Create thread and wait for its readiness. */ if( vlc_thread_create( p_input, "input", Run, - VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) ) + VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) ) { msg_Err( p_input, "cannot create input thread" ); vlc_object_detach( p_input ); @@ -238,75 +257,55 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, return p_input; } -/***************************************************************************** - * input_PreParse: Lightweight input for playlist item preparsing - *****************************************************************************/ -int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item ) + +/** + * Initialize an input thread and run it. This thread will clean after himself, + * you can forget about it. It can work either in blocking or non-blocking mode + * + * \param p_parent a vlc_object + * \param p_item an input item + * \param b_block should we block until read is finished ? + */ +void __input_Read( vlc_object_t *p_parent, input_item_t *p_item, + vlc_bool_t b_block ) { input_thread_t *p_input; /* thread descriptor */ - int i; - /* Allocate descriptor */ - p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT ); - if( p_input == NULL ) + p_input = Create( p_parent, p_item, VLC_FALSE ); + /* Now we can attach our new input */ + vlc_object_attach( p_input, p_parent ); + + if( b_block ) { - msg_Err( p_parent, "out of memory" ); - return VLC_EGENERIC; + RunAndClean( p_input ); } - - /* Init Common fields */ - p_input->b_eof = VLC_FALSE; - p_input->b_can_pace_control = VLC_TRUE; - p_input->i_start = 0; - p_input->i_time = 0; - p_input->i_stop = 0; - p_input->i_title = 0; - p_input->title = NULL; - p_input->i_title_offset = p_input->i_seekpoint_offset = 0; - p_input->i_state = INIT_S; - p_input->i_rate = INPUT_RATE_DEFAULT; - p_input->i_bookmark = 0; - p_input->bookmark = NULL; - p_input->p_meta = NULL; - p_input->p_es_out = NULL; - p_input->p_sout = NULL; - p_input->b_out_pace_control = VLC_FALSE; - p_input->i_pts_delay = 0; - - /* Init Input fields */ - p_input->input.p_item = p_item; - p_input->input.p_access = NULL; - p_input->input.p_stream = NULL; - p_input->input.p_demux = NULL; - p_input->input.b_title_demux = VLC_FALSE; - p_input->input.i_title = 0; - p_input->input.title = NULL; - p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0; - p_input->input.b_can_pace_control = VLC_TRUE; - p_input->input.b_eof = VLC_FALSE; - p_input->input.i_cr_average = 0; - - /* No slave */ - p_input->i_slave = 0; - p_input->slave = NULL; - - /* Init control buffer */ - vlc_mutex_init( p_input, &p_input->lock_control ); - p_input->i_control = 0; - - /* Parse input options */ - vlc_mutex_lock( &p_item->lock ); - for( i = 0; i < p_item->i_options; i++ ) + else { - ParseOption( p_input, p_item->ppsz_options[i] ); + if( vlc_thread_create( p_input, "input", RunAndClean, + VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) ) + { + msg_Err( p_input, "cannot create input thread" ); + vlc_object_detach( p_input ); + vlc_object_destroy( p_input ); + return; + } } - vlc_mutex_unlock( &p_item->lock ); +} - /* Create Object Variables for private use only */ - input_ConfigVarInit( p_input ); - input_ControlVarInit( p_input ); +/** + * Initialize an input and initialize it to preparse the item + * This function is blocking. It will only accept to parse files + * + * \param p_parent a vlc_object_t + * \param p_item an input item + * \return VLC_SUCCESS or an error + */ +int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item ) +{ + input_thread_t *p_input; /* thread descriptor */ - p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" ); + /* Allocate descriptor */ + p_input = Create( p_parent, p_item, VLC_TRUE ); /* Now we can attach our new input */ vlc_object_attach( p_input, p_parent ); @@ -332,11 +331,11 @@ int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item ) return VLC_SUCCESS; } -/***************************************************************************** - * input_StopThread: mark an input thread as zombie - ***************************************************************************** - * This function should not return until the thread is effectively cancelled. - *****************************************************************************/ +/** + * Request a running input thread to stop and die + * + * \param the input thread to stop + */ void input_StopThread( input_thread_t *p_input ) { vlc_list_t *p_list; @@ -375,11 +374,12 @@ void input_StopThread( input_thread_t *p_input ) input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL ); } -/***************************************************************************** - * input_DestroyThread: mark an input thread as zombie - ***************************************************************************** - * This function should not return until the thread is effectively cancelled. - *****************************************************************************/ +/** + * Clean up a dead input thread + * This function does not return until the thread is effectively cancelled. + * + * \param the input thread to kill + */ void input_DestroyThread( input_thread_t *p_input ) { /* Join the thread */ @@ -394,16 +394,11 @@ void input_DestroyThread( input_thread_t *p_input ) /***************************************************************************** * Run: main thread loop - ***************************************************************************** - * Thread in charge of processing the network packets and demultiplexing. - * - * TODO: - * read subtitle support (XXX take care of spu-delay in the right way). - * multi-input support (XXX may be done with subs) + * This is the "normal" thread that spawns the input processing chain, + * reads the stream, cleans up and waits *****************************************************************************/ static int Run( input_thread_t *p_input ) { - int64_t i_intf_update = 0; /* Signal that the thread is launched */ vlc_thread_ready( p_input ); @@ -421,7 +416,88 @@ static int Run( input_thread_t *p_input ) return 0; } - /* Main loop */ + MainLoop( p_input ); + + if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof ) + { + /* We have finish to demux data but not to play them */ + while( !p_input->b_die ) + { + if( input_EsOutDecodersEmpty( p_input->p_es_out ) ) + break; + + msg_Dbg( p_input, "waiting decoder fifos to empty" ); + + msleep( INPUT_IDLE_SLEEP ); + } + + /* We have finished */ + p_input->b_eof = VLC_TRUE; + } + + /* Wait we are asked to die */ + if( !p_input->b_die ) + { + Error( p_input ); + } + + /* Clean up */ + End( p_input ); + + return 0; +} + +/***************************************************************************** + * RunAndClean: main thread loop + * This is the "just forget me" thread that spawns the input processing chain, + * reads the stream, cleans up and releases memory + *****************************************************************************/ +static int RunAndClean( input_thread_t *p_input ) +{ + /* Signal that the thread is launched */ + vlc_thread_ready( p_input ); + + if( Init( p_input, VLC_FALSE ) ) + { + /* If we failed, just exit */ + return 0; + } + + MainLoop( p_input ); + + if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof ) + { + /* We have finish to demux data but not to play them */ + while( !p_input->b_die ) + { + if( input_EsOutDecodersEmpty( p_input->p_es_out ) ) + break; + + msg_Dbg( p_input, "waiting decoder fifos to empty" ); + + msleep( INPUT_IDLE_SLEEP ); + } + /* We have finished */ + p_input->b_eof = VLC_TRUE; + } + + /* Clean up */ + End( p_input ); + + /* Release memory */ + vlc_object_detach( p_input ); + vlc_object_destroy( p_input ); + + return 0; +} + + +/***************************************************************************** + * Main loop: Fill buffers from access, and demux + *****************************************************************************/ +static void MainLoop( input_thread_t *p_input ) +{ + int64_t i_intf_update = 0; while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof ) { vlc_bool_t b_force_update = VLC_FALSE; @@ -570,34 +646,6 @@ static int Run( input_thread_t *p_input ) i_intf_update = mdate() + I64C(150000); } } - - if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof ) - { - /* We have finish to demux data but not to play them */ - while( !p_input->b_die ) - { - if( input_EsOutDecodersEmpty( p_input->p_es_out ) ) - break; - - msg_Dbg( p_input, "waiting decoder fifos to empty" ); - - msleep( INPUT_IDLE_SLEEP ); - } - - /* We have finished */ - p_input->b_eof = VLC_TRUE; - } - - /* Wait we are asked to die */ - if( !p_input->b_die ) - { - Error( p_input ); - } - - /* Clean up */ - End( p_input ); - - return 0; } diff --git a/src/libvlc.c b/src/libvlc.c index ec3efc2683..2e22fa4339 100644 --- a/src/libvlc.c +++ b/src/libvlc.c @@ -1219,7 +1219,7 @@ int VLC_AddTarget( int i_object, char const *psz_target, } /***************************************************************************** - * VLC_Play: play + * VLC_Play: play the playlist *****************************************************************************/ int VLC_Play( int i_object ) { diff --git a/src/playlist/playlist.c b/src/playlist/playlist.c index 8fc8c75de4..6e86f9445d 100644 --- a/src/playlist/playlist.c +++ b/src/playlist/playlist.c @@ -37,7 +37,7 @@ #define TITLE_ALL N_( "All items, unsorted" ) #undef PLAYLIST_PROFILE -#undef PLAYLIST_DEBUG +#define PLAYLIST_DEBUG 1 /***************************************************************************** * Local prototypes @@ -364,8 +364,8 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) i_view = (int)va_arg( args,int ); p_node = (playlist_item_t *)va_arg( args, playlist_item_t * ); p_item = (playlist_item_t *)va_arg( args, playlist_item_t * ); - if ( p_node == NULL || (p_item != NULL && p_item->input.psz_uri - == NULL )) + if ( p_node == NULL ) //|| (p_item != NULL && p_item->input.psz_uri + // == NULL )) { p_playlist->status.i_status = PLAYLIST_STOPPED; p_playlist->request.b_request = VLC_TRUE; @@ -378,10 +378,8 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) p_playlist->request.p_node = p_node; p_playlist->request.p_item = p_item; - /* If we select a node, play only it. - * If we select an item, continue */ - if( p_playlist->request.p_item == NULL || - ! p_playlist->request.p_node->i_flags & PLAYLIST_SKIP_FLAG ) + /* Don't go further if the node doesn't want to */ + if( ! p_playlist->request.p_node->i_flags & PLAYLIST_SKIP_FLAG ) { p_playlist->b_go_next = VLC_FALSE; } @@ -468,7 +466,7 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) break; default: - msg_Err( p_playlist, "unimplemented playlist query" ); + msg_Err( p_playlist, "unknown playlist query" ); return VLC_EBADVAR; break; } @@ -680,7 +678,6 @@ static void RunThread ( playlist_t *p_playlist ) * Get the next item to play */ p_item = NextItem( p_playlist ); - /* We must stop */ if( p_item == NULL ) { @@ -899,7 +896,7 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) /* TODO: use the "shuffled view" internally ? */ /* Random case. This is an exception: if request, but request is skip +- 1 * we don't go to next item but select a new random one. */ - if( b_random && + if( b_random && ( !p_playlist->request.b_request || ( p_playlist->request.b_request && ( p_playlist->request.p_item == NULL || p_playlist->request.i_skip == 1 || p_playlist->request.i_skip == -1 ) ) ) ) diff --git a/src/playlist/view.c b/src/playlist/view.c index b963d083e1..3d8c2365e9 100644 --- a/src/playlist/view.c +++ b/src/playlist/view.c @@ -29,7 +29,7 @@ #include "vlc_playlist.h" -#undef PLAYLIST_DEBUG +#define PLAYLIST_DEBUG 1 /************************************************************************ * Local prototypes