音视频-SDL的简单使用

使用SDL进行音视频的播放

SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。

SDL的下载地址: https://www.libsdl.org/

现在较为新的版本在main函数中需要添加#define SDL_MAIN_HANDLED定义, 初步代码如下:

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define SDL_MAIN_HANDLED
#include <SDL.h>

//自定义消息类型
#define REFRESH_EVENT   (SDL_USEREVENT + 1)     // 请求画面刷新事件
#define QUIT_EVENT      (SDL_USEREVENT + 2)     // 退出事件

//定义分辨率
// YUV像素分辨率
#define YUV_WIDTH   320
#define YUV_HEIGHT  240

//定义YUV格式
#define YUV_FORMAT  SDL_PIXELFORMAT_IYUV

int s_thread_exit = 0;  // 退出标志 = 1则退出

int refresh_video_timer(void *data)
{
    while (!s_thread_exit)
    {
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
        SDL_Delay(40);
    }

    s_thread_exit = 0;

    //push quit event
    SDL_Event event;
    event.type = QUIT_EVENT;
    SDL_PushEvent(&event);

    return 0;
}


int main()
{
    if (SDL_Init(SDL_INIT_VIDEO)) {
        fprintf(stderr, "Can't not initialize SDL, err: %s\n", SDL_GetError());
    }

    SDL_Event event;                    // 事件
    SDL_Rect rect;                      // 矩形
    SDL_Window *window = NULL;          // 窗口
    SDL_Renderer *renderer = NULL;      // 渲染
    SDL_Texture *texture = NULL;        // 纹理
    SDL_Thread *timer_thread = NULL;    // 请求刷新线程
    uint32_t pixformat = YUV_FORMAT;    // YUV420P,即是SDL_PIXELFORMAT_IYUV

    // 分辨率
    // 1. YUV的分辨率
    int video_width = YUV_WIDTH;
    int video_height = YUV_HEIGHT;
    // 2.显示窗口的分辨率
    int win_width = YUV_WIDTH;
    int win_height = YUV_WIDTH;

    // YUV文件句柄
    FILE *video_fd = NULL;
    const char *yuv_path = "yuv420p_320x240.yuv";

    size_t video_buff_len = 0;

    uint8_t *video_buf = NULL; //读取数据后先把放到buffer里面

    // 我们测试的文件是YUV420P格式
    uint32_t y_frame_len = video_width * video_height;
    uint32_t u_frame_len = video_width * video_height / 4; // 420p是4个y对应一个u
    uint32_t v_frame_len = video_width * video_height / 4; // 420p是4个y对应一个v
    uint32_t yuv_frame_len = y_frame_len + u_frame_len + v_frame_len;

    window = SDL_CreateWindow("Simplest YUV Player",
                              SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED,
                              video_width, video_height,
                              SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if (!window) {
        printf("Can't create window, err: %s\n", SDL_GetError());
        goto _FAIL;
    }

    // 基于窗口创建渲染器
    renderer = SDL_CreateRenderer(window, -1, 0);

    // 基于渲染器创建纹理
    texture = SDL_CreateTexture(renderer,
                                pixformat,
                                SDL_TEXTUREACCESS_STREAMING,
                                video_width,
                                video_height);

    // 分配空间
    video_buf = (uint8_t*)malloc(yuv_frame_len);
    if (!video_buf) {
        fprintf(stderr, "Failed to alloce yuv frame space!\n");
        goto _FAIL;
    }

    // 打开YUV文件
    video_fd = fopen(yuv_path, "rb");
    if (!video_fd) {
        fprintf(stderr, "Failed to open yuv file\n");
        goto _FAIL;
    }

    // 创建请求刷新线程
    timer_thread = SDL_CreateThread(refresh_video_timer, NULL, NULL);

    while (1) {
        SDL_WaitEvent(&event);

        if (event.type == REFRESH_EVENT) {
            video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd);
            if (video_buff_len <= 0) {
                fprintf(stderr, "Failed to read data from yuv file!\n");
                goto _FAIL;
            }

            // 设置纹理的数据
            SDL_UpdateTexture(texture, NULL, video_buf, video_width);

            // 显示区域, 可以通过修改w和h进行缩放
            rect.x = 0;
            rect.y = 0;
            float w_ratio = win_width * 1.0 / video_width;
            float h_ratio = win_height * 1.0 / video_height;
            rect.w = video_width * w_ratio;
            rect.h = video_height * h_ratio;

            // 清屏
            SDL_RenderClear(renderer);
            // 将纹理的数据拷贝给渲染器
            SDL_RenderCopy(renderer, texture, NULL, &rect);
            // 显示
            SDL_RenderPresent(renderer);
        } else if (event.type == SDL_WINDOWEVENT) {
            SDL_GetWindowSize(window, &win_width, &win_height);
            printf("SDL_WINDOWEVENT win_width:%d, win_height:%d\n", win_width, win_height);
        } else if (event.type == SDL_QUIT) {
            s_thread_exit = 1;
        } else if (event.type == QUIT_EVENT) {
            break;
        }
    }

_FAIL:
    s_thread_exit = 1;

    // 释放资源
    if(timer_thread)
        SDL_WaitThread(timer_thread, NULL); // 等待线程退出
    if(video_buf)
        free(video_buf);
    if(video_fd)
        fclose(video_fd);
    if(texture)
        SDL_DestroyTexture(texture);
    if(renderer)
        SDL_DestroyRenderer(renderer);
    if(window)
        SDL_DestroyWindow(window);

    SDL_Quit();

    return 0;
}
相关推荐
镭封13 小时前
短剧多人对白怎么配?一人完成多角色配音的办法
人工智能·音视频·语音识别·媒体
技灵AI15 小时前
Wan 3.0 API怎么做多参考商品视频?从图片、视频、音频分工到30秒交付
人工智能·prompt·aigc·音视频·wan 3.0
赛博仓鼠16 小时前
MiniMax H3 实测:8GB显存跑2K视频+原生音频,开源视频生成的新卷王
开源·aigc·音视频
byte轻骑兵17 小时前
【LE Audio】PBP精讲[4]: 公共广播通告的设计逻辑与数据交互流程
人工智能·音视频·le audio·低功耗蓝牙音频
hz5678917 小时前
手术室视频示教系统解决方案:让临床教学突破空间限制
安全·音视频·实时音视频·信息与通信·智能硬件
可乐鸡翅yeah_19 小时前
混合内容 Mixed‑Content 安全策略,HLS HTTPS 页面加载 HTTP 资源排错实战
运维·ffmpeg·音视频·媒体·m3u8
揽秀亭长21 小时前
音轨分离处理方案及效果测试分析
人工智能·音视频
美狐美颜SDK开放平台1 天前
直播APP如何兼顾画质与低延迟?视频美颜SDK性能优化开发思路
人工智能·深度学习·音视频·美颜sdk·第三方美颜sdk
山顶夕景1 天前
【VLM】Qwen3.8-Omni-Flash长音视频理解Agentic模型
音视频·vlm·视频理解·agentic·全模态
tedcloud1231 天前
emilkowalski/skills:让 AI 写出来的网页更有“设计感”
服务器·人工智能·开源·音视频·ai编程