SDL学习四:使用SDL编写一个播放器播放YUV格式的视频文件

1.视频播放的大致流程如下:
初始化—>创建窗口—>创建渲染器—>创建纹理—>读取一帧数据—>设置纹理数据—->将纹理数据拷贝给渲染器—>显示—>退出
2.代码分析:

//自定义的刷新事件
#define REFRESH_EVENT  (SDL_USEREVENT + 1)
//自定义的结束事件
#define BREAK_EVENT  (SDL_USEREVENT + 2)

int thread_exit = 0;
int screen_w = 640;
int screen_h = 360;

int refresh_video(void *opaque);
 
int main()
{
    SDL_Window* Window = NULL;
    const int pixel_w = 640;
    const int pixel_h = 360;
    const int bpp = 12;
    Uint32 pixformat = SDL_PIXELFORMAT_IYUV;
    unsigned char buffer[pixel_w*pixel_h*bpp/8];

    //打开用于测试的yuv格式的视频文件
    FILE *fp = fopen("./sintel_640_360.yuv","rb");
    if(fp == NULL)
    {
	perror("open");
    }

    //SDL初始化
    if(SDL_Init(SDL_INIT_VIDEO)<0)
    {
        printf( "Could not init SDL: %s\n", SDL_GetError());
        return -1;
    }

    //创建窗口
    Window = SDL_CreateWindow("YUV播放器",
	    SDL_WINDOWPOS_UNDEFINED,
	    SDL_WINDOWPOS_UNDEFINED,
	    screen_w,
	    screen_h,
	    SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
    if(Window == NULL)
    {
	printf("Could not create window: %s\n", SDL_GetError());
    }

    //创建渲染器
    SDL_Renderer* sdlRenderer = SDL_CreateRenderer(Window,-1,0);

    //创建纹理(表示一帧或者一张图片)
    SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat,SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);

    SDL_Rect sdlRect;
    //创建刷新线程
    SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL);
    SDL_Event event;

    while(1)
    {
        SDL_WaitEvent(&event);	//查询是否有事件发生,方便后续处理
        //while(SDL_PollEvent(&event)){}		这种写法也是可以的
        if(event.type == REFRESH_EVENT)
        {
        	//表示读取一帧数据
        	//Y = pixel_w*pixel_h
        	//U = V = pixel_w*pixel_h/4
        	//因此加起来就是1.5倍pixel_w*pixel_h,也就是bpp(12)/8 = 1.5
            if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8)
            {
                fseek(fp, 0, SEEK_SET);
                fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp);
            }

            SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w);  

			//表示要显示的内容的左上角顶点相较于显示框左上角顶点的坐标
            sdlRect.x = 0;  
            sdlRect.y = 0;
            //表示要显示的内容的大小  
            sdlRect.w = screen_w;  
            sdlRect.h = screen_h;  

            SDL_RenderClear( sdlRenderer );   	//清除上一帧的画面
            //复制现在这一帧画面到显示框上
            SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, &sdlRect);  
            //显示出显示框
            SDL_RenderPresent( sdlRenderer );  
	}

       else if(event.type == SDL_WINDOWEVENT)	//窗口事件,拉伸窗口
       {
      	 //获得放大后的窗口的尺寸,最终传递给sdlRect结构体,改变下一次刷新时的显示效果
	    SDL_GetWindowSize(Window,&screen_w,&screen_h);
       }
       //点击窗口上的X触发事件
       else if(event.type == SDL_QUIT)
       {
 	    thread_exit = 1; 
       }
       else if(event.type == BREAK_EVENT)
       {
	    break;
       }
       SDL_Delay(5);		//减少cpu使用
    }

    SDL_DestroyTexture(sdlTexture);
    SDL_DestroyRenderer(sdlRenderer);
    SDL_DestroyWindow(Window);
    SDL_Quit();

    return 0;
}

int refresh_video(void *opaque)
{
    SDL_Event event;

	//触发SDL_QUIT事件的时候将thread_exit置1,停止刷新
    while (thread_exit == 0)
    {
    	//触发刷新事件,执行主线程中的相应代码,实现刷新的循环执行 
        event.type = REFRESH_EVENT;	
        //将事件添加到事件队列中
        SDL_PushEvent(&event);
        SDL_Delay(40);
    }

    thread_exit = 0;	
    event.type = BREAK_EVENT;
    SDL_PushEvent(&event);
    return 0;
}

3.程序的框架简介:
SDL_Texture用于显示YUV数据,一个SDL_Texture对应一帧YUV数据。
SDL_Renderer用于渲染SDL_Texture至SDL_Window。
SDL_Rect用于确定SDL_Texture显示的位置。
4.官方文档:https://wiki.libsdl.org/FrontPage

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值