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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/9207.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[MySQL]索引

索引介绍 索引是帮助数据库高效获取数据的数据结构。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用数据&#xff0c; 这样就可以在这些数据结构上实现高级查找算法&#xff0c;这种数据结构就是索引。 假设我们有…

window 利用Putty免密登录远程服务器

1 在本地电脑用putty-gen生成密钥 参考1 参考2 2 服务器端操作 将公钥上传至Linux服务器。 复制上述公钥到服务器端的authorized_keys文件 mkdir ~/.ssh vi ~/.ssh/authorized_keys在vi编辑器中&#xff0c;按下ShiftInsert键或者右键选择粘贴&#xff0c;即可将剪贴板中的文…

【大数据技术基础 | 实验八】HBase实验:新建HBase表

文章目录 一、实验目的二、实验要求三、实验原理四、实验环境五、实验内容和步骤&#xff08;一&#xff09;启动HBase集群&#xff08;二&#xff09;编写项目java代码&#xff08;三&#xff09;将代码导出jar包 六、实验结果七、实验心得 一、实验目的 掌握HBase数据模型(逻…

密钥管理服务 (KMS) 故障排除指南

企业客户将密钥管理服务 (KMS) 设置为部署流程的一部分&#xff0c;因为通过该服务&#xff0c;他们可以使用简单、直接的过程在其环境中激活 Windows。 通常&#xff0c;一旦设置了 KMS 主机&#xff0c;KMS 客户端就会自动连接到主机并自行激活。 然而&#xff0c;有时该流程…

CSS的配色

目录 1 十六进制2 CSS中的十六进制2.1 十六进制颜色的基本结构2.2 十六进制颜色的范围2.3 简写形式2.4 透明度 3 CSS的命名颜色4 配色4.1 色轮4.2 互补色4.3 类似色4.4 配色工具 日常在开发小程序中&#xff0c;客户总是希望你的配色是美的&#xff0c;但是美如何定义&#xff…

基于 RNN 的语言模型

基于 RNN 的语言模型 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类网络连接中包含环路的 神经网络的总称。 给定一个序列&#xff0c;RNN 的环路用于将历史状态叠加到当前状态上。沿着时间维度&#xff0c;历史状态被循环累积&#xff0c;并作为…

【软考网工笔记】网络基础理论——物理层

文章目录 贝尔系统 T1 载波光纤 - SFP接口差分&&曼彻斯特编码网桥MAC-in-MACQ-in-QIPv6的链路本地地址CRC校验与计算E1载波编码效率对称xDSL坚持算法-CSMAUDP头部字段万兆以太网标准 IEEE 802.3ae海明码-纠错码ARP帧中的目标MAC地址快速以太区网物理层标准 100BASE-TXM…

现代Web开发:TypeScript 深入解析与最佳实践

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 现代Web开发&#xff1a;TypeScript 深入解析与最佳实践 现代Web开发&#xff1a;TypeScript 深入解析与最佳实践 现代Web开发&a…

HCIP MPLS基础

一、 实验拓扑 二、 实验需求及解法 本实验模拟BGP路由黑洞环境&#xff0c;使用MPLS LDP解决路由黑洞。 完成以下需求&#xff1a; 1.设备IP地址配置&#xff0c;请测试直连。 sysname R1 interface GigabitEthernet0/0/0ip address 12.1.1.1 255.255.255.0interface Loop…

Kubernetes架构及核心组件

一、基本架构 Kubernetes集群可以被看作是一个工厂,而各个组件则是这个工厂里的不同部门: Kubernetes API服务器:就像是这个工厂的总经理,负责接收所有的请求并将它们分配给相应的部门进行处理。 etcd:就像是这个工厂的记事本,负责记录所有的配置信息和状态信息,以便其…

移动开发(七):.NET MAUI使用RESTAPI实现查询天气笔记

目录 一、接口准备 二、实体部分 三、页面部分 四、后台代码逻辑 五、总结 在移动开发过程中,第三方对接是非常常见的。今天给大家分享.NET MAUI如何使用REST API实现输入城市名称查询天气的示例,希望对大家学习.NET MAUI可以提供一些帮助! 一、接口准备 首先我们需要…

聊聊基于BERT模型实现多标签分类任务的实践与思考

概述 以预训练大模型为基座神经网络模型&#xff0c;通过模型预训练后的泛化能力与微调后的领域能力&#xff0c;作为NLP任务的解决方案。 在github上找了一个简单的仓库——multi_label_classification&#xff0c;该仓库基于BERT预训练大模型实现了多分类任务。通过对该仓库…

C语言 【大白话讲指针(中)】

在之前的文章中我们已经知道了指针的概念&#xff0c;指针就是一个变量&#xff0c;用来存放地址&#xff0c;地址指向唯一一块内存空间。指针的大小是固定的4/8个字节&#xff08;32为机器/64位机器&#xff09;。指针是有类型的&#xff0c;指针的类型决定了指针加减整数的步…

大数据分析在市场营销中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 大数据分析在市场营销中的应用 大数据分析在市场营销中的应用 大数据分析在市场营销中的应用 引言 大数据分析概述 定义与原理 发…

启明云端触觉智能与您相约2024年慕尼黑国际电子元器件博览会,不见不散!

展会信息 展会日期: 2024年11月12-15日 展馆名称: 慕尼黑国际展览中心 MesseMnchen exhibition center 展馆地址: Messegelnde 81829 Mnchen Germany 启明云端&触觉智能展位号&#xff1a;B6-351 诚邀您莅临我司展位&#xff0c;让我们在慕尼黑不见不散&#xff01; …

OPPO开源Diffusion多语言适配器—— MultilingualSD3-adapter 和 ChineseFLUX.1-adapter

MultilingualSD3-adapter 是为 SD3 量身定制的多语言适配器。 它源自 ECCV 2024 的一篇题为 PEA-Diffusion 的论文。ChineseFLUX.1-adapter是为Flux.1系列机型量身定制的多语言适配器&#xff0c;理论上继承了ByT5&#xff0c;可支持100多种语言&#xff0c;但在中文方面做了额…

【JavaEE初阶】网络原理(4)

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 网络层 > IP协议 IP协议报头结构 4位版本 4位首部长度 8位服务类型(TOS) 16位总长度(字节数), 16位标识 3位标志位 13位片偏移 8位生存时间(TTL) 8位协议 16位首部…

树莓派上安装与配置 Nginx Web 服务器教程

在树莓派上配置 Nginx 作为 Web 服务器的步骤如下&#xff1a; 1. 更新树莓派 首先&#xff0c;确保你的树莓派系统是最新的。打开终端并执行以下命令&#xff1a; sudo apt update sudo apt upgrade -y2. 安装 Nginx 在树莓派上安装 Nginx&#xff1a; sudo apt install …

Android Studio 中关于com.github.barteksc:android-pdf-viewer 无法正确加载的问题

Android Studio 的app 模块下&#xff0c;添加依赖&#xff1a; implementation com.github.barteksc:android-pdf-viewer:3.2.0-beta.1 运行程序报错&#xff1a; Caused by: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveEx…

[JAVA]Maven项目标准结构介绍

什么是Maven&#xff1f; Maven 是一个强大的项目管理和构建自动化工具&#xff0c;在Java开发中&#xff0c;一个项目通常会依赖许多外部的库&#xff0c;比如开发一个Web应用可能需要依赖Servlet APL&#xff0c;Spring框架等&#xff0c;和需要引入大量的Jar包。往往一个Ja…