//MainLoop主要做两件事:1.获取demux后的数据;2.处理control事件。即MainLoop其实是VLC的读线程和事件处理线程 //这里将读数据和事件处理放在同一线程里可能会存在隐患,因为读数据是耗时操作,可能会导致事件处理不及时。ffplay在这一点上做的比较好,事件处理是和video刷新放在同一线程,可以确保每两个视频帧间能够处理消息;ijkplayer则是在jni层单独创建了事件处理线程,确保播放器事件的及时响应。 /** * MainLoop * The main input loop. */ static void MainLoop( input_thread_t *p_input, bool b_interactive ) { ...... while ( !input_Stopped( p_input ) && input_priv(p_input)->i_state != ERROR_S ) { ...... //这里调用MainLoopDemux获取解封装后的数据 if ( !b_paused ) { if ( !input_priv(p_input)->master->b_eof ) { bool b_force_update = false ; MainLoopDemux( p_input, &b_force_update ); if ( b_can_demux ) i_wakeup = es_out_GetWakeup( input_priv(p_input)->p_es_out ); if ( b_force_update ) i_intf_update = 0 ; b_paused_at_eof = false ; } else if ( !es_out_GetEmpty( input_priv(p_input)->p_es_out ) ) { //msg_Dbg( p_input, "waiting decoder fifos to empty" ); i_wakeup = mdate() + INPUT_IDLE_SLEEP; } /* Pause after eof only if the input is pausable. * This way we won't trigger timeshifting for nothing */ else if ( b_pause_after_eof && input_priv(p_input)->b_can_pause ) { if ( b_paused_at_eof ) break ; vlc_value_t val = { .i_int = PAUSE_S }; msg_Dbg( p_input, "pausing at EOF (pause after each)" ); Control( p_input, INPUT_CONTROL_SET_STATE, val ); b_paused = true ; b_paused_at_eof = true ; } else { if ( MainLoopTryRepeat( p_input ) ) break ; } /* Update interface and statistics */ mtime_t now = mdate(); if ( now >= i_intf_update ) { MainLoopStatistics( p_input ); i_intf_update = now + INT64_C( 250000 ); } } /* Handle control */ for ( ;; ) { mtime_t i_deadline = i_wakeup; /* Postpone seeking until ES buffering is complete or at most * 125 ms. */ bool b_postpone = es_out_GetBuffering( input_priv(p_input)->p_es_out ) && !input_priv(p_input)->master->b_eof; if ( b_postpone ) { mtime_t now = mdate(); /* Recheck ES buffer level every 20 ms when seeking */ if ( now < i_last_seek_mdate + INT64_C( 125000 ) && (i_deadline < 0 || i_deadline > now + INT64_C( 20000 )) ) i_deadline = now + INT64_C( 20000 ); else b_postpone = false ; } int i_type; vlc_value_t val; //这里从control队列中获取control事件 if ( ControlPop( p_input, &i_type, &val, i_deadline, b_postpone ) ) { if ( b_postpone ) continue ; break ; /* Wake-up time reached */ } #ifndef NDEBUG msg_Dbg( p_input, "control type=%d" , i_type ); #endif //这里是control事件生效的位置 if ( Control( p_input, i_type, val ) ) { if ( ControlIsSeekRequest( i_type ) ) i_last_seek_mdate = mdate(); i_intf_update = 0 ; } /* Update the wakeup time */ if ( i_wakeup != 0 ) i_wakeup = es_out_GetWakeup( input_priv(p_input)->p_es_out ); } } } //不同control类型的处理逻辑 static bool Control( input_thread_t *p_input, int i_type, vlc_value_t val ) { const mtime_t i_control_date = mdate(); /* FIXME b_force_update is abused, it should be carefully checked */ bool b_force_update = false ; if ( !p_input ) return b_force_update; switch ( i_type ) { ...... case INPUT_CONTROL_SET_TIME: { int64_t i_time; int i_ret; if ( input_priv(p_input)->b_recording ) { msg_Err( p_input, "INPUT_CONTROL_SET_TIME ignored while recording" ); break ; } i_time = val.i_int; if ( i_time < 0 ) i_time = 0 ; //flush esout及解码器 /* Reset the decoders states and clock sync (before calling the demuxer */ es_out_SetTime( input_priv(p_input)->p_es_out, - 1 ); //demux seek i_ret = demux_Control( input_priv(p_input)->master->p_demux, DEMUX_SET_TIME, i_time, !input_priv(p_input)->b_fast_seek ); if ( i_ret ) { int64_t i_length; /* Emulate it with a SET_POS */ if ( !demux_Control( input_priv(p_input)->master->p_demux, DEMUX_GET_LENGTH, &i_length ) && i_length > 0 ) { double f_pos = ( double )i_time / ( double )i_length; i_ret = demux_Control( input_priv(p_input)->master->p_demux, DEMUX_SET_POSITION, f_pos, !input_priv(p_input)->b_fast_seek ); } } if ( i_ret ) { msg_Warn( p_input, "INPUT_CONTROL_SET_TIME %" PRId64 " failed or not possible" , i_time ); } else { if ( input_priv(p_input)->i_slave > 0 ) SlaveSeek( p_input ); input_priv(p_input)->master->b_eof = false ; b_force_update = true ; } break ; } ...... default : msg_Err( p_input, "not yet implemented" ); break ; } ControlRelease( i_type, val ); return b_force_update; } |