SDL视频播放
SDL视频显示的流程
SDL视频显示函数简介
SDL_Init():初始化SDL系统
SDL_GreateWindow():创建窗口SDL_Window
SDL_GreateRenderer():创建渲染器SDL_Renderer
SDL_GreateTexture():创建纹理SDL_Texture
SDL_UpdateTexture():设置纹理的数据
SDL_RenderCopy():将纹理的数据拷贝给渲染器
SDL_RenderPresent():显示
SDL_Delay():工具函数,用于延时。
SDL_Quit():退出SDL系统
视频显示的数据结构
SDL数据结构简介
SDL_Window:代表了一个“窗口”
SDL_Renderer:代表了一个“渲染器”
SDL_Texture:代表了一个“纹理”
SDL_Rect:一个简单的矩形结构
SDL多线程
函数
SDL_GreateThread():创建一个线程
数据结构
SDL_Thread:线程的句柄
SDL事件
函数
SDL_WaitEvent():等待一个事件
SDL_PushEvent():发送一个事件
数据结构
SDL_Event:代表一个事件
代码
#include <jni.h>
#include <android/log.h>
#define LOG_I(...) __android_log_print(ANDROID_LOG_ERROR,"main",__VA_ARGS__)
#include "SDL.h"
//测试SDL环境
//int main(int argc, char *argv[]){
// if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1){
// LOG_I("SDL_Init failed %s",SDL_GetError());
// return 0;
// }
// LOG_I("SDL_Init Success!");
//
// SDL_Quit();
// return 0;
//}
//利用SDL播放YUV视频像素数据
int main(int argc, char *argv[]){
//初始化SDL组件
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1){
LOG_I("SDL_Init failed %s",SDL_GetError());
return 0;
}
LOG_I("SDL_Init Success!");
int screen_width = 3130;
int screen_height = 1914;
int frame_width = screen_width;
int frame_height = screen_height;
//创建SDL_Window
//参数一:The title of the window, in UTF-8 encoding.窗口的标题
//参数二:The x position of the window, ::SDL_WINDOWPOS_CENTERED, or ::SDL_WINDOWPOS_UNDEFINED.窗口出现的位置X
//参数三:The y position of the window, ::SDL_WINDOWPOS_CENTERED, or ::SDL_WINDOWPOS_UNDEFINED.窗口出现的位置Y
//参数四:The width of the window, in screen coordinates.窗口的大小宽
//参数五:The height of the window, in screen coordinates.窗口的大小高
//参数六:The flags for the window, a mask of any of the following: 窗口的 状态,支持下列标识。包括了窗口的是否最大化、最小化,能否调整边界等等属性
//SDL_WINDOW_SHOWN,表示显示窗口;不过我更喜欢SDL_WINDOW_BORDERLESS,这样。。SDL2创建的窗口就没有那些标题和窗口的最大化之类的按键了 ;最后一个参数是可选参数,
//::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.
SDL_Window *sdl_window = SDL_CreateWindow(
"SDL_Window_Title"
,SDL_WINDOWPOS_CENTERED
,SDL_WINDOWPOS_CENTERED
,screen_width
,screen_height
,SDL_WINDOW_OPENGL|SDL_WINDOW_BORDERLESS);
if(sdl_window == NULL){
LOG_I("SDL_window创建失败");
return -1;
}
//创建SDL_Renderer渲染器
// 参数含义如下:
// window : 渲染的目标窗口。
// index:打算初始化的渲染设备的索引。设置“-1”则初始化默认的渲染设备。
// flags :支持以下值(位于SDL_RendererFlags定义中)
// SDL_RENDERER_SOFTWARE :使用软件渲染
// SDL_RENDERER_ACCELERATED :使用硬件加速
// SDL_RENDERER_PRESENTVSYNC:和显示器的刷新率同步
// SDL_RENDERER_TARGETTEXTURE :不太懂
// 返回创建完成的渲染器的ID。如果创建失败则返回NULL。
SDL_Renderer *sdl_renderer = SDL_CreateRenderer(sdl_window
,-1
,SDL_RENDERER_ACCELERATED);
//SDL_Texture创建纹理
// renderer:目标渲染器。
// format :纹理的格式。后面会详述。
// 其中用了一个宏SDL_DEFINE_PIXELFORMAT用于将几种属性合并到一个格式中。下面我们看看一个格式都包含哪些属性:
// SDL_PIXELTYPE_PACKED32:代表了像素分量的存储方式。PACKED代表了像素的几个分量是一起存储的,内存中存储方式如下:R1|G1|B1,R2|G2|B2…;ARRAY则代表了像素的几个分量是分开存储的,内存中存储方式如下:R1|R2|R3…,G1|G2|G3…,B1|B2|B3…
// SDL_PACKEDORDER_ARGB:代表了PACKED存储方式下像素分量的顺序。注意,这里所说的顺序涉及到了一个“大端”和“小端”的问题。这个问题在《最简单的视音频播放示例2:GDI播放YUV, RGB》中已经叙述,不再重复记录。对于Windows这样的“小端”系统,“ARGB”格式在内存中的存储顺序是B|G|R|A。
// SDL_PACKEDLAYOUT_8888:说明了每个分量占据的比特数。例如ARGB格式每个分量分别占据了8bit。
// 32:每个像素占用的比特数。例如ARGB格式占用了32bit(每个分量占据8bit)。
// 4:每个像素占用的字节数。例如ARGB格式占用了4Byte(每个分量占据1Byte)。
// access :可以取以下值(定义位于SDL_TextureAccess中)
// SDL_TEXTUREACCESS_STATIC :变化极少
// SDL_TEXTUREACCESS_STREAMING:变化频繁
// SDL_TEXTUREACCESS_TARGET :暂时没有理解
// w :纹理的宽
// h :纹理的高
// 创建成功则返回纹理的ID,失败返回0。
SDL_Texture *sdl_texture = SDL_CreateTexture(sdl_renderer
,SDL_PIXELFORMAT_IYUV
,SDL_TEXTUREACCESS_TARGET
,screen_width
,screen_height);
//设置纹理的数据
FILE *file_yuv = fopen("/storage/emulated/0/qq_video.yuv","rb+");
if(file_yuv == NULL){
LOG_I("打开文件失败!");
return -1;
}
SDL_Rect sdl_rect;
char buffer_pixels[screen_width*screen_height*3/2];
//循环读取YUV文件视频像素数据每一帧画面,进行渲染
while (true){
//判断文件是否读取完毕(视频是否播放完成)
if(feof(file_yuv)){
break;
}
// buffer 用于接收数据的内存地址
// size 要读的每个数据项的字节数,单位是字节
// count 要读count个数据项,每个数据项size个字节.
// stream file输入流
fread(buffer_pixels,1,screen_width*screen_height*3/2,file_yuv);
// texture:目标纹理。
// rect:更新像素的矩形区域。设置为NULL的时候更新整个区域。
// pixels:像素数据。
// pitch:一行像素数据的字节数。
// 成功的话返回0,失败的话返回-1。
SDL_UpdateTexture(sdl_texture,NULL,buffer_pixels,frame_width);
//将纹理数据拷贝给渲染器
sdl_rect.x = 0;
sdl_rect.y = 0;
sdl_rect.w = screen_width;
sdl_rect.h = screen_height;
//先清空帧画面,再重新绘制
SDL_RenderClear(sdl_renderer);
// renderer:渲染目标。
// texture:输入纹理。
// srcrect:选择输入纹理的一块矩形区域作为输入。设置为NULL的时候整个纹理作为输入。
// dstrect:选择渲染目标的一块矩形区域作为输出。设置为NULL的时候整个渲染目标作为输出。
// 成功的话返回0,失败的话返回-1。
SDL_RenderCopy(sdl_renderer,sdl_texture,NULL,&sdl_rect);
//显示帧画面
SDL_RenderPresent(sdl_renderer);
//延时渲染
SDL_Delay(50);//延时50ms
}
//释放资源
fclose(file_yuv);
SDL_DestroyTexture(sdl_texture);
SDL_DestroyRenderer(sdl_renderer);
//退出SDL系统
SDL_Quit();
return 0;
}
代码地址:CSDN地址