SDL窗口拉伸時顯示YUV

(本博客旨在個人總結回顧)

本例子是在雷神的SDL例子基礎上改的,發現雷神的例子上實現yuv數據顯示時進行窗口拉伸,發現顯示異常。

(原因:視頻播放時,需要窗口資源,窗口拉伸時也需要窗口資源,而且兩者在不同線程中,同時時訪問同個資源就需要加鎖來解決)

效果:

關鍵源碼:

// testSDL.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#ifdef __cplusplus
extern "C"
{
#endif

#include "SDL.h"

#ifdef __cplusplus
};
#endif

#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")


//Refresh Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)
//Break
#define BREAK_EVENT  (SDL_USEREVENT + 2)


//實現拉伸時可播放視頻

int g_nTheadExit = 0;
bool g_bResize = false;

SDL_mutex* g_pSdlMutex = SDL_CreateMutex();

SDL_Window* g_pScreen = NULL;

struct ThreadData
{
    SDL_Window* pSdlWindow;
    SDL_Renderer* pSDLRenderer;
    SDL_Texture* pSDLTexture;
    SDL_mutex* pSdlMutex;

};

int RefreshVideo(void* pOpaque)
{
    ThreadData* pSDLThreadDate = (ThreadData*)pOpaque;
    const int nBpp = 12;
    int nScreenWidth = 640, nScreenHeight = 360;
    const int nPixelWidth = 640, nPixelHeight = 360;

    unsigned char buffer[nPixelWidth*nPixelHeight*nBpp / 8];
    g_nTheadExit = 0;

    FILE* pFile = NULL;
    pFile = fopen("./sintel_640_360.yuv", "rb+");

    if (NULL == pFile)
    {
        cout << "Can not open this file!" << endl;
        return -1;
    }
    
    while (0 == g_nTheadExit)
    {            
        SDL_Delay(40);
        SDL_LockMutex(pSDLThreadDate->pSdlMutex);
        if (g_bResize)
        {
            g_bResize = false;
            SDL_UnlockMutex(pSDLThreadDate->pSdlMutex);
            continue;
        }
        if (fread(buffer, 1, nPixelWidth*nPixelHeight*nBpp / 8, pFile) != nPixelWidth*nPixelHeight*nBpp / 8)
        {
            fseek(pFile, 0, SEEK_SET);
            fread(buffer, 1, nPixelWidth*nPixelHeight*nBpp / 8, pFile);
            //break;
        }
        SDL_GetWindowSize(pSDLThreadDate->pSdlWindow, &nScreenWidth, &nScreenHeight);
        //SDL_SetWindowSize(pSDLThreadDate->pSdlWindow, nScreenWidth, nScreenHeight);
        
        //設置紋理數據
        int ret = SDL_UpdateTexture(pSDLThreadDate->pSDLTexture, NULL, buffer, nPixelWidth);

        ret = SDL_RenderClear(pSDLThreadDate->pSDLRenderer);
        SDL_Rect sdlRect;
        sdlRect.x = 0;
        sdlRect.y = 0;
        sdlRect.w = 640;
        sdlRect.h = 360;

        cout << nScreenWidth << "X" << nScreenHeight << endl;
        //將紋理拷貝給渲染器
        ret = SDL_RenderCopy(pSDLThreadDate->pSDLRenderer, pSDLThreadDate->pSDLTexture, NULL, &sdlRect);
        //cout << __LINE__ << endl;
        //顯示
        SDL_RenderPresent(pSDLThreadDate->pSDLRenderer);
        SDL_UnlockMutex(pSDLThreadDate->pSdlMutex);
        cout << "refresh video!" << endl;
        SDL_Event sdlEvent;
        sdlEvent.type = REFRESH_EVENT;
        SDL_PushEvent(&sdlEvent);
    }
    g_nTheadExit = 0;

    SDL_Event tmpSdlEvent;
    tmpSdlEvent.type = BREAK_EVENT;
    SDL_PushEvent(&tmpSdlEvent);
    return 0;
}

int MySdlEventFilter(void *userdata, SDL_Event * event)
{
    if (event->type == SDL_WINDOWEVENT)
    {
        switch (event->window.event)
        {
        case SDL_WINDOWEVENT_RESIZED:
            SDL_Log("Window %d resized to %dx%d",
                event->window.windowID, event->window.data1,
                event->window.data2);
            cout << "window resized!" << endl;
            SDL_LockMutex(g_pSdlMutex);
            g_bResize = true;
            SDL_SetWindowSize(g_pScreen, event->window.data1, event->window.data2);
            SDL_UnlockMutex(g_pSdlMutex);
            return 0;
            break;
        case SDL_WINDOWEVENT_SIZE_CHANGED:
            SDL_Log("Window %d size changed to %dx%d",
                event->window.windowID, event->window.data1,
                event->window.data2);
            cout << "window size changed!" << endl;
            SDL_LockMutex(g_pSdlMutex);
            g_bResize = true;                    
            
            SDL_UnlockMutex(g_pSdlMutex);
            return 0;
            break;
        default:
            break;
        }
    }
    return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{

    const int nBpp = 12;
    int nScreenWidth = 640, nScreenHeight = 360;
    const int nPixelWidth = 640, nPixelHeight = 360;

    //初始化SDL系統
    if (SDL_Init(SDL_INIT_VIDEO))
    {
        cout << "Could not initialize SDL:" << SDL_GetError() << endl;
    }
    SDL_SetEventFilter(MySdlEventFilter, NULL);

    //創建窗口
    g_pScreen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        nScreenWidth, nScreenHeight, SDL_WINDOW_RESIZABLE);
    if (!g_pScreen)
    {
        cout << "SDL: could not create window - exiting:" << SDL_GetError() << endl;
    }

    //創建渲染器
    SDL_Renderer* pSDLRenderer = SDL_CreateRenderer(g_pScreen, -1, 0);

    Uint32 unPixformat = 0;
    //IYUV: Y + U + V (3 planes)
    //YV12: Y + V + U (3 planes)
    unPixformat = SDL_PIXELFORMAT_IYUV;

    //創建紋理
    SDL_Texture* pSDLTexture = SDL_CreateTexture(pSDLRenderer, unPixformat, SDL_TEXTUREACCESS_STREAMING, nPixelWidth, nPixelHeight);

    

    ThreadData threadDate;
    threadDate.pSdlWindow = g_pScreen;
    threadDate.pSDLTexture = pSDLTexture;
    threadDate.pSDLRenderer = pSDLRenderer;
    threadDate.pSdlMutex = g_pSdlMutex;

    SDL_Thread* pRefreshThread = SDL_CreateThread(RefreshVideo, NULL, &threadDate);
    SDL_Event sdlEvent;
    
    while (true)
    {        
        //SDL_PollEvent(&sdlEvent);
        SDL_WaitEvent(&sdlEvent);
        //cout << "SDL Event type:" << sdlEvent.type << endl;
        //cout << "SDL Event drop type:" << sdlEvent.drop.type << endl;
        switch (sdlEvent.type)
        {
        case SDL_WINDOWEVENT:
            SDL_GetWindowSize(g_pScreen, &nScreenWidth, &nScreenHeight);
            break;
        case REFRESH_EVENT:            
            //顯示
            SDL_LockMutex(g_pSdlMutex);
            SDL_RenderPresent(pSDLRenderer);
            SDL_UnlockMutex(g_pSdlMutex);
            break;

        case SDL_QUIT:
            g_nTheadExit = 1;
            SDL_HideWindow(g_pScreen);
            break;
        case BREAK_EVENT:
            break;
        default:
            break;
        } 

    }

    SDL_DestroyWindow(g_pScreen);
    SDL_DestroyRenderer(pSDLRenderer);
    SDL_DestroyTexture(pSDLTexture);

    SDL_DestroyMutex(g_pSdlMutex);

    SDL_Quit();
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章