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
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 * ) );
......
......@@ -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__ */
......
......@@ -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;
}
......
......@@ -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 )
{
......
......@@ -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 ) ) ) )
......
......@@ -29,7 +29,7 @@
#include "vlc_playlist.h"
#undef PLAYLIST_DEBUG
#define PLAYLIST_DEBUG 1
/************************************************************************
* 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