当前位置: 首页 > news >正文

SDL显示YUV视频

文章目录

      • 1. **宏定义和初始化**
      • 2. **全局变量**
      • 3. **`refresh_video_timer` 函数**
      • 4. **`WinMain` 函数**
      • 主要功能及工作流程:
      • 总结:


1. 宏定义和初始化

#define REFRESH_EVENT   (SDL_USEREVENT + 1)     // 请求画面刷新事件
#define QUIT_EVENT      (SDL_USEREVENT + 2)     // 退出事件
  • REFRESH_EVENTQUIT_EVENT 是自定义的事件类型,用来触发画面刷新和退出操作。

2. 全局变量

int s_thread_exit = 0;  // 退出标志
  • s_thread_exit 标志用于控制视频播放线程的退出。

3. refresh_video_timer 函数

int refresh_video_timer(void *data)
{
    while (!s_thread_exit)
    {
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event); // 触发刷新事件
        SDL_Delay(40); // 约每40ms触发一次
    }

    s_thread_exit = 0;

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

    return 0;
}
  • refresh_video_timer 函数是一个线程函数,每隔 40 毫秒触发一次 REFRESH_EVENT,用于请求刷新画面。线程会一直运行,直到 s_thread_exit 被设置为 1。
  • 当播放完毕后,触发 QUIT_EVENT 以结束程序。

4. WinMain 函数

int WinMain(int argc, char* argv[])
{
    // 初始化 SDL
    if (SDL_Init(SDL_INIT_VIDEO))
    {
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
        return -1;
    }

    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; // YUV格式

    // 视频文件路径
    const char *yuv_path = "H:/SDL/SDL_test/yuv420p_320x240.yuv";
    FILE *video_fd = NULL;

    uint8_t *video_buf = NULL; // 存储视频数据
    uint32_t y_frame_len = video_width * video_height;
    uint32_t u_frame_len = video_width * video_height / 4;
    uint32_t v_frame_len = video_width * video_height / 4;
    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)
    {
        fprintf(stderr, "SDL: could not 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);

    // 分配内存用于存储 YUV 数据
    video_buf = (uint8_t*)malloc(yuv_frame_len);
    if (!video_buf)
    {
        fprintf(stderr, "Failed to allocate 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);

            // 设置显示区域的矩形(缩放保持比例)
            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;
}

主要功能及工作流程:

  1. SDL 初始化:

    • SDL_Init(SDL_INIT_VIDEO) 初始化 SDL 的视频模块。
    • 创建一个窗口 (SDL_CreateWindow)、一个渲染器 (SDL_CreateRenderer) 和一个纹理 (SDL_CreateTexture) 来渲染 YUV 数据。
  2. 读取 YUV 数据:

    • 打开 YUV 文件并读取 YUV 数据到缓冲区 video_buf
    • YUV 数据根据视频的分辨率和 YUV420P 格式计算出每一帧的长度。
  3. 视频帧渲染:

    • 每次读取一帧数据后,使用 SDL_UpdateTexture 将 YUV 数据更新到纹理。
    • 通过渲染器 SDL_Renderer 渲染纹理到窗口。
  4. 刷新和退出事件:

    • 创建了一个独立的线程定时触发 REFRESH_EVENT,控制视频的刷新频率。
    • 如果读取到文件结尾或退出事件,程序会退出。
  5. 窗口大小调整:

    • 在窗口大小变化时,程序会自动调整渲染区域的比例,保持视频的宽高比。
  6. 资源释放:

    • 在退出程序时,确保释放所有分配的资源,包括 SDL 相关的资源(窗口、渲染器、纹理)以及 YUV 数据缓冲区。

总结:

这个程序通过 SDL2 创建一个视频播放窗口,读取并显示 YUV 文件的每一帧视频数据。它通过一个单独的线程来周期性触发视频帧的刷新,保持视频播放的流畅。

http://www.dtcms.com/a/113516.html

相关文章:

  • 快速从零部署一个DeepSeek-R1服务
  • NAS原理与技术详解:从基础概念到实践应用
  • 基础知识补充篇:关于数据不可修改
  • 功能测试和性能测试的区别有哪些?
  • 使用Geotools中的原始方法来操作PostGIS空间数据库
  • java高并发------守护线程Daemon Thread
  • Redis数据结构之ZSet
  • P3654 First Step (ファーストステップ)
  • Linux:(五种IO模型)
  • 基于SSM的高校宿舍水电管理系统
  • 0201线性回归-机器学习-人工智能
  • 开篇 - 配置Unlua+VsCode的智能提示、调试以及学习方法
  • 【LeetCode 热题100】23:合并 K 个升序链表(详细解析)(Go语言版)
  • 《UNIX网络编程卷1:套接字联网API》第7章:套接字选项深度解析
  • 如何理解分类(Category)?Kotlin 扩展是何方神圣?C/C++编译器的C/C++扩展
  • 关于 Spring自定义缓存管理器 的详细说明,包含两种实现方式的对比和代码示例,并附表格总结
  • 复古未来主义屏幕辉光像素化显示器反乌托邦效果PS(PSD)设计模板样机 Analog Retro-Futuristic Monitor Effect
  • 多线程代码案例 - 2
  • 高速电路 PCB 设计要点二
  • 【代码模板】如何用FILE操作符打开文件?fopen、fclose
  • KUKA机器人软件WorkVisual更改语言方法
  • Springboot定时任务开发
  • Java 大视界 -- Java 大数据在智能医疗远程护理与患者健康管理中的应用与前景(175)
  • 游戏引擎学习第205天
  • infinityfree最新免费建站详细教程_无需备案_5G空间_无限流量_免费域名_免费SSL
  • [巴黎高师课程] 同步反应式系统(2024-2025)第三课 - Kind 2: 基于SMT的Lustre模型检查器
  • 快速解决 Java 服务 CPU 过高问题指南
  • Tomcat的部署
  • 泡棉压缩对显示模组漏光的定位分析及论述
  • C 语言函数四(递归)