用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 "); 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 "); exit(1); } thread = SDL_CreateThread(ThreadCallBack, (void*)¶m); if(NULL == thread) { printf("Thread Cread error "); 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 ",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