0

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);

コードは非常に大きいため、コード全体を掲載するつもりはありませんが、ビデオ オーバーレイを表示する方法を以下に示します。formatCtx一部の変数は、やなど、私の Video クラスのクラスメンバーであることに注意してください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_BlitSurfaceSDL_FillRect画面に何も描画できません。すでにフラグを追加しようとしましSDL_DOUBLEBUFたが、状況は変わりませんでした。

必要に応じてさらにコードを提供できますが、問題は投稿したコードのどこかにあると思いますSDL_Flip.

私は何を間違っていますか?

4

3 に答える 3

2

SWSURFACE を使用しているため、SDL_Flip(screen) を使用しないでください。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);
于 2013-05-06T08:34:53.800 に答える
0

これはまだ最善の解決策ではないと思いますが、うまくいくものを見つけました! コマンドSDL_UpdateRect(screen, 0, 0, 0, 0);は画面全体を更新します。ビデオが描画されていない画面の部分だけを更新すると、ビデオがちらつきません。SDL_Overlays が通常のサーフェスとは異なる方法で処理されていることに関係があるのではないかと思います。

于 2013-05-22T17:56:56.763 に答える
0

ちらつきを防ぐには、ダブル バッファリングを使用する必要があります。

screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF);
于 2013-05-05T21:45:29.823 に答える