SDL2---编译SDL库、测试播放简单像素数据(YUV、RGB等)

版权声明:凡本人原创,转发请注明出处,谢谢! https://blog.csdn.net/qq_41248872/article/details/83415319

本篇博文整理自雷神(雷霄骅https://blog.csdn.net/leixiaohua1020/article/list/3)多篇博文,多谢分享,在此致敬!

SDL简介:

SDL库的作用说白了就是封装了复杂的视音频底层操作,简化了视音频处理的难度。

以下转自WiKi:

SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。
SDL使用GNU宽通用公共许可证为授权方式,意指动态链接(dynamic link)其库并不需要开放本身的源代码。因此诸如《雷神之锤4》等商业游戏也使用SDL来开发。

结构
虽然SDL时常被比较为‘跨平台的DirectX’,然而事实上SDL是定位成以精简的方式来完成基础的功能,它大幅度简化了控制图像、声音、输出入等工作所需撰写的代码。但更高级的绘图功能或是音效功能则需搭配OpenGL和OpenAL等API来达成。另外它本身也没有方便创建图形用户界面的函数。
SDL在结构上是将不同操作系统的库再包装成相同的函数,例如SDL在Windows平台上其实是DirectX的再包装,旧版本包装的是DirectX 5,现时的版本(SDL 1.2)则是DirectX 7。而在使用X11的平台上(包括Linux),SDL则是与Xlib库沟通来输出图像。
虽然SDL本身是使用C语言写成,但是它几乎可以被所有的编程语言所使用,例如:C++、Perl、Python(借由pygame库)、Pascal等等,甚至是Euphoria、Pliant这类较不流行的编程语言也都可行。
SDL库分为 Video、Audio、CD-ROM、Joystick 和 Timer 等若干子系统,除此之外,还有一些单独的官方扩充函数库。这些库由官方网站提供,并包含在官方文档中,共同组成了SDL的“标准库”:
SDL_image—支持时下流行的图像格式:BMP、PPM、XPM、 PCX、GIF、JPEG、PNG、TGA。
SDL_mixer—更多的声音输出函数以及更多的声音格式支持。
SDL_net—网络支持。
SDL_ttf—TrueType字体渲染支持。
SDL_rtf—简单的RTF渲染支持。


子系统
SDL将功能分成下列数个子系统(subsystem):
Video(图像)—图像控制以及线程(thread)和事件管理(event)。
Audio(声音)—声音控制
Joystick(摇杆)—游戏摇杆控制
CD-ROM(光盘驱动器)—光盘媒体控制
Window Management(视窗管理)-与视窗程序设计集成
Event(事件驱动)-处理事件驱动

SDL播放器开发流程:

SDL播放视频的代码流程大致如下:
初始化:  

SDL_Init(): 初始化SDL。 
SDL_CreateWindow(): 创建窗口(Window)。 
SDL_CreateRenderer(): 基于窗口创建渲染器(Render)。 
SDL_CreateTexture(): 创建纹理(Texture)。 

循环渲染数据: 

SDL_UpdateTexture(): 设置纹理的数据。 
SDL_RenderCopy(): 纹理复制给渲染器。 
SDL_RenderPresent(): 显示。

各函数的原型及参数分析: 

SDL_Init()

int SDLCALL SDL_Init(Uint32 flags)

其中,flags可以取下列值: 

SDL_INIT_TIMER:定时器
SDL_INIT_AUDIO:音频
SDL_INIT_VIDEO:视频
SDL_INIT_JOYSTICK:摇杆
SDL_INIT_HAPTIC:触摸屏
SDL_INIT_GAMECONTROLLER:游戏控制器
SDL_INIT_EVENTS:事件
SDL_INIT_NOPARACHUTE:不捕获关键信号(这个不理解)
SDL_INIT_EVERYTHING:包含上述所有选项

SDL_CreateWindow()

函数简介

SDL_CreateWindow()用于创建一个视频播放的窗口。SDL_CreateWindow()的原型如下。

SDL_Window * SDLCALL SDL_CreateWindow(const char *title,
                                                      int x, int y, int w,
                                                      int h, Uint32 flags);

参数含义如下。 

title    :窗口标题
x    :窗口位置x坐标。也可以设置为SDL_WINDOWPOS_CENTERED或SDL_WINDOWPOS_UNDEFINED。
y    :窗口位置y坐标。同上。
w    :窗口的宽
h    :窗口的高
flags :支持下列标识。包括了窗口的是否最大化、最小化,能否调整边界等等属性。
       ::SDL_WINDOW_FULLSCREEN,    ::SDL_WINDOW_OPENGL,
       ::SDL_WINDOW_HIDDEN,        ::SDL_WINDOW_BORDERLESS,
       ::SDL_WINDOW_RESIZABLE,     ::SDL_WINDOW_MAXIMIZED,
       ::SDL_WINDOW_MINIMIZED,     ::SDL_WINDOW_INPUT_GRABBED,
       ::SDL_WINDOW_ALLOW_HIGHDPI.
 返回创建完成的窗口的ID。如果创建失败则返回0。
 

SDL_CreateRenderer()

函数简介

SDL中使用SDL_CreateRenderer()基于窗口创建渲染器。SDL_CreateRenderer()原型如下。

SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window,
                                               int index, Uint32 flags);

参数含义如下。

window    : 渲染的目标窗口。

index    :打算初始化的渲染设备的索引。设置“-1”则初始化默认的渲染设备。

flags    :支持以下值(位于SDL_RendererFlags定义中)

    SDL_RENDERER_SOFTWARE :使用软件渲染
    SDL_RENDERER_ACCELERATED :使用硬件加速

    SDL_RENDERER_PRESENTVSYNC:和显示器的刷新率同步
    SDL_RENDERER_TARGETTEXTURE :不太懂

返回创建完成的渲染器的ID。如果创建失败则返回NULL。

SDL_CreateTexture()

函数简介

使用SDL_CreateTexture()基于渲染器创建一个纹理。SDL_CreateTexture()的原型如下。

SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer,
                                                        Uint32 format,
                                                        int access, int w,
                                                        int h);

 参数的含义如下。

renderer:目标渲染器。

format    :纹理的格式。后面会详述。
access    :可以取以下值(定义位于SDL_TextureAccess中)

    SDL_TEXTUREACCESS_STATIC    :变化极少
    SDL_TEXTUREACCESS_STREAMING    :变化频繁
    SDL_TEXTUREACCESS_TARGET    :暂时没有理解

w    :纹理的宽

h    :纹理的高

创建成功则返回纹理的ID,失败返回0。
 

SDL_UpdateTexture()

函数简介

SDL使用SDL_UpdateTexture()设置纹理的像素数据。SDL_UpdateTexture()的原型如下。

int SDLCALL SDL_UpdateTexture(SDL_Texture * texture,
                                          const SDL_Rect * rect,
                                              const void *pixels, int pitch);

参数的含义如下。

texture:目标纹理。

rect:更新像素的矩形区域。设置为NULL的时候更新整个区域。

pixels:像素数据。

pitch:一行像素数据的字节数。

成功的话返回0,失败的话返回-1。

SDL_RenderCopy()

函数简介

SDL使用SDL_RenderCopy()将纹理数据复制给渲染目标。SDL_RenderCopy()的原型如下。

int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer,
                                           SDL_Texture * texture,
                                           const SDL_Rect * srcrect,
                                           const SDL_Rect * dstrect);

 参数的含义如下。 

renderer:渲染目标。
texture:输入纹理。
srcrect:选择输入纹理的一块矩形区域作为输入。设置为NULL的时候整个纹理作为输入。
dstrect:选择渲染目标的一块矩形区域作为输出。设置为NULL的时候整个渲染目标作为输出。


成功的话返回0,失败的话返回-1。

SDL_RenderPresent()

函数简介

SDL使用SDL_RenderPresent()显示画面。SDL_RenderPresent()的原型如下。

void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);

 参数renderer用于指定渲染器。

环境准备:

(由于我测试得系统环境是在虚拟机上的ubuntu12.04下,系统安装包里面只有SDL1.2的包,所以需要下载SDL2-2.0的源码包进行手动编译,从而生成SDL库)

编译SDL库:

1.下载SDL-691c32a30fb9.tar.gz (官网获取即可)

2.解压,进入主目录

   tar zvxf SDL-691c32a30fb9.tar.gz

  cd  SDL-691c32a30fb9.tar.gz

3.配置:

  mkdir _install

 ./configure --prefix=${PWD}/_install  --enable-shared

4.编译:

 make -j4

5.安装:

 make install

(编译完成,在_install目录下可找到生成的库文件及头文件)

简单测试

SDL像素数据播放器,代码如下:

/**
 * 最简单的SDL2播放视频的例子(SDL2播放RGB/YUV)
 * Simplest Video Play SDL2 (SDL2 play RGB/YUV) 
 *
 * 本程序使用SDL2播放RGB/YUV视频像素数据。SDL实际上是对底层绘图
 * API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层
 * API。
 *
 * 函数调用步骤如下: 
 *
 * [初始化]
 * SDL_Init(): 初始化SDL。
 * SDL_CreateWindow(): 创建窗口(Window)。
 * SDL_CreateRenderer(): 基于窗口创建渲染器(Render)。
 * SDL_CreateTexture(): 创建纹理(Texture)。
 *
 * [循环渲染数据]
 * SDL_UpdateTexture(): 设置纹理的数据。
 * SDL_RenderCopy(): 纹理复制给渲染器。
 * SDL_RenderPresent(): 显示。
 *
 * This software plays RGB/YUV raw video data using SDL2.
 * SDL is a wrapper of low-level API (Direct3D, OpenGL).
 * Use SDL is much easier than directly call these low-level API.  
 *
 * The process is shown as follows:
 *
 * [Init]
 * SDL_Init(): Init SDL.
 * SDL_CreateWindow(): Create a Window.
 * SDL_CreateRenderer(): Create a Render.
 * SDL_CreateTexture(): Create a Texture.
 *
 * [Loop to Render data]
 * SDL_UpdateTexture(): Set Texture's data.
 * SDL_RenderCopy(): Copy Texture to Render.
 * SDL_RenderPresent(): Show.
 */
 
#include <stdio.h>

#include "SDL.h"

 
const int bpp=12;
 
int screen_w=800,screen_h=800;
const int pixel_w=640,pixel_h=480;
 
unsigned char buffer[pixel_w*pixel_h*bpp/8];
 
 
//Refresh Event
#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) {
		SDL_Event event;
		event.type = REFRESH_EVENT;
		SDL_PushEvent(&event);
		SDL_Delay(40);
	}
	thread_exit=0;
	//Break
	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; 
	//SDL 2.0 Support for multiple windows
	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;
 
	//IYUV: Y + U + V  (3 planes)
	//YV12: Y + V + U  (3 planes)
	pixformat= SDL_PIXELFORMAT_IYUV;  
 
	SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);
 
	FILE *fp=NULL;
	fp=fopen("yuv420p_640x480.yuv","rb+");
 
	if(fp==NULL){
		printf("cannot open this file\n");
		return -1;
	}
 
	SDL_Rect sdlRect;  
    
    //Create thread
	SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL);
	SDL_Event event;
	while(1){
		//Wait event
		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){
				// Loop
				fseek(fp, 0, SEEK_SET);
				fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp);
			}
 
			SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w);  
 
			//FIX: If window is resize
			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){
			//If Resize
			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;
}

创建头文件、库文件目录:

mkdir include lib

chmod 777 include lib

拷贝SDL头文件、库文件:

cp   (SDL库安装路径)/lib/lib*    lib/ -r      (记得加入权限:chmod 777 lib/*)    

cp    (SDL库安装路径) /include/SDL2/* include  (记得加入权限:chmod 777 include/*)    

编写Makefile:

BIN = player_SDL
IDIR = include/SDL2
SRC = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(SRC))

LDIR = lib
CFLAGS = -I$(IDIR) -g
LIBS = -L$(LDIR) -lSDL2 -lpthread

CC = gcc

#$@:所有的目标文件
#$^:所有的依赖文件

$(BIN): $(OBJS)
	$(CC) -o $@ $^ $(LIBS)


.PHONY: clean

clean:
	rm -rf $(OBJS) $(BIN)

 编译:

          make

          (若出现提示找不到libsdl2-2.0.so....错误,原因出在gcc编译器只能在系统目录下寻找链接库,所以解决办法是:

              拷贝所有sdl动态库到系统目录lib下,cp  lib/*  /lib)

运行:

        ./player_SDL

         (若运行出错,提示Could not initialize OpenGL / GLES library

         原因在于mesa-common-dev

         解决办法:尝试删除它 

          apt-get remove mesa-common-dev

          重新编译SDL库:./configure --prefix=${PWD}/_install  --enable-shared   

                                      make  -j4 

                                      make install

         完成后拷贝至相应位置即可,重新编译,并运行player_SDL。 .

         效果如下图(截图截得不是很好,不过结果正确了就行,将就看吧^^):

猜你喜欢

转载自blog.csdn.net/qq_41248872/article/details/83415319
SDL
今日推荐