yuv播放器

用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

posted @ 2014-01-16 12:48  海滨银枪小霸王  阅读(473)  评论(0编辑  收藏  举报