SDL视频覆盖闪烁与SDL_Flip

SDL video overlay flickers with SDL_Flip

本文关键字:SDL Flip 闪烁 视频 覆盖      更新时间:2023-10-16

我在Linux下使用c++中的SDL和libav在屏幕上绘制视频。我的大部分视频打开代码都是基于本教程,但我改变了一些不推荐的函数。我这样初始化SDL:

SDL_Init(SDL_INIT_EVERYTHING);
const SDL_VideoInfo * info = SDL_GetVideoInfo();
screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN);

我不打算张贴整个代码,因为它是相当大的,但以下显示了我如何尝试显示视频覆盖。请注意,一些变量是来自我的Video类的类成员,如formatCtxpacket

void Video::GetOverlay(SDL_Overlay * overlay) {
    int frameFinished;
    while (av_read_frame(formatCtx, &packet) >= 0) {
        if (packet.stream_index == videoStream) {
            avcodec_decode_video2(codecCtx, frame, &frameFinished, &packet);
            if (frameFinished) {
                SDL_LockYUVOverlay(overlay);
                AVPicture pict;
                pict.data[0] = overlay->pixels[0];
                pict.data[1] = overlay->pixels[2];
                pict.data[2] = overlay->pixels[1];
                pict.linesize[0] = overlay->pitches[0];
                pict.linesize[1] = overlay->pitches[2];
                pict.linesize[2] = overlay->pitches[1];
                SwsContext * ctx = sws_getContext (codecCtx->width, codecCtx->height, codecCtx->pix_fmt,
                                   codecCtx->width, codecCtx->height,  PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
                sws_scale(ctx, frame->data, frame->linesize, 0, codecCtx->height, pict.data, pict.linesize);
                sws_freeContext(ctx);
                SDL_UnlockYUVOverlay(overlay);
                ++frameIndex;
                return;
            }   
        }   
        av_free_packet(&packet);
    }   
}

然后在mainloop中:

SDL_Overlay * overlay = SDL_CreateYUVOverlay(video->GetWidth(), video->GetHeight(), SDL_YV12_OVERLAY, screen);
while (true) {
    video->GetOverlay(overlay);
    SDL_Rect rect = { 400, 200, video->GetWidth(), video->GetHeight() };
    SDL_DisplayYUVOverlay(overlay, &rect);
    SDL_Flip(screen);
}

这工作,视频播放,但它闪烁很多。比如它试图在每一帧的同一个地方画一个图像。当我移除呼叫SDL_Flip(screen)时,视频播放良好。太快了,我还没有解决视频计时问题,但是当我添加一个临时的SDL_Delay(10)时,它看起来很好。但是当我删除SDL_Flip来显示我的视频时,我不能在屏幕上画任何其他东西。SDL_BlitSurfaceSDL_FillRect都无法在屏幕上绘制任何内容。我已经尝试将SDL_DOUBLEBUF添加到标志中,但这并没有改变这种情况。

如果需要的话,我可以提供更多的代码,但我认为问题是在我发布的代码中的某个地方,因为其他一切都工作正常(绘制图像,或显示没有SDL_Flip的视频)。

我做错了什么?

由于您使用SWSURFACE不使用SDL_Flip(屏幕)使用sdl_updat竖立。你不需要设置SDL_DOUBLEBUF

http://sdl.beuc.net/sdl.wiki/SDL_UpdateRect

这就是我所做的,我没有闪烁。

我把屏幕设置成这样

screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE | SDL_FULLSCREEN);

在主循环中我调用

SDL_UpdateRect(screen, 0, 0, 0, 0);

应该使用双缓冲来防止闪烁。

screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF);

我仍然认为这不是最好的解决方案,但我发现了一些工作!命令SDL_UpdateRect(screen, 0, 0, 0, 0);将更新整个屏幕。如果我只更新屏幕上没有视频的部分,视频就不会再闪烁了。我认为这可能与SDL_Overlays的处理方式不同于普通表面有关。