Qt+FFmpeg网络视频流播放

  • init 函数用于初始化 FFmpeg,包括设置参数、打开输入、初始化视频和音频等。
  • initOption 函数用于设置 FFmpeg 的参数选项。
bool FFmpegThread::init()
{if (url.isEmpty()) {return false;}//判断该摄像机是否能联通if (checkConn && isRtsp) {if (!checkUrl(url, checkTime)) {return false;}}//启动计时QElapsedTimer time;time.start();//初始化参数this->initOption();//初始化输入if (!initInput()) {return false;}//初始化视频if (!initVideo()) {return false;}//初始化音频if (!initAudio()) {return false;}//初始化其他this->initOther();QString useTime = QString::number((float)time.elapsed() / 1000, 'f', 3);qDebug() << TIMEMS << fileFlag << QString("初始化完 -> 用时: %1 秒  地址: %2").arg(useTime).arg(url);return true;
}bool FFmpegThread::initInput()
{//实例化格式处理上下文formatCtx = avformat_alloc_context();//设置超时回调,有些不存在的地址或者网络不好的情况下要卡很久formatCtx->interrupt_callback.callback = AVInterruptCallBackFun;formatCtx->interrupt_callback.opaque = this;//必须要有tryOpen标志位来控制超时回调,由他来控制是否继续阻塞tryOpen = false;tryRead = true;//先判断是否是本地设备(video=设备名字符串),打开的方式不一样QByteArray urlData = url.toUtf8();AVInputFormat *ifmt = nullptr;if (isUsbCamera) {
#if defined(Q_OS_WIN)ifmt = av_find_input_format("dshow");
#elif defined(Q_OS_LINUX)//ifmt = av_find_input_format("v4l2");ifmt = av_find_input_format("video4linux2");
#elif defined(Q_OS_MAC)ifmt = av_find_input_format("avfoundation");
#endif}//设置 avformat_open_input 非阻塞默认阻塞 不推荐这样设置推荐采用回调//formatCtx->flags |= AVFMT_FLAG_NONBLOCK;int result = avformat_open_input(&formatCtx, urlData.data(), ifmt, &options);tryOpen = true;if (result < 0) {qDebug() << TIMEMS << fileFlag << "open input error" << getError(result) << url;emit ffmpegDecodeSignal(fileFlag + " open input error " + getError(result));return false;}//释放设置参数if (options != nullptr) {av_dict_free(&options);}//根据自己项目需要开启下面部分代码加快视频流打开速度
#if 0//接口内部读取的最大数据量,从源文件中读取的最大字节数//默认值5000000导致这里卡很久最耗时,可以调小来加快打开速度formatCtx->probesize = 50000;//从文件中读取的最大时长,单位为 AV_TIME_BASE unitsformatCtx->max_analyze_duration = 5 * AV_TIME_BASE;//内部读取的数据包不放入缓冲区//formatCtx->flags |= AVFMT_FLAG_NOBUFFER;
#endif//获取流信息result = avformat_find_stream_info(formatCtx, nullptr);if (result < 0) {qDebug() << TIMEMS << fileFlag << "find stream info error" << getError(result);emit ffmpegDecodeSignal(fileFlag + " find stream info error " + getError(result));return false;}return true;
}
  • run 函数是线程的运行函数,用于循环读取音视频数据包,并进行解码和播放。
void FFmpegThread::run()
{//记住开始解码的时间用于用视频同步startTime = av_gettime();while (!stopped) {//根据标志位执行初始化操作if (isPlay) {if (init()) {//这里也需要更新下最后的时间lastTime = QDateTime::currentDateTime();initSave();//初始化完成变量放在这里,绘制那边判断这个变量是否完成才需要开始绘制if (videoIndex >= 0) {isInit = true;}emit receivePlayStart();} else {emit receivePlayError();break;}isPlay = false;continue;}//处理暂停 本地文件才会执行到这里 视频流的暂停在其他地方处理if (isPause) {//这里需要假设正常,暂停期间继续更新时间lastTime = QDateTime::currentDateTime();msleep(1);continue;}//QMutexLocker locker(&mutex);//解码队列中帧数过多暂停读取 下面这两个值可以自行调整 表示缓存的大小if (videoSync->getPacketCount() >= 100 || audioSync->getPacketCount() >= 100) {msleep(1);continue;}//必须要有tryRead标志位来控制超时回调,由他来控制是否继续阻塞tryRead = false;//下面还有个可以改进的地方就是如果是视频流暂停情况下只要保证 av_read_frame 一直读取就行无需解码处理frameFinish = av_read_frame(formatCtx, packet);//qDebug() << TIMEMS << fileFlag << "av_read_frame" << frameFinish;if (frameFinish >= 0) {tryRead = true;//更新最后的解码时间 错误计数清零errorCount = 0;lastTime = QDateTime::currentDateTime();//判断当前包是视频还是音频int index = packet->stream_index;if (index == videoIndex) {//qDebug() << TIMEMS << fileFlag << "videoPts" << qint64(getPtsTime(formatCtx, packet) / 1000) << packet->pts << packet->dts;decodeVideo(packet);} else if (index == audioIndex) {//qDebug() << TIMEMS << fileFlag << "audioPts" << qint64(getPtsTime(formatCtx, packet) / 1000) << packet->pts << packet->dts;decodeAudio(packet);}} else if (!isRtsp) {//如果不是视频流则说明是视频文件播放完毕if (frameFinish == AVERROR_EOF) {//当同步队列中的数量为0才需要跳出 表示解码处理完成if (videoSync->getPacketCount() == 0 && audioSync->getPacketCount() == 0) {//循环播放则重新设置播放位置,在这里执行的代码可以做到无缝切换循环播放if (playRepeat) {this->position = 0;videoSync->reset();audioSync->reset();videoSync->start();audioSync->start();QMetaObject::invokeMethod(this, "setPosition", Q_ARG(qint64, position));qDebug() << TIMEMS << fileFlag << "repeat" << url;} else {break;}}}} else {//下面这种情况在摄像机掉线后出现,如果想要快速识别这里直接break即可//一般3秒钟才会执行一次错误累加errorCount++;//qDebug() << TIMEMS << fileFlag << "errorCount" << errorCount << url;if (errorCount >= 3) {errorCount = 0;break;}}free(packet);msleep(2);}QMetaObject::invokeMethod(this, "stopSave");//线程结束后释放资源msleep(100);free();freeAudioDevice();emit receivePlayFinsh();//qDebug() << TIMEMS << fileFlag << "stop ffmpeg thread" << url;
}

以上是部分代码,这个类的主要目的是使用 FFmpeg 库来处理多媒体数据,包括视频和音频的解码、播放、保存等操作。

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

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

相关文章

【SpringBoot】Spring Boot 高并发优化终极指南,涵盖线程模型、JVM 调优、数据库访问、缓存策略等 15+ 核心模块

Spring Boot 高并发优化终极指南&#xff0c;涵盖线程模型、JVM 调优、数据库访问、缓存策略等 15 核心模块一、线程模型深度调优&#xff08;核心瓶颈突破&#xff09;1. Tomcat 线程池原子级配置2. 异步任务线程池隔离策略二、JVM 层终极调参&#xff08;G1GC 深度优化&#…

linux(CentOS-7-x86_64:NAT模式下解决yum无法使用:更新yum源的详细操作步骤2025)

目录 一、CentOS-7-x86_64的NAT模式下解决yum无法使用。&#xff08;更新可用的yum&#xff09; &#xff08;1&#xff09;首先保证能够ping通&#xff0c;也就是NAT模式下虚拟机有网络。 &#xff08;2&#xff09;错误&#xff1a;无法使用yum。比如我现在无法yum search if…

C++11的整理笔记

Lambda 表达式Lambda 表达式是 C11 引入的一种强大的功能&#xff0c;它允许你在代码中直接定义匿名函数对象。Lambda 表达式可以捕获上下文中的变量&#xff0c;并在需要时使用它们。它们通常用于简化代码&#xff0c;尤其是那些需要传递函数对象作为参数的场景&#xff08;如…

MS1826+MS9332 4K@30Hz HD4×2视频分割器

MS1826MS9332是一款支持4K30Hz分辨率的HD42视频分割器方案。支持四路HD输入两路HD输出&#xff0c;最高支持4K30Hz分辨率。该方案具有Scaler、OSD、画面分割、无缝切换、淡入淡出及旋转等功能。该方案现已实现量产&#xff0c;并提供完善的技术支持&#xff0c;适用于各类高清视…

用 MATLAB 模拟传染病传播:从 SI 模型到 SIS 模型的可视化之旅

在公共卫生研究中&#xff0c;数学模型是理解传染病传播规律的重要工具。通过数值模拟&#xff0c;我们能直观看到 “易感人群” 和 “感染人群” 随时间的变化趋势&#xff0c;甚至能预测疫情发展的关键节点。今天就带大家用 MATLAB 实现两个经典的传染病模型 ——SI 模型和SI…

Ruby如何采集直播数据源地址

在当今数字化的时代&#xff0c;实时获取并处理信息变得尤为重要。特别是在体育赛事、新闻报道等领域&#xff0c;及时获取最新的直播数据源对于提升用户体验至关重要。本文将介绍如何使用Ruby语言来采集特定网站的数据源地址 一、准备工作 首先&#xff0c;确保你的环境中已…

【fitz+PIL】PDF图片文字颜色加深

文章目录0 引言1 解决思路及流程1.1 思路1.2 代码实现2 完整代码与效果3 总结0 引言 没错&#xff0c;这是连续剧。女友对上一篇【fitzOpenCV】去除PDF图片中的水印得到的去水印效果很满意&#xff0c;于是问我可不可以再帮她处理一下另一个PDF文件&#xff0c;我二话不说答应…

tp8.0\jwt接口安全验证

环境&#xff1a;php8.3\tp8.1\firebase-jwt6.1app\middleware\JwtAuth<?php namespace app\middleware;use app\common\library\JwtHandler; use think\Request; use think\facade\Env;class JwtAuth {public function handle(Request $request, \Closure $next){// 获取当…

ReactNative【实战系列教程】我的小红书 5 -- 文章详情(含轮播图 ImageSlider,点亮红心动画 Heart,嵌套评论等)

最终效果 安装依赖 npm i dayjs用于对时间进行格式化 必备组件 轮播图 ImageSlider https://blog.csdn.net/weixin_41192489/article/details/149224510 点亮红心动画 Heart components/Heart.tsx import AntDesign from "expo/vector-icons/AntDesign"; import …

哔哩哔哩第三方TV-BBLL最新版

—————【下 载 地 址】——————— 【​本章下载一】&#xff1a;https://pan.xunlei.com/s/VOUtUcaymd9rpgurgDKS9pswA1?pwdp76n# 【​本章下载二】&#xff1a;https://pan.xunlei.com/s/VOUtUcaymd9rpgurgDKS9pswA1?pwdp76n# 【百款黑科技】&#xff1a;https://uc…

用YOLOv5系列教程(1)-用YOLOv5轻松实现设备状态智能监控!工业级教程来了

用YOLOv5轻松实现设备状态智能监控&#xff01;工业级教程来了设备运维革命&#xff1a;15分钟教会你的摄像头看懂指示灯状态工业现场各种设备状态指示灯是工程师的"眼睛"——红灯报警、绿灯运行、黄灯待机。但人工巡检耗时费力&#xff0c;关键故障容易漏检&#xf…

笔记-分布式计算基础

Distributed Computing 划分数据并行&#xff08;DataParallelism&#xff09;将数据分为n份&#xff0c;发送到n个GPU上&#xff0c;每个GPU上都存在一个完整的大模型 缺点&#xff1a; 模型太大Pipeline Parallelism&#xff08;串行的&#xff09;将模型做split,每个GPU负责…

Android Studio 2024,小白入门喂饭级教程

一、下载Android Studio 1、从安卓官网安卓官网下载Android Studio。 ​ ​ 二、安装Android Studio 1、双击android-studio-2024.3.2.15-windows.exe。 ​ ​​ ​ ​ ​ ​ 三、新建工程 1、双击桌面图标​ 打开Android Studio。 ​ 选“Empty Views Activity…

AI智能体 | 使用Coze制作一键生成单词洗脑循环视频,一天批量生成100条视频不是梦!(附保姆级教程)

目录 一、整体工作流设计 二、制作工作流 2.1 开始节点 2.2 大模型-单词 2.3 大模型_图像生成 2.4 输出 2.5 图像生成_1 2.6 输出_2 2.7 画板_2 2.8 文本处理 2.9 输出_3 2.10 speech_synthesis_1x5 2.11 get_audio_duration_1 2.12 代码 2.13 get_audio_durati…

质量属性场景(Quality Attribute Scenario)深度解析

本质定义:质量属性场景(Quality Attribute Scenario)是精确描述软件系统质量要求的结构化方法,通过标准化的场景模板将抽象的质量属性转化为可测量、可验证的具体行为描述,为架构设计提供客观评估基准。 一、质量属性场景核心结构 1. 六元组标准模板 #mermaid-svg-AGbvPVRu…

Java_Springboot技术框架讲解部分(一)

首先讲解一下&#xff1a;Java技术栈中&#xff0c;目前Spring Boot在国内的关注趋势也日渐超过Spring。Spring Boot是Spring家族中的一个全新的框架&#xff0c;它用来简化Spring应用程序的创建和开发过程。采用Spring Boot可以非常容易和快速的构建基于Spring框架的应用程序&…

从OpenMV到执行器:当PID算法开始“调教”舵机

如果到现在还不会驱动舵机——朋友&#xff0c;电赛的元器件清单每年都在对你“明示”&#xff0c;二维云台都快成祖传考题了&#xff01;补课&#xff1f;现在&#xff01;立刻&#xff01;&#xff08;当然&#xff0c;如果你脸皮够厚&#xff0c;也可以私信骚扰作者&#xf…

xml映射文件的方式操作mybatis

映射文件 在Java spring中使用mybatis有两种方式&#xff0c;一种是注释的方式&#xff0c;一种是xml映射文件的方式。在简单的功能需求可以使用注释&#xff0c;方便简洁。而在大的功能逻辑上&#xff0c;更推荐使用xml映射文件&#xff0c;方便管理且结构清晰。 首先xml文件结…

Carla自动驾驶仿真_快速安装与运行Carla

大家好&#xff0c;我是橙子&#xff0c;今天给大家介绍Carla的基础安装和使用 目录 1.Carla介绍 2.Carla的安装与使用 3.Carla0.9.15安装包下载&#xff1a; ​编辑 4.运行Demo 5.运行一个简单场景&#xff1a; 6.相关资源 1.Carla介绍 Carla 是一个开源的自动驾驶仿…

远程登录docker执行shell报错input is not a terminal问题

背景 最近要远程去k8s docker里面获取信息&#xff0c;于是&#xff0c;写了一个如下的命令&#xff0c;执行完之后&#xff0c;报错了。 ssh 192.168.100.2 sudo crictl exec -it xxx.docker /usr/bin/lscpu --online --extended错误信息如下&#xff1a; time“2025-07-11T21…