📄 input.c
字号:
/** * Initialize an input thread and run it. This thread will clean after itself, * 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 ? * \return the input object id if non blocking, an error code else */int __input_Read( vlc_object_t *p_parent, input_item_t *p_item, bool b_block ){ input_thread_t *p_input; p_input = Create( p_parent, p_item, NULL, false, NULL ); if( !p_input ) return VLC_EGENERIC; if( b_block ) { RunAndDestroy( VLC_OBJECT(p_input) ); return VLC_SUCCESS; } else { if( vlc_thread_create( p_input, "input", RunAndDestroy, VLC_THREAD_PRIORITY_INPUT, true ) ) { input_ChangeState( p_input, ERROR_S ); msg_Err( p_input, "cannot create input thread" ); vlc_object_release( p_input ); return VLC_EGENERIC; } } return p_input->i_object_id;}/** * 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; /* Allocate descriptor */ p_input = Create( p_parent, p_item, NULL, true, NULL ); if( !p_input ) return VLC_EGENERIC; if( !Init( p_input ) ) End( p_input ); vlc_object_detach( p_input ); vlc_object_release( p_input ); return VLC_SUCCESS;}/** * Request a running input thread to stop and die * * \param the input thread to stop */static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj ){ vlc_list_t *p_list; int i; if( p_obj->i_object_type == VLC_OBJECT_VOUT || p_obj->i_object_type == VLC_OBJECT_AOUT || p_obj == VLC_OBJECT(p_input->p->p_sout) ) return; vlc_object_kill( p_obj ); p_list = vlc_list_children( p_obj ); for( i = 0; i < p_list->i_count; i++ ) ObjectKillChildrens( p_input, p_list->p_values[i].p_object ); vlc_list_release( p_list );}void input_StopThread( input_thread_t *p_input ){ /* Set die for input and ALL of this childrens (even (grand-)grand-childrens) * It is needed here even if it is done in INPUT_CONTROL_SET_DIE handler to * unlock the control loop */ ObjectKillChildrens( p_input, VLC_OBJECT(p_input) ); input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );}sout_instance_t * input_DetachSout( input_thread_t *p_input ){ sout_instance_t *p_sout = p_input->p->p_sout; vlc_object_detach( p_sout ); p_input->p->p_sout = NULL; return p_sout;}/***************************************************************************** * Run: main thread loop * This is the "normal" thread that spawns the input processing chain, * reads the stream, cleans up and waits *****************************************************************************/static void* Run( vlc_object_t *p_this ){ input_thread_t *p_input = (input_thread_t *)p_this; /* Signal that the thread is launched */ vlc_thread_ready( p_input ); if( Init( p_input ) ) { /* If we failed, wait before we are killed, and exit */ WaitDie( p_input ); /* Tell we're dead */ p_input->b_dead = true; return NULL; } MainLoop( p_input ); if( !p_input->b_eof && !p_input->b_error && p_input->p->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->p_es_out ) ) break; msg_Dbg( p_input, "waiting decoder fifos to empty" ); msleep( INPUT_IDLE_SLEEP ); } /* We have finished */ input_ChangeState( p_input, END_S ); } /* Wait until we are asked to die */ if( !p_input->b_die ) { WaitDie( p_input ); } /* Clean up */ End( p_input ); return NULL;}/***************************************************************************** * RunAndDestroy: 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 void* RunAndDestroy( vlc_object_t *p_this ){ input_thread_t *p_input = (input_thread_t *)p_this; /* Signal that the thread is launched */ vlc_thread_ready( p_input ); if( Init( p_input ) ) goto exit; MainLoop( p_input ); if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof ) { /* We have finished demuxing data but not playing it */ while( !p_input->b_die ) { if( input_EsOutDecodersEmpty( p_input->p->p_es_out ) ) break; msg_Dbg( p_input, "waiting decoder fifos to empty" ); msleep( INPUT_IDLE_SLEEP ); } /* We have finished */ input_ChangeState( p_input, END_S ); } /* Clean up */ End( p_input );exit: /* Release memory */ vlc_object_release( p_input ); return 0;}/***************************************************************************** * Main loop: Fill buffers from access, and demux *****************************************************************************/static void MainLoop( input_thread_t *p_input ){ int64_t i_start_mdate = mdate(); int64_t i_intf_update = 0; int i_updates = 0; /* Stop the timer */ stats_TimerStop( p_input, STATS_TIMER_INPUT_LAUNCHING ); while( !p_input->b_die && !p_input->b_error && !p_input->p->input.b_eof ) { bool b_force_update = false; int i_ret; int i_type; vlc_value_t val; /* Do the read */ if( p_input->i_state != PAUSE_S ) { if( ( p_input->p->i_stop > 0 && p_input->i_time >= p_input->p->i_stop ) || ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) ) i_ret = 0; /* EOF */ else i_ret = p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux); if( i_ret > 0 ) { /* TODO */ if( p_input->p->input.b_title_demux && p_input->p->input.p_demux->info.i_update ) { i_ret = UpdateFromDemux( p_input ); b_force_update = true; } else if( !p_input->p->input.b_title_demux && p_input->p->input.p_access && p_input->p->input.p_access->info.i_update ) { i_ret = UpdateFromAccess( p_input ); b_force_update = true; } } if( i_ret == 0 ) /* EOF */ { vlc_value_t repeat; var_Get( p_input, "input-repeat", &repeat ); if( repeat.i_int == 0 ) { /* End of file - we do not set b_die because only the * playlist is allowed to do so. */ msg_Dbg( p_input, "EOF reached" ); p_input->p->input.b_eof = true; } else { msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int ); if( repeat.i_int > 0 ) { repeat.i_int--; var_Set( p_input, "input-repeat", repeat ); } /* Seek to start title/seekpoint */ val.i_int = p_input->p->input.i_title_start - p_input->p->input.i_title_offset; if( val.i_int < 0 || val.i_int >= p_input->p->input.i_title ) val.i_int = 0; input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val ); val.i_int = p_input->p->input.i_seekpoint_start - p_input->p->input.i_seekpoint_offset; if( val.i_int > 0 /* TODO: check upper boundary */ ) input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val ); /* Seek to start position */ if( p_input->p->i_start > 0 ) { val.i_time = p_input->p->i_start; input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &val ); } else { val.f_float = 0.0; input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val ); } /* */ i_start_mdate = mdate(); } } else if( i_ret < 0 ) { input_ChangeState( p_input, ERROR_S ); } if( i_ret > 0 && p_input->p->i_slave > 0 ) { SlaveDemux( p_input ); } } else { /* Small wait */ msleep( 10*1000 ); } /* Handle control */ vlc_mutex_lock( &p_input->p->lock_control ); ControlReduce( p_input ); while( !ControlPopNoLock( p_input, &i_type, &val ) ) { msg_Dbg( p_input, "control type=%d", i_type ); if( Control( p_input, i_type, val ) ) b_force_update = true; } vlc_mutex_unlock( &p_input->p->lock_control ); if( b_force_update || i_intf_update < mdate() ) { vlc_value_t val; double f_pos; int64_t i_time, i_length; /* update input status variables */ if( !demux_Control( p_input->p->input.p_demux, DEMUX_GET_POSITION, &f_pos ) ) { val.f_float = (float)f_pos; var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL ); } if( !demux_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) ) { p_input->i_time = i_time; val.i_time = i_time; var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL ); } if( !demux_Control( p_input->p->input.p_demux, DEMUX_GET_LENGTH, &i_length ) ) { vlc_value_t old_val; var_Get( p_input, "length", &old_val ); val.i_time = i_length; var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL ); if( old_val.i_time != val.i_time ) { UpdateItemLength( p_input, i_length ); } } var_SetBool( p_input, "intf-change", true ); i_intf_update = mdate() + INT64_C(150000); } /* 150ms * 8 = ~ 1 second */ if( ++i_updates % 8 == 0 ) { stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats ); /* Are we the thread responsible for computing global stats ? */ if( libvlc_priv (p_input->p_libvlc)->p_stats_computer == p_input ) { stats_ComputeGlobalStats( p_input->p_libvlc, p_input->p_libvlc->p_stats ); } } }}static void InitStatistics( input_thread_t * p_input ){ if( p_input->b_preparsing ) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -