我在C ++中使用SDL和libav在Linux上的屏幕上绘制视频。我的大多数视频开放代码都基于this tutorial,但我更改了一些已弃用的功能。我像这样初始化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);
我不会发布整个代码,因为它非常大,但以下显示了我如何尝试显示视频叠加层。请注意,某些变量是我的视频类中的类成员,例如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_Flip(screen)
的通话时,视频播放正常。太快了,我还没有进行过录像,但是当我添加一个临时的SDL_Delay(10)
时,它看起来还不错。
但是当我删除SDL_Flip
以显示我的视频时,我无法在屏幕上绘制任何其他内容。 SDL_BlitSurface
和SDL_FillRect
都无法在屏幕上绘制任何内容。我已经尝试将SDL_DOUBLEBUF
添加到标志中,但这并没有改变这种情况。
如果需要,我可以提供更多代码,但我认为问题出现在我发布的代码中,因为其他一切正常(绘制图像或显示没有SDL_Flip
的视频)。
我做错了什么?
答案 0 :(得分:1)
由于您使用的是SWSURFACE,请不要使用SDL_Flip(屏幕)使用SDL_UpdateRect。您不需要设置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);
答案 1 :(得分:0)
您应该使用双缓冲来防止闪烁。
screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF);
答案 2 :(得分:0)
我仍然认为这不是最佳解决方案,但我找到了有效的方法!
命令SDL_UpdateRect(screen, 0, 0, 0, 0);
将更新整个屏幕。如果我只更新屏幕中没有绘制视频的部分,则视频不再闪烁。我认为这可能与SDL_Overlay的处理方式有关,而处理的方式与普通表面不同。