[TOC]
SDL视频显示 视频显示的流程
视频显示的流程,就是将像素数据“画”在屏幕上的过程。
例如显示YUV,就是将YUV“画”在系统的窗口中。
SDL简介 作用
SDL(Simple DirectMedia Layer)库的作用说白了就是封装了复杂的视音频底层交互工作,简化了视音频处理的难度。 本课程中只涉及到SDL库的一小部分——视频显示部分。
特点
PS:尽管SDL已经简化了视音频底层交互工作,对于新手来说学习还是有一些难度的
结构 SDL结构如下所示。可以看出它实际上还是调用了DirectX等底层的API完成了和硬件的交互。
VC下SDL开发环境的搭建 1、新建VC项目 新建->项目->控制台应用->创建
2、拷贝SDL开发文件 1 2 3 1、头文件(*.h)拷贝至项目文件夹的include子文件夹下 2、导入库文件(*.lib)拷贝至项目文件夹的lib子文件夹下 3、动态库文件(*.dll)拷贝至项目文件夹下
3、配置开发文件 step1: 打开属性面板 解决方案资源管理器->右键单击项目->属性
step2: 头文件配置 配置属性->C/C++->常规->附加包含目录,输入“include”(刚才拷贝头文件的目录)
step3: 导入库配置 配置属性->链接器->常规->附加库目录,输入“lib” (刚才拷贝库文件的目录)
配置属性->链接器->输入->附加依赖项,输入“SDL2.lib; SDL2main.lib”(导入库的文件名)
动态库不用配置
4、测试 step1: 创建源代码文件 在工程中创建一个包含main()函数的C/C++文件(如果已经有了可以跳过这一步)。 step2: 包含头文件
1 2 3 4 5 6 7 8 9 10 11 12 #include <iostream> #include "SDL2/SDL.h" int main (int argc, char * argv[]) { if (SDL_Init(SDL_INIT_VIDEO)) { printf ("Could not initialize SDL - %s\n" , SDL_GetError()); } else { printf ("Success init SDL" ); } return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream> extern "C" { #include "SDL2/SDL.h" } int main (int argc, char * argv[]) { if (SDL_Init(SDL_INIT_VIDEO)) { printf ("Could not initialize SDL - %s\n" , SDL_GetError()); } else { printf ("Success init SDL" ); } return 0 ; }
如果运行无误,则代表SDL已经配置完成。
出现的问题:
原因 :SDL_main.h这个文件中给main 取了别名,将主函数main当做SDL_main识别了
解决 :将int main
改成 int main(int argc, char *argv[])
SDL视频显示的函数 SDL视频显示的流程图如下所示:
SDL视频显示函数简介 1 2 3 4 5 6 7 8 9 SDL_Init():初始化SDL系统 SDL_CreateWindow():创建窗口SDL_Window SDL_CreateRenderer():创建渲染器SDL_Renderer SDL_CreateTexture():创建纹理SDL_Texture SDL_UpdateTexture():设置纹理的数据 SDL_RenderCopy():将纹理的数据拷贝给渲染器 SDL_RenderPresent():显示 SDL_Delay():工具函数,用于延时。 SDL_Quit():退出SDL系统
SDL视频显示的数据结构 SDL视频显示的数据结构如下所示:
SDL数据结构简介 1、SDL_Window : 代表了一个“窗口” 2、SDL_Renderer :代表了一个“渲染器” 3、SDL_Texture :代表了一个“纹理” 4、SDL_Rect :一个简单的矩形结构
进阶-SDL中事件和多线程 SDL多线程 函数:
1 SDL_CreateThread():创建一个线程
数据结构
SDL事件 函数 :
1 2 SDL_WaitEvent()等待一个事件 SDL_PushEvent()发送一个事件
数据结构 :
示例程序1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #include <stdio.h> #pragma comment(lib, "legacy_stdio_definitions.lib" ) extern "C" { #include "sdl/SDL.h" FILE __iob_func[3 ] = { *stdin ,*stdout ,*stderr }; }; const int bpp=12 ;int screen_w=640 ,screen_h=360 ;const int pixel_w=640 ,pixel_h=360 ;unsigned char buffer [pixel_w*pixel_h*bpp/8 ];int main (int argc, char * argv[]) { if (SDL_Init(SDL_INIT_VIDEO)) { printf ( "Could not initialize SDL - %s\n" , SDL_GetError()); return -1 ; } SDL_Window *screen; screen = SDL_CreateWindow("Simplest Video Play SDL2" , SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); if (!screen) { printf ("SDL: could not create window - exiting:%s\n" ,SDL_GetError()); return -1 ; } SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1 , 0 ); Uint32 pixformat=0 ; pixformat= SDL_PIXELFORMAT_IYUV; SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h); FILE *fp=NULL ; fp=fopen("sintel_640_360.yuv" ,"rb+" ); if (fp==NULL ){ printf ("cannot open this file\n" ); return -1 ; } SDL_Rect sdlRect; while (1 ){ 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 ); SDL_Delay(20 ); } SDL_Quit(); return 0 ; }
问题1:
解决 :在源文件里加入下面代码:
1 #pragma comment(lib, "legacy_stdio_definitions.lib" )
问题2:
解决:在源文件里加入下面代码:
1 FILE __iob_func[3 ] = { *stdin ,*stdout ,*stderr };
练习 修改源代码。对于测试文件,实现以下几种显示基本练习 :
1、二倍速度
2、二倍宽高
1 int screen_w=640 ,screen_h=360 ;
3、窗口大小固定为500x500
1 int screen_w=500 ,screen_h=500 ;
4、视频周围包围10像素的“黑框”
1 2 3 4 sdlRect.x = 10 ; sdlRect.y = 10 ; sdlRect.w = screen_w-20 ; sdlRect.h = screen_h-20 ;
5、换一段测试YUV素材进行播放
1 2 const int pixel_w=320 ,pixel_h=180 ;fp=fopen("test_yuv420p_320x180.yuv" ,"rb+" );
示例程序2: 需求:
1 2 3 4 1、窗口可以移动 2、窗口可以调整大小 3、按下空格键(SPACE)后暂停,再次按下空格后继续播放 4、显示黑白图像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 #include <stdio.h> extern "C" { #include "sdl/SDL.h" }; const int bpp=12 ;int screen_w=500 ,screen_h=500 ;const int pixel_w=320 ,pixel_h=180 ;unsigned char buffer [pixel_w*pixel_h*bpp/8 ];#define REFRESH_EVENT (SDL_USEREVENT + 1) #define BREAK_EVENT (SDL_USEREVENT + 2) int thread_exit=0 ;int refresh_video (void *opaque) { thread_exit=0 ; while (thread_exit==0 ) { SDL_Event event; event.type = REFRESH_EVENT; SDL_PushEvent(&event); SDL_Delay(40 ); } thread_exit=0 ; SDL_Event event; event.type = BREAK_EVENT; SDL_PushEvent(&event); return 0 ; } int main (int argc, char * argv[]) { if (SDL_Init(SDL_INIT_VIDEO)) { printf ( "Could not initialize SDL - %s\n" , SDL_GetError()); return -1 ; } SDL_Window *screen; screen = SDL_CreateWindow("Simplest Video Play SDL2" , SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); if (!screen) { printf ("SDL: could not create window - exiting:%s\n" ,SDL_GetError()); return -1 ; } SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1 , 0 ); Uint32 pixformat=0 ; pixformat= SDL_PIXELFORMAT_IYUV; SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h); FILE *fp=NULL ; fp=fopen("test_yuv420p_320x180.yuv" ,"rb+" ); if (fp==NULL ){ printf ("cannot open this file\n" ); return -1 ; } SDL_Rect sdlRect; SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL ,NULL ); SDL_Event event; while (1 ){ SDL_WaitEvent(&event); if (event.type==REFRESH_EVENT){ 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){ SDL_GetWindowSize(screen,&screen_w,&screen_h); }else if (event.type==SDL_QUIT){ thread_exit=1 ; }else if (event.type==BREAK_EVENT){ break ; } } SDL_Quit(); return 0 ; }