当前位置: 首页 > news >正文

流媒体服务器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(&param, "preset", "fast", 0);av_dict_set(&param, "tune", "zerolatency", 0);if (avcodec_open2(m_pOvCodecCtx, m_pOvCodec, &param) < 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推流客户端的编写

一、前言 目前市面上有很多开源的流媒体服务器解决方案&#xff0c;常见的有SRS、EasyDarwin、ZLMediaKit和Monibuca。这几种的对比如下&#xff1a; &#xff08;本图来源&#xff1a;https://www.ngui.cc/zz/1781086.html?actiononClick&#xff09; 二、SRS的介绍 SRS&am…...

Effective C++条款11——在operator=中处理“自我赋值”(构造/析构/赋值运算)

“自我赋值”发生在对象被赋值给自己时: class Widget {}; Widget w; // ... w w; // 赋值给自己 这看起来有点愚蠢&#xff0c;但它合法&#xff0c;所以不要认定客户绝不会那么做。此外赋值动作并不总是那么可被一眼辨识出来&#xff0c;例如: a[i] a[j]; …...

可视化绘图技巧100篇基础篇(八)-气泡图(一)

目录 前言 适用场景 图例 绘图工具及代码实现 EXCEL 1、单轴气泡图...

Elasticsearch查询之Disjunction Max Query

前言 Disjunction Max Query 又称最佳 best_fields 匹配策略&#xff0c;用来优化当查询关键词出现在多个字段中&#xff0c;以单个字段的最大评分作为文档的最终评分&#xff0c;从而使得匹配结果更加合理 写入数据 如下的两条例子数据&#xff1a; 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安装数据库是一个非常好的选择&#xff0c;后续的读写分离、数据分片等功能的数据库都是由docker创建。 一、安装准备 1、前提条件 Docker可以运行在Windows、Mac、CentOS、Ubuntu等操作系统上 Docker支持以下的CentOS版本&#xff1a; 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 …...

电商系统架构设计系列(九):如何规划和设计分库分表?

上篇文章中&#xff0c;我给你留了一个思考题&#xff1a;分库分表该如何设计&#xff1f; 今天这篇文章&#xff0c;我们来聊一下如何规划和设计分库分表&#xff0c;以及要考虑哪些问题。 引言 当要解决海量数据的问题&#xff0c;就必须要用到分布式的存储集群了&#xff…...

从Web 2.0到Web 3.0,互联网有哪些变革?

文章目录 Web 2.0时代&#xff1a;用户参与和社交互动Web 3.0时代&#xff1a;语义化和智能化影响和展望 &#x1f389;欢迎来到Java学习路线专栏~从Web 2.0到Web 3.0&#xff0c;互联网有哪些变革&#xff1f; ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#x…...

QT中资源文件resourcefile的使用,使用API完成页面布局

QT中资源文件resourcefile的使用 之前添加图标的方法使用资源文件的方法创建资源文件资源文件添加前缀资源文件添加资源使用资源文件中的资源 使用API完成布局使用QHBoxLayout完成水平布局使用QVBoxLayout完成垂直布局使用QGridLayout完成网格布局 在Qt中引入资源文件好处在于他…...

2337. 移动片段得到字符串

题目描述&#xff1a; 给你两个字符串 start 和 target &#xff0c;长度均为 n 。每个字符串 仅 由字符 ‘L’、‘R’ 和 ‘_’ 组成&#xff0c;其中&#xff1a; 字符 ‘L’ 和 ‘R’ 表示片段&#xff0c;其中片段 ‘L’ 只有在其左侧直接存在一个 空位 时才能向 左 移动&a…...

Java并发编程第5讲——volatile关键字(万字详解)

volatile关键字大家并不陌生&#xff0c;尤其是在面试的时候&#xff0c;它被称为“轻量级的synchronized”。但是它并不容易完全被正确的理解&#xff0c;以至于很多程序员都不习惯去用它&#xff0c;处理并发问题的时候一律使用“万能”的sychronized来解决&#xff0c;然而如…...

6.小程序api分类

事件监听 以on开头&#xff0c;监听某个事件触发&#xff0c;例如&#xff1a;wx.WindowResize事件 同步 以Sync结尾的是同步&#xff0c;可以通过函数返回值直接获取&#xff0c;例如&#xff1a;wx.setStorageSync 异步 需要通过函数接收调用结果&#xff0c;例如&#…...

什么是PPS和TOD时序?授时防护设备是什么?

介绍 PPS和TOD PPS和TOD是两种用于精确时间同步的技术&#xff0c;它们在许多领域都有广泛的应用&#xff0c;总的来说&#xff0c;PPS和TOD被广泛应用于各种需要高度精确时间同步的领域&#xff0c;包括通信、测量、测试、系统集成和计算机网络等。 一、PPS PPS&#xff08…...

推荐一款好用的开源视频播放器(免费无广告)

mpv是一个自由开源的媒体播放器&#xff0c;它支持多种音频和视频格式&#xff0c;并且具有高度可定制性。mpv的设计理念是简洁、高效和功能强大。 软件特点&#xff1a; 1. 开源、跨平台。可以在Windows\Linux\MacOS\BSD等系统上使用&#xff0c;完全免费无广告。Windows版解压…...

STM32 CubeMX (第三步Freertos中断管理和软件定时)

STM32 CubeMX STM32 CubeMX &#xff08;第三步Freertos中断管理和软件定时&#xff09; STM32 CubeMX一、STM32 CubeMX设置时钟配置HAL时基选择TIM1&#xff08;不要选择滴答定时器&#xff1b;滴答定时器留给OS系统做时基&#xff09;使用STM32 CubeMX 库&#xff0c;配置Fre…...

Java虚拟机(JVM):堆溢出

一、概念 Java堆溢出&#xff08;Java Heap Overflow&#xff09;是指在Java程序中&#xff0c;当创建对象时&#xff0c;无法分配足够的内存空间来存储对象&#xff0c;导致堆内存溢出的情况。 Java堆是Java虚拟机中用于存储对象的一块内存区域。当程序创建对象时&#xff0c…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]

报错信息&#xff1a;libc.so.6: cannot open shared object file: No such file or directory&#xff1a; #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

JS红宝书笔记 - 3.3 变量

要定义变量&#xff0c;可以使用var操作符&#xff0c;后跟变量名 ES实现变量初始化&#xff0c;因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符&#xff0c;可以创建一个全局变量 如果需要定义…...

从零手写Java版本的LSM Tree (一):LSM Tree 概述

&#x1f525; 推荐一个高质量的Java LSM Tree开源项目&#xff01; https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree&#xff0c;专为高并发写入场景设计。 核心亮点&#xff1a; ⚡ 极致性能&#xff1a;写入速度超…...