音视频学习(二十二)——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

相关文章

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

python判断文件是否存在常用的几种方式

《python判断文件是否存在常用的几种方式》在Python中我们在读写文件之前,首先要做的事情就是判断文件是否存在,否则很容易发生错误的情况,:本文主要介绍python判断文件是否存在常用的几种... 目录1. 使用 os.path.exists()2. 使用 os.path.isfile()3. 使用

Mybatis的分页实现方式

《Mybatis的分页实现方式》MyBatis的分页实现方式主要有以下几种,每种方式适用于不同的场景,且在性能、灵活性和代码侵入性上有所差异,对Mybatis的分页实现方式感兴趣的朋友一起看看吧... 目录​1. 原生 SQL 分页(物理分页)​​2. RowBounds 分页(逻辑分页)​​3. Page

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

RedisTemplate默认序列化方式显示中文乱码的解决

《RedisTemplate默认序列化方式显示中文乱码的解决》本文主要介绍了SpringDataRedis默认使用JdkSerializationRedisSerializer导致数据乱码,文中通过示... 目录1. 问题原因2. 解决方案3. 配置类示例4. 配置说明5. 使用示例6. 验证存储结果7.

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Python程序打包exe,单文件和多文件方式

《Python程序打包exe,单文件和多文件方式》:本文主要介绍Python程序打包exe,单文件和多文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python 脚本打成exe文件安装Pyinstaller准备一个ico图标打包方式一(适用于文件较少的程