SDL视频叠加随着SDL_翻转而闪烁 < >我在C++中使用SDL和LIBAV在Linux上画一个视频。我的大部分视频打开代码都基于,但我更改了一些不推荐使用的函数。我像这样初始化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);
我不打算发布整个代码,因为它相当大,但下面展示了我如何尝试显示视频覆盖。请注意,有些变量是我的视频类的类成员,如SDL视频叠加随着SDL_翻转而闪烁 < >我在C++中使用SDL和LIBAV在Linux上画一个视频。我的大部分视频打开代码都基于,但我更改了一些不推荐使用的函数。我像这样初始化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);,c++,video,sdl,libav,C++,Video,Sdl,Libav,我不打算发布整个代码,因为它相当大,但下面展示了我如何尝试显示视频覆盖。请注意,有些变量是我的视频类的类成员,如formatCtx和packet void Video::GetOverlay(SDL_Overlay * overlay) { int frameFinished; while (av_read_frame(formatCtx, &packet) >= 0) { if (packet.stream_index == videoStream
formatCtx
和packet
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);
}
}
然后在我的主循环中:
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\u Flip(屏幕)
的调用时,视频播放正常。太快了,我还没有完成视频计时,但是当我添加一个临时的SDL\u延迟(10)
时,它看起来相当不错。
但是当我移除SDL_Flip来显示我的视频时,我无法在屏幕上绘制任何其他内容。SDL_BlitSurface
和SDL_FillRect
都无法在屏幕上绘制任何内容。我已经尝试将SDL_DOUBLEBUF
添加到标志中,但这并没有改变情况
如果需要的话,我可以提供更多的代码,但我认为问题出在我发布的代码中的某个地方,因为其他一切都正常工作(绘制图像,或者显示没有SDL\u Flip
)的视频)
我做错了什么 应该使用双缓冲来防止闪烁
screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF);
因为您使用的是SWSURFACE,所以不要使用SDL_Flip(屏幕)使用SDL_Update。您不需要设置SDL_DOUBLEBUF 我就是这么做的,我不会被忽悠 我把屏幕设置成这样
screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE | SDL_FULLSCREEN);
在我的主循环中,我调用
SDL_UpdateRect(screen, 0, 0, 0, 0);
我仍然认为这不是最好的解决方案,但我发现了一些有效的方法!
命令
SDL_update(屏幕,0,0,0,0)代码>将更新整个屏幕。如果我只更新屏幕上没有绘制视频的部分,视频将不再闪烁。我认为这可能与SDL_覆盖层的处理方式不同于普通表面有关。显然,有许多平台或情况(如ATI/nVidia驱动程序设置)会导致SDL_Flip关闭或不使用vsync;建议您搜索一下“sdl_flip vsync”。你可能会碰到这些东西中的任何一个。我以前应该提到过这个,但我已经试过了,但没有效果,视频仍然闪烁。我试过了,但没有效果。视频仍在闪烁。您是否也在SDL\u覆盖图上绘制视频?不,我直接写入像素。像这样:memcpy((int*)屏幕->像素,图像,大小*4);我仍然使用单个线程,但我计划稍后使用多个线程。您是否将视频帧加载到图像中?或者你只是加载一个图像?不确定你到底是什么意思。我读了一个targa文件,因为它的格式很容易使用,我直接写屏幕->像素。你可以尝试SDL_BlitSurface而不是memcpy,但是memcpy对我来说足够快。如果我理解正确,targa是一种图像格式。但我正在加载mp4视频,并试图在SDL_覆盖上显示视频帧。所以我认为仅仅画一幅图像,或者在覆盖图上画视频帧是有区别的,但我不确定。