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_OBJECT

public:
    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 也可以读取,这里我们并没有使用qfile
    QFile _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 init
    ret = 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 init
    ret = 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;

}

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

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

相关文章

golang将指针传给cgo后还能被回收吗?

问题&#xff1a; 如果把golang分配的变量&#xff0c;其指针通过cgo传给c&#xff0c;并被c存储&#xff0c;那这个变量还能被gc回收吗&#xff1f; 实验代码&#xff1a; test_memory_leak.go package main/* #include <stdlib.h> #include <string.h> #incl…

基于docker-compose编排部署微服务快速开发框架

1. 规划节点 节点规划&#xff0c;见表1。 表1 节点规划 IP主机名节点10.24.2.10masterdocker-compose节点 2. 基础准备 Docker和Docker Compose已安装完成&#xff0c;将提供的软件包Pig.tar.gz上传至master节点/root目录下并解压。 案例实施 1. 基础环境准备 &#x…

渗透测试-百日筑基—SQL注入篇时间注入绕过HTTP数据编码绕过—下

day8-渗透测试sql注入篇&时间注入&绕过&HTTP数据编码绕过 一、时间注入 SQL注入时间注入&#xff08;也称为延时注入&#xff09;是SQL注入攻击的一种特殊形式&#xff0c;它属于盲注&#xff08;Blind SQL Injection&#xff09;的一种。在盲注中&#xff0c;攻击…

模型评估:Accuracy、Precision、Recall、F1、ROC曲线、AUC、PR曲线

Accuracy & Precision & Recall & F1 准确率 Accuracy A c c u r a c y T T T F A L L Accuracy \frac{TT TF}{ALL} AccuracyALLTTTF​ 1.分类器到底分对了多少&#xff1f; 精确率 Precision 2.返回的图片中正确的有多少&#xff1f; 召回率 / 查全率 …

了解光耦合器输入输出关系---腾恩科技

光耦合器&#xff0c;也称为光隔离器&#xff0c;是电子电路中必不可少的元件&#xff0c;主要用于在隔离部分之间传输信号&#xff0c;同时防止电噪声或高压影响敏感元件。其独特的设计使它们能够在没有直接电接触的情况下&#xff0c;弥合不同电压域之间的差距。在本文中&…

解决docker拉取readeck镜像报Error response from daemon: toomanyrequests问题

readeck 是一个内容中心&#xff0c;目前已支持中文翻译 这是本地化部署后的效果&#xff1a; 原命令为&#xff1a; docker run --rm -ti -p 8000:8000 -v readeck-data:/readeck codeberg.org/readeck/readeck:latest Unable to find image codeberg.org/readeck/readeck:la…

LeetCode 热题 100之普通数组

1.最大子数组和 思路分析&#xff1a;这个问题可以通过动态规划来解决&#xff0c;我们可以使用Kadane’s Algorithm&#xff08;卡登算法&#xff09;来找到具有最大和的连续子数组。 Kadane’s Algorithm 的核心思想是利用一个变量存储当前的累加和 currentSum&#xff0c;并…

【高中生讲机器学习】22. 信息论基础:信息熵、交叉熵、相对熵

创建时间&#xff1a;2024-10-16 首发时间&#xff1a;2024-10-24 最后编辑时间&#xff1a;2024-10-24 作者&#xff1a;Geeker_LStar FIRST OF ALL!!! 2024.10.24&#xff01;&#xff01; 1024 快乐&#xff01;&#xff01;&#xff01; 你好呀~这里是 Geeker_LStar 的人工…

IDEA初探:深入理解 Structure 功能

一、Structure - 类视图 Structure 是 IDEA 中的一个视图工具&#xff0c;它提供了对当前文件中结构元素的快速访问。通过 Structure&#xff0c;我们可以方便地查看和导航到代码中的各个部分&#xff0c;从而提高代码编辑和浏览的效率。 1.1 基本概念 Structure 视图以树形结…

Spring Boot:植物健康监测的智能先锋

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了植物健康系统的开发全过程。通过分析植物健康系统管理的不足&#xff0c;创建了一个计算机管理植物健康系统的方案。文章介绍了植物健康系统的系统分析部分&…

一文带你搞懂RabbitMQ 如何保证消息不丢失

RabbitMQ使用场景&#xff1a; 异步发送&#xff08;验证码、短信、邮件&#xff09;MySQL和Redis&#xff0c;ES之间的数据同步分布式事务削峰填谷 什么情况下消息容易丢失&#xff1a; 消息未到达交换机消息未到达队列队列中消息丢失消费者未接收到消息 解决消息丢失的方法…

python查询并安装项目所依赖的所有包

引言 如果需要进行代码的移植&#xff0c;肯定少不了在另一台pc或者服务器上进行环境的搭建&#xff0c;那么首先是要知道在已有的工程的代码中用到了哪些包&#xff0c;此时&#xff0c;如果是用人工去一个一个的代码文件中去查看调用了哪些包&#xff0c;这个工作甚是繁琐。…

js面试问题笔记(一)

一.热门js面试 1.简述同步和异步的区别? 同步: 浏览器访问服务器请求,用户看到页面刷新 ,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作 异步: 浏览器访问服务器请求,用户正常操作,浏览器后端进行请求,等请求完,页面不刷新,新内容也会出现,用户看到…

【HarmonyOS Next】原生沉浸式界面

背景 在实际项目中&#xff0c;为了软件使用整体色调看起来统一&#xff0c;一般顶部和底部的颜色需要铺满整个手机屏幕。因此&#xff0c;这篇帖子是介绍设置的方法&#xff0c;也是应用沉浸式效果。如下图&#xff1a;底部的绿色延伸到上面的状态栏和下面的导航栏 UI 在鸿蒙…

Grid View 网格视图

GoTo DevExpress Data Grid 数据网格 Grid View 网格视图 GridView 是默认的数据网格视图&#xff0c;它以传统的表格格式显示数据。View 将数据源记录呈现为行&#xff0c;将数据源字段呈现为列。数据值显示在各个单元格中。 以下文档包含有关此表格布局的主要元素的深入信…

多线程——线程安全的集合类

目录 前言 一、多线程环境使用 ArrayList 1.进行加锁 2.使用 SynchronizedList 类 3.使用 CopyOnWriteArrayList 类 二、多线程环境使用队列 1.进行加锁 2.使用阻塞队列 三、多线程环境使用哈希表 1.Hashtable 2.ConcurrentHashMap &#xff08;1&#xff09;缩小锁…

vue文件转AST,并恢复成vue文件(适用于antdv版本升级)

vue文件转AST&#xff0c;并恢复成vue文件---antdvV3升级V4 vue文件转AST&#xff0c;重新转回原文件过程如何获取项目路径读取项目文件&#xff0c;判断文件类型分别获取vue文件 template js&#xff08;vue2和vue3&#xff09;处理vue 文件template部分处理vue script部分uti…

【线下+线上会议|国内外双会场】2024年第四届数字化社会与智能系统国际学术会议(DSInS 2024)-悉尼/郑州双会场

2024年第四届数字化社会与智能系统国际学术会议&#xff08;DSInS 2024&#xff09;-悉尼/郑州双会场 2024 4th International Conference on Digital Society and Intelligent Systems 会议官网&#xff1a;www.dsins.org 2024 4th International Conference on Digital Soc…

龙迅#LT89101 适用于 MIPI DSI/CSI摄像头和 LVDS 中继信号延长功能,分辨率可支持 1080P@60HZ!

1. 描述 Lontium LT89101 是一款高性能 MIPI DSI/CSI-2 和 LVDS 中继器&#xff0c;用于汽车系统应用的移动显示或摄像头信号整形。 LT89101采用先进的 CMOS 工艺制造&#xff0c;并采用小外形 7.5mm x 7.5mm QFN64 封装。该封装符合 RoHS 标准&#xff0c;额定工作温度范围为 …

MySQL8.0.40编译安装

近期MySQL发布了8.0.40版本&#xff0c;与之前的版本相比&#xff0c;部分依赖包发生了变化&#xff0c;因此重新编译一版&#xff0c;也便于大家参考。 1. 下载源码 选择对应的版本、选择源码、操作系统 如果没有登录或者没有MySQL官网账号&#xff0c;可以选择只下载 2. 进…