设置ABLoop
vlc_player.h声明
VLC_API int
vlc_player_SetAtoBLoop(vlc_player_t *player, enum vlc_player_abloop abloop);
src/player/player.c实现
int
vlc_player_SetAtoBLoop(vlc_player_t *player, enum vlc_player_abloop abloop)
{struct vlc_player_input *input = vlc_player_get_input_locked(player);if (!input || !vlc_player_CanSeek(player))return VLC_EGENERIC;vlc_tick_t time = vlc_player_GetTime(player);float pos = vlc_player_GetPosition(player);int ret = VLC_SUCCESS;switch (abloop){case VLC_PLAYER_ABLOOP_A:if (input->abloop_state[1].set)return VLC_EGENERIC;input->abloop_state[0].time = time;input->abloop_state[0].pos = pos;input->abloop_state[0].set = true;break;case VLC_PLAYER_ABLOOP_B:if (!input->abloop_state[0].set)return VLC_EGENERIC;input->abloop_state[1].time = time;input->abloop_state[1].pos = pos;input->abloop_state[1].set = true;if (input->abloop_state[0].time != VLC_TICK_INVALID&& time != VLC_TICK_INVALID){if (time > input->abloop_state[0].time){vlc_player_SetTime(player, input->abloop_state[0].time);break;}}else if (pos > input->abloop_state[0].pos){vlc_player_SetPosition(player, input->abloop_state[0].pos);break;}/* Error: A time is superior to B time. */abloop = VLC_PLAYER_ABLOOP_NONE;ret = VLC_EGENERIC;/* fall-through */case VLC_PLAYER_ABLOOP_NONE:input->abloop_state[0].set = input->abloop_state[1].set = false;time = VLC_TICK_INVALID;pos = 0.f;break;default:vlc_assert_unreachable();}vlc_player_SendEvent(player, on_atobloop_changed, abloop, time, pos);return ret;
}
业务调用过程:
//AtoBButton.qml
onClicked: Player.toggleABloopState()
==>
//player_controller.cpp
void PlayerController::toggleABloopState()
==>
void PlayerController::setABloopState(ABLoopState state)
==>
//vlc_player.h
vlc_player_SetAtoBLoop( d->m_player, static_cast<vlc_player_abloop>(state));
设置完后会有状态回调
//src/player/palyer.c
vlc_player_SendEvent(player, on_atobloop_changed, abloop, time, pos);//src/player/palyer.h
struct vlc_list listeners;
#define vlc_player_SendEvent(player, event, ...) do { \vlc_player_listener_id *listener; \vlc_list_foreach(listener, &player->listeners, node) \{ \if (listener->cbs->event) \listener->cbs->event(player, ##__VA_ARGS__, listener->cbs_data); \} \
} while(0)<==
vlc_player_listener_id *
vlc_player_AddListener(vlc_player_t *player,const struct vlc_player_cbs *cbs, void *cbs_data)
{assert(cbs);vlc_player_assert_locked(player);vlc_player_listener_id *listener = malloc(sizeof(*listener));if (!listener)return NULL;listener->cbs = cbs;listener->cbs_data = cbs_data;vlc_list_append(&listener->node, &player->listeners);return listener;
}<==
//modules/gui/qt/player_controller.cpp
PlayerControllerPrivate::PlayerControllerPrivate(PlayerController *playercontroller, qt_intf_t *p_intf)
{{vlc_player_locker locker{m_player};m_player_listener = vlc_player_AddListener( m_player, &player_cbs, this );m_player_aout_listener = vlc_player_aout_AddListener( m_player, &player_aout_cbs, this );m_player_vout_listener = vlc_player_vout_AddListener( m_player, &player_vout_cbs, this );m_player_timer = vlc_player_AddTimer( m_player, VLC_TICK_FROM_MS(500), &player_timer_cbs, this );}
}//modules/gui/qt/player_controller.cpp
static const struct vlc_player_cbs player_cbs = {on_player_current_media_changed,on_player_stats_changed,on_player_atobloop_changed,nullptr, // on_media_attachments_added: not usedon_player_vout_changed,on_player_corks_changed,
};//modules/gui/qt/player_controller.cpp 状态回调到了UI
static void on_player_atobloop_changed(vlc_player_t *, enum vlc_player_abloop state, vlc_tick_t time, double, void *data)
{PlayerControllerPrivate* that = static_cast<PlayerControllerPrivate*>(data);msg_Dbg( that->p_intf, "on_player_atobloop_changed");that->callAsync([that,state,time] (){PlayerController* q = that->q_func();switch (state) {case VLC_PLAYER_ABLOOP_NONE:that->m_ABLoopA = VLC_TICK_INVALID;that->m_ABLoopB = VLC_TICK_INVALID;emit q->ABLoopAChanged(that->m_ABLoopA);emit q->ABLoopBChanged(that->m_ABLoopB);break;case VLC_PLAYER_ABLOOP_A:that->m_ABLoopA = time;emit q->ABLoopAChanged(that->m_ABLoopA);break;case VLC_PLAYER_ABLOOP_B:that->m_ABLoopB = time;emit q->ABLoopBChanged(that->m_ABLoopB);break;}that->m_ABLoopState = static_cast<PlayerController::ABLoopState>(state);emit q->ABLoopStateChanged(that->m_ABLoopState);});
}
player/innput.c 检查是否到了B点,到B点后重新从A点执行
//player/innput.c
static void
vlc_player_input_HandleAtoBLoop(struct vlc_player_input *input, vlc_tick_t time,double pos)
{vlc_player_t *player = input->player;if (player->input != input)return;assert(input->abloop_state[0].set && input->abloop_state[1].set);if (time != VLC_TICK_INVALID&& input->abloop_state[0].time != VLC_TICK_INVALID&& input->abloop_state[1].time != VLC_TICK_INVALID){ if (time >= input->abloop_state[1].time)vlc_player_SetTime(player, input->abloop_state[0].time);}else if (pos >= input->abloop_state[1].pos)vlc_player_SetPosition(player, input->abloop_state[0].pos);
}
<==
player/input.c
static void
vlc_player_input_UpdateTime(struct vlc_player_input *input)
{if (input->abloop_state[0].set && input->abloop_state[1].set){vlc_tick_t now = vlc_tick_now();vlc_player_input_HandleAtoBLoop(input,vlc_player_input_GetTime(input, false, now),vlc_player_input_GetPos(input, false, now));}
}<==//player/input.c
static void
input_thread_Events(input_thread_t *input_thread,const struct vlc_input_event *event, void *user_data)
{struct vlc_player_input *input = user_data;vlc_player_t *player = input->player;input_thread_private_t *priv = input_priv(input_thread);assert(input_thread == input->thread);/* No player lock for this event */if (event->type == INPUT_EVENT_OUTPUT_CLOCK){if (event->output_clock.system_ts != VLC_TICK_INVALID){const struct vlc_player_timer_point point = {.position = 0,.rate = event->output_clock.rate,.ts = event->output_clock.ts,.length = VLC_TICK_INVALID,.system_date = event->output_clock.system_ts,};vlc_player_UpdateTimer(player, event->output_clock.id,event->output_clock.master, &point,VLC_TICK_INVALID,event->output_clock.frame_rate,event->output_clock.frame_rate_base, 0);}else{vlc_player_UpdateTimerEvent(player, event->output_clock.id,VLC_PLAYER_TIMER_EVENT_DISCONTINUITY,VLC_TICK_INVALID);}return;}vlc_mutex_lock(&player->lock);switch (event->type){case INPUT_EVENT_TIMES: //这个哪里发出来{bool changed = false;vlc_tick_t system_date = VLC_TICK_INVALID;vlc_tick_t duration = input_GetItemDuration(input->thread, event->times.length);if (event->times.time != VLC_TICK_INVALID&& (input->time != event->times.time|| input->position != event->times.position)){input->time = event->times.time;input->position = event->times.position;system_date = vlc_tick_now();changed = true;vlc_player_SendEvent(player, on_position_changed,input->time, input->position);vlc_player_input_UpdateTime(input);}if (input->length != duration){input->length = duration;input_item_SetDuration(input_GetItem(input->thread), duration);vlc_player_SendEvent(player, on_length_changed, input->length);changed = true;}if (input->normal_time != event->times.normal_time){input->normal_time = event->times.normal_time;changed = true;}if (changed){const struct vlc_player_timer_point point = {.position = input->position,.rate = input->rate,.ts = input->time,.length = input->length,.system_date = system_date,};vlc_player_UpdateTimer(player, NULL, false, &point,input->normal_time, 0, 0, priv->i_start);}break;}case INPUT_EVENT_VOUT:vlc_player_input_HandleVoutEvent(input, &event->vout);break;case INPUT_EVENT_SUBITEMS:vlc_player_SendEvent(player, on_media_subitems_changed,input_GetItem(input->thread), event->subitems);break;case INPUT_EVENT_DEAD:if (input->started) /* Can happen with early input_thread fails */vlc_player_input_HandleState(input, VLC_PLAYER_STATE_STOPPING,VLC_TICK_INVALID);vlc_player_destructor_AddJoinableInput(player, input);break;case INPUT_EVENT_VBI_TRANSPARENCY:input->teletext_transparent = event->vbi_transparent;vlc_player_SendEvent(player, on_teletext_transparency_changed,input->teletext_transparent);break;case INPUT_EVENT_ATTACHMENTS:vlc_player_SendEvent(player, on_media_attachments_added,input_GetItem(input->thread),event->attachments.array,event->attachments.count);break;}vlc_mutex_unlock(&player->lock);
}struct vlc_player_input *
vlc_player_input_New(vlc_player_t *player, input_item_t *item)
{input->thread = input_Create(player, input_thread_Events, input, item,INPUT_TYPE_NONE, player->resource,player->renderer);}《==
static inline void input_SendEventTimes(input_thread_t *p_input,double f_position, vlc_tick_t i_time,vlc_tick_t i_normal_time,vlc_tick_t i_length)
{input_SendEvent(p_input, &(struct vlc_input_event) {.type = INPUT_EVENT_TIMES,.times = { f_position, i_time, i_normal_time, i_length }});
}
static int EsOutVaPrivControlLocked(es_out_sys_t *p_sys, input_source_t *source,int query, va_list args)
{case ES_OUT_PRIV_SET_TIMES:{double f_position = va_arg( args, double );vlc_tick_t i_time = va_arg( args, vlc_tick_t );vlc_tick_t i_normal_time = va_arg( args, vlc_tick_t );vlc_tick_t i_length = va_arg( args, vlc_tick_t );if (i_normal_time != VLC_TICK_INVALID)source->i_normal_time = i_normal_time;if( source != p_sys->main_source )return VLC_SUCCESS;if (p_sys->b_buffering){input_SendEventTimes(p_sys->p_input, 0.0, VLC_TICK_INVALID,i_normal_time, i_length);return VLC_SUCCESS;}vlc_tick_t i_delay;/* Fix for buffering delay */if (!input_priv(p_sys->p_input)->p_sout ||!input_priv(p_sys->p_input)->b_out_pace_control)i_delay = EsOutGetBuffering(p_sys);elsei_delay = 0;if (i_time != VLC_TICK_INVALID){i_time -= i_delay;if (i_time < VLC_TICK_0)i_time = VLC_TICK_0;}if (i_length != 0)f_position -= (double)i_delay / i_length;if (f_position < 0)f_position = 0;input_SendEventTimes(p_sys->p_input, f_position, i_time,i_normal_time, i_length);return VLC_SUCCESS;}}//src/input/es_out.c
static int EsOutPrivControl(struct vlc_input_es_out *out,input_source_t *source,int query,va_list args)
{es_out_sys_t *p_sys = PRIV(&out->out);vlc_mutex_lock( &p_sys->lock );int ret = EsOutVaPrivControlLocked(p_sys, source, query, args);vlc_mutex_unlock( &p_sys->lock );return ret;
}
//src/input/input.cstatic void MainLoopStatistics( input_thread_t *p_input )
{input_thread_private_t *priv = input_priv(p_input);InputSourceStatistics( priv->master, priv->p_item, priv->p_es_out );for (size_t i = 0; i < priv->i_slave; i++){input_source_t *in = priv->slave[i];InputSourceStatistics( in, NULL, in->p_slave_es_out );}if (priv->stats != NULL){struct input_stats_t new_stats;input_stats_Compute(priv->stats, &new_stats);vlc_mutex_lock(&priv->p_item->lock);*priv->p_item->p_stats = new_stats;vlc_mutex_unlock(&priv->p_item->lock);input_SendEventStatistics(p_input, &new_stats);}
}//src/input/input.c
static void MainLoop( input_thread_t *p_input, bool b_interactive )
{/* Update interface and statistics */vlc_tick_t now = vlc_tick_now();if( now >= i_intf_update ){MainLoopStatistics( p_input );i_intf_update = now + VLC_TICK_FROM_MS(250);}}
追踪到最后发现精度为250ms