SDL打开YUV视频
文章目录
- 问题1:如何控制帧率?
- 问题2:如何触发退出事件?
- 问题3:如何实时调整视频窗口的大小
- 问题4:YUV如何一次读取一帧的数据?
问题1:如何控制帧率?

单独用一个子线程给主线程发送刷新画面的事件 主线程负责刷新画面 每次发送刷新画面的命令后就延迟一段事件 具体的帧率公式为1000 / 延迟事件 = 帧率
问题2:如何触发退出事件?
SDL_QUIT 事件通常由用户触发,当关闭窗口时,SDL 会生成此事件。这可以通过用户点击窗口的关闭按钮(如窗口右上角的 “X”)或通过其他机制关闭窗口(例如按 Alt+F4)来触发。在事件循环中检测到 SDL_QUIT 后,通常会执行相应的退出操作,如设置退出标志(s_thread_exit = 1),从而安全地终止程序或线程。

问题3:如何实时调整视频窗口的大小

接受窗口变化的消息 实时更新窗口的尺寸 根据窗口和视频部分的比例
让实时渲染的时候 视频部分乘上这部分比例 就能到达 视频和窗口同步大小
问题4:YUV如何一次读取一帧的数据?
在 YUV420 格式中,一帧的数据大小可以通过以下方式计算:
Y 分量占据整个画面的大小:video_width * video_height
U 和 V 分量各占 Y 分量的四分之一:(video_width * video_height) / 4
因此,一帧的总大小为:
y_frame_len + u_frame_len + v_frame_len = video_width * video_height + 2 * (video_width * video_height / 4)
简化为:
yuv_frame_len = video_width * video_height * 1.5
这样你就可以通过 yuv_frame_len 获取一帧的总大小。
#include <stdio.h>
#include <string.h>#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_IYUVint s_thread_exit = 0; // 退出标志 = 1则退出// 通过线程去控制1s刷多少帧
int refresh_video_timer(void *data) {while (!s_thread_exit) {SDL_Event event;// 事件类型为刷新事件event.type = REFRESH_EVENT;// 将事件推送到事件队列中SDL_PushEvent(&event);SDL_Delay(40); // 1000 / 40 = 25 帧}// 停止控制视频输出帧数的时候 将这里的状态重置s_thread_exit = 0;// push quit eventSDL_Event event;event.type = QUIT_EVENT;SDL_PushEvent(&event);return 0;
}
#undef main
int main(int argc, char *argv[]) {// 初始化 SDLif (SDL_Init(SDL_INIT_VIDEO)) {fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());return -1;}// SDLSDL_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;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, // 指定yuv格式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系统里面的事件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;}// 设置纹理的数据 video_width = 320, planeSDL_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;// 320x240 怎么保持原视频的宽高比例rect.w = video_width * w_ratio;rect.h = video_height * h_ratio;// rect.w = video_width * 0.5;// rect.h = video_height * 0.5;// 清除当前显示SDL_RenderClear(renderer);// 将纹理的数据拷贝给渲染器 会把比例还原回来设置一个视频SDL_RenderCopy(renderer, texture, NULL, &rect);// 显示SDL_RenderPresent(renderer);} else if (event.type == SDL_WINDOWEVENT) {// If Resize 更新窗口的尺寸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;
}相关文章:
SDL打开YUV视频
文章目录 问题1:如何控制帧率?问题2:如何触发退出事件?问题3:如何实时调整视频窗口的大小问题4:YUV如何一次读取一帧的数据? 问题1:如何控制帧率? 单独用一个子线程给主线…...
微服务架构面试内容整理-Archaius
Archaius 是由 Netflix 开发的一个配置管理库,主要用于处理动态配置和环境配置。在微服务架构中,Archaius 允许开发者以灵活的方式管理配置,从而更好地应对变化的需求。以下是 Archaius 的主要特点、工作原理和使用场景: 主要特点 1. 动态配置: Archaius 支持动态更新配置…...
实现 Nuxt3 预览PDF文件
安装必要的库,这里使用PDF.js库 npm install pdfjs-dist --save 为了解决跨域问题,在server/api 下 创建一个请求api, downloadFileByProxy.ts import { defineEventHandler } from h3;export default defineEventHandler(async event >…...
udp为什么会比tcp 有更低的延迟
UDP(User Datagram Protocol,用户数据报协议)相比TCP(Transmission Control Protocol,传输控制协议)具有更低的延迟,这主要归因于UDP协议的设计特点和机制。以下是对UDP比TCP延迟低的原因的详细…...
基于java+SpringBoot+Vue的洗衣店订单管理系统设计与实现
项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: Springboot mybatis Maven mysql5.7或8.0等等组成&#x…...
HarmonyOS-消息推送
一. 服务简述 Push Kit(推送服务)是华为提供的消息推送平台,建立了从云端到终端的消息推送通道。所有HarmonyOS 应用可通过集成 Push Kit,实现向应用实时推送消息,使消息易见,构筑良好的用户关系࿰…...
数据分析:宏基因组DESeq2差异分析筛选差异物种
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍原理:计算步骤:结果:加载R包准备画图主题数据链接导入数据Differential abundance (No BP vs 2BP TA)构建`countData`矩阵过滤低丰度物种构建DESeq数据对象DESeq2差异分析画图Di…...
出海企业如何借助云计算平台实现多区域部署?
云计算de小白 如需进一步了解,请单击链接了解有关 Akamai 云计算的更多信息 在本文中我们将告诉大家如何在Linode云计算平台上借助VLAN快速实现多地域部署。 首先我们需要明确一些基本概念和思想: 部署多区域 VLAN 为了在多区域部署中在不同的 VLAN …...
硬件---1电路设计安全要点以及欧姆定律
前言: 一直搞的东西都偏软件,硬件也一直在学,元器件、基础电路知识、PCB设计、模电运放都学的马马虎虎,因此决定进行系统性学习,内容基本来源于手里的视频和书本以及自己的感悟。 一电路安全 1电路安全 在初期基础…...
Linux如何更优质调节系统性能
一、硬件优化 增加物理内存:最直接的提升系统性能的方法。内存不足时,系统会频繁进行交换(swapping)活动,这会显著降低系统的响应速度,因为磁盘IO速度远低于内存访问速度。通过增加内存,可以减…...
第三十五章 Vue路由进阶之声明式导航(跳转传参)
目录 一、引言 二、查询参数传参 2.1. 使用方式 2.2. 完整代码 2.2.1. main.js 2.2.2. App.vue 2.2.3. Search.vue 2.2.4. Home.vue 2.2.5. index.js 三、动态路由传参 3.1. 使用方式 3.2. 完整代码 3.2.1. main.js 3.2.2. App.vue 3.2.3. Search.vue 3.2.4. Hom…...
python爬虫自动库DrissionPage保存网页快照mhtml/pdf/全局截图/打印机另存pdf
目录 零一、保存网页快照的三种方法二、利用打印机保存pdf的方法 零 最近星球有人问如何使用页面打印功能,另存为pdf 一、保存网页快照的三种方法 解决方案已经放在星球内:https://articles.zsxq.com/id_55mr53xahr9a.html当然也可以看如下代码&…...
基于毫米波雷达和TinyML的车内检测、定位与分类
英文标题:In-Cabin Detection, Localization and Classification based on mmWave Radar with TinyML 作者信息: 王志飞,程一格,彭辉,周会强,王铮,刘宏全所属机构:Calterah Semico…...
小E的射击训练
问题描述 小E正在训练场进行射击练习,靶有10个环,靶心位于坐标(0, 0)。每个环对应不同的得分,靶心内(半径为1)得10分,依次向外的每个环分数减少1分。若射击点在某个半径为i的圆内,则得11-i分。…...
React的概念以及发展前景如何?
React是一个由Facebook开发的用于构建用户界面的的开源JavaScript库,它主要用于构建大型、动态的Web应用程序。React的主要特点是使用VirtualDOM(虚拟DOM)来优化性能,并使用声明式的编程方式来编写UI。 React的主要概念包括&#…...
PDF生成:全面解析,C# 如何使用iTextSharp库(或其他类似库)生成PDF文档,包括如何将位图图像嵌入PDF中。
一、概述 PDF(Portable Document Format)是一种广泛使用的文档格式,由Adobe公司在1993年推出。PDF的目标是能够在任何设备上呈现固定格式的文档,无论是在不同的操作系统、硬件设备,还是在打印时,都能保证文…...
如何选择最适合的消息队列?详解 Kafka、RocketMQ、RabbitMQ 的使用场景
引言 在日常开发中,消息队列已经成为业务场景中几乎不可或缺的一部分。无论是订单系统、日志收集、分布式事务,还是大数据实时流处理,消息队列都在支撑着这些关键环节。目前市面上常用的消息队列有三种(ActiveMQ 虽然在企业集成中仍有应用&a…...
gitlab项目如何修改主分支main为master,以及可能遇到的问题
如果你希望将 Git 仓库的主分支名称从 main 修改为 master: 1. 本地修改分支名称 首先,切换到 main 分支: git checkout main将 main 分支重命名为 master: git branch -m main master2. 更新远程仓库 将本地更改推送到远程仓库…...
RRF(Reciprocal Rank Fusion,倒数排序融合)
RRF(Reciprocal Rank Fusion,倒数排序融合) 摘要 倒数排序融合 RRF 是一种简单的方法,用于结合多个 IR(Information Retrieval) 系统的文档排名,始终比任何单独的系统产生更好的结果。 通过使用 RRF 来结合几个TREC实验的结果,并建立一个 …...
移动开发(七):.NET MAUI使用RESTAPI实现查询天气笔记
目录 一、接口准备 二、实体部分 三、页面部分 四、后台代码逻辑 五、总结 在移动开发过程中,第三方对接是非常常见的。今天给大家分享.NET MAUI如何使用REST API实现输入城市名称查询天气的示例,希望对大家学习.NET MAUI可以提供一些帮助! 一、接口准备 首先我们需要…...
破局 AIGC 检测重围:PaperXie 如何让论文从 “机器量产“ 回归 “学术原创“——3000 字深度解构双效降重新范式
paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AIPPThttps://www.paperxie.cn/weight?type1https://www.paperxie.cn/weight?type1 引言:当学术写作撞上 AIGC 检测,毕业与投稿的双重困局凌晨两点的图书馆,屏幕上刺眼…...
AMD GPU大模型部署与优化指南:基于ollama-for-amd的本地AI解决方案
AMD GPU大模型部署与优化指南:基于ollama-for-amd的本地AI解决方案 【免费下载链接】ollama-for-amd Get up and running with Llama 3, Mistral, Gemma, and other large language models.by adding more amd gpu support. 项目地址: https://gitcode.com/gh_mir…...
SmolVLA部署案例:树莓派5+USB GPU加速器运行SmolVLA轻量版可行性探索
SmolVLA部署案例:树莓派5USB GPU加速器运行SmolVLA轻量版可行性探索 1. 引言 你有没有想过,让一个巴掌大的树莓派也能跑起来一个能“看懂”世界、听懂指令、并控制机器人动作的AI模型?这听起来像是科幻电影里的场景,但今天我们要…...
OWL ADVENTURE编辑功能展示:一键换装、智能擦除,效果自然
OWL ADVENTURE编辑功能展示:一键换装、智能擦除,效果自然 1. 编辑功能概览:像玩游戏一样修图 OWL ADVENTURE的图片编辑功能让人眼前一亮。不同于传统修图软件的复杂操作,它通过自然语言指令就能完成各种编辑任务,效果…...
图像比对与像素级分析:用diffimg实现高效差异检测
图像比对与像素级分析:用diffimg实现高效差异检测 【免费下载链接】diffimg Differentiate images in python - get a ratio or percentage difference, and generate a diff image 项目地址: https://gitcode.com/gh_mirrors/di/diffimg 在视觉内容创作与技…...
APIFox签名生成实战:从环境变量配置到MD5签名一键搞定
APIFox签名生成实战:从环境变量配置到MD5签名一键搞定 在接口开发与测试过程中,签名机制是保障接口安全性的重要手段。APIFox作为一款强大的API协作平台,提供了灵活的脚本功能,能够帮助开发者快速实现签名生成与自动化测试。本文将…...
基于VibeVoice和卷积神经网络的语音风格迁移
基于VibeVoice和卷积神经网络的语音风格迁移 1. 引言 你有没有想过,让AI用你喜欢的名人声音来朗读一篇文章?或者用某个特定角色的声音来讲述你的故事?这就是语音风格迁移技术的魅力所在。 传统的语音合成技术虽然已经相当成熟,…...
开源音频工作站Audacity:专业级音频处理的自由解决方案
开源音频工作站Audacity:专业级音频处理的自由解决方案 【免费下载链接】audacity Audio Editor 项目地址: https://gitcode.com/GitHub_Trending/au/audacity 在数字音频创作领域,专业软件往往意味着高昂的许可费用和陡峭的学习曲线。Audacity作…...
DeepSeek-R1-Distill-Qwen-7B效果展示:复杂问题推理实测
DeepSeek-R1-Distill-Qwen-7B效果展示:复杂问题推理实测 1. 模型能力概览 DeepSeek-R1-Distill-Qwen-7B是DeepSeek团队基于Qwen架构开发的7B参数推理模型,通过强化学习训练和知识蒸馏技术优化,在数学推理、代码生成和逻辑分析任务上展现出卓…...
告别Swagger原生UI!用Knife4j给你的SpringBoot API文档做个‘美容’
从Swagger到Knife4j:打造专业级API文档的终极指南 如果你已经厌倦了Swagger原生UI那千篇一律的界面和笨拙的操作体验,那么是时候给你的API文档来一次全面升级了。在当今这个注重用户体验的时代,一个美观、易用且功能强大的API文档界面&#x…...
