使用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 vv
    SDL_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);
    //初始化SDL
    SDL_Init(SDL_INIT_VIDEO);
    //创建窗口
    sdl_win = SDL_CreateWindowFrom((void*)ui.label->winId());
    //创建渲染器
    sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED);
    //创建材质 支持YUV
    sdl_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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

每日练习之数学——砝码和天平

砝码和天平 题目描述 运行代码 #include<iostream> using namespace std; int main() {int w,m,T;cin>>T;while(T--){cin>>w>>m;while(m){if((m-1)%w0)m(m-1)/w;else if((m1)%w0)m(m1)/w;else if(m%w0)m/w;else break;}if(!m)cout<<"YES&…

检测头篇 | YOLOv8改进之添加小目标检测头 / 添加大目标检测头 / 减少检测头

前言:Hello大家好,我是小哥谈。本文首先给大家展示原始YOLOv8的网络结构图,然后再对其进行改变,即增加小目标检测头、增加大目标检测头和减少检测头。🌈 目录 🚀1.网络结构图

10.2.k8s的附加组件-Metrics-server组件与hpa资源pod水平伸缩

目录 一、概述 二、安装部署Metrics-Server组件 1.下载Metrics-Server资源清单 2.编辑Metrics-Server的资源清单 3.验证Metrics-Server是否成功安装 4.使用top命令测试是否管用 三、hpa资源实现pod水平伸缩&#xff08;自动扩缩容&#xff09; 1.编写deploy资源清单 2.…

什么是创造力?如何判断自己的创造力?

创造力&#xff0c;主要表现为创新思想、发现和创造新事物的能力&#xff0c;是知识&#xff0c;智力和能力的综合能力&#xff0c;尤其是在职业发展方面&#xff0c;创造力具有重要的意义&#xff0c;企业的核心竞争力就来源于创造力&#xff0c;这就需要具有创造力的员工来推…

HCIP-Datacom-ARST自选题库__OSPF单选【80道题】

1.OSPFV2是运行在IPV4网络的IGP&#xff0c;OSPFV3是运行在IPV6网络的ICP&#xff0c;OSPFV3与OSPFv2的报文类型相同&#xff0c;包括Hello报文、DD报文、LSR报文、LSU报文和LSAck报文。关于OSPFv3报文&#xff0c;以下哪个说法是正确的 OSPFv3使用报文头部的认证字段完成报文…

.DS_store文件

感觉mac里的这个.DS_store文件烦人&#xff0c;老是莫名其妙的出现&#xff0c;然后造成困扰 处理方式如下&#xff1a; import os pic_list os.listdir("./mask_pic/") print(len(pic_list)) # 从文件夹中删掉 if(".DS_Store" in pic_list):print(&quo…

如何关闭或者减少屏蔽 CloudFlare 的真人检测

经常浏览境外网站的应该常碰到一个真人检测的提示(如下图所示)。最近,明月就收到了一个知乎上的付费咨询:问我如何去掉这个提示,由此明月也特别的研究了一下这个“真人检测”,这算是 CloudFlare 的一个特色了,基本上大家看到站点访问有这个提示的几乎都是用了 CloudFlar…

亚马逊测评自养号需要解决哪些问题?

我们首先了解一下测评是什么 测评就是类似于国内某宝和某多补销量一样&#xff0c;可以快速提升产品销量和优质的评价&#xff0c;从而让产品的权重上升&#xff0c;可以上升产品排名 也可以防范同行的恶意差评&#xff0c;可以用好评稀释差评&#xff0c;从而控评&#xff0…

VSCODE gcc运行多个.c文件

一、简介 很多时候&#xff0c;开发者需要使用VSCODE进行C语言算法验证。而VSCODE的gcc编译&#xff0c;默认是只编译本文件的内容&#xff0c;其他.c文件是不参与编译的。这就给开发者带来很大的困扰&#xff0c;因为开发者不可能把所有的算法都写在一个.c文件&#xff0c;特别…

2024年5月计算机视觉论文推荐:包括扩散模型、视觉语言模型、图像编辑和生成、视频处理和生成以及图像识别等各个主题

我们今天总结下2024年5月发表的最重要的论文&#xff0c;重点介绍了计算机视觉领域的最新研究和进展&#xff0c;包括扩散模型、视觉语言模型、图像编辑和生成、视频处理和生成以及图像识别等各个主题。 Diffusion Models 1、Dual3D: Efficient and Consistent Text-to-3D Ge…

mac清理软件推荐免费 mac清理系统数据怎么清理 cleanmymac和腾讯柠檬哪个好

macbook是苹果公司的一款高性能的笔记本电脑&#xff0c;受到了很多用户的喜爱。但是&#xff0c;随着使用时间的增长&#xff0c;macbook的系统也会积累一些垃圾文件&#xff0c;影响其运行速度和空间。那么&#xff0c;macbook系统清理软件推荐有哪些呢&#xff1f;macbook用…

模板编译之入口分析

Vue 是一个渐进式 JavaScript 框架&#xff0c;提供了简单易用的模板语法&#xff0c;帮助开发者以声明式的方式构建用户界面。Vue 的模板编译原理是其核心之一&#xff0c;它将模板字符串编译成渲染函数&#xff0c;并在运行时高效地更新 DOM。本文将深入探讨 Vue 模板编译的原…

Optica数据库 (原OSA美国光学学会电子期刊)文献去哪里查找下载

Optica&#xff08;OSA&#xff09;数据库涵盖了光学和光子学理论研究和实际应用的各个领域&#xff0c;包括&#xff1a;光学设备、光学成像、光纤通信、分析方法、光通信、光纤、半导体激光、光传输、光学系统、计量学、带宽、量子电子学。 该库包括18种学会期刊&#xff08…

5月21日 网络编程day4

1.项目中如何实现TCP的并发&#xff1f; 答&#xff1a;采用多进程、多线程或者IO多路复用进行通信。 2.TCP通信过程中的三次握手&#xff1f; 答&#xff1a;①&#xff1a;客户端发送SYN包&#xff08;SYN1&#xff0c;seq0&#xff09;给服务器&#xff0c;并进入SYN_SEN…

【大模型】 基于AI和全球化进程的权衡:开源大模型与闭源大模型

【大模型】 基于AI和全球化进程的权衡&#xff1a;开源大模型与闭源大模型 前言 实际上关于开源or闭源&#xff0c;一直以来都是颇有争议的话题&#xff0c;人们争执于数据的隐私性和共享性&#xff0c;到底哪一方能获得的收益更大。而对于开源与闭源哪个更好实际上也就是说是…

YoloV9实战与改进——专栏目录

摘要 &#x1f525;&#x1f680;本专栏教你如何嗨翻Yolov9&#xff01;&#x1f680;&#x1f525; &#x1f680;炸裂升级&#xff1a;嗨&#xff0c;小伙伴们&#xff01;这里有一波Yolov9的升级大招&#xff0c;带你领略最新论文的精华&#xff01;&#x1f4a5; 什么注意…

ue引擎游戏开发笔记(47)——设置状态机解决跳跃问题

1.问题分析&#xff1a; 目前当角色起跳时&#xff0c;只是简单的上下移动&#xff0c;空中仍然保持行走动作&#xff0c;并没有设置跳跃动作&#xff0c;因此&#xff0c;给角色设置新的跳跃动作&#xff0c;并优化新的动作动画。 2.操作实现&#xff1a; 1.实现跳跃不复杂&…

得物小程序逆向+qt可视化(不含sku)

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章未…

loguru和print输出顺序乱序

执行代码&#xff1a; from loguru import logger for i in range(1000):print(i)logger.info(i)执行效果&#xff1a; 0 1 2 3 4 2024-05-25 09:52:01.974 | INFO | __main__:<module>:6 - 0 2024-05-25 09:52:01.974 | INFO | __main__:<module>:6 - 1…

Java面试八股之可重入锁ReentrantLock是怎么实现可重入的

可重入锁ReentrantLock是怎么实现可重入的 ReentrantLock实现可重入性的机制主要依赖于以下几个核心组件和步骤&#xff1a; 状态计数器&#xff1a;ReentrantLock内部维护一个名为state的整型变量作为状态计数器&#xff0c;这个计数器不仅用来记录锁是否被持有&#xff0c;…