音视频学习(二十二)——rtmp发流(tcp方式)

2023-12-28 12:36

本文主要是介绍音视频学习(二十二)——rtmp发流(tcp方式),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

本文主要介绍自研的RtmpStreamSender.dll,rtmp库提供接口接收裸流数据,支持将裸流数据封装为flv格式并通过rtmp协议发流。

关于rtmp协议基础介绍可查看:https://blog.csdn.net/www_dong/article/details/131026072

关于rtmp收流介绍可查看:https://blog.csdn.net/www_dong/article/details/135073488

设计

在这里插入图片描述

主要流程:

  1. rtmp服务端启动tcp(端口:1935)监听,创建rtmp server对象;
  2. rtmp客户端发起tcp连接,连接成功后等到收流;
  3. rtmp服务端以动态库的形式呈现,提供SendData接口,有上层应用调用时塞入数据;
  4. rtmp服务端接收数据,将数据封装为flv格式;
  5. rtmp服务端将flv格式的流发送给rtmp客户端;
  6. rtmp客户端将数据解复用、解码和播放;

流程

  • 创建tcp、启动端口监听;
int RtmpServerThread(void* param)
{assert(param);CRtmpStreamSender* receiver = (CRtmpStreamSender*)param;receiver->RtmpServerWorker();return 0;
}int CRtmpStreamSender::InitRtmpSession_()
{if (0 != ParseUrl_()){printf("parse url failed\n");return -1;}do{m_tcpServer = std::make_shared<ZDTcpServer>(nullptr, this);if (!m_tcpServer.get()|| 0 != m_tcpServer->TcpCreate()|| 0 != m_tcpServer->TcpBind(m_rtmpPort)|| 0 != m_tcpServer->TcpListen(5)){break;}m_command = std::make_shared<CRtmpServerCommand>(m_tcpServer);if (!m_command.get()|| 0 != m_command->Create()){break;}m_thread = std::thread(RtmpServerThread, this);return 0;} while (0);Stop();return 0;
}// 在线程中等待连接
void CRtmpStreamSender::RtmpServerWorker()
{bool bAccept = false;while (m_running){if (!bAccept){if (0 == m_tcpServer->TcpAccept()){bAccept = true;}continue;}std::this_thread::sleep_for(std::chrono::seconds(5));}
}
  • 创建rtmp server
// CRtmpServerCommand:librtmp封装类
m_command = std::make_shared<CRtmpServerCommand>(m_tcpServer);
if (!m_command.get()|| 0 != m_command->Create())
{break;
}// 创建rtmp server
int CRtmpServerCommand::Create()
{// 创建flv复用对象m_flvMuxer = flv_muxer_create(SendRtmpDataMutexFLV, this);if (!m_flvMuxer)return -1;struct rtmp_server_handler_t handler;memset(&handler, 0, sizeof(handler));handler.send = SendCallback;// 创建rtmp serverm_rtmp = rtmp_server_create(this, &handler);if (!m_rtmp)return -1;return 0;
}
  • 数据封装
// 上层通过SendData塞数据
int CRtmpStreamSender::SendData(void* data, int len, char* codec)
{if (!m_command.get())return -1;return m_command->InputData(data, len, codec);
}// 数据做flv封装
int CRtmpServerCommand::InputData(void* data, int len, const std::string& codec)
{if (!m_flvMuxer || !data || len <= 0 || codec.empty())return -1;int ret = -1;if (0 == codec.compare("H264")){ret = flv_muxer_avc(m_flvMuxer, data, len, 0, 0);}else if (0 == codec.compare("H265")){ret = flv_muxer_hevc(m_flvMuxer, data, len, 0, 0);}else if (0 == codec.compare("AAC")){ret = flv_muxer_aac(m_flvMuxer, data, len, 0, 0);}return 0;
}
  • 发送数据
int CRtmpServerCommand::Package(int type, const void* data, size_t bytes, uint32_t timestamp)
{if (!m_rtmp || !data || bytes <= 0)return -1;int ret = -1;if (FLV_TYPE_AUDIO == type){ret = rtmp_server_send_audio(m_rtmp, data, bytes, timestamp);}else if (FLV_TYPE_VIDEO == type){ret = rtmp_server_send_video(m_rtmp, data, bytes, timestamp);}else if (FLV_TYPE_SCRIPT == type){ret = rtmp_server_send_script(m_rtmp, data, bytes, timestamp);}if (0 != ret)return ret;return 0;
}
  • 资源销毁
void CRtmpServerCommand::Destroy()
{if (m_rtmp){rtmp_server_destroy(m_rtmp);m_rtmp = nullptr;}if (m_flvMuxer){flv_muxer_destroy(m_flvMuxer);m_flvMuxer = nullptr;}
}

这篇关于音视频学习(二十二)——rtmp发流(tcp方式)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/545955

相关文章

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

Django中的函数视图和类视图以及路由的定义方式

《Django中的函数视图和类视图以及路由的定义方式》Django视图分函数视图和类视图,前者用函数处理请求,后者继承View类定义方法,路由使用path()、re_path()或url(),通过in... 目录函数视图类视图路由总路由函数视图的路由类视图定义路由总结Django允许接收的请求方法http

Python yield与yield from的简单使用方式

《Pythonyield与yieldfrom的简单使用方式》生成器通过yield定义,可在处理I/O时暂停执行并返回部分结果,待其他任务完成后继续,yieldfrom用于将一个生成器的值传递给另一... 目录python yield与yield from的使用代码结构总结Python yield与yield

pandas数据的合并concat()和merge()方式

《pandas数据的合并concat()和merge()方式》Pandas中concat沿轴合并数据框(行或列),merge基于键连接(内/外/左/右),concat用于纵向或横向拼接,merge用于... 目录concat() 轴向连接合并(1) join='outer',axis=0(2)join='o

shell脚本批量导出redis key-value方式

《shell脚本批量导出rediskey-value方式》为避免keys全量扫描导致Redis卡顿,可先通过dump.rdb备份文件在本地恢复,再使用scan命令渐进导出key-value,通过CN... 目录1 背景2 详细步骤2.1 本地docker启动Redis2.2 shell批量导出脚本3 附录总

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Oracle数据库定时备份脚本方式(Linux)

《Oracle数据库定时备份脚本方式(Linux)》文章介绍Oracle数据库自动备份方案,包含主机备份传输与备机解压导入流程,强调需提前全量删除原库数据避免报错,并需配置无密传输、定时任务及验证脚本... 目录说明主机脚本备机上自动导库脚本整个自动备份oracle数据库的过程(建议全程用root用户)总结

Debian系和Redhat系防火墙配置方式

《Debian系和Redhat系防火墙配置方式》文章对比了Debian系UFW和Redhat系Firewalld防火墙的安装、启用禁用、端口管理、规则查看及注意事项,强调SSH端口需开放、规则持久化,... 目录Debian系UFW防火墙1. 安装2. 启用与禁用3. 基本命令4. 注意事项5. 示例配置R

最新Spring Security的基于内存用户认证方式

《最新SpringSecurity的基于内存用户认证方式》本文讲解SpringSecurity内存认证配置,适用于开发、测试等场景,通过代码创建用户及权限管理,支持密码加密,虽简单但不持久化,生产环... 目录1. 前言2. 因何选择内存认证?3. 基础配置实战❶ 创建Spring Security配置文件