使用SDL_QT直接播放渲染YUV格式文件

0.前要

  •   下载一个文件,名字为 400_300_25.mp4,我们用ffmplay.exe将其转化为yuv文件,具体操作如下:
  •   进入cmd控制台,进入ffmplay.exe文件的目录下,输入ffmpeg -i 文件名.mp4 文件名.yuv 回车,会生成一个yuv文件
  • IYUV 是 YUV420 格式的一种变体,其中 Y 分量在内存中是连续存储的,而 U 和 V 分量是交错存储的。因此,一个 IYUV 像素点的大小与 YUV420 相同。

    在 IYUV 中,一个像素的大小通常为:

Y 分量:8 位(1 字节)

U 分量:8 位/4 = 2 位(0.25 字节)

V 分量:8 位/4 = 2 位(0.25 字节)

  • 400*300的图像,指的是 400列 300行,每行400个像素点

1.代码

#include "sdlqtrgb.h"
#include <sdl/SDL.h>
#include <fstream>
#include <QMessageBox>
using namespace std;
#pragma comment(lib,"SDL2.lib")
static SDL_Window* sdl_win = NULL;
static SDL_Renderer* sdl_render = NULL;
static SDL_Texture* sdl_texture = NULL;
static int sdl_width = 0;
static int sdl_height = 0;
static unsigned  char* yuv = NULL;
static int pix_size = 2;
static ifstream yuv_file;
void SdlQtRGB::timerEvent(QTimerEvent* ev)
{yuv_file.read((char*)yuv, sdl_width * sdl_height * 1.5);//yuv 平面存储存储// yyyyyyyy uu vvSDL_UpdateTexture(sdl_texture, NULL, yuv,sdl_width  //一行 y的字节数);SDL_RenderClear(sdl_render);SDL_Rect rect;rect.x = 0;rect.y = 0;rect.w = sdl_width;rect.h = sdl_height;SDL_RenderCopy(sdl_render, sdl_texture, NULL, &rect);SDL_RenderPresent(sdl_render);
}SdlQtRGB::SdlQtRGB(QWidget* parent): QWidget(parent)
{//打开yuv文件yuv_file.open("D:\\lesson\\code\\bin\\x86\\400_300_25.yuv", ios::binary);if (!yuv_file.is_open()){QMessageBox::information(this, "", "open yuv failed!");return;}ui.setupUi(this);sdl_width = 400;sdl_height = 300;ui.label->resize(sdl_width, sdl_height);//初始化SDLSDL_Init(SDL_INIT_VIDEO);//创建窗口sdl_win = SDL_CreateWindowFrom((void*)ui.label->winId());//创建渲染器sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED);//创建材质 支持YUVsdl_texture = SDL_CreateTexture(sdl_render,SDL_PIXELFORMAT_IYUV,SDL_TEXTUREACCESS_STREAMING,sdl_width,sdl_height);yuv = new unsigned char[sdl_width * sdl_height * pix_size];startTimer(10);
}

2.代码解析

1.构造函数解析

  • 打开了一个YUV文件,文件路径是指定的路径。ios::binary 表示以二进制模式打开文件,注意yuv文件名用绝对路径,且用双斜杠,不然报错!!我因为这个试过多种排错,比如打印当前工作目录,没问题,换了一个yuv文件怀疑我的yuv文件损坏了,也是一样的问题,最后加了双斜杠才能打开这个文件,再windows下可能\后跟一个字母会被误认为一个操作,比如\n是换行,那如果一个文件名为nnn.yuv呢 就会出现歧义,反正我的环境要打双斜杠
  • 设置了窗口的宽度和高度,并将界面上的 label 控件的大小设置为这些值。这个控件将用于显示YUV视频帧,其实可以直接再QT的UI可视化界面上进行操作,直接拖动一个label到wiget上设置为400*300的大小即可,用代码有点烦喏
  • 调用 SDL_Init 函数来初始化SDL库的视频子系统。这是必要的,因为我们将使用SDL来处理图形。
  • 调用 SDL_CreateWindowFrom 函数来创建一个SDL窗口,并将其与界面上的 label 控件关联起来。
  • 调用 SDL_CreateRenderer 函数来创建一个SDL渲染器,用于在窗口上进行绘制。
  • 调用 SDL_CreateTexture 函数来创建一个SDL纹理。参数包括渲染器、纹理格式(SDL_PIXELFORMAT_IYUV 表示YUV格式)、纹理访问方式(SDL_TEXTUREACCESS_STREAMING 表示数据将被频繁更新)、宽度和高度。
  • 动态分配了一个大小为 sdl_width * sdl_height * pix_size 字节的内存块,并将指针存储在 yuv 变量中。这个内存块用于存储YUV视频帧的数据。
  • 调用 startTimer 函数,启动一个定时器,每隔10毫秒触发一次定时器事件。定时器事件在之前的代码中已经被重载,用于读取YUV数据、更新纹理和刷新屏幕显示。

这样,构造函数完成了打开YUV文件、设置窗口大小、初始化SDL、创建窗口、渲染器和纹理,以及分配内存并启动定时器的一系列操作。整个流程为在SDL窗口中显示YUV视频提供了基础。

2.定时器函数解析

  • 使用 read 函数从 yuv_file 文件流中读取数据,并将其存储到 yuv 数组中。这个数组通常用于存储YUV格式的视频帧数据。数据的大小为 sdl_width * sdl_height * 1.5 字节,这是因为YUV格式中,每个像素有一个Y分量和两个色度分量(U和V),所以总共需要 sdl_width * sdl_height * 1.5 字节的空间来存储整个图像的数据。
  • yuv 数据的存储方式。在这个示例中,Y分量依次存储在数组的前面,接着是U分量,最后是V分量。yyyyyyyy uu vv yyyyyyyy uu vv.......(IYUV像素点存储格式)一直循环 对比 BGRABGRABGRA........(ARGB像素点的存储格式)
yyyyyyyy
uu
vv
yyyyyyyy
uu
vv
yyyyyyyy
uu
vv
...
...
...
  • 调用 SDL_UpdateTexture 函数来更新SDL纹理中的数据。参数包括要更新的纹理、要更新的矩形区域(在这里是整个纹理)、指向新数据的指针(yuv 数组),以及一行Y分量的字节数。由于YUV数据是按行存储的,所以传递一行Y分量的字节数可以帮助SDL正确地解析数据。SDL_UpdateTexture 函数中,第四个参数表示每一行的像素大小,为什么本代码传的是sdl_width而对ARGB格式处理的时候传的是sdl_width*像素大小呢?因为YUV420P中每个Y分量大小为1B,对YUV处理的时候默认传一行Y所占字节数也就是sdl_width*1B=sdl_width。
  • 调用 SDL_RenderClear 函数来清空渲染器的内容,准备绘制新的帧。
  • 定义了一个 SDL_Rect 结构体变量 rect,用于表示要绘制的矩形区域的位置和大小。在这个例子中,矩形的位置是窗口的左上角,大小是整个窗口的大小。
  • 调用 SDL_RenderCopy 函数来将纹理复制到渲染器中。参数包括渲染器、要复制的纹理、源矩形(在这里是整个纹理,即 NULL),以及目标矩形(在这里是整个窗口的矩形区域)。
  • 调用 SDL_RenderPresent 函数来更新屏幕显示,将渲染器中的内容呈现到屏幕上。

这样,timerEvent 函数完成了读取YUV数据、更新纹理、清空渲染器、复制纹理到渲染器中以及更新屏幕显示的一系列操作。这些操作使得YUV视频帧得以在SDL窗口中实时显示。

3.运行结果展示

giao giao giao

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java进阶学习笔记15——接口概述

认识接口&#xff1a; Java提供了一个关键字Interface&#xff0c;用这个关键字我们可以定义一个特殊的结构&#xff1a;接口。 接口不能创建对象。 注意&#xff1a;接口不能创建对象&#xff0c;接口是用来被类实现&#xff08;implements&#xff09;的&#xff0c;实现接口…

kotlinx.coroutines.debug.AgentPremain

大家好 我是苏麟 . 项目引入AI大模型 debug 出现报错 设置 勾选

微调Llama3实现在线搜索引擎和RAG检索增强生成功能

视频中所出现的代码 Tavily SearchRAG 微调Llama3实现在线搜索引擎和RAG检索增强生成功能&#xff01;打造自己的perplexity和GPTs&#xff01;用PDF实现本地知识库_哔哩哔哩_bilibili 一.准备工作 1.安装环境 conda create --name unsloth_env python3.10 conda activate …

读书笔记-Java并发编程的艺术--持续更新中

文章目录 第1章 并发编程的挑战1.1 上下文切换1.1.1 多线程一定快吗1.1.2 如何减少上下文切换 1.2 死锁1.3 资源限制的挑战 第2章 Java并发机制的底层实现原理第3章 Java内存模型第4章 Java编发编程基础第5章 Java中的锁第6章 Java并发容器和框架第7章 Java中的13个原子操作类第…

不知道是该怎么引用多个函数片段?具体示例如代码

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

Linux之共享内存mmap用法实例(六十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

三前奏:获取/ 读取/ 评估数据【数据分析】

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 前面的博客 数据分析—技术栈和开发环境搭建 …

【全网最全】2024电工杯数学建模B题问题一14页论文+19建模过程代码+py代码+2种保奖思路+数据等(后续会更新成品论文等)

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片链接&#xff0c;那是获取资料的入口&#xff01; 【全网最全】2024电工杯数学建模B题问一论文19建模过程代码py代码2种保奖思路数据等&#xff08;后续会更新成品论文等&#xff09;「首先来看看目前已…

香蕉成熟度检测YOLOV8NANO

香蕉成熟度检测YOLOV8NANO&#xff0c;采用YOLOV8NANO训练&#xff0c;得到PT模型&#xff0c;然后转换成ONNX模型&#xff0c;让OEPNCV调用&#xff0c;从而摆脱PYTORCH依赖&#xff0c;支持C。python&#xff0c;安卓开发。能检测六种香蕉类型freshripe freshunripe overripe…

轻松拿捏C语言——【字符串函数】的使用及模拟实现

&#x1f970;欢迎关注 轻松拿捏C语言系列&#xff0c;来和 小哇 一起进步&#xff01;✊ &#x1f389;创作不易&#xff0c;请多多支持&#x1f389; &#x1f308;感谢大家的阅读、点赞、收藏和关注&#x1f495; &#x1f339;如有问题&#xff0c;欢迎指正 感谢 目录 一、…

力扣--哈希表13.罗马数字转整数

首先我们可以知道&#xff0c;一个整数&#xff0c;最多由2个罗马数字组成。 思路分析 这个方法能够正确将罗马数字转换为阿拉伯数字的原因在于它遵循了罗马数字的规则&#xff0c;并且对这些规则进行了正确的编码和处理。 罗马数字规则 罗马数字由以下字符组成&#xff1a…

解决 Failed to parse remote port from server output【Remote-SSH】【VSCode】

描述 一早起来&#xff0c;发现remote-ssh无法进入服务器容器&#xff0c;本地使用git bash进行ssh可正常连接服务器&#xff0c;基本确定是vscode工具本身的问题。重装本地用户的.vscode相关目录清空&#xff0c;vscode重装均无果&#xff0c;不建议尝试。弹窗信息为Could no…

element-plusDate Picker 日期选择器获取年月日

代码逻辑 对选择日期选择后进行搜索 &#xff1a; function dataValue(value) {console.log(value);scenic_list.value arrlist.value.filter(function (item) {// 判断是否满足搜索条件if (String(item.create_time).indexOf(String(value)) > -1) {return scenic_list}}…

WordPress国外超人气主题Vikinger汉化版

WordPress国外超人气主题Vikinger汉化版 前言效果图安装教程领取主题下期更新预报 前言 我们在上一个教程已经学过如何安装WordPress&#xff0c;所以现在不用多说。 效果图 安装教程 下载后先本地解压&#xff0c;找到vikinger.zip文件&#xff0c;上传安装并启用主题。 访…

【Linux】进程终止与进程等待

目录 进程终止 errno exit和_exit 进程等待 wait和waitpid 宏&#xff1a;WIFEXITED 非阻塞等待 进程终止 下面要谈的一个话题就是进程终止&#xff0c;就是说一个进程退出了&#xff0c;可能有三种情况 1.进程代码执行完&#xff0c;结果是正确的 2.进程代码执行完&…

c++入门的基础知识

c入门 C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等。熟悉C语言之后&#xff0c;对C学习有一定的帮助&#xff0c;本章节主要目标&#xff1a; 补充C语言语法的不足&#xff0c;以及C是如何对C语言设计…

手机边听边充音频转接器双盲插系列:便捷充电,畅享音乐6500

在快节奏的生活中&#xff0c;手机已经成为我们不可或缺的日常用品。无论是工作、学习还是娱乐&#xff0c;手机都扮演着重要角色。然而&#xff0c;当我们沉浸在音乐的海洋中时&#xff0c;手机电量不足的困扰却时常打断我们的美好体验。为了解决这一难题&#xff0c;手机边听…

WEB攻防【2】——ASPX/.NET项目/DLL反编译/未授权访问/配置调试报错

ASP&#xff1a;windowsiisaspaccess .net&#xff1a;windowsiisaspxsqlserver IIS上的安全问题也会影响到 WEB漏洞&#xff1a;本身源码上的问题 服务漏洞&#xff1a;1、中间件 2、数据库 3、第三方软件 #知识点: 1、.NET:配置调试-信息泄绵 2、.NET:源码反编译-DLL…

5.23.12 计算机视觉的 Inception 架构

1. 介绍 分类性能的提升往往会转化为各种应用领域中显着的质量提升&#xff0c;深度卷积架构的架构改进可用于提高大多数其他计算机视觉任务的性能&#xff0c;这些任务越来越依赖于高质量的学习视觉特征。在 AlexNet 功能无法与手工设计、制作的解决方案竞争的情况下&#xf…

python 面对对象 类 魔法方法

魔法方法 一、__init__ 构造函数&#xff0c;可以理解为初始化 触发条件&#xff1a;在实例化的时候就会触发 class People():def __init__(self, name):print(init被执行)self.name namedef eat(self):print(f{self.name}要吃饭)a People(张三) a.eat() # in…