ffplay 的事件處理分析

ffplay 的事件處理依賴於SDL。在 main 函數中:ide

...
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 中進行:oop

/* 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 中完成。.net

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 函數主動收集來自輸入設備的事件,填入事件循環中,從而更新事件隊列。code

SDL_PeepEvents 會檢查事件隊列,若是隊列中有事件,回取出事件進行處理;若是沒有則會按照REFRESH_RATE的延遲去刷新視頻。視頻

具體的SDL事件機制能夠參考 https://my.oschina.net/u/735973/blog/832117 。blog

相關文章
相關標籤/搜索