VLC-Android视频显示流程

本文深入探讨了VLC在Android平台上视频显示的流程,从video_output.c的线程逻辑到关键函数ThreadDisplayPreparePicture和ThreadDisplayRenderPicture的功能分析,揭示了Android vout模块的实现细节,并指出display流程中的两个重要关注点:drop_next_frame变量和Picture的真正渲染时机。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做MEMC调试涉及到了播放器刷帧频率的问题,因此深入研究了一下VLC视频的显示流程,仔细研究过后发现还是有挺多坑的,在这里分享下:

VLC的视频显示逻辑主要在video_output.c中,其内部维护了一个线程用来接收control和刷新显示(这里和ijkplayer很像):

//vout中其实有两个线程,分别名为Thread和ThreadStep,视频正常播放走的是Thread,步进播放走的是ThreadStep(类似ffplay的s键),这里主要还是介绍Thread

/*****************************************************************************

 * Thread: video output thread

 *****************************************************************************

 * Video output thread. This function does only returns when the thread is

 * terminated. It handles the pictures arriving in the video heap and the

 * display device events.

 *****************************************************************************/

static void *Thread(void *object)

{

    vout_thread_t *vout = object;

    vout_thread_sys_t *sys = vout->p;

    mtime_t deadline = VLC_TS_INVALID;

    bool wait = false;

    //这里是一个大的死循环

    for (;;) {

        vout_control_cmd_t cmd;

        //对deadline进行修正

        if (wait)

        {

            const mtime_t max_deadline = mdate() + 100000;

            deadline = deadline <= VLC_TS_INVALID ? max_deadline : __MIN(deadline, max_deadline);

        else {

            deadline = VLC_TS_INVALID;

        }

        //处理control

        while (!vout_control_Pop(&sys->control, &cmd, deadline))

            if (ThreadControl(vout, cmd))

                return NULL;

        //显示Picture

        deadline = VLC_TS_INVALID;

        wait = ThreadDisplayPicture(vout, &deadline) != VLC_SUCCESS;

        const bool picture_interlaced = sys->displayed.is_interlaced;

        vout_SetInterlacingState(vout, picture_interlaced);

        vout_ManageWrapper(vout);

    }

}

Thread调用ThreadDisplayPicture刷新显示:

static int ThreadDisplayPicture(vout_thread_t *vout, mtime_t *deadline)

{

    bool frame_by_frame = !deadline;

    bool paused = vout->p->pause.is_on;

    //vout->p->displayed.current代表当前正在播放的帧(类比ffplay video_refresh函数中的lastvp)

    bool first = !vout->p->displayed.current;

    //调用ThreadDisplayPreparePicture准备一帧

    if (first)

        if (ThreadDisplayPreparePicture(vout, true, frame_by_frame)) /* FIXME not sure it is ok */

            return VLC_EGENERIC;

    //vout->p->displayed.next代表要播放的下一帧(类比ffplay video_refresh函数中的vp)

    if (!paused || frame_by_frame)

        while (!vout->p->displayed.next && !ThreadDisplayPreparePicture(vout, false, frame_by_frame))

            ;

    const mtime_t date = mdate();

    //这里计算render_delay来决定要提前多久显示

    //这里补充说明一点,Google在MediaCodec.java中建议提前两个VSYNC时间显示,原因可以自行百度Android的VSYNC显示机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值