Qt通过FFmpeg打开RTSP并截图一帧作为背景

该代码基于 Qt 和 FFmpeg 实现了从 RTSP 视频流中截取一帧图像,并将其渲染到 QWidget 作为背景图。整个实现流程分为 Qt 界面构建、FFmpeg 解码 RTSP 流、视频帧转换和 QImage 显示四个主要部分。

首先,RtspImageWidget 继承自 QWidget,在其构造函数中创建了一个 QLabel,用于显示截取的图像,并将其添加到 QVBoxLayout 进行布局管理。loadRtspFrame() 方法负责使用 FFmpeg 解析 RTSP 地址,获取视频帧,并将其转换为 QImage 供 Qt 界面显示。

loadRtspFrame() 方法中,代码首先调用 avformat_network_init() 初始化 FFmpeg 网络环境,然后使用 avformat_open_input() 打开 RTSP 地址,并通过 avformat_find_stream_info() 获取流信息。随后,遍历流列表,查找视频流的索引。如果成功找到视频流,则获取 AVCodecParameters 并通过 avcodec_find_decoder() 查找解码器,再用 avcodec_alloc_context3() 创建解码器上下文,并将参数填充到该上下文中。

接着,调用 avcodec_open2() 打开解码器,并分配 AVPacketAVFrame 以存储解码数据。同时,为了将解码后的 YUV 图像转换为 RGB,代码使用 sws_getContext() 创建了 SwsContext,并分配缓冲区用于存储 RGB 图像数据。

在主解码循环中,av_read_frame() 逐帧读取数据包,检查是否属于视频流,并调用 avcodec_send_packet() 进行解码。如果解码成功,调用 sws_scale() 进行格式转换,并将 RGB 数据封装成 QImage。最后,通过 setPixmap() 方法更新 QLabel 以显示截取的图像,并使用 goto CLEANUP 语句跳出循环,确保程序在成功截取到第一帧后立即释放资源。

资源释放部分采用 FFmpeg 提供的 av_packet_free()av_frame_free()avcodec_free_context()avformat_close_input() 等方法,确保程序不发生内存泄漏。main() 函数则创建 QApplication 并实例化 RtspImageWidget,加载 RTSP 地址后显示窗口。

整体来看,该代码逻辑清晰、模块分明,结合了 Qt 的 UI 渲染能力和 FFmpeg 的视频解码能力,实现了高效的 RTSP 视频帧截取与显示。

#include <QWidget>
#include <QLabel>
#include <QPixmap>
#include <QImage>
#include <QVBoxLayout>
#include <QDebug>extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}class RtspImageWidget : public QWidget {Q_OBJECTpublic:explicit RtspImageWidget(const QString& rtspUrl, QWidget* parent = nullptr): QWidget(parent), rtspUrl(rtspUrl) {QVBoxLayout* layout = new QVBoxLayout(this);imageLabel = new QLabel(this);imageLabel->setAlignment(Qt::AlignCenter);layout->addWidget(imageLabel);this->setLayout(layout);// 启动截取线程loadRtspFrame();}private:QLabel* imageLabel;QString rtspUrl;void loadRtspFrame() {// 初始化 FFmpegavformat_network_init();AVFormatContext* fmtCtx = nullptr;if (avformat_open_input(&fmtCtx, rtspUrl.toStdString().c_str(), nullptr, nullptr) < 0) {qDebug() << "Failed to open RTSP stream";return;}if (avformat_find_stream_info(fmtCtx, nullptr) < 0) {qDebug() << "Failed to find stream info";avformat_close_input(&fmtCtx);return;}int videoStreamIndex = -1;for (unsigned int i = 0; i < fmtCtx->nb_streams; ++i) {if (fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStreamIndex = i;break;}}if (videoStreamIndex == -1) {qDebug() << "No video stream found";avformat_close_input(&fmtCtx);return;}AVCodecParameters* codecPar = fmtCtx->streams[videoStreamIndex]->codecpar;AVCodec* codec = avcodec_find_decoder(codecPar->codec_id);if (!codec) {qDebug() << "Failed to find codec";avformat_close_input(&fmtCtx);return;}AVCodecContext* codecCtx = avcodec_alloc_context3(codec);if (!codecCtx) {qDebug() << "Failed to allocate codec context";avformat_close_input(&fmtCtx);return;}if (avcodec_parameters_to_context(codecCtx, codecPar) < 0) {qDebug() << "Failed to copy codec parameters to codec context";avcodec_free_context(&codecCtx);avformat_close_input(&fmtCtx);return;}if (avcodec_open2(codecCtx, codec, nullptr) < 0) {qDebug() << "Failed to open codec";avcodec_free_context(&codecCtx);avformat_close_input(&fmtCtx);return;}AVPacket* packet = av_packet_alloc();AVFrame* frame = av_frame_alloc();AVFrame* rgbFrame = av_frame_alloc();if (!packet || !frame || !rgbFrame) {qDebug() << "Failed to allocate frames or packet";av_packet_free(&packet);av_frame_free(&frame);av_frame_free(&rgbFrame);avcodec_free_context(&codecCtx);avformat_close_input(&fmtCtx);return;}SwsContext* swsCtx = sws_getContext(codecCtx->width, codecCtx->height, codecCtx->pix_fmt,codecCtx->width, codecCtx->height, AV_PIX_FMT_RGB24,SWS_BILINEAR, nullptr, nullptr, nullptr);int rgbBufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height, 1);uint8_t* rgbBuffer = (uint8_t*)av_malloc(rgbBufferSize);av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, rgbBuffer, AV_PIX_FMT_RGB24,codecCtx->width, codecCtx->height, 1);while (av_read_frame(fmtCtx, packet) >= 0) {if (packet->stream_index == videoStreamIndex) {if (avcodec_send_packet(codecCtx, packet) == 0) {while (avcodec_receive_frame(codecCtx, frame) == 0) {// 转换为RGB格式sws_scale(swsCtx, frame->data, frame->linesize, 0, codecCtx->height,rgbFrame->data, rgbFrame->linesize);// 创建QImage并设置为背景QImage image(rgbFrame->data[0], codecCtx->width, codecCtx->height,rgbFrame->linesize[0], QImage::Format_RGB888);imageLabel->setPixmap(QPixmap::fromImage(image).scaled(this->size(), Qt::KeepAspectRatio));goto CLEANUP;  // 截取一帧后退出循环}}}av_packet_unref(packet);}CLEANUP:av_packet_free(&packet);av_frame_free(&frame);av_frame_free(&rgbFrame);av_free(rgbBuffer);sws_freeContext(swsCtx);avcodec_free_context(&codecCtx);avformat_close_input(&fmtCtx);}
};#include <QApplication>int main(int argc, char* argv[]) {QApplication app(argc, argv);RtspImageWidget widget("rtsp://your_rtsp_address");widget.resize(800, 600);widget.show();return app.exec();
}

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

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

相关文章

力扣hot100刷题第一天

哈希 1. 两数之和 题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。你可以按任意…

Linux(CentOS)安装 Nginx

CentOS版本&#xff1a;CentOS 7 Nginx版本&#xff1a;1.24.0 两种安装方式&#xff1a; 一、通过 yum 安装&#xff0c;最简单&#xff0c;一键安装&#xff0c;全程无忧。 二、通过编译源码包安装&#xff0c;需具备配置相关操作。 最后附&#xff1a;设置 Nginx 服务开…

项目6:基于大数据校园一卡通数据分析和可视化

1、项目简介 本项目是基于大数据的清华校园卡数据分析系统&#xff0c;通过Hadoop&#xff0c;spark等技术处理校园卡交易、卡号和商户信息数据。系统实现消费类别、男女消费差异、学院消费排行和年级对比等分析&#xff0c;并通过Web后端和可视化前端展示结果。项目运行便捷&…

Django项目中创建app并快速上手(pycharm Windows)

1.打开终端 我选择的是第二个 2.运行命令 python manage.py startapp 名称 例如&#xff1a; python manage.py startapp app01 回车&#xff0c;等待一下&#xff0c;出现app01的文件夹说明创建成功 3.快速上手 1.app注册 增加一行 "app01.apps.App01Config"&#…

使用Docker + Ollama在Ubuntu中部署deepseek

1、安装docker 这里建议用docker来部署&#xff0c;方便简单 安装教程需要自己找详细的&#xff0c;会用到跳过 如果你没有安装 Docker&#xff0c;可以按照以下步骤安装&#xff1a; sudo apt update sudo apt install apt-transport-https ca-certificates curl software-p…

信创领域的PostgreSQL管理员认证

信创产业&#xff0c;全称为信息技术应用创新产业&#xff0c;是中国为应对国际技术竞争、保障信息安全、实现科技自立而重点发展的战略性新兴产业。其核心目标是通过自主研发和生态构建&#xff0c;逐步替代国外信息技术产品&#xff0c;形成自主可控的国产化信息技术体系。 发…

jemalloc的malloc案例来分析GOT表和PLT表有关流程

一、背景 在之前的博客 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 里&#xff0c;我们分析了在preload jemalloc的库之后&#xff0c;main之前的一次malloc分配&#xff08;分配72704字节&#xff09;的源头原因并做了jemalloc的初始…

Centos Ollama + Deepseek-r1+Chatbox运行环境搭建

Centos Ollama Deepseek-r1Chatbox运行环境搭建 内容介绍下载ollama在Ollama运行DeepSeek-r1模型使用chatbox连接ollama api 内容介绍 你好&#xff01; 这篇文章简单讲述一下如何在linux环境搭建 Ollama Deepseek-r1。并在本地安装的Chatbox中进行远程调用 下载ollama 登…

使用sunshine和moonlight串流时的音频输出问题

设备&#xff1a;电脑和平板串流&#xff0c;把平板当副屏使用 1.如果启用安装steam音频驱动程序&#xff0c;则平板有声&#xff0c;电脑无声&#xff0c;在moonlight端可以设置平板和电脑同时发声&#xff0c;但是有点卡 2.只想电脑发声&#xff0c;平板无声 禁用安装steam…

微信小程序案例2——天气微信小程序(学会绑定数据)

文章目录 一、项目步骤1 创建一个weather项目2 进入index.wxml、index.js、index.wxss文件,清空所有内容,进入App.json,修改导航栏标题为“中国天气网”。3进入index.wxml,进行当天天气情况的界面布局,包括温度、最低温、最高温、天气情况、城市、星期、风行情况,代码如下…

如何在WPS和Word/Excel中直接使用DeepSeek功能

以下是将DeepSeek功能集成到WPS中的详细步骤&#xff0c;无需本地部署模型&#xff0c;直接通过官网连接使用&#xff1a;1. 下载并安装OfficeAI插件 &#xff08;1&#xff09;访问OfficeAI插件下载地址&#xff1a;OfficeAI助手 - 免费办公智能AI助手, AI写作&#xff0c;下载…

数字电路-基础逻辑门实验

基础逻辑门是数字电路设计的核心元件&#xff0c;它们执行的是基本的逻辑运算。通过这些基本运算&#xff0c;可以构建出更为复杂的逻辑功能。常见的基础逻辑门包括与门&#xff08;AND&#xff09;、或门&#xff08;OR&#xff09;、非门&#xff08;NOT&#xff09;、异或门…

哪吒闹海!SCI算法+分解组合+四模型原创对比首发!SGMD-FATA-Transformer-LSTM多变量时序预测

哪吒闹海&#xff01;SCI算法分解组合四模型原创对比首发&#xff01;SGMD-FATA-Transformer-LSTM多变量时序预测 目录 哪吒闹海&#xff01;SCI算法分解组合四模型原创对比首发&#xff01;SGMD-FATA-Transformer-LSTM多变量时序预测效果一览基本介绍程序设计参考资料 效果一览…

C++,STL 迭代器简介:概念、分类、操作

文章目录 引言一、迭代器的基本概念1.1 什么是迭代器?1.2 迭代器的意义二、迭代器的分类2.1 示意图:迭代器能力层级2.2 示例:不同迭代器的操作三、迭代器的常用操作3.1 基本操作3.2 随机访问迭代器专用操作示例代码:随机访问迭代器四、迭代器的通用用法4.1 遍历容器4.2 配合…

EasyExcel 导出合并层级单元格

EasyExcel 导出合并层级单元格 一、案例 案例一 1.相同订单号单元格进行合并 合并结果 案例二 1.相同订单号的单元格进行合并2.相同订单号的总数和总金额进行合并 合并结果 案例三 1.相同订单号的单元格进行合并2.相同订单号的商品分类进行合并3.相同订单号的总数和总金额…

常用的python库-安装与使用

常用的python库函数 yield关键字openslide库openslide对象的常用属性 cv2库numpy库ASAP库-multiresolutionimageinterface库ASAP库的安装ASAP库的使用 concurrent.futures.ThreadPoolExecutorxml.etree.ElementTree库skimage库PIL.Image库 PIL.Image.Imagedetectron2库数据增强…

C++基础系列【8】如何解决编译器报的错误

博主介绍&#xff1a;程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章&#xff0c;首发gzh&#xff0c;见文末&#x1f447;&#x1f…

程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<8>

大家好啊&#xff0c;我是小象٩(๑ω๑)۶ 我的博客&#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家&#xff0c;希望能够和大家一起交流学习&#xff0c;共同进步。 今天我们复习前面学习的指针知识 目录 关于指针数组和数组指针的区别指针数组&#xff08;Array of Poi…

UE5.5 PCGFrameWork--GPU CustomHLSL

在上一篇UE5.5 PCGFrameWork使用入门-CSDN博客 大致介绍了UE5 PCG框架的基本使用. 本篇探索PCGFrame的高级应用--GPU点云。也就是利用GPU HLSL编程对点云进行操纵&#xff0c;可以大幅度提升点云生成效率。 目前在UE5 PCG框架中&#xff0c;点云GPU的应用大致分为三类: Point…

Games202 Lecture11 LTC | Disney principled BRDF | NPR

Shading with microfacet BRDFs under polygonal lighting -Linearly Transformed Cosines(LTC)Real-Time PBR Materials cont. -Disney principled BRDFNon-photorealistic rendering(NPR) Linearly Transformed Cosines(LTC) lobe花瓣 BRDF的2d形状 基本思路: 任意BRDF变…