Qt/C++音视频开发49-推流到各种流媒体服务程序

news2025/4/18 18:45:23

一、前言

最近将推流程序完善了很多功能,尤其是增加了对多种流媒体服务程序的支持,目前支持mediamtx、LiveQing、EasyDarwin、nginx-rtmp、ZLMediaKit、srs、ABLMediaServer等,其中经过大量的对比测试,个人比较建议使用mediamtx和ZLMediaKit,因为这两者支持的格式众多,不仅同时支持rtsp/rtmp推流,还支持各种格式rtsp/rtmp/hls/flv/ws-flv/webrtc等拉流,涵盖面非常全,而且拉流的画面非常流畅,在局域网没有出现花屏的现象,对视频文件、视频流支持都非常友好。

为了增强程序的拓展性,以便适应后期增加其他流媒体服务器程序,特意将流媒体服务程序的信息用配置文件存取来,可以自行增删改,推流和拉流对应的端口都可以自行修改,这样非常适用于一台电脑多种流媒体服务,通过配置不同的端口来保证同时推流到多个流媒体服务程序,比如windows系统554端口很可能被系统的进程占用,所以需要更改为其他端口,在流媒体服务程序对应的配置文件更改后,还需要在推流程序对应的配置文件中修改,这样后期如果增加了其他的流媒体服务程序,只需要在配置文件增加即可,程序会自动读取并加载到下拉框。

二、效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、体验地址

  1. 国内站点:https://gitee.com/feiyangqingyun
  2. 国际站点:https://github.com/feiyangqingyun
  3. 个人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
  4. 体验地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_push。

四、功能特点

  1. 支持各种本地视频文件和网络视频文件。
  2. 支持各种网络视频流,网络摄像头,协议包括rtsp、rtmp、http。
  3. 支持将本地摄像头设备推流,可指定分辨率和帧率等。
  4. 支持将本地桌面推流,可指定屏幕区域和帧率等。
  5. 自动启动流媒体服务程序,默认mediamtx(原rtsp-simple-server),可选用srs、EasyDarwin、LiveQing、ZLMediaKit等。
  6. 可实时切换预览视频文件,可切换视频文件播放进度,切换到哪里就推流到哪里。
  7. 推流的清晰度和质量可调。
  8. 可动态添加文件、目录、地址。
  9. 视频文件自动循环推流,如果视频源是视频流,在掉线后会自动重连。
  10. 网络视频流自动重连,重连成功自动继续推流。
  11. 网络视频流实时性极高,延迟极低,延迟时间大概在100ms左右。
  12. 极低CPU占用,4路主码流推流只需要占用0.2%CPU。理论上常规普通PC机器推100路毫无压力,主要性能瓶颈在网络。
  13. 推流可选推流到rtsp/rtmp两种,推流后的数据支持直接rtsp/rtmp/hls/webrtc四种方式访问,可以直接浏览器打开看实时画面。
  14. 可以推流到外网服务器,然后通过手机、电脑、平板等设备播放对应的视频流。
  15. 每个推流都可以手动指定唯一标识符(方便拉流/用户无需记忆复杂的地址),没有指定则按照策略随机生成hash值。
  16. 自动生成测试网页直接打开播放,可以看到实时效果,自动按照数量对应宫格显示。
  17. 推流过程中可以在表格中切换对应推流项,实时预览正在推流的视频,并可以切换视频文件的播放进度。
  18. 音视频同步推流,符合264/265/aac格式的自动原数据推流,不符合的自动转码再推流(会占用一定CPU)。
  19. 转码策略支持三种,自动处理(符合要求的原数据/不符合的转码),仅限文件(文件类型的转码视频),所有转码。
  20. 表格中实时显示每一路推流的分辨率和音视频数据状态,灰色表示没有输入流,黑色表示没有输出流,绿色表示原数据推流,红色表示转码后的数据推流。
  21. 自动重连视频源,自动重连流媒体服务器,保证启动后,推流地址和打开地址都实时重连,只要恢复后立即连上继续采集和推流。
  22. 提供循环推流示例,一个视频源同时推流到多个流媒体服务器,比如打开一个视频同时推流到抖音/快手/B站等,可以作为录播推流,列表循环,非常方便实用。
  23. 根据不同的流媒体服务器类型,自动生成对应的rtsp/rtmp/hls/flv/ws-flv/webrtc地址,用户可以直接复制该地址到播放器或者网页中预览查看。
  24. 编码视频格式可以选择自动处理(源头是264就264/源头是265就265),转H264(强制转264),转H265(强制转265)。
  25. 支持Qt4/Qt5/Qt6任意版本,支持任意系统(windows/linux/macos/android/嵌入式linux等)。

五、相关代码

QList<QString> VideoPushUrl::listPushType = QList<QString>();
QList<QString> VideoPushUrl::listPullType = QList<QString>();
QList<int> VideoPushUrl::listPullPort = QList<int>();

void VideoPushUrl::initServerInfo()
{
    listPushType.clear();
    listPullType.clear();
    listPullPort.clear();

    listPushType << "mediamtx" << "mediamtx" << "mediamtx" << "mediamtx";
    listPullType << "rtsp" << "rtmp" << "hls" << "webrtc";
    listPullPort << 8554 << 1935 << 8888 << 8889;

    listPushType << "LiveQing" << "LiveQing" << "LiveQing" << "LiveQing" << "LiveQing";
    listPullType << "rtmp" << "hls" << "flv" << "ws-flv" << "webrtc";
    listPullPort << 10085 << 18000 << 18000 << 18000 << 18000;

    listPushType << "EasyDarwin";
    listPullType << "rtsp";
    listPullPort << 5541;

    listPushType << "nginx-rtmp";
    listPullType << "rtmp";
    listPullPort << 1935;

    listPushType << "ZLMediaKit" << "ZLMediaKit" << "ZLMediaKit" << "ZLMediaKit" << "ZLMediaKit" << "ZLMediaKit";
    listPullType << "rtsp" << "rtmp" << "hls" << "flv" << "ws-flv" << "webrtc";
    listPullPort << 554 << 1935 << 80 << 80 << 80 << 80;

    listPushType << "srs" << "srs" << "srs" << "srs";
    listPullType << "rtmp" << "hls" << "flv" << "webrtc";
    listPullPort << 1935 << 8080 << 8080 << 8080;

    listPushType << "ABLMediaServer" << "ABLMediaServer" << "ABLMediaServer" << "ABLMediaServer" << "ABLMediaServer";
    listPullType << "rtsp" << "rtmp" << "hls" << "flv" << "ws-flv";
    listPullPort << 554 << 1935 << 9088 << 8088 << 6088;
}

void VideoPushUrl::initServerInfo(const QString &fileName)
{
    listPushType.clear();
    listPullType.clear();
    listPullPort.clear();

    QFile file(fileName);
    if (file.open(QFile::ReadOnly | QFile::Text)) {
        while (!file.atEnd()) {
            QString content = file.readLine();
            content.replace("\r", "");
            content.replace("\n", "");
            if (content.isEmpty()) {
                continue;
            }

            QStringList list = content.split(",");
            if (list.count() == 3) {
                listPushType << list.at(0);
                listPullType << list.at(1);
                listPullPort << list.at(2).toInt();
            }
        }
    }
}

QStringList VideoPushUrl::getPushType()
{
    QStringList types;
    foreach (QString type, listPushType) {
        if (!types.contains(type)) {
            types << type;
        }
    }
    return types;
}

QString VideoPushUrl::getPushPath(const QString &pushUrl)
{
    //("rtsp:", "", "127.0.0.1:5541") ("rtsp:", "", "127.0.0.1:5541", "live") ("rtsp:", "", "127.0.0.1:5541", "live/test")
    QString path = "/";
    QStringList list = pushUrl.split("/");
    int count = list.count();
    //从第三位开始后面所有的都是资源目录
    for (int i = 3; i < count; ++i) {
        path = path + list.at(i) + "/";
    }

    //末尾的斜杠去掉
    return path.mid(0, path.length() - 1);
}

int VideoPushUrl::getPullPort(const QString &pushType, const QString &pullType)
{
    int port = 80;
    int count = listPushType.count();
    for (int i = 0; i < count; ++i) {
        if (listPushType.at(i) == pushType && listPullType.at(i) == pullType) {
            port = listPullPort.at(i);
            break;
        }
    }
    return port;
}

//各种拉流协议分析 https://www.cnblogs.com/xi-jie/p/14031604.html
QString VideoPushUrl::getPullUrl(const QString &pushUrl, const QString &pushType, const QString &pullType, const QString &ip, const QString &flag)
{
    //找到对应服务器类型和拉流类型的端口
    int port = getPullPort(pushType, pullType);
    //资源目录(可以为空)
    QString path = getPushPath(pushUrl);
    //去掉特殊字符比如?
    QString name = flag.split("?").first();

    //根据服务器类型获取对应的地址
    QString url = QString("://%1:%2%3/%4").arg(ip).arg(port).arg(path).arg(name);
    if (pushType == "mediamtx") {
        //同时支持rtsp/rtmp推拉流(非常棒)
        if (pullType == "rtsp") {
            url = "rtsp" + url;
        } else if (pullType == "rtmp") {
            url = "rtmp" + url;
        } else if (pullType == "hls") {
            url = "http" + url;
        } else if (pullType == "webrtc") {
            url = "http" + url;
        }
    } else if (pushType == "LiveQing") {
        //只支持rtmp推流
        if (pullType == "rtmp") {
            url = QString("rtmp://%1:%2/hls/%3").arg(ip).arg(port).arg(name);
        } else if (pullType == "hls") {
            url = QString("http://%1:%2/hls/%3/%3_live.m3u8").arg(ip).arg(port).arg(name);
        } else if (pullType == "flv") {
            url = QString("http://%1:%2/flv/hls/%3.flv").arg(ip).arg(port).arg(name);
        } else if (pullType == "ws-flv") {
            url = QString("ws://%1:%2/ws-flv/hls/%3.flv").arg(ip).arg(port).arg(name);
        } else if (pullType == "webrtc") {
            url = QString("webrtc://%1:%2/rtc/hls/%3").arg(ip).arg(port).arg(name);
        }
    } else if (pushType == "EasyDarwin") {
        //只支持rtsp推流拉流
        if (pullType == "rtsp") {
            url = "rtsp" + url;
        }
    } else if (pushType == "nginx-rtmp") {
        //只支持rtmp推流拉流
        if (pullType == "rtmp") {
            url = "rtmp" + url;
        }
    } else if (pushType == "ZLMediaKit") {
        //同时支持rtsp/rtmp推拉流(名气最大/用户最多)
        if (pullType == "rtsp") {
            url = "rtsp" + url;
        } else if (pullType == "rtmp") {
            url = "rtmp" + url;
        } else if (pullType == "hls") {
            url = "http" + url + "/hls.m3u8";
        } else if (pullType == "flv") {
            url = "http" + url + ".live.flv";
        } else if (pullType == "ws-flv") {
            url = "ws" + url + ".live.flv";
        } else if (pullType == "webrtc") {

        }
    } else if (pushType == "srs") {
        //不支持rtsp推流拉流(以前支持/后面都移除了)
        if (pullType == "rtmp") {
            url = "rtmp" + url;
        } else if (pullType == "hls") {
            url = "http" + url + ".m3u8";
        } else if (pullType == "flv") {
            url = "http" + url + ".flv";
        } else if (pullType == "webrtc") {
            url = "webrtc" + url;
        }
    } else if (pushType == "ABLMediaServer") {
        //支持rtsp/rtmp推流拉流(目前还不稳定/兼容性不够好)
        if (pullType == "rtsp") {
            url = "rtsp" + url;
        } else if (pullType == "rtmp") {
            url = "rtmp" + url;
        } else if (pullType == "hls") {
            url = "http" + url + ".m3u8";
        } else if (pullType == "flv") {
            url = "http" + url + ".flv";
        } else if (pullType == "ws-flv") {
            url = "ws" + url + ".flv";
        }
    } else if (pushType == "Monibuca") {
        //支持rtsp/rtmp推流拉流(拉流格式众多/各种插件/性能很强劲/具体有待验证)
        if (pullType == "rtsp") {
            url = "rtsp" + url;
        } else if (pullType == "rtmp") {
            url = "rtmp" + url;
        } else if (pullType == "hls") {
            url = QString("http://%1:%2/hls%3/%4.m3u8").arg(ip).arg(port).arg(path).arg(name);
        } else if (pullType == "flv") {
            url = QString("http://%1:%2/hdl%3/%4.flv").arg(ip).arg(port).arg(path).arg(name);
        } else if (pullType == "ws-flv") {
            url = QString("ws://%1:%2/jessica%3/%4.flv").arg(ip).arg(port).arg(path).arg(name);
        } else if (pullType == "webrtc") {
            url = QString("webrtc://%1:%2/webrtc/play%3/%4").arg(ip).arg(port).arg(path).arg(name);
        }
    }

    return url;
}

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

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

相关文章

QT DAY6

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);socket new QTcpSocket(this);//如果连接服务器成功&#xff0c;该客户端就会发射一个connected的信号。//我们…

【TypeScript学习】—基本类型(二)

【TypeScript学习】—基本类型&#xff08;二&#xff09; 一、TypeScript基本类型 //也可以直接用字面量进行类型声明let a:10; a10;//也可以使用 |来连接多个类型&#xff08;联合类型&#xff09;let b:"male"|"female"; b"male"; b"fe…

【Java】Java新特性--Records记录类型

Java 14引入了一个新的语言特性&#xff0c;即Records。Records是一种新的数据类&#xff0c;旨在简化Java中的数据类创建过程。它们提供了一种简洁的方式来创建具有默认的getter、setter、equals、hashCode和toString方法的不可变数据类。 以下是Records的基本语法&#xff1…

一文讲透:erp系统是什么?

erp系统是什么&#xff1f;这个看似简单的问题还真不好解答。因为现在99%的人都把ERP“系统”和ERP“软件”混淆了&#xff01; ERP原本主要是专注于制造业的信息化问题&#xff0c;我把它叫真正的ERP“系统”。 但现在基本上只要是一个软件系统都可以叫ERP系统&#xff0c;什…

【动态规划】面试题 08.01. 三步问题

Halo&#xff0c;这里是Ppeua。平时主要更新C&#xff0c;数据结构算法&#xff0c;Linux与ROS…感兴趣就关注我bua&#xff01; 文章目录 0. 题目解析1. 算法原理1.1 状态表示1.2 状态转移方程1.3初始化1.4 填表顺序1.5 返回值 2.算法代码 &#x1f427; 本篇是整个动态规划的…

9.2 消息对话框 画板 定时器

#include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {//设置定时器timernew QTimer(this);timeidthis->startTimer(1000);connect(timer,&QTimer::timeout,this,&Widget::timeout_slot);speechernew QTextToSpeech(this);//边框this-&…

天眼情报分析——编程赛道——研究对象001续

前言&#xff1a; 此次情报分析依旧会分为几大块 一、ACWING 算法基础课 1.高精度加法和减法听都没听过 1.什么是高精度加减法&#xff1f; "高精度加法"和"高精度减法"是一类编程题目&#xff0c;通常出现在算法竞赛和在线编程平台上&#xff0c;比如…

金蝶云星空和金蝶云星空单据接口对接

金蝶云星空和金蝶云星空单据接口对接 接入系统&#xff1a;金蝶云星空 金蝶K/3Cloud&#xff08;金蝶云星空&#xff09;是移动互联网时代的新型ERP&#xff0c;是基于WEB2.0与云技术的新时代企业管理服务平台。金蝶K/3Cloud围绕着“生态、人人、体验”&#xff0c;旨在帮助企业…

【科研论文配图绘制】task8 总结与回顾

task8 总结与回顾&#xff0c;这次组队学习大致掌握了常见python绘图工具包的使用&#xff0c;整体上和matlab的语法类似&#xff0c;也是用画布形式控制元素的绘制。印象深刻的是seaborn的使用&#xff0c;在之前做波士顿房价预测时候先接触了seaborn绘制的散点图、直方图和核…

手写Ribbon基本原理

本文已收录于专栏 《中间件合集》 目录 概念说明什么是RibbonRibbon和Nginx负载均衡的区别 工作流程代码实现RibbonSDK发送请求端引入RibbonSDK和Nacos的依赖配置文件中填写负载均衡策略调用代码 接收请求端执行效果发送请求端接收请求端 总结提升 概念说明 什么是Ribbon Ribb…

揭秘企业标准化作业:提升效率、降低成本、保障质量!为什么需要推行?

企业标准化作业是现今生产车间中出现频率非常高的一个词&#xff0c;那么什么是企业标准化作业&#xff1f;企业为什么推行标准化作业&#xff1f;标准化作业的实施有哪些好处&#xff1f;实施过程又有哪些难点呢&#xff1f;今天就来说一说&#xff01; 企业标准化作业是对生产…

智能制造效率与创新:RFID智能设备的引领作用

在现代制造业中&#xff0c;如何提升生产效率、降低成本、实现创新已经成为制造企业持续追求的目标。随着科技的不断进步&#xff0c;智能制造RFID智能设备正逐渐成为实现这些目标的得力工具。本文将探讨智能制造RFID智能设备在提升制造效率和创新方面的引领作用。 实时生产监控…

如何使用ArcGIS去除卫星影像上的云

虽然目前发布的地图都是对云量进行过筛选&#xff08;一般低于20%&#xff09;&#xff0c;但是还是有可能会遇到有云的情况&#xff08;特别是下载历史影像的时候&#xff09;&#xff0c;那么这些云应该怎么去除呢&#xff0c;我们可以尝试使用ArcGIS进行处理。 识别像素 将…

通过使用过硫酸铵溶液轻松预处理铜催化剂基底具有独特底部轮廓的剥离光刻胶的开发

引言 石墨烯是sp2杂化碳原子的二维蜂窝晶格&#xff0c;自首次成功分离和表征单层石墨烯以来就引起了广泛关注。载流子迁移率、稳健的机械公差和高光学透明度为未来的超大规模器件的应用提供了巨大的利用机会。因此&#xff0c;英思特提出了化学剥离、外延生长、热解和化学气相…

FreeRTOS中断与任务之间同步(Error:..\..\FreeRTOS\portable\RVDS\ARM_CM4F\port.c,422 )

前言&#xff1a; FreeRTOS中&#xff0c;中断需要注意几点&#xff1a; 何时使用中断&#xff1b;中断服务函数&#xff08;ISR&#xff09;要处理的数据量有多大&#xff0c;通常我们希望中断的切换越快越好&#xff0c;也就是说&#xff0c;ISR尽量采用耗时较少的处理方式…

2000-2022年上市公司融资约束SA指数(含原始数据+计算方法+计算结果)

2000-2022年上市企业的融资约束指数&#xff08;含原始数据计算方法计算结果&#xff09; 1、时间&#xff1a;2000-2022年 2、范围&#xff1a;沪深A股上市公司 3、指标&#xff1a; 证券代码、证券简称、统计截止日期、是否发生ST或*ST或PT、是否发生暂停上市、行业代码、…

【Java 基础篇】Java多态:让你的代码更灵活而强大

多态是面向对象编程中的一个重要概念&#xff0c;它允许我们在不同的对象上调用相同的方法&#xff0c;但根据对象的不同&#xff0c;可以产生不同的行为。在 Java 中&#xff0c;多态性是一个强大的特性&#xff0c;它有助于代码的可扩展性和可维护性。本篇博客将深入探讨 Jav…

javaee spring aop实现事务 项目结构

spring配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:context"http://www.springframewo…

搭建hadoop集群的常见问题及解决办法

问题一: namenode -format重复初始化 出现问题的原因是重复初始化时会重新生成集群ID&#xff0c;而dn还是原先的集群ID&#xff0c;两者不匹配时无法启动相应的dn进程。 怎么查找问题原因&#xff1a;在logs目录下找到对应节点的.log文件&#xff0c;使用tail -200 文件名来查…

(vue)Vue项目中使用jsPDF和html2canvas生成PDF

(vue)Vue项目中使用jsPDF和html2canvas生成PDF 效果&#xff1a; 安装与使用 1.&#xff1a;安装jsPDF和html2canvas npm install jspdf html2canvas2.在需要生成PDF文档的组件中引入jsPDF和html2canvas <template><div><el-button type"primary"…