(本博客旨在个人总结回顾)
本例子是在雷神的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;
}