SDL2 播放视频数据(YUV420P)

时间: 2023-11-14 admin 维修知识

SDL2 播放视频数据(YUV420P)

SDL2 播放视频数据(YUV420P)

1.简介

这里以常用的视频原始数据YUV420P为例,展示视频的播放。

SDL播放视频的流程如下:

  • 初始化SDL:SDL_Init();
  • 创建窗口:SDL_CreateWindow();
  • 创建渲染器:SDL_CreateRenderer();
  • 创建纹理:SDL_CreateTexture();
  • 设置纹理数据:SDL_UpdateTexture();
  • 纹理复制给渲染目标:使用SDL_RenderCopy()将纹理数据复制给渲染目标。在使用SDL_RenderCopy()之前,可以使用SDL_RenderClear()先使用清空渲染目标。
  • 显示界面:SDL_RenderPresent();

2.使用的数据结构以及方法介绍

SDL显示视频涉及到下列结构体:

  • SDL_Window:代表了窗口
  • SDL_Renderer:代表了渲染器
  • SDL_Texture:代表了纹理
  • SDL_Rect:一个矩形框,用于确定纹理显示的位置。

YUV/RGB像素数据首先加载至SDL_Texture,然后通过SDL_Render渲染至SDL_Window。其中SDL_Rect可以指定显示的位置。

SDL_CreateWindow:创建窗口

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

flags有以下的类型:

typedef enum
{SDL_WINDOW_FULLSCREEN = 0x00000001,         /**< fullscreen window */SDL_WINDOW_OPENGL = 0x00000002,             /**< window usable with OpenGL context */SDL_WINDOW_SHOWN = 0x00000004,              /**< window is visible */SDL_WINDOW_HIDDEN = 0x00000008,             /**< window is not visible */SDL_WINDOW_BORDERLESS = 0x00000010,         /**< no window decoration */SDL_WINDOW_RESIZABLE = 0x00000020,          /**< window can be resized */SDL_WINDOW_MINIMIZED = 0x00000040,          /**< window is minimized */SDL_WINDOW_MAXIMIZED = 0x00000080,          /**< window is maximized */SDL_WINDOW_MOUSE_GRABBED = 0x00000100,      /**< window has grabbed mouse input */SDL_WINDOW_INPUT_FOCUS = 0x00000200,        /**< window has input focus */SDL_WINDOW_MOUSE_FOCUS = 0x00000400,        /**< window has mouse focus */SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),SDL_WINDOW_FOREIGN = 0x00000800,            /**< window not created by SDL */SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported.On macOS NSHighResolutionCapable must be set true in theapplication's Info.plist for this to have any effect. */SDL_WINDOW_MOUSE_CAPTURE    = 0x00004000,   /**< window has mouse captured (unrelated to MOUSE_GRABBED) */SDL_WINDOW_ALWAYS_ON_TOP    = 0x00008000,   /**< window should always be above others */SDL_WINDOW_SKIP_TASKBAR     = 0x00010000,   /**< window should not be added to the taskbar */SDL_WINDOW_UTILITY          = 0x00020000,   /**< window should be treated as a utility window */SDL_WINDOW_TOOLTIP          = 0x00040000,   /**< window should be treated as a tooltip */SDL_WINDOW_POPUP_MENU       = 0x00080000,   /**< window should be treated as a popup menu */SDL_WINDOW_KEYBOARD_GRABBED = 0x00100000,   /**< window has grabbed keyboard input */SDL_WINDOW_VULKAN           = 0x10000000,   /**< window usable for Vulkan surface */SDL_WINDOW_METAL            = 0x20000000,   /**< window usable for Metal view */SDL_WINDOW_INPUT_GRABBED = SDL_WINDOW_MOUSE_GRABBED /**< equivalent to SDL_WINDOW_MOUSE_GRABBED for compatibility */
} SDL_WindowFlags;

SDL_CreateRenderer:创建渲染器

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

flags有以下的类型:

typedef enum
{SDL_RENDERER_SOFTWARE = 0x00000001,         /**< The renderer is a software fallback */SDL_RENDERER_ACCELERATED = 0x00000002,      /**< The renderer uses hardwareacceleration */SDL_RENDERER_PRESENTVSYNC = 0x00000004,     /**< Present is synchronizedwith the refresh rate */SDL_RENDERER_TARGETTEXTURE = 0x00000008     /**< The renderer supportsrendering to texture */
} SDL_RendererFlags;

SDL_CreateTexture:创建纹理

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

 access有以下的类型:

typedef enum
{SDL_TEXTUREACCESS_STATIC,    /**< Changes rarely, not lockable */SDL_TEXTUREACCESS_STREAMING, /**< Changes frequently, lockable */SDL_TEXTUREACCESS_TARGET     /**< Texture can be used as a render target */
} SDL_TextureAccess;

3.示例

#include <stdio.h>
#include <SDL.h>#define WINDOW_W 800
#define WINDOW_H 600const int bpp = 12;
const int pixel_w = 1920, pixel_h = 1080;
unsigned char buffer[pixel_w*pixel_h*bpp / 8];//Refresh Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)int thread_exit = 0;
int refresh_video(void *opaque) 
{while (thread_exit == 0) {SDL_Event event;event.type = REFRESH_EVENT;SDL_PushEvent(&event);SDL_Delay(40);}return 0;
}#undef main
int main(int argc,char* argv[])
{/*SDL初始化*/SDL_Init(SDL_INIT_VIDEO);/*创建窗口*/SDL_Window *window = SDL_CreateWindow("SDL SHOW VIDEO", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_W, WINDOW_H, SDL_WINDOW_SHOWN);/*创建渲染器*/SDL_Renderer *render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);/*设置渲染器颜色*/SDL_SetRenderDrawColor(render, 255, 255, 255, 255);/*清空渲染器*/SDL_RenderClear(render);//YUV420PUint32 pixformat = SDL_PIXELFORMAT_IYUV;//创建纹理SDL_Texture* sdlTexture = SDL_CreateTexture(render, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);//添加边框int border = 0;SDL_Rect sdlRect;sdlRect.x = border;sdlRect.y = border;sdlRect.w = WINDOW_W - border * 2;sdlRect.h = WINDOW_H - border * 2;//加载文件FILE *fp = NULL;fp = fopen("./test_yuv420p_1920x1080.yuv", "rb+");if (fp == NULL) {printf("cannot open this file\n");return -1;}//刷新线程SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL);SDL_Event event;while (1){//WaitSDL_WaitEvent(&event);if (event.type == REFRESH_EVENT) {if (fread(buffer, 1, pixel_w*pixel_h*bpp / 8, fp) != pixel_w * pixel_h*bpp / 8) {// Loopfseek(fp, 0, SEEK_SET);fread(buffer, 1, pixel_w*pixel_h*bpp / 8, fp);}SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);SDL_RenderClear(render);SDL_RenderCopy(render, sdlTexture, NULL, &sdlRect);SDL_RenderPresent(render);//Delay 40msSDL_Delay(40);}else if (event.type == SDL_QUIT){break;}}SDL_DestroyTexture(sdlTexture);/*释放纹理*/SDL_DestroyWindow(window);SDL_DestroyRenderer(render);return 0;
}

4.更多参考

[总结]FFMPEG视音频编解码零基础学习方法_零基础ffmpeg 雷霄骅-CSDN博客