Commit cbc8fb03 authored by Clément Stenac's avatar Clément Stenac

Add a input_Read function that reads a stream in blocking or non-blocking mode...

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
parent 8d65083c
...@@ -411,6 +411,9 @@ struct input_thread_t ...@@ -411,6 +411,9 @@ struct input_thread_t
VLC_EXPORT( input_thread_t *, __input_CreateThread, ( vlc_object_t *, input_item_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) #define input_Preparse(a,b) __input_Preparse(VLC_OBJECT(a),b)
VLC_EXPORT( int, __input_Preparse, ( vlc_object_t *, input_item_t * ) ); 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_StopThread, ( input_thread_t * ) );
VLC_EXPORT( void, input_DestroyThread, ( input_thread_t * ) ); VLC_EXPORT( void, input_DestroyThread, ( input_thread_t * ) );
......
...@@ -263,6 +263,7 @@ int net_Printf (vlc_object_t *p_this, int fd, v_socket_t *, const char *psz_fmt, ...@@ -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 __vlc_thread_set_priority (vlc_object_t *, char *, int, int);
int ACL_LoadFile (vlc_acl_t *p_acl, const char *path); int ACL_LoadFile (vlc_acl_t *p_acl, const char *path);
void input_StopThread (input_thread_t *); 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 *); intf_thread_t * __intf_Create (vlc_object_t *, const char *);
void aout_ChannelReorder (uint8_t *, int, int, const int *, int); void aout_ChannelReorder (uint8_t *, int, int, const int *, int);
int __var_DelCallback (vlc_object_t *, const char *, vlc_callback_t, void *); int __var_DelCallback (vlc_object_t *, const char *, vlc_callback_t, void *);
...@@ -847,6 +848,7 @@ struct module_symbols_t ...@@ -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); int (*osd_ShowTextAbsolute_inner) (spu_t *, int, char *, text_style_t *, int, int, int, mtime_t, mtime_t);
char * (*config_GetUserDir_inner) (void); char * (*config_GetUserDir_inner) (void);
char * (*FromUTF32_inner) (const wchar_t *); char * (*FromUTF32_inner) (const wchar_t *);
void (*__input_Read_inner) (vlc_object_t *, input_item_t *, vlc_bool_t);
}; };
# if defined (__PLUGIN__) # if defined (__PLUGIN__)
# define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner # define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner
...@@ -1256,6 +1258,7 @@ struct module_symbols_t ...@@ -1256,6 +1258,7 @@ struct module_symbols_t
# define osd_ShowTextAbsolute (p_symbols)->osd_ShowTextAbsolute_inner # define osd_ShowTextAbsolute (p_symbols)->osd_ShowTextAbsolute_inner
# define config_GetUserDir (p_symbols)->config_GetUserDir_inner # define config_GetUserDir (p_symbols)->config_GetUserDir_inner
# define FromUTF32 (p_symbols)->FromUTF32_inner # define FromUTF32 (p_symbols)->FromUTF32_inner
# define __input_Read (p_symbols)->__input_Read_inner
# elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__) # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__)
/****************************************************************** /******************************************************************
* STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access. * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access.
...@@ -1668,6 +1671,7 @@ struct module_symbols_t ...@@ -1668,6 +1671,7 @@ struct module_symbols_t
((p_symbols)->osd_ShowTextAbsolute_inner) = osd_ShowTextAbsolute; \ ((p_symbols)->osd_ShowTextAbsolute_inner) = osd_ShowTextAbsolute; \
((p_symbols)->config_GetUserDir_inner) = config_GetUserDir; \ ((p_symbols)->config_GetUserDir_inner) = config_GetUserDir; \
((p_symbols)->FromUTF32_inner) = FromUTF32; \ ((p_symbols)->FromUTF32_inner) = FromUTF32; \
((p_symbols)->__input_Read_inner) = __input_Read; \
(p_symbols)->net_ConvertIPv4_deprecated = NULL; \ (p_symbols)->net_ConvertIPv4_deprecated = NULL; \
# endif /* __PLUGIN__ */ # endif /* __PLUGIN__ */
......
...@@ -43,10 +43,13 @@ ...@@ -43,10 +43,13 @@
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static int Run ( input_thread_t *p_input ); static int Run ( input_thread_t *p_input );
static int RunAndClean ( 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 int Init ( input_thread_t *p_input, vlc_bool_t b_quick );
static void Error( input_thread_t *p_input ); static void Error ( input_thread_t *p_input );
static void End ( 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 inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
static void ControlReduce( input_thread_t * ); static void ControlReduce( input_thread_t * );
...@@ -76,8 +79,6 @@ static void SlaveSeek( input_thread_t *p_input ); ...@@ -76,8 +79,6 @@ static void SlaveSeek( input_thread_t *p_input );
static vlc_meta_t *InputMetaUser( 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 * This function creates a new input, and returns a pointer
* to its description. On error, it returns NULL. * to its description. On error, it returns NULL.
* *
...@@ -101,9 +102,8 @@ static vlc_meta_t *InputMetaUser( input_thread_t *p_input ); ...@@ -101,9 +102,8 @@ static vlc_meta_t *InputMetaUser( input_thread_t *p_input );
* TODO explain when Callback is called * TODO explain when Callback is called
* TODO complete this list (?) * TODO complete this list (?)
*****************************************************************************/ *****************************************************************************/
input_thread_t *__input_CreateThread( vlc_object_t *p_parent, static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
input_item_t *p_item ) vlc_bool_t b_quick )
{ {
input_thread_t *p_input; /* thread descriptor */ input_thread_t *p_input; /* thread descriptor */
vlc_value_t val; vlc_value_t val;
...@@ -172,7 +172,8 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, ...@@ -172,7 +172,8 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
input_ControlVarInit( p_input ); input_ControlVarInit( p_input );
p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" ); p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
/* TODO */ if( !b_quick )
{
var_Get( p_input, "bookmarks", &val ); var_Get( p_input, "bookmarks", &val );
if( val.psz_string ) if( val.psz_string )
{ {
...@@ -190,7 +191,6 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, ...@@ -190,7 +191,6 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
backup = *psz_parser; backup = *psz_parser;
*psz_parser = 0; *psz_parser = 0;
*psz_end = ','; *psz_end = ',';
while( (psz_end = strchr( psz_start, ',' ) ) ) while( (psz_end = strchr( psz_start, ',' ) ) )
{ {
*psz_end = 0; *psz_end = 0;
...@@ -217,11 +217,30 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, ...@@ -217,11 +217,30 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
} }
free( val.psz_string ); free( val.psz_string );
} }
}
/* Remove 'Now playing' info as it is probably outdated */ /* Remove 'Now playing' info as it is probably outdated */
input_Control( p_input, INPUT_DEL_INFO, _("Meta-information"), 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 */ /* Now we can attach our new input */
vlc_object_attach( p_input, p_parent ); vlc_object_attach( p_input, p_parent );
...@@ -238,75 +257,55 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, ...@@ -238,75 +257,55 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
return p_input; return p_input;
} }
/*****************************************************************************
* input_PreParse: Lightweight input for playlist item preparsing /**
*****************************************************************************/ * Initialize an input thread and run it. This thread will clean after himself,
int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item ) * 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 */ input_thread_t *p_input; /* thread descriptor */
int i;
/* Allocate descriptor */ p_input = Create( p_parent, p_item, VLC_FALSE );
p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT ); /* Now we can attach our new input */
if( p_input == NULL ) vlc_object_attach( p_input, p_parent );
if( b_block )
{ {
msg_Err( p_parent, "out of memory" ); RunAndClean( p_input );
return VLC_EGENERIC;
} }
else
/* 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++ )
{ {
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 ); * Initialize an input and initialize it to preparse the item
input_ControlVarInit( p_input ); * 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 */ /* Now we can attach our new input */
vlc_object_attach( p_input, p_parent ); vlc_object_attach( p_input, p_parent );
...@@ -332,11 +331,11 @@ int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item ) ...@@ -332,11 +331,11 @@ int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/***************************************************************************** /**
* input_StopThread: mark an input thread as zombie * Request a running input thread to stop and die
***************************************************************************** *
* This function should not return until the thread is effectively cancelled. * \param the input thread to stop
*****************************************************************************/ */
void input_StopThread( input_thread_t *p_input ) void input_StopThread( input_thread_t *p_input )
{ {
vlc_list_t *p_list; vlc_list_t *p_list;
...@@ -375,11 +374,12 @@ void input_StopThread( input_thread_t *p_input ) ...@@ -375,11 +374,12 @@ void input_StopThread( input_thread_t *p_input )
input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL ); input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
} }
/***************************************************************************** /**
* input_DestroyThread: mark an input thread as zombie * Clean up a dead input thread
***************************************************************************** * This function does not return until the thread is effectively cancelled.
* This function should not return until the thread is effectively cancelled. *
*****************************************************************************/ * \param the input thread to kill
*/
void input_DestroyThread( input_thread_t *p_input ) void input_DestroyThread( input_thread_t *p_input )
{ {
/* Join the thread */ /* Join the thread */
...@@ -394,16 +394,11 @@ void input_DestroyThread( input_thread_t *p_input ) ...@@ -394,16 +394,11 @@ void input_DestroyThread( input_thread_t *p_input )
/***************************************************************************** /*****************************************************************************
* Run: main thread loop * Run: main thread loop
***************************************************************************** * This is the "normal" thread that spawns the input processing chain,
* Thread in charge of processing the network packets and demultiplexing. * reads the stream, cleans up and waits
*
* TODO:
* read subtitle support (XXX take care of spu-delay in the right way).
* multi-input support (XXX may be done with subs)
*****************************************************************************/ *****************************************************************************/
static int Run( input_thread_t *p_input ) static int Run( input_thread_t *p_input )
{ {
int64_t i_intf_update = 0;
/* Signal that the thread is launched */ /* Signal that the thread is launched */
vlc_thread_ready( p_input ); vlc_thread_ready( p_input );
...@@ -421,7 +416,88 @@ static int Run( input_thread_t *p_input ) ...@@ -421,7 +416,88 @@ static int Run( input_thread_t *p_input )
return 0; 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 ) while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof )
{ {
vlc_bool_t b_force_update = VLC_FALSE; vlc_bool_t b_force_update = VLC_FALSE;
...@@ -570,34 +646,6 @@ static int Run( input_thread_t *p_input ) ...@@ -570,34 +646,6 @@ static int Run( input_thread_t *p_input )
i_intf_update = mdate() + I64C(150000); 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;
} }
......
...@@ -1219,7 +1219,7 @@ int VLC_AddTarget( int i_object, char const *psz_target, ...@@ -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 ) int VLC_Play( int i_object )
{ {
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#define TITLE_ALL N_( "All items, unsorted" ) #define TITLE_ALL N_( "All items, unsorted" )
#undef PLAYLIST_PROFILE #undef PLAYLIST_PROFILE
#undef PLAYLIST_DEBUG #define PLAYLIST_DEBUG 1
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
...@@ -364,8 +364,8 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) ...@@ -364,8 +364,8 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args )
i_view = (int)va_arg( args,int ); i_view = (int)va_arg( args,int );
p_node = (playlist_item_t *)va_arg( args, playlist_item_t * ); p_node = (playlist_item_t *)va_arg( args, playlist_item_t * );
p_item = (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 if ( p_node == NULL ) //|| (p_item != NULL && p_item->input.psz_uri
== NULL )) // == NULL ))
{ {
p_playlist->status.i_status = PLAYLIST_STOPPED; p_playlist->status.i_status = PLAYLIST_STOPPED;
p_playlist->request.b_request = VLC_TRUE; p_playlist->request.b_request = VLC_TRUE;
...@@ -378,10 +378,8 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) ...@@ -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_node = p_node;
p_playlist->request.p_item = p_item; p_playlist->request.p_item = p_item;
/* If we select a node, play only it. /* Don't go further if the node doesn't want to */
* If we select an item, continue */ if( ! p_playlist->request.p_node->i_flags & PLAYLIST_SKIP_FLAG )
if( p_playlist->request.p_item == NULL ||
! p_playlist->request.p_node->i_flags & PLAYLIST_SKIP_FLAG )
{ {
p_playlist->b_go_next = VLC_FALSE; p_playlist->b_go_next = VLC_FALSE;
} }
...@@ -468,7 +466,7 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) ...@@ -468,7 +466,7 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args )
break; break;
default: default:
msg_Err( p_playlist, "unimplemented playlist query" ); msg_Err( p_playlist, "unknown playlist query" );
return VLC_EBADVAR; return VLC_EBADVAR;
break; break;
} }
...@@ -680,7 +678,6 @@ static void RunThread ( playlist_t *p_playlist ) ...@@ -680,7 +678,6 @@ static void RunThread ( playlist_t *p_playlist )
* Get the next item to play */ * Get the next item to play */
p_item = NextItem( p_playlist ); p_item = NextItem( p_playlist );
/* We must stop */ /* We must stop */
if( p_item == NULL ) if( p_item == NULL )
{ {
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "vlc_playlist.h" #include "vlc_playlist.h"
#undef PLAYLIST_DEBUG #define PLAYLIST_DEBUG 1
/************************************************************************ /************************************************************************
* Local prototypes * Local prototypes
......
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