FFmpeg 4.3 音视频-多路H265监控录放C++开发六,使用SDLVSQT显示yuv文件
使用QT 显示YUV 文件
在最后一帧的时候会不停的显示最后一帧图片。
Vsqtshowyuv.h
#pragma once#include <QtWidgets/QWidget>
#include "ui_vsqtshowyuv.h"
#include <sdl/SDL.h>
#include <iostream>
#include <fstream>
#include <QFile>
using namespace std;#undef main
class Vsqtshowyuv : public QWidget
{Q_OBJECTpublic:Vsqtshowyuv(QWidget *parent = nullptr);~Vsqtshowyuv();private:Ui::VsqtshowyuvClass ui;WId _labelid = 0;//我们这里要显示的yuv是400x300x25 的,在yuv的file 中我们是无法知道yuv大小的,因此要固定。///后面我们解析的mp4文件,flv文件,由于头文件是有 视频文件的大小的,因此可以通过代码从mp4文件中获得int _label_width = 400;int _label_height = 300;SDL_Window* _sdlwindow = nullptr;SDL_Renderer* _sdlrenderer = nullptr;SDL_Texture* _sdltexture = nullptr;//使用qfile 也可以读取,这里我们并没有使用qfileQFile _qt_yuvfile;ifstream _yuv_file;unsigned char* _yuv_data = nullptr;
private:int startSDL();void timerEvent(QTimerEvent* ev) override;void endSDL();
};
Vsqtshowyuv.cpp
#include "vsqtshowyuv.h"
#include <fstream>Vsqtshowyuv::Vsqtshowyuv(QWidget *parent): QWidget(parent)
{int ret = 0;ui.setupUi(this);_labelid = ui.label->winId();resize(_label_width, _label_height);ui.label->resize(_label_width, _label_height);ui.label->move(0, 0);ret = startSDL(); if (ret < 0) {///如果 SDL 的初始化什么的都失败了,需要销毁资源,并且退出endSDL();cout << "startSDL error, so can not show YUV information ." << endl;ui.label->setText("can not show YUV becase SDL has error");return;}else {//我们这里要播放yuv数据,每次播放yuv视频中的一张,那么有三个事情要做:// 1。打开yuv file,// 2。并通过 starttimer 定时在timerEvent从 yuv中读取一张数据,然后显示// 3. 每个40ms 通过 timerevent 刷新一次。//我们的yuv视频是25帧,1秒25次,1000毫秒/25 = 40,也就是说,我们40毫秒更新一次//但是实际测试并不能在40ms中更新一次,这里只是通过 QT 的这个机制显示出来,在实际开发中不能用这个方法_yuv_file.open("400_300_25.yuv", ios::binary);if (!_yuv_file) {cout << "_yuv_file open 400_300_25.yuv ios::binary error, so can not show YUV information ." << endl;ui.label->setText("can not show YUV becase open 400_300_25.yuv ios::binary error");endSDL();return;}//将要存储的数据的大小 new 出来_yuv_data = new unsigned char[_label_width * _label_height * 1.5];startTimer(40);}}Vsqtshowyuv::~Vsqtshowyuv()
{endSDL();
}int Vsqtshowyuv::startSDL() {int ret = 0;/// 1. SDL initret = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO);if (ret < 0) {ret = -1;cout << "SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) error " << SDL_GetError() << endl;return ret;}/// 2. create SDL windows_sdlwindow = SDL_CreateWindowFrom((void *)_labelid);if (!_sdlwindow) {ret = -2;cout << "SDL_CreateWindowFrom error " << SDL_GetError() << endl;return ret;}/// 3。 create SDL renderer 渲染器_sdlrenderer = SDL_CreateRenderer(_sdlwindow, -1, SDL_RENDERER_ACCELERATED);if (!_sdlrenderer) {cout << "SDL_CreateRenderer SDL_RENDERER_ACCELERATED error now try use SDL_RENDERER_SOFTWARE create SDL_RENDERER " << SDL_GetError() << endl;_sdlrenderer = SDL_CreateRenderer(_sdlwindow, -1, SDL_RENDERER_SOFTWARE);if (!_sdlrenderer) {ret = -3;cout << "SDL_CreateRenderer SDL_RENDERER_SOFTWARE also error " << SDL_GetError() << endl;return ret;}return ret;}///4. create texture 材质,要显示YUV数据,因此用SDL_PIXELFORMAT_IYUV_sdltexture = SDL_CreateTexture(_sdlrenderer,SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, _label_width, _label_height);if (!_sdltexture) {ret = -4;cout << "SDL_CreateTexture error " << SDL_GetError() << endl;return ret;}return ret;
}void Vsqtshowyuv::endSDL() {if (_sdltexture) {SDL_DestroyTexture(_sdltexture);_sdltexture = nullptr;}if (_sdlrenderer) {SDL_DestroyRenderer(_sdlrenderer);_sdlrenderer = nullptr;}if (_sdlwindow) {SDL_DestroyWindow(_sdlwindow);_sdlwindow = nullptr;}SDL_Quit();
}void Vsqtshowyuv::timerEvent(QTimerEvent* ev) {cout << "timerEvent start" << endl;//将数据读取到_yuv_data,每次读取数据的大小为一张图片的大小,我们是YUV420P的图片,一张图片大小为 1.5 * 宽 * 高;实际上是一个 SDL_PIXELFORMAT_IYUV = /**< Planar mode: Y + U + V (3 planes) */int datasize = _label_width * _label_height * 1.5;//read 方法说明,The function read() is used with input streams, and reads num bytes from the stream before placing them in buffer.If EOF is encountered, read() stops, leaving however many bytes it put into buffer as they are._yuv_file.read((char*)_yuv_data, datasize);//我们这里是要做一些判断的,如果读取发生了问题,或者读取到了文件的末尾,需要做额外的处理//由于read 方法在读取到文件的EOF的时候,read会stop,这时候会发生什么情况呢 ?_yuv_data里面保存着最后一帧,因此理论上会一直刷新最后一帧图片数据//来验证猜想,验证确实是这样。SDL_UpdateTexture(_sdltexture, NULL, _yuv_data, _label_width //一行 y的字节数);SDL_RenderClear(_sdlrenderer);SDL_Rect rect;rect.x = 0;rect.y = 0;rect.w = _label_width;rect.h = _label_height;SDL_RenderCopy(_sdlrenderer, _sdltexture, NULL, &rect);SDL_RenderPresent(_sdlrenderer);cout << "timerEvent end" << endl;}
使用QT 显示循环 播放YUV 文件
#include "vsqtshowyuv.h"
#include <fstream>Vsqtshowyuv::Vsqtshowyuv(QWidget *parent): QWidget(parent)
{int ret = 0;ui.setupUi(this);_labelid = ui.label->winId();resize(_label_width, _label_height);ui.label->resize(_label_width, _label_height);ui.label->move(0, 0);ret = startSDL(); if (ret < 0) {///如果 SDL 的初始化什么的都失败了,需要销毁资源,并且退出endSDL();cout << "startSDL error, so can not show YUV information ." << endl;ui.label->setText("can not show YUV becase SDL has error");return;}else {//我们这里要播放yuv数据,每次播放yuv视频中的一张,那么有三个事情要做:// 1。打开yuv file,// 2。并通过 starttimer 定时在timerEvent从 yuv中读取一张数据,然后显示// 3. 每个40ms 通过 timerevent 刷新一次。//我们的yuv视频是25帧,1秒25次,1000毫秒/25 = 40,也就是说,我们40毫秒更新一次//但是实际测试并不能在40ms中更新一次,这里只是通过 QT 的这个机制显示出来,在实际开发中不能用这个方法_yuv_file.open("400_300_25.yuv", ios::binary);if (!_yuv_file) {cout << "_yuv_file open 400_300_25.yuv ios::binary error, so can not show YUV information ." << endl;ui.label->setText("can not show YUV becase open 400_300_25.yuv ios::binary error");endSDL();return;}//将要存储的数据的大小 new 出来_yuv_data = new unsigned char[_label_width * _label_height * 1.5];startTimer(40);}}Vsqtshowyuv::~Vsqtshowyuv()
{endSDL();
}int Vsqtshowyuv::startSDL() {int ret = 0;/// 1. SDL initret = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO);if (ret < 0) {ret = -1;cout << "SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) error " << SDL_GetError() << endl;return ret;}/// 2. create SDL windows_sdlwindow = SDL_CreateWindowFrom((void *)_labelid);if (!_sdlwindow) {ret = -2;cout << "SDL_CreateWindowFrom error " << SDL_GetError() << endl;return ret;}/// 3。 create SDL renderer 渲染器_sdlrenderer = SDL_CreateRenderer(_sdlwindow, -1, SDL_RENDERER_ACCELERATED);if (!_sdlrenderer) {cout << "SDL_CreateRenderer SDL_RENDERER_ACCELERATED error now try use SDL_RENDERER_SOFTWARE create SDL_RENDERER " << SDL_GetError() << endl;_sdlrenderer = SDL_CreateRenderer(_sdlwindow, -1, SDL_RENDERER_SOFTWARE);if (!_sdlrenderer) {ret = -3;cout << "SDL_CreateRenderer SDL_RENDERER_SOFTWARE also error " << SDL_GetError() << endl;return ret;}return ret;}///4. create texture 材质,要显示YUV数据,因此用SDL_PIXELFORMAT_IYUV_sdltexture = SDL_CreateTexture(_sdlrenderer,SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, _label_width, _label_height);if (!_sdltexture) {ret = -4;cout << "SDL_CreateTexture error " << SDL_GetError() << endl;return ret;}return ret;
}void Vsqtshowyuv::endSDL() {if (_sdltexture) {SDL_DestroyTexture(_sdltexture);_sdltexture = nullptr;}if (_sdlrenderer) {SDL_DestroyRenderer(_sdlrenderer);_sdlrenderer = nullptr;}if (_sdlwindow) {SDL_DestroyWindow(_sdlwindow);_sdlwindow = nullptr;}SDL_Quit();
}void Vsqtshowyuv::timerEvent(QTimerEvent* ev) {cout << "timerEvent start" << endl;//将数据读取到_yuv_data,每次读取数据的大小为一张图片的大小,我们是YUV420P的图片,一张图片大小为 1.5 * 宽 * 高;实际上是一个 SDL_PIXELFORMAT_IYUV = /**< Planar mode: Y + U + V (3 planes) */int datasize = _label_width * _label_height * 1.5;//read 方法说明,The function read() is used with input streams, and reads num bytes from the stream before placing them in buffer.If EOF is encountered, read() stops, leaving however many bytes it put into buffer as they are.istream& is= _yuv_file.read((char*)_yuv_data, datasize);if (_yuv_file.good()) {cout << "Read " << _yuv_file.gcount() << endl;}else {cout << "Error occurred during read" << endl;if (_yuv_file.eof()) {cout << "Reached end of file" << endl;///这里有个问题,就是我们是通过 file 关闭,然后重新打开的方式让从头读取,应该是可以改动指针来完成_yuv_file.close();_yuv_file.open("400_300_25.yuv", ios::binary);}}//我们这里是要做一些判断的,如果读取发生了问题,或者读取到了文件的末尾,需要做额外的处理//由于read 方法在读取到文件的EOF的时候,read会stop,这时候会发生什么情况呢 ?_yuv_data里面保存着最后一帧,因此理论上会一直刷新最后一帧图片数据//来验证猜想,验证确实是这样。SDL_UpdateTexture(_sdltexture, NULL, _yuv_data, _label_width //一行 y的字节数);SDL_RenderClear(_sdlrenderer);SDL_Rect rect;rect.x = 0;rect.y = 0;rect.w = _label_width;rect.h = _label_height;SDL_RenderCopy(_sdlrenderer, _sdltexture, NULL, &rect);SDL_RenderPresent(_sdlrenderer);cout << "timerEvent end" << endl;}
相关文章:
FFmpeg 4.3 音视频-多路H265监控录放C++开发六,使用SDLVSQT显示yuv文件
使用QT 显示YUV 文件 在最后一帧的时候会不停的显示最后一帧图片。 Vsqtshowyuv.h #pragma once#include <QtWidgets/QWidget> #include "ui_vsqtshowyuv.h" #include <sdl/SDL.h> #include <iostream> #include <fstream> #include <Q…...
Spring 设计模式之适配器模式
Spring 设计模式之适配器模式 适配器模式用到的场景java举例 适配器模式 适配器模式(Adapter Pattern)是一种结构型设计模式,它允许接口不兼容的类一起工作。 其核心思想是通过一个适配器类将不兼容的接口转换成客户端期望的另一个接口&…...

多传感器数字化分析系统
在工业飞速发展的今天,设备的安全稳定运行成为企业高效生产的关键因素。然而,传统的人工巡检方式面临着诸多挑战,如效率低下、漏检误检以及难以精准掌握设备运行状态等。旗晟凭借深厚的技术积累和创新精神,推出了多传感器数字化分…...
Java 基础教学:面向对象编程基础-封装、继承与多态
面向对象编程(OOP)是现代编程的重要范式,Java 语言提供了丰富的 OOP 特性,主要包括封装、继承和多态。本文将详细讲解这三个概念及其实现方式,并提供相应的代码示例。 1. 封装 1.1 概念 封装是将对象的状态…...

Ubuntu环境本地部署DbGate数据库管理工具并实现无公网IP远程访问
文章目录 前言1. 安装Docker2. 使用Docker拉取DbGate镜像3. 创建并启动DbGate容器4. 本地连接测试5. 公网远程访问本地DbGate容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 前言 本文主要介绍如何在Linux Ubuntu系统中使用Docker部署DbGate数…...

【AI抠图整合包及教程】Meta SAM 2:视觉分割的革命性飞跃
在人工智能的浪潮中,每一次技术的革新都如同一场视觉盛宴,让我们见证着数字时代的变迁。Meta再次以Segment Anything Model 2(SAM 2)引领了图像和视频分割技术的新纪元。作为首个用于实时、可提示的图像和视频对象分割的统一模型&…...

使用语言模型进行文本摘要的五个级别(llm)
视频链接:5 Levels Of LLM Summarizing: Novice to Expert...

ubuntu交叉编译libffi库给arm平台使用
1.下载并解压: 2.生成makefile 编译: make 编译成功: 安装: make install 安装成功 查看安装后的libffi库...
【jvm】空间分配担保策略
目录 1. 说明2. 工作原理2.1 估算新生代存活对象大小2.2 判断老年代的剩余空间2.3 触发Full GC的条件 3. 相关参数与配置3.1 -XX:HandlePromotionFailure3.2 -XX:PretenureSizeThreshold3.3 -XX:MaxTenuringThreshold3.4 -XX:TargetSurvivorRatio 4.作用与意义 1. 说明 1.在Ja…...

iQOO手机怎样将屏幕投射到MacBook?可以同步音频吗?
众所周知,苹果品牌的设备自己有AirPlay的投屏功能,iPhone要投屏到MacBook只要连接同一网络,然后开启AirPlay就可以投屏。但其他品牌的手机没有AirPlay,怎么将手机屏幕投射到MacBook呢? 安卓系统的手机可以使用无线投屏…...

BUU usualCrypt1
查壳,32bit,丢进ida32中进行反编译,简单的不多说,直接进main分析 简单分析,打上注释,没啥好看的,就一个加密函数,加密完后和一个字符串进行比较,由此可以逆推出加密前的字…...

第十七章 标准库特殊设施
17.1 tuple类型 当希望将一些数据合成单一对象,但又不想麻烦地定义一个新数据结构来表示这些数据时,tuple非常有用。tuple是类似pair的模板。 tuple<size_t, size_t, size_t> threeD; //三个成员都设置为0//为每个成员提供初始值 tuple<strin…...
【格言分享】程序员的经典名言解读
上一期文章我们分享了一些程序员的经典名言,每一句都蕴含着深刻的道理。 接下来就给大家一个一个分析一下 这些格言确实捕捉到了编程和软件开发的精髓,每一条都蕴含着丰富的经验和智慧。下面我将逐一解释这些格言,并分享一些我的看法。 C程序员永远不会灭亡。他们只是cast…...
SpringBoot接收LocalDateTime参数
一、通过RequestBody接收 方式1:实体类上加上 JsonFormat,并通过 pattern 属性指定时间格式 public class Time {JsonFormat(pattern "yyyy-MM-dd HH:mm:ss")LocalDateTime localDateTime;JsonFormat(pattern "yyyy-MM-dd")Loca…...

Typora配置GitHub图床--结合PicGo
【当前问题】Typora文档分享时 无法看到本地路径图片 【怎么解决】把文档中的图片设置为 公开链接 【准备工具】 Typora 官网https://typoraio.cn/(购买 / 自寻破解法)GitHub账号 https://github.com/PicGo https://github.com/Molunerfinn/PicGo/relea…...

【书生.浦语实战营】——入门岛
【书生.浦语实战营】——入门岛_第一关_Linux基础 任务分布1. 本地vscode远程连接并进行端口映射端口映射What——何为端口映射How——怎么进行端口映射 2. Linux基础命令touch :创建文件mkdir :创建目录cd:进入 退出 目录pwd :确定当前所在目录cat:可以…...

WPF+MVVM案例实战(十四)- 封装一个自定义消息弹窗控件(下)
文章目录 1、案例效果2、弹窗控件使用1.引入用户控件2、按钮命令实现 3、总结4、源代码获取 1、案例效果 2、弹窗控件使用 1.引入用户控件 打开 Wpf_Examples 项目,在引用中添加用户控件库,在 MainWindow.xaml 界面引用控件库,代码如下&…...
嵌入式——STM32外设应用
STM32 微控制器以其高性能、低功耗和丰富的外设资源,在嵌入式系统设计中得到了广泛应用。以下将详细介绍 STM32 的主要外设及其典型应用,帮助开发者更好地理解和应用这些功能。 1. GPIO(通用输入输出端口) 功能:GPIO…...

HCIA(ACL)
第七节 ACL:访问控制列表 访问控制----在路由器的入或者出的接口上,匹配流量,之后产生动作---允许或拒绝 定义感兴趣流量-----帮助其他软件抓流量 匹配规则: 至上而下,逐一匹配,上调匹配按照上条执行…...

react基础之reactHooks
文章目录 React Hooks 使用指南常用 Hooks使用规则 小结 React Hooks 使用指南 React Hooks 是 React 16.8 引入的一种新特性,允许在函数组件中使用状态和其他 React 特性,而无需编写类组件。以下是一些基础的 Hooks 及其使用规则。 常用 Hooks useSta…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...

【若依】框架项目部署笔记
参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作: 压缩包下载:http://download.redis.io/releases 1. 上传压缩包,并进入压缩包所在目录,解压到目标…...