第5课 使用FFmpeg将rtmp流再转推到rtmp服务器
本课对应源文件下载链接:
https://download.csdn.net/download/XiBuQiuChong/88801992
通过前面的学习,我们已经可以正常播放网络rtmp流及本地mp4文件。这节课,我们将在前面的基础上实现一个常用的转推功能:读取rtmp流或mp4文件并转推到rtmp服务器上实现直播转发功能。
一、最终实现的效果

上面左图为播放的rtmp流并将该流转推到另一台rtmp服务器,右图为用vlc播放的另一台rtmp服务器上被转发的流。
二、使用FFmpeg将rtmp流转推到另一台rtmp服务器的原理
使用FFmpeg API 转码推流的一般过程如下:
1.引入ffmpeg库:在代码中引入ffmpeg库,以便使用其提供的功能。
2.打开输入文件:使用avformat_open_input()函数打开输入文件,并获取输入文件的相关信息。
3.查找流信息:使用avformat_find_stream_info()函数查找输入文件中的流信息,并将其存储在AVFormatContext结构体中。
4.创建输出上下文:使用avformat_alloc_output_context2()函数创建输出上下文,并设置输出格式。
5.添加输出流:根据输入文件的流信息,使用avformat_new_stream()函数创建输出流,并将其添加到输出上下文中。
6.设置编码参数:为输出流设置编码参数,包括编码器、编码器参数等。
7.输出文件:使用avio_open()函数打开输出文件,并将输出文件的相关信息存储在输出上下文中。
8.写入文件头:使用avformat_write_header()函数写入输出文件的文件头。
9.转码推流:循环读取输入文件的数据包,使用av_read_frame()函数读取数据包,然后使用avcodec_send_frame()函数发送数据包给编码器进行编码,再使用avcodec_receive_packet()函数接收编码后的数据包,最后使用av_interleaved_write_frame()函数将编码后的数据包写入输出流。
10.写入文件尾:使用av_write_trailer()函数写入输出文件的文件尾。
11.释放资源:释放所有的上下文、流和其他资源,使用avformat_close_input()函数关闭输入文件。
三、转推功能的具体实现
与rtmp流或mp4文件播放功能相比,转推功能只是在原来的基础上又增加了编码功能和向rtmp服务器的推送功能。为了降低难度,这节课的转推功能不涉及编码部分,只实现将拉取来的rtmp流直接进行转推。
1.为了与上节课的播放功能区分,新建或直接复制fmlp(Flash Media Live Player)类为一个新的fmlt(Flash Media Live Transcoder)类,并修改主对话框相应代码使fmlt能正常工作并实现正常的播放功能。
修改如下:
//#include "fmlp.h"
#include "fmlt.h"
………………
//fmlp *myFmlp = new fmlp();
fmlt *myFmlt = new fmlt();
2.与mp4文件相比,rtmp流转推实现起来相对容易,因此,我们先在原来的基础上实现rtmp流的转推功能。
(1)直接拷贝原fmlp.cpp的代码到fmt.cpp中,并定义转推到另一台rtmp服务器的流地址等变量:
//转码输出初始化 const char *outFileName = "rtmp://192.168.0.101/hk/cctv"; AVOutputFormat *outFormat = NULL;AVFormatContext *outFormatCtx = NULL;//定义输出音视频流AVStream *videoStream = NULL;AVStream *audioStream = NULL;
(2)打开输出流:
avformat_alloc_output_context2(&outFormatCtx, NULL, "flv", outFileName);………………videoStream = avformat_new_stream(outFormatCtx, vDecodec);videoStream->id = outFormatCtx->nb_streams - 1;videoStream->codecpar->codec_tag = 0;avcodec_parameters_from_context(videoStream->codecpar, vDecodeCtx);audioStream = avformat_new_stream(outFormatCtx, aDecodec);audioStream->codecpar->codec_tag = 0;audioStream->id = outFormatCtx->nb_streams - 1;avcodec_parameters_from_context(audioStream->codecpar, aDecodeCtx);av_dump_format(outFormatCtx, 0, outFileName, 1);ret = avio_open2(&outFormatCtx->pb, outFileName, AVIO_FLAG_READ_WRITE, nullptr, nullptr);if (ret < 0){return -1;}ret = avformat_write_header(outFormatCtx, NULL);if (ret < 0){TRACE("ret:%d\n", ret);return -1;}
(3)获取到原rtmp流并正常播放音视频后,将音视频包直接写入输出流:
if (normalPkt.stream_index == videoIndex) {//原视频播放代码normalPkt.stream_index = videoStream->index;normalPkt.pts = currentTime;normalPkt.dts = currentTime;normalPkt.duration = currentTime;normalPkt.pos = -1;//enVideoPacket.flags = AV_PKT_FLAG_KEY;if (normalPkt.size > 0){ret = av_interleaved_write_frame(outFormatCtx, &normalPkt);}av_packet_unref(&normalPkt);}else if (normalPkt.stream_index == audioIndex){ //原音频播放代码normalPkt.stream_index = audioStream->index;normalPkt.pts = currentTime;normalPkt.dts = currentTime;normalPkt.duration = currentTime;normalPkt.pos = -1;//enVideoPacket.flags = AV_PKT_FLAG_KEY;if (normalPkt.size > 0){ret = av_interleaved_write_frame(outFormatCtx, &normalPkt);}av_packet_unref(&normalPkt);}
这样,就实现了在播放音视频的同时又能将该流转推到另一台服务器的功能。
相关文章:
第5课 使用FFmpeg将rtmp流再转推到rtmp服务器
本课对应源文件下载链接: https://download.csdn.net/download/XiBuQiuChong/88801992 通过前面的学习,我们已经可以正常播放网络rtmp流及本地mp4文件。这节课,我们将在前面的基础上实现一个常用的转推功能:读取rtmp流或mp4文件并…...
Vue中v-if和v-show区别
Vue中v-if和v-show是两个常用的指令,用于控制元素的显示和隐藏。虽然它们都能达到相同的效果,但在实现机制和使用场景上有一些区别。本文将详细介绍v-if和v-show的区别,并且通过示例代码来演示它们的使用。 首先,让我们来看一下v…...
LabVIEW与EtherCAT实现风洞安全联锁及状态监测
LabVIEW与EtherCAT实现风洞安全联锁及状态监测 在现代风洞试验中,安全联锁与状态监测系统发挥着至关重要的作用,确保了试验过程的安全性与高效性。介绍了一套基于EtherCAT总线技术和LabVIEW软件开发的风洞安全联锁及状态监测系统。该系统通过实时、可靠…...
PostgreSQL的wal文件回收问题
引子 将PostgreSQL的GUC参数wal_recycle设置为on,然后对数据库执行一定业务量的操作,会发现在pg_wal目录下,有很多未来使用的wal文件,且创建时间比现在正在使用的wal文件更早,下文将描述和分析这种情况。 问题描述 …...
java-JUC并发编程学习笔记05(尚硅谷)
我们写一段测试代码: 会出现线程不安全的问题。 使用Vector解决线程不安全问题: 但是这个类几乎不会被使用了,因为效率太低。 方法二:通过Collections解决: 但是这种方案实际中也不太会使用。 我们还有第三种方法使用CopyOnWri…...
vulhub中spring的CVE-2022-22947漏洞复现
Spring Cloud Gateway是Spring中的一个API网关。其3.1.0及3.0.6版本(包含)以前存在一处SpEL表达式注入漏洞,当攻击者可以访问Actuator API的情况下,将可以利用该漏洞执行任意命令。 参考链接: https://tanzu.vmware.c…...
网络原理TCP/IP(1)
文章目录 端口号UDP协议 在网络通信中,协议非常重要 协议进行了分层 应用层就是对应着应用程序,是程序员打交道最多的这一层,调用系统提供的网络api写出来的代码都是属于应用层的 应用层有很多现成的协议,但是更多的还是程序员需要…...
EasyExcel使用,实体导入导出
简介 Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中…...
让IIS支持SSE (Server Sent Events)
本文只探讨IISPython网站的情况,对于asp.net也应该不用这么麻烦。 先上结论:用反向代理: IIS URL Rewrite waitress Waitress是一个纯python编写独立的WSGI服务器,功能比Gunicorn弱一些,但可以运行在windows平台上&…...
新手从零开始学习数学建模论文写作(美赛论文临时抱佛脚篇)
本文记录于数学建模老哥视频的学习过程中。b站视频:http://【【零基础教程】老哥:数学建模算法、编程、写作和获奖指南全流程培训!】https://www.bilibili.com/video/BV1kC4y1a7Ee?p50&vd_sourceff53a726c62f94eda5f615bd4a62c458 目录…...
k8s存储之PV、PVC
在k8s集群中,资源存储会散落到各个工作节点上,这样对用资源调用很不方便,那么k8s是如何实现存储资源共享的呢,本文浅尝辄止的探讨一下,k8s是通过pv、pvc实现的。 一、PV、PVC的概念 1、持久卷(PV) pv是Pe…...
go-基于逃逸分析来提升性能程序
go-基于逃逸分析来提升性能程序 为什么要学习逃逸分析: 为了提高程序的性能,通过逃逸分析我们能知道指标是分配到堆上还是栈上,如何是 分配到栈上,内存的分配和释放都是由编译器进行管理的,分配和释放的速度都非常的…...
[软件工具]文档页数统计工具软件pdf统计页数word统计页数ppt统计页数图文打印店快速报价工具
文档页数统计工具软件——打印方面好帮手 在信息化时代,文档已成为我们工作、学习、生活中不可或缺的一部分。无论是学术论文、商业报告,还是个人日记,都需要我们对其进行有效的管理。而在这个过程中,文档页数统计工具软件就显得…...
linux编译ffmpeg动态库
1,获取源码:git clone https://git.ffmpeg.org/ffmpeg.git 2,创建编译目录,并编译、安装, cd ffmpeg mkdir build cd build ../configure --prefix~/ffmpeg --enable-shared --enable-debug1 //configure后需要使…...
Unity3d Cinemachine篇(完)— TargetGroup
文章目录 前言使用TargetGroup追随多个模型1. 创建二个游戏物体2. 创建TargetGroup相机3. 设置相机4. 完成 前言 上一期我们简单的使用了ClearShot相机,这次我们来使用一下TargetGroup 使用TargetGroup追随多个模型 1. 创建二个游戏物体 2. 创建TargetGroup相机 3…...
事件驱动架构:使用Flask实现MinIO事件通知Webhooks
MinIO的事件通知可能一开始看起来并不激动人心,但一旦掌握了它们的力量,它们就能照亮您存储桶内的动态。事件通知是一个全面、高效的对象存储系统中的关键组件。Webhooks是我个人最喜欢的工具,用于与MinIO集成。它们在事件的世界中就像一把瑞…...
力扣面试150 只出现一次的数字Ⅱ 哈希 统计数位 DFA有穷自动机
Problem: 137. 只出现一次的数字 II 文章目录 思路💖 哈希💖 位数统计💖 DFA 状态机 思路 👨🏫 参考 💖 哈希 ⏰ 时间复杂度: O ( n ) O(n) O(n) 🌎 空间复杂度: O ( n ) O(n) O(n) cl…...
R语言学习case10:ggplot基础画图Parallel Coordinate Plot 平行坐标图
step1: 导入ggplot2库文件 library(ggplot2)step2:带入自带的iris数据集 iris <- datasets::irisstep3:查看数据信息 dim(iris)维度为 [150,5] head(iris)查看数据前6行的信息 step4:利用ggplot工具包绘图 plot5 <- ggparcoord(…...
Easy Excel动态表头的实现
步骤: 1.查找官方API文档理解实现 2.实现融入到代码里面 一:Easy Excel动态头实时生成头写入 动态头实时生成头写入 二:实现 目的:实现表头为,第一列是固定列,第二列为动态生成的时间段的每一天的日期…...
kvm qemu 优化 windows 虚拟机速度
主要优化磁盘 io 和网络 io 都选为 virtio windows 驱动下载 https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.185-2/virtio-win-0.1.185.iso I also had incredibly slow performance with my virtual HDD. The followin…...
VideoAgentTrek-ScreenFilter开发环境配置:从零开始搭建Java调用示例
VideoAgentTrek-ScreenFilter开发环境配置:从零开始搭建Java调用示例 如果你是一名Java开发者,最近听说了VideoAgentTrek-ScreenFilter这个视频处理服务,想在自己的项目里试试看,但不知道从哪儿下手,那这篇文章就是为…...
Qwen3-14B制造业工艺文档生成:设备操作SOP自动编写与版本管理
Qwen3-14B制造业工艺文档生成:设备操作SOP自动编写与版本管理 1. 引言:制造业文档自动化的迫切需求 在制造业生产现场,设备操作标准作业程序(SOP)是确保产品质量和生产安全的关键文档。传统SOP编写方式面临三大痛点: 人力成本高…...
vLLM显存优化实战:如何用enable-chunked-prefill和max_num_batched_tokens解决CUDA out of memory
vLLM显存优化实战:突破CUDA内存瓶颈的深度调优指南 当你在8张RTX 3090上部署大语言模型时,突然弹出的"Cuda out of memory"错误就像一场噩梦。这不是简单的内存不足警告,而是高性能计算环境中常见的显存管理挑战。本文将带你深入vL…...
RotaryDial库:嵌入式脉冲拨号信号采集与处理
1. RotaryDial 库深度解析:面向嵌入式系统的脉冲拨号信号采集与处理1.1 脉冲拨号技术原理与工程价值脉冲拨号(Pulse Dialing),又称环路断续拨号(Loop Disconnect Dialing),是模拟电话系统中最早…...
MS5611高精度气压温度传感器Arduino驱动库
1. 项目概述MS5611-Mike-Refactored 是一款面向嵌入式平台(特别是 Arduino 兼容生态)的 MS5611 高精度气压/温度传感器驱动库。该库并非简单封装,而是对 Korneliusz Jarzebski 原始实现的一次系统性重构与工程化增强。其核心目标是将一个基础…...
C++27执行策略演进全图谱(从C++17到C++27 TS23742的5次关键修订与ABI兼容性断崖预警)
第一章:C27执行策略的范式跃迁与标准定位C27正将执行策略(Execution Policies)从“并行化提示”升格为“可验证执行契约”,标志着标准库算法语义模型的根本性重构。这一转变不再仅依赖实现对std::execution::par_unseq等策略的启发…...
手机号码定位查询工具:3分钟快速部署,轻松查询号码归属地
手机号码定位查询工具:3分钟快速部署,轻松查询号码归属地 【免费下载链接】location-to-phone-number This a project to search a location of a specified phone number, and locate the map to the phone number location. 项目地址: https://gitco…...
扩散模型对抗样本经典baselines
1. 流图:数据的河流 如果把传统的堆叠面积图想象成一块块整齐堆叠的积木,那么流图就像一条蜿蜒流淌的河流,河道的宽窄变化自然流畅,波峰波谷过渡平滑。 它特别适合展示多个类别数据随时间的变化趋势,尤其是当你想强调整…...
OpenClaw技能开发入门:为Phi-3-mini-128k-instruct定制自动化插件
OpenClaw技能开发入门:为Phi-3-mini-128k-instruct定制自动化插件 1. 为什么需要自定义OpenClaw技能 去年夏天,我发现自己每天要重复做三件事:查看天气、整理会议纪要、归档下载的文件。这些琐事看似简单,但累积起来每天要消耗我…...
Arduino压力变送器信号处理库:模拟传感器线性标定与鲁棒读取
1. 项目概述PressureTransducer 是一个面向嵌入式传感器应用的轻量级 Arduino 库,专为模拟式压力变送器(Analog Pressure Transducer)设计。其核心价值不在于提供复杂驱动或协议栈,而在于将硬件信号链中多级、易出错的手动计算封装…...
