自学内容网 自学内容网

VLC ABLoop实现原理

设置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 used
    on_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);
        else
            i_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.c

static 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


原文地址:https://blog.csdn.net/gdliweibing/article/details/142698801

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!