2013-05-05 3 views
0

Я использую SDL и libav в C++ для рисования видео на экране в Linux. Большая часть моего кода для открытия видео основана на this tutorial, но я изменил некоторые функции, которые были устаревшими. Я инициализация SDL как это:SDL видео наложения мерцает с SDL_Flip

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, например 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

По-видимому, существует несколько платформ или ситуаций (таких как настройки драйвера ATI/nVidia), которые могут привести к отключению или отсутствию vsync в SDL_Flip; предлагаю вам немного поискать «sdl_flip vsync». Вы могли бы поразить любую из этих вещей. – leander

ответ

0

Я до сих пор считаю, что это не самое лучшее решение, но я нашел то, что работает! Команда SDL_UpdateRect(screen, 0, 0, 0, 0); обновит весь экран. Если я обновляю только те части экрана, на которых нет видео, видео больше не мерцает. Я думаю, что это может быть связано с тем, что SDL_Overlays обрабатывается иначе, чем обычные поверхности.

0

Вы должны использовать двойную буферизацию, чтобы предотвратить мерцание.

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

Я должен был упомянуть об этом раньше, но я пробовал это уже, но это не повлияло, видео все еще мерцает. – Carlito

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

Я пробовал это, но это не сработало. Видео все еще мерцало. Вы также рисуете видео на «SDL_Overlay»? – Carlito

+0

Нет, я пишу прямо в пиксели.Пример: memcpy ((int *) screen-> pixels, image, size * 4); – 2013-05-07 09:11:54

+0

Вопрос: Вы используете несколько потоков? – 2013-05-07 09:13:08

Смежные вопросы