ffplay 的事件处理分析

本文详细介绍了ffplay中事件处理的过程,包括SDL初始化、事件循环(event_loop)、事件获取(refresh_loop_wait_event)等核心环节,并解释了事件处理如何与视频刷新相结合。

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

ffplay 的事件处理依赖于SDL。在 main 函数中:

...
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
...
if (SDL_Init (flags)) {
        av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError());
        av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n");
        exit(1);
    }

以上代码完成SDL的初始化工作,其中包含SDL_EVENT的初始化。

事件处理都是在 event_loop 中进行:

/* handle an event sent by the GUI */
static void event_loop(VideoState *cur_stream)
{
    SDL_Event event;
    double incr, pos, frac;

    for (;;) {
        double x;
        refresh_loop_wait_event(cur_stream, &event);
        switch (event.type) {
        case SDL_KEYDOWN:
            if (exit_on_keydown) {
                do_exit(cur_stream);
                break;
            }
            switch (event.key.keysym.sym) {
            case SDLK_ESCAPE:
            case SDLK_q:
                do_exit(cur_stream);
                break;
            case SDLK_f:
                toggle_full_screen(cur_stream);
                cur_stream->force_refresh = 1;
                break;
            ...
            break;

        case SDL_VIDEOEXPOSE:
            cur_stream->force_refresh = 1;
            break;

        case SDL_MOUSEBUTTONDOWN:
            ...

        case SDL_MOUSEMOTION:
            ...
            break;

        case SDL_VIDEORESIZE:
            ...
            break;

        case SDL_QUIT:
        case FF_QUIT_EVENT:
            do_exit(cur_stream);
            break;
        case FF_ALLOC_EVENT:
            alloc_picture(event.user.data1);
            break;
        default:
            break;
        }
    }
}

event_loop 中有循环不停的获取事件,具体的获取事件及刷新视频的操作在函数 refresh_loop_wait_event 中完成。

static void refresh_loop_wait_event(VideoState *is, SDL_Event *event)
{
    double remaining_time = 0.0;
    SDL_PumpEvents();//更新事件队列
    while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS))
    {
        /* 根据时间差值判断是否隐藏焦点 */
        if (!cursor_hidden && av_gettime_relative() - cursor_last_shown > CURSOR_HIDE_DELAY)
        {
            SDL_ShowCursor(0);
            cursor_hidden = 1;
        }

        if (remaining_time > 0.0)
            av_usleep((int64_t)(remaining_time * 1000000.0));
        remaining_time = REFRESH_RATE;
        if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
            video_refresh(is, &remaining_time);
        SDL_PumpEvents();
    }
}

其中,SDL_PumpEvents 函数主动收集来自输入设备的事件,填入事件循环中,从而更新事件队列。

SDL_PeepEvents 会检查事件队列,如果队列中有事件,回取出事件进行处理;如果没有则会按照REFRESH_RATE的延迟去刷新视频。

具体的SDL事件机制可以参考 https://my.oschina.net/u/735973/blog/832117 。

转载于:https://my.oschina.net/u/735973/blog/832566

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值