SDL入门

本篇主要用于记录SDL2.0.22的基本用法,参考别人的代码,并加了注释方便理解这些api

以下两个demo可以在VS中编译并运行,代码参考 SDL视频显示_奋斗吧!骚年!的博客-CSDN博客

1、SimpleSDL

这个demo使用SDL api来播放yuv视频,运行可以发现窗口并不能移动或者缩放

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

extern "C"
{
#include "SDL.h" 
}

int main(int argc, char* argv[]) {
    // 窗口大小
    int screen_w = 1000;
    int screen_h = 1000;

    // 视频大小
    const int pixel_w = 352, pixel_h = 288;
    const int bpp = 12;

    // 这里buffer大小为 1 帧数据 width * height * 3 / 2,主要是因为YUV420这种采样方式
    unsigned char buffer[pixel_w * pixel_h * bpp / 8];

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

    // 创建一个SDL_Window
    // 第二个参数、第三个参数是相对于显示器左上角的坐标
    // 第四个参数、第五个参数是窗口大小
    // 最后一个参数为窗口选项
    SDL_Window *screen = SDL_CreateWindow("SimpleSDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if (!screen)
    {
        printf("could not create window: %s\n", SDL_GetError());
        return -1;
    }

    // 创建一个SDL_Render对象,第一个参数为SDL_Window,第二个参数为图层序号、第三个参数为flags
    SDL_Renderer *sdlRenderer = SDL_CreateRenderer(screen, -1, 0);

    // 数据的存储格式
    Uint32 pixformat = SDL_PIXELFORMAT_IYUV;

    // 创建一个SDL_Texture对象
    // 第一个参数为SDL_Render
    // 第二个参数为数据格式
    // 
    // 第四第五个为视频的宽高
    SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);

    FILE *fp = fopen("E:\\Videos\\YUV\\352_288.yuv", "rb+");
    if (fp == NULL) {
        printf("cannot open this file\n");
        return -1;
    }

    // 这个sdlRect表示渲染的视频相对窗口的位置
    SDL_Rect sdlRect;
    sdlRect.x = 20;
    sdlRect.y = 50;
    sdlRect.w = screen_w;
    sdlRect.h = screen_h;

    int i = 0;

    while (1) {
        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_Texture
        // 最后一个参数为 pitch
        SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);


        // 清除Render中的数据
        SDL_RenderClear(sdlRenderer);
        // 将sdltexture中的数据拷贝给render
        // 第三个参数SDL_Rect表示拷贝的数据范围
        // 第四个参数SDL_Rect表示渲染的大小以及相对渲染窗口的位置
        SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
        // 渲染
        SDL_RenderPresent(sdlRenderer);
        //Delay 40ms
        SDL_Delay(40);

    }
    SDL_Quit();
    return 0;
}

 

2、advanced SDL

主要用了消息事件机制来做视频播放,这时候窗口可以自由移动并且缩放

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

extern "C"
{
#include "SDL.h" 
}

// 自定义事件
//Refresh Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)
//Break
#define BREAK_EVENT  (SDL_USEREVENT + 2)

int thread_exit = 0;

int refresh_video(void* opaque) {
    thread_exit = 0;
    while (thread_exit == 0) {
        // 每隔40ms发送一个Refresh
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
        SDL_Delay(4000);
    }
    thread_exit = 0;
    //Break
    SDL_Event event;
    event.type = BREAK_EVENT;
    SDL_PushEvent(&event);
    return 0;
}

int main(int argc, char* argv[])
{
    const int bpp = 12;

    int screen_w = 500, screen_h = 500;
    const int pixel_w = 352, pixel_h = 288;

    unsigned char buffer[pixel_w * pixel_h * bpp / 8];

    if (SDL_Init(SDL_INIT_VIDEO)) {
        printf("Could not initialize SDL - %s\n", SDL_GetError());
        return -1;
    }

    SDL_Window* screen = SDL_CreateWindow("Advanced 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 = SDL_PIXELFORMAT_IYUV;

    SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);

    FILE *fp = fopen("E:\\Videos\\YUV\\352_288.yuv", "rb+");
    if (fp == NULL) {
        printf("cannot open this file\n");
        return -1;
    }

    SDL_Rect sdlRect;

    // 创建一个SDL线程
    SDL_Thread* refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL);
    SDL_Event event;
    while (1) {
        // Wait 阻塞等待事件
        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;
}

 

posted @ 2022-05-28 18:43  青山渺渺  阅读(263)  评论(0编辑  收藏  举报