流媒体服务器SRS的搭建及QT下RTMP推流客户端的编写
一、前言
目前市面上有很多开源的流媒体服务器解决方案,常见的有SRS、EasyDarwin、ZLMediaKit和Monibuca。这几种的对比如下:

(本图来源:https://www.ngui.cc/zz/1781086.html?action=onClick)
二、SRS的介绍
SRS(Simple Real-time Server)是一个开源的流媒体服务器,它支持RTMP、HLS、HTTP-FLV等多种流媒体协议。SRS提供了丰富的功能,包括推流、拉流、转码、录制、转发等,并且具有高性能、低延迟的特点。使用SRS可以搭建自己的流媒体服务器,实现音视频的实时传输和播放。你可以通过SRS推送音视频流到服务器,也可以从SRS服务器拉取音视频流进行播放或者转发给其他客户端。SRS支持多线程推拉流,可以利用多核处理器的优势,提高处理能力和并发性能。在使用多线程推拉流时,需要注意线程同步和数据共享的问题。
三、SRS的搭建
3.1 下载
虚拟机环境:CentOS 7 64位
SRS下载地址:https://gitcode.net/mirrors/ossrs
(SRS 4.0以上版本,4.0版本以下不支持GB/28181协议)
3.2 配置、编译、运行
下载后,解压到CentOS 7目录下(注意不要在共享目录下操作不然会出现ln软链接错误问题)。
1)执行配置命令:
cd srs/trunk
./configure

2)执行编译命令:
make

3)执行运行命令:
./etc/init.d/srs start

配置文件位置在:conf/srs.conf,可修改配置文件内容:

4)检查srs服务启动是否正常:
ps -ef | grep srs

3.3 网页登录
(默认端口8080) 红框中的为推流地址

四、QT下推流客户端
本客户端基于我的博客:https://blog.csdn.net/linyibin_123/article/details/132107948 开发的播放器下新增RTMP推流。
播放器可以支持软硬解码,截图、录像等功能,详细功能看该博客。本客户端支持读取文件解码后推流,也支持拉取网络流解码后进行推流。推流地址为前面搭建的RTMP流媒体服务器,推流成功后,通过VLC播放器从RTMP服务器上拉流下来播放。
4.1 读取本地文件解码后推流:

4.2 拉取网络流解码后推流:

4.3 相关代码:
初始化推流:
bool ctFFmpeg::initPushStream()
{if(m_bEnablePush){int nRet = avformat_alloc_output_context2(&m_pOfmtCtx, nullptr, "flv", m_sRtmpServerAddr.toUtf8().data());if(!m_pOfmtCtx || nRet < 0){MY_DEBUG << "avformat_alloc_output_context2 failed";return false;}m_pOvCodec = avcodec_find_encoder(AV_CODEC_ID_H264);if(!m_pOvCodec){MY_DEBUG << "avcodec_find_encoder failed";return false;}m_pOvCodecCtx = avcodec_alloc_context3(m_pOvCodec);if(!m_pOvCodecCtx){MY_DEBUG << "avcodec_alloc_context3 failed";return false;}m_pOvCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;m_pOvCodecCtx->width = m_nVideoW;m_pOvCodecCtx->height = m_nVideoH;m_pOvCodecCtx->time_base.num = 1;m_pOvCodecCtx->time_base.den = 25;m_pOvCodecCtx->bit_rate = 300000;m_pOvCodecCtx->gop_size = 250;//Some formats want stream headers to be separate.if (m_pOfmtCtx->oformat->flags & AVFMT_GLOBALHEADER)m_pOvCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;m_pOvCodecCtx->qmin = 10;m_pOvCodecCtx->qmax = 51;m_pOvCodecCtx->max_b_frames = 0;AVDictionary *param = 0;av_dict_set(¶m, "preset", "fast", 0);av_dict_set(¶m, "tune", "zerolatency", 0);if (avcodec_open2(m_pOvCodecCtx, m_pOvCodec, ¶m) < 0){MY_DEBUG << "avcodec_open2 failed.";return false;}m_pVideoSt = avformat_new_stream(m_pOfmtCtx, m_pOvCodec);if (nullptr == m_pVideoSt){MY_DEBUG << "avformat_new_stream failed.";return false;}m_pVideoSt->time_base.num = 1;m_pVideoSt->time_base.den = 30;avcodec_parameters_from_context(m_pVideoSt->codecpar, m_pOvCodecCtx);av_dump_format(m_pOfmtCtx, 0, m_sRtmpServerAddr.toLatin1().data(), 1);//Open output URLif (!(m_pOfmtCtx->oformat->flags & AVFMT_NOFILE)){nRet = avio_open(&m_pOfmtCtx->pb, m_sRtmpServerAddr.toLatin1().data(), AVIO_FLAG_READ_WRITE);if (nRet < 0){MY_DEBUG << "avio_open failed. url:" << m_sRtmpServerAddr;return false;}}m_pOfmtCtx->video_codec_id = m_pOfmtCtx->oformat->video_codec;nRet = avformat_write_header(m_pOfmtCtx, NULL);if (nRet < 0){MY_DEBUG << "avformat_write_header failed. nRet:" << nRet;return false;}m_pOutFrameYUV = av_frame_alloc();int nBufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, m_nVideoW, m_nVideoH, 1);m_pOutDstBuffer = (unsigned char*)av_malloc(nBufferSize);if (!m_pOutDstBuffer){return false;}MY_DEBUG << "storeAvFrame 111";nRet = av_image_fill_arrays(m_pOutFrameYUV->data, m_pOutFrameYUV->linesize,m_pOutDstBuffer, AV_PIX_FMT_YUV420P, m_nVideoW, m_nVideoH, 1);if(nRet < 0){return false;}m_pImgConvertCtx = sws_getContext(m_pVideoCodecCxt->width, m_pVideoCodecCxt->height,m_pVideoCodecCxt->pix_fmt, m_pVideoCodecCxt->width,m_pVideoCodecCxt->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);m_nStartTime = av_gettime();m_nFramecnt = 0;return true;}return false;
}
推流过程:
void ctFFmpeg::pushStream()
{if(m_bEnablePush && m_bSupportPush && m_pYuvFrame){sws_scale(m_pImgConvertCtx, (const uint8_t* const*)m_pYuvFrame->data, m_pYuvFrame->linesize, 0,m_pVideoCodecCxt->height, m_pOutFrameYUV->data, m_pOutFrameYUV->linesize);m_pOutFrameYUV->width = m_pYuvFrame->width;m_pOutFrameYUV->height = m_pYuvFrame->height;m_pOutFrameYUV->format = AV_PIX_FMT_YUV420P;m_encPkt.data = NULL;m_encPkt.size = 0;av_init_packet(&m_encPkt);int nRet = avcodec_send_frame(m_pOvCodecCtx, m_pOutFrameYUV);while(nRet >= 0){nRet = avcodec_receive_packet(m_pOvCodecCtx, &m_encPkt);if (nRet == AVERROR(EAGAIN) || nRet == AVERROR_EOF || nRet < 0){//MY_DEBUG << "avcodec_receive_packet nRet == AVERROR(EAGAIN) || nRet == AVERROR_EOF";break;}m_nFramecnt++;m_encPkt.stream_index = m_pVideoSt->index;//av_packet_rescale_ts(&pkt, m_pOvCodecCtx->time_base, m_pVideoSt->time_base);AVRational time_base = m_pOfmtCtx->streams[0]->time_base;//{ 1, 1000 };AVRational time_base_q = {1, AV_TIME_BASE};AVRational rFramerate1 = m_pAVFmtCxt->streams[0]->r_frame_rate;int64_t nCalcDuration = (double)(AV_TIME_BASE)*(1 / av_q2d(rFramerate1)); //内部时间戳//Parametersm_encPkt.pts = av_rescale_q(m_nFramecnt*nCalcDuration, time_base_q, time_base);m_encPkt.dts = m_encPkt.pts;m_encPkt.duration = av_rescale_q(nCalcDuration, time_base_q, time_base);m_encPkt.pos = -1;//MY_DEBUG << "m_encPkt.pts:" << m_encPkt.pts;int64_t pts_time = av_rescale_q(m_encPkt.pts, time_base, time_base_q);int64_t now_time = av_gettime() - m_nStartTime;if ((pts_time > now_time))av_usleep(pts_time - now_time);nRet = av_interleaved_write_frame(m_pOfmtCtx, &m_encPkt);if(nRet < 0){MY_DEBUG << "av_interleaved_write_frame fail nRet:" << nRet;}av_packet_unref(&m_encPkt);}}
}
结束推流:
void ctFFmpeg::endPushStream()
{if(m_bEnablePush && m_bSupportPush){av_write_trailer(m_pOfmtCtx);if (m_pOfmtCtx && !(m_pOfmtCtx->oformat->flags & AVFMT_NOFILE))avio_close(m_pOfmtCtx->pb);avformat_free_context(m_pOfmtCtx);if(nullptr != m_pOvCodecCtx){avcodec_free_context(&m_pOvCodecCtx);m_pOvCodecCtx = nullptr;}if(m_pOutDstBuffer)av_free(m_pOutDstBuffer);}
}
五、客户端下载:
https://download.csdn.net/download/linyibin_123/88237527
相关文章:
流媒体服务器SRS的搭建及QT下RTMP推流客户端的编写
一、前言 目前市面上有很多开源的流媒体服务器解决方案,常见的有SRS、EasyDarwin、ZLMediaKit和Monibuca。这几种的对比如下: (本图来源:https://www.ngui.cc/zz/1781086.html?actiononClick) 二、SRS的介绍 SRS&am…...
Effective C++条款11——在operator=中处理“自我赋值”(构造/析构/赋值运算)
“自我赋值”发生在对象被赋值给自己时: class Widget {}; Widget w; // ... w w; // 赋值给自己 这看起来有点愚蠢,但它合法,所以不要认定客户绝不会那么做。此外赋值动作并不总是那么可被一眼辨识出来,例如: a[i] a[j]; …...
可视化绘图技巧100篇基础篇(八)-气泡图(一)
目录 前言 适用场景 图例 绘图工具及代码实现 EXCEL 1、单轴气泡图...
Elasticsearch查询之Disjunction Max Query
前言 Disjunction Max Query 又称最佳 best_fields 匹配策略,用来优化当查询关键词出现在多个字段中,以单个字段的最大评分作为文档的最终评分,从而使得匹配结果更加合理 写入数据 如下的两条例子数据: docId: 1 title: java …...
Lock wait timeout exceeded; try restarting transaction的错误
文章目录 一、异常发现二、异常定位1、锁表语句确认2、实际场景排查三、解决思路1、本次解决方式2、其他场景解决思路扩展1、【治标方法】innodb_lock_wait_timeout 锁定等待时间改大2、【治标方法】事务信息查询3、【治标方法】如果杀掉线程依然不能解决,可以查找执行线程耗时…...
ShardingSphere01-docker环境安装
使用docker安装数据库是一个非常好的选择,后续的读写分离、数据分片等功能的数据库都是由docker创建。 一、安装准备 1、前提条件 Docker可以运行在Windows、Mac、CentOS、Ubuntu等操作系统上 Docker支持以下的CentOS版本: CentOS 7 (64-bit)CentOS …...
Java代码审计13之URLDNS链
文章目录 1、简介urldns链2、hashmap与url类的分析2.1、Hashmap类readObject方法的跟进2.2、URL类hashcode方法的跟进2.3、InetAddress类的getByName方法 3、整个链路的分析3.1、整理上述的思路3.2、一些疑问的测试3.3、hashmap的put方法分析3.4、反射3.5、整个代码 4、补充说明…...
区间预测 | MATLAB实现QRBiGRU双向门控循环单元分位数回归时间序列区间预测
区间预测 | MATLAB实现QRBiGRU双向门控循环单元分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRBiGRU双向门控循环单元分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现QRBiGRU双向门控循环单元分位数回归时间序列…...
Python面向对象植物大战僵尸
先来一波效果图 来看看如何设计游戏架构 import sysimport pygameclass BaseSprite(pygame.sprite.Sprite):def __init__(self, name):super().__init__()self.image pygame.image.load(name)self.rect self.image.get_rect()class AnimateSprite(BaseSprite):def __init__(…...
大屏模板,增加自适应(包含websocket)
1、简单的Node服务端 const WebSocket require(ws);// 创建 WebSocket 服务器 const wss new WebSocket.Server({ port: 8888 });const getHeader (protocol) > {const protocolArr protocol.split(,)const headers {};for (let i 0; i < protocolArr.length; i …...
电商系统架构设计系列(九):如何规划和设计分库分表?
上篇文章中,我给你留了一个思考题:分库分表该如何设计? 今天这篇文章,我们来聊一下如何规划和设计分库分表,以及要考虑哪些问题。 引言 当要解决海量数据的问题,就必须要用到分布式的存储集群了ÿ…...
从Web 2.0到Web 3.0,互联网有哪些变革?
文章目录 Web 2.0时代:用户参与和社交互动Web 3.0时代:语义化和智能化影响和展望 🎉欢迎来到Java学习路线专栏~从Web 2.0到Web 3.0,互联网有哪些变革? ☆* o(≧▽≦)o *☆嗨~我是IT陈寒🍹✨博客主页&#x…...
QT中资源文件resourcefile的使用,使用API完成页面布局
QT中资源文件resourcefile的使用 之前添加图标的方法使用资源文件的方法创建资源文件资源文件添加前缀资源文件添加资源使用资源文件中的资源 使用API完成布局使用QHBoxLayout完成水平布局使用QVBoxLayout完成垂直布局使用QGridLayout完成网格布局 在Qt中引入资源文件好处在于他…...
2337. 移动片段得到字符串
题目描述: 给你两个字符串 start 和 target ,长度均为 n 。每个字符串 仅 由字符 ‘L’、‘R’ 和 ‘_’ 组成,其中: 字符 ‘L’ 和 ‘R’ 表示片段,其中片段 ‘L’ 只有在其左侧直接存在一个 空位 时才能向 左 移动&a…...
Java并发编程第5讲——volatile关键字(万字详解)
volatile关键字大家并不陌生,尤其是在面试的时候,它被称为“轻量级的synchronized”。但是它并不容易完全被正确的理解,以至于很多程序员都不习惯去用它,处理并发问题的时候一律使用“万能”的sychronized来解决,然而如…...
6.小程序api分类
事件监听 以on开头,监听某个事件触发,例如:wx.WindowResize事件 同步 以Sync结尾的是同步,可以通过函数返回值直接获取,例如:wx.setStorageSync 异步 需要通过函数接收调用结果,例如&#…...
什么是PPS和TOD时序?授时防护设备是什么?
介绍 PPS和TOD PPS和TOD是两种用于精确时间同步的技术,它们在许多领域都有广泛的应用,总的来说,PPS和TOD被广泛应用于各种需要高度精确时间同步的领域,包括通信、测量、测试、系统集成和计算机网络等。 一、PPS PPS(…...
推荐一款好用的开源视频播放器(免费无广告)
mpv是一个自由开源的媒体播放器,它支持多种音频和视频格式,并且具有高度可定制性。mpv的设计理念是简洁、高效和功能强大。 软件特点: 1. 开源、跨平台。可以在Windows\Linux\MacOS\BSD等系统上使用,完全免费无广告。Windows版解压…...
STM32 CubeMX (第三步Freertos中断管理和软件定时)
STM32 CubeMX STM32 CubeMX (第三步Freertos中断管理和软件定时) STM32 CubeMX一、STM32 CubeMX设置时钟配置HAL时基选择TIM1(不要选择滴答定时器;滴答定时器留给OS系统做时基)使用STM32 CubeMX 库,配置Fre…...
Java虚拟机(JVM):堆溢出
一、概念 Java堆溢出(Java Heap Overflow)是指在Java程序中,当创建对象时,无法分配足够的内存空间来存储对象,导致堆内存溢出的情况。 Java堆是Java虚拟机中用于存储对象的一块内存区域。当程序创建对象时,…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
