用sdl写个播放器, 播放yuv
发现播放yuv的应用还很广,主要是测试时用到
基于sdl, 现在出了sdl2.0, 暂用1.2的, 这个比较熟悉
todo:
1. 支持size的改变
2. 读取yuv的信息
3. 截取其中的一帧
4. 支持yuv nv12 yuv444, yuv422 , rgb24等主流
5. 跨平台
先贴个1.0(暂且这么叫吧)
#include<stdio.h>
#include<unistd.h>
#include<SDL/SDL.h>
FILE *fp;
SDL_Surface *screen;
const int width = 1920;
const int height = 1080;
void QuitSdl(SDL_Event event);
SDL_Surface* SDL_ScaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height);
void ApplySurface( int x, int y, SDL_Surface* source, SDL_Surface* destination );
int ThreadCallBack(void *para);
int main(int argc, char **argv)
{
const SDL_VideoInfo *monitor;
SDL_Surface *background;
SDL_Surface *ground;
SDL_Event event;
SDL_Thread *thread = NULL;
void *param;
if(SDL_Init(SDL_INIT_VIDEO))
{
printf("Coundnot init SDL\n");
exit(1);
}
monitor = SDL_GetVideoInfo();
screen = SDL_SetVideoMode(width, height, 24, SDL_SWSURFACE);
background = SDL_LoadBMP("background.bmp");
ground = SDL_ScaleSurface(background, width, height);
SDL_BlitSurface(ground, NULL, screen, NULL);
ApplySurface(0, 0, ground, screen);
SDL_Flip(screen);
fp = fopen("a.yuv","r");
if(NULL == fp)
{
printf("open file error\n");
exit(1);
}
thread = SDL_CreateThread(ThreadCallBack, (void*)¶m);
if(NULL == thread)
{
printf("Thread Cread error\n");
exit(1);
}
while(1)
{
SDL_WaitEvent(&event);
QuitSdl(event);
}
return 0;
}
void ApplySurface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
//Temporary rectangle to hold the offsets
SDL_Rect offset;
//Get the offsets
offset.x = x;
offset.y = y;
SDL_BlitSurface( source, NULL, destination, &offset );
}
void QuitSdl(SDL_Event event)
{
switch(event.type)
{
case SDL_QUIT:
SDL_Quit();
break;
}
return ;
}
Uint32 ReadPixel(SDL_Surface *surface, int x, int y)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
return *p;
break;
case 2:
return *(Uint16 *)p;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 16;
break;
case 4:
return *(Uint32 *)p;
break;
default:
return 0; /* shouldn't happen, but avoids warnings */
}
}
void DrawPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
SDL_Surface* SDL_ScaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height)
{
SDL_Surface *_ret = SDL_CreateRGBSurface(Surface->flags, Width, Height, Surface->format->BitsPerPixel,
Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask);
double _stretch_factor_x = ((double)Width / (double)(Surface->w)),
_stretch_factor_y = ((double)(Height) / (double)(Surface->h));
for(Sint32 y = 0; y < Surface->h; y++) //Run across all Y pixels.
for(Sint32 x = 0; x < Surface->w; x++) //Run across all X pixels.
for(Sint32 o_y = 0; o_y < _stretch_factor_y; ++o_y) //Draw _stretch_factor_y pixels for each Y pixel.
for(Sint32 o_x = 0; o_x < _stretch_factor_x; ++o_x) //Draw _stretch_factor_x pixels for each X pixel.
DrawPixel(_ret, (Sint32)(_stretch_factor_x * x) + o_x,
(Sint32)(_stretch_factor_y * y) + o_y, ReadPixel(Surface, x, y));
return _ret;
}
int ThreadCallBack(void *para)
{
unsigned char buf[width*height*3/2];
unsigned char *py, *pu, *pv;
int len, pyLen, puLen, pvLen;
SDL_Overlay *bmp;
SDL_Rect rect;
bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen);
// buf = (unsigned char*)malloc(sizeof(unsigned char)*1920*1080*3/2);
py = buf;
pu = buf + width*height;
pv = buf + width*height*5/4;
pyLen = width*height;
puLen = pvLen = width*height/4;
rect.x = 0;
rect.y = 0;
rect.w = width;
rect.h = height;
while(1)
{
len = fread(buf, 1, width*height*3/2, fp);
printf("len=%d\n",len);
SDL_LockYUVOverlay(bmp);
bmp->pixels[0] = py;
bmp->pixels[2] = pu;
bmp->pixels[1] = pv;
bmp->pitches[0] = pyLen;
bmp->pitches[2] = puLen;
bmp->pitches[1] = pvLen;
SDL_UnlockYUVOverlay(bmp);
SDL_DisplayYUVOverlay(bmp, &rect);
sleep(1);
}
return 0;
}
里面有两个文件,一个yuv, 一个bmp