FFmpeg rtp rtp_mpegts的区别
rtp
在FFmpeg中,rtpenc是一个用于将音视频数据封装成RTP(Real-time Transport Protocol)数据包并发送到网络上的编码器。RTP是一种用于实时传输音视频数据的协议,常用于视频会议、流媒体等场景。
rtpenc可以将音视频数据封装成RTP数据包,并通过UDP协议发送到指定的IP地址和端口号。它支持多种音视频编码格式,如H.264、AAC等,并可以设置RTP头部信息、负载类型、时间戳等参数。
使用rtpenc,可以将FFmpeg中的音视频数据实时传输到网络上,实现实时音视频传输的功能。例如,可以将摄像头采集的视频数据通过rtpenc编码后发送到网络上,实现视频监控、视频会议等应用。
ff_rtp_muxer
rtp muxer的定义中,默认的codec格式也是AV_CODEC_ID_MPEG4和AV_CODEC_ID_PCM_MULAW,rtp_write_packet可以看到这个rtp packet的封包发送过程。
const AVOutputFormat ff_rtp_muxer = {.name              = "rtp",.long_name         = NULL_IF_CONFIG_SMALL("RTP output"),.priv_data_size    = sizeof(RTPMuxContext),.audio_codec       = AV_CODEC_ID_PCM_MULAW,.video_codec       = AV_CODEC_ID_MPEG4,.write_header      = rtp_write_header,.write_packet      = rtp_write_packet,.write_trailer     = rtp_write_trailer,.priv_class        = &rtp_muxer_class,.flags             = AVFMT_TS_NONSTRICT,
};rtp_write_packet
rtp_write_packet中根据codec_id,调用对应的ff_rtp_send_xxx函数,比如H264对应的是ff_rtp_send_h264_hevc:
static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) {RTPMuxContext *s = s1->priv_data;AVStream *st = s1->streams[0];int rtcp_bytes;int size= pkt->size;switch(st->codecpar->codec_id) {case AV_CODEC_ID_AAC:if (s->flags & FF_RTP_FLAG_MP4A_LATM)ff_rtp_send_latm(s1, pkt->data, size);elseff_rtp_send_aac(s1, pkt->data, size);break;case AV_CODEC_ID_H264:ff_rtp_send_h264_hevc(s1, pkt->data, size);break;   
}
ff_rtp_send_h264_hevc
该函数的主要作用是将H.264/HEVC视频流分割成NAL单元,并将其打包成RTP数据包进行传输。
该函数首先将传入的视频流数据buf1拷贝到RTPMuxContext结构体中,并设置当前时间戳为s->cur_timestamp。然后,该函数通过调用ff_avc_find_startcode或ff_avc_mp4_find_startcode函数找到NAL单元的起始位置,并将NAL单元的数据通过nal_send函数打包成RTP数据包进行传输。最后,该函数通过调用flush_buffered函数将缓存中的数据进行传输。
需要注意的是,该函数中的s->nal_length_size表示NAL单元长度的字节数,不为0,buffer就是avcc类型,如果为0,就是annex
格式,根据起始码0x000001或0x00000001来找到buffer的结束位置。
void ff_rtp_send_h264_hevc(AVFormatContext *s1, const uint8_t *buf1, int size)
{const uint8_t *r, *end = buf1 + size;RTPMuxContext *s = s1->priv_data;s->timestamp = s->cur_timestamp;s->buf_ptr   = s->buf;if (s->nal_length_size)r = ff_avc_mp4_find_startcode(buf1, end, s->nal_length_size) ? buf1 : end;elser = ff_avc_find_startcode(buf1, end);while (r < end) {const uint8_t *r1;if (s->nal_length_size) {r1 = ff_avc_mp4_find_startcode(r, end, s->nal_length_size);if (!r1)r1 = end;r += s->nal_length_size;} else {while (!*(r++));r1 = ff_avc_find_startcode(r, end);}nal_send(s1, r, r1 - r, r1 == end);r = r1;}flush_buffered(s1, 1);
}
然后nal_send将NAL单元发送到RTP流中。NAL单元是视频编码中的基本单元,它包含了视频编码中的一个帧或片段。
nal_send首先检查NAL单元的大小是否小于等于最大负载大小,如果是,则将NAL单元添加到缓冲区中。如果缓冲区中已经有了一些NAL单元,则将它们作为STAP-A/AP包发送。如果NAL单元的大小大于最大负载大小,则将其分割成多个分片,并将它们作为FU-A包发送。
nal_send还根据编解码器类型设置了一些标志位,以便在发送NAL单元时进行适当的处理。例如,对于H.264编解码器,如果使用了FF_RTP_FLAG_H264_MODE0标志,则将NAL单元分割成多个分片。
ff_rtp_send_data
ff_rtp_send_data是rtp用于将数据通过RTP协议发送出去的函数。具体来说,它会构建RTP头部,将数据写入输出流,并更新一些统计信息。
void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m)
{RTPMuxContext *s = s1->priv_data;av_log(s1, AV_LOG_TRACE, "rtp_send_data size=%d\n", len);/* build the RTP header */avio_w8(s1->pb, RTP_VERSION << 6);avio_w8(s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7));avio_wb16(s1->pb, s->seq);avio_wb32(s1->pb, s->timestamp);avio_wb32(s1->pb, s->ssrc);avio_write(s1->pb, buf1, len);avio_flush(s1->pb);s->seq = (s->seq + 1) & 0xffff;s->octet_count += len;s->packet_count++;
}
函数的参数包括一个AVFormatContext结构体指针s1,一个指向数据缓冲区的指针buf1,数据长度len,以及一个标志位m。其中,s1包含了输出流的相关信息,buf1是要发送的数据,len是数据长度,m表示是否是最后一个数据包。
函数首先从s1中获取RTPMuxContext结构体指针s,该结构体包含了一些RTP相关的信息。然后,函数会使用avio_w8、avio_wb16、avio_wb32等函数将RTP头写入输出流中。其中,RTP头部的格式如下:
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X|  CC   |M|     PT      |       sequence number         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           timestamp                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           synchronization source (SSRC) identifier            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            contributing source (CSRC) identifiers             |
|                             ....                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
其中,V表示协议版本号,P表示是否有填充,X表示是否有扩展头部,CC表示CSRC计数器,M表示是否是最后一个数据包,PT表示负载类型,sequence number表示序列号,timestamp表示时间戳,SSRC表示同步源标识符,CSRC表示贡献源标识符。
接下来,函数会使用avio_write函数将数据写入输出流中,并使用avio_flush函数将输出流中的数据刷新。最后,函数会更新s中的一些统计信息,包括序列号、字节计数和数据包计数。
rtp_mpegts
rtp_mpegts是ffmpeg中支持的唯一一个rtp muxer,通过rtp_mpegts发送音视频数据,可以解决rtp支持一路流的问题,默认支持的audio codec是AAC,video codec是H264。
比如可以这样发送:
ffmpeg -re -stream_loop -1 -i h264.mp4 -i aac.mp4 -f rtp_mpegts rtp://10.0.1.1:5008
h264.mp4 - 只包含h264编码的视频文件
aac.mp4 - 只包含aac编码的音频文件
如果使用rtp发送,则会输出ERROR:“Only one stream supported in the RTP muxer”。
ffmpeg -re -stream_loop -1 -i h264.mp4 -i aac.mp4 -f rtp rtp://10.0.1.1:5008
ff_rtp_mpegts_muxer
const AVOutputFormat ff_rtp_mpegts_muxer = {.name              = "rtp_mpegts",.long_name         = NULL_IF_CONFIG_SMALL("RTP/mpegts output format"),.priv_data_size    = sizeof(MuxChain),.audio_codec       = AV_CODEC_ID_AAC,.video_codec       = AV_CODEC_ID_MPEG4,.write_header      = rtp_mpegts_write_header,.write_packet      = rtp_mpegts_write_packet,.write_trailer     = rtp_mpegts_write_close,.priv_class        = &rtp_mpegts_class,
};
在write_header函数中,指定codec id为AV_CODEC_ID_MPEG2TS,这个会在rtp enc中处理,调用rtp_send_mpegts_raw,发送mpegts数据。
    st->time_base.num   = 1;st->time_base.den   = 90000;st->codecpar->codec_id = AV_CODEC_ID_MPEG2TS;rtp_ctx->pb = s->pb;
所以,rtp muxer直接对音视频数据封包成rtp payload进行发送,而rtp_mpegts则对音视频数据先进行mpegts封装,然后再封装为rtp payload发送。
相关文章:
FFmpeg rtp rtp_mpegts的区别
rtp 在FFmpeg中,rtpenc是一个用于将音视频数据封装成RTP(Real-time Transport Protocol)数据包并发送到网络上的编码器。RTP是一种用于实时传输音视频数据的协议,常用于视频会议、流媒体等场景。 rtpenc可以将音视频数据封装成R…...
 
【链表OJ】相交链表 环形链表1
前言: 💥🎈个人主页:Dream_Chaser~ 🎈💥 ✨✨刷题专栏:http://t.csdn.cn/UlvTc ⛳⛳本篇内容:力扣上链表OJ题目 目录 一.leetcode 160. 相交链表 1.问题描述: 2.解题思路: 二.leetcode 141.环形链表 …...
 
DevOps之自动化测试
什么是自动化测试? 明确一下自动化测试不是什么。自动化测试不是指自动化生成测试代码,而是自动化地执行由开发人员或测试人员编写的测试代码。正如下面这句谚语:“绝不要手工去做任何可以被自动化处理的事情。——Curt Hibbs” 之前是由人…...
 
Java 程序打印 OpenCV 的版本
我们可以使用 Java 程序来使用 OpenCV。 OpenCV 的使用需要动态库的加载才可以。 加载动态库 到 OpenCV 的官方网站上下载最新的发布版本。 Windows 下载的是一个可执行文件,没关系,这个可执行文件是一个自解压程序。 当你运行以后会提示你进行解压。…...
 
ChatGPT⼊门到精通(2):ChatGPT 能为我们做什么
⼀、雇佣免费的⼲活⼩弟 有了ChatGPT后,就好⽐你有了好⼏个帮你免费打⼯的「⼩弟」,他们可以帮你做很多 ⼯作。我简单总结⼀些我⽬前使⽤过的⽐较好的基于ChatGPT的服务和应⽤。 1、总结、分析 当我们在阅读⼀些⽂章和新闻的时候,有的⽂章写…...
线程和进程的区别是什么?
线程(Thread)和进程(Process)是操作系统中两个重要的概念,用于管理程序的执行。它们有以下区别: 定义:进程:进程是程序的一个执行实例,它包含了程序的代码、数据以及执行上下文。进程是操作系统分配资源和调度的基本单位。线程:线程是进程的子执行单元,一个进程可以…...
力扣27.移除元素
27. 移除元素 提示 简单 1.9K 相关企业 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序…...
 
指针(个人学习笔记黑马学习)
1、指针的定义和使用 #include <iostream> using namespace std;int main() {int a 10;int* p;p &a;cout << "a的地址为:" << &a << endl;cout << "a的地址为:" << p << endl;…...
vue 路由动态加载
在 Vue.js 中,可以使用 webpack 的动态导入语法来实现路由动态加载。下面是一个简单的示例: const Home () > import(/* webpackChunkName: "home" */ ./views/Home.vue); const About () > import(/* webpackChunkName: "about…...
 
电脑识别不了固态硬盘怎么办?
在使用固态硬盘时,可能会出现电脑无法识别的情况,这时我们就无法使用固态硬盘中的数据。那么,电脑识别不了固态硬盘怎么办? 为什么电脑识别不了固态硬盘? 一般来说,电脑识别不了固态硬盘是因为以下3个原因…...
QCustomPlot 绘制卡顿问题
大数据量导致曲线绘制卡顿问题 这里提供一个思路在跟踪源码中发现底层卡顿在vector的resize() 此处扩容中 所以尽量使用下面的接口 /*! \overloadAdds the provided data point as \a key and \a value to the current data.Alternatively, you can also access and modify t…...
 
uni-app开发小程序,radio单选按钮,点击可以选中,再次点击可以取消
一、实现效果: 二、代码实现: 不适用官方的change方法,自己定义点击方法。 动态判断定义的值是否等于遍历的值进行回显,如果和上一次点击的值一样,就把定义的值改为null <template><view><radio-group&…...
 
【Qt专栏】实现单例程序,禁止程序多开的几种方式
目录 一,简要介绍 二,实现示例(Windows) 1.使用系统级别的互斥机制 2.通过共享内存(进程间通信-IPC) 3.使用命名互斥锁(不推荐) 4.使用文件锁 5.通过网络端口检测 一…...
力扣26. 删除有序数组中的重复项
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k ,你需要做…...
【机器学习】鸢尾花分类-逻辑回归示例
这段代码是一个完整的示例,展示了如何使用逻辑回归对鸢尾花数据集进行训练、保存模型,并允许用户输入数据进行预测。以下是对这段代码的总结:功能: 这段代码演示了如何使用逻辑回归对鸢尾花数据集进行训练,并将训练好的…...
 
Flink CDC介绍
1.CDC概述 CDC(Change Data Capture)是一种用于捕获和处理数据源中的变化的技术。它允许实时地监视数据库或数据流中发生的数据变动,并将这些变动抽取出来,以便进行进一步的处理和分析。 传统上,数据源的变化通常通过…...
 
Java集合sort排序报错UnsupportedOperationException处理
文章目录 报错场景排查解决UnmodifiableList类介绍 报错场景 我们使用的是PostgreSQL数据库,存储业务数据,业务代码使用的是Spring JPA我们做的是智慧交通信控平台,有个功能是查询展示区域的交通态势,需要按照不同维度排序展示区…...
 
安防监控/磁盘阵列存储/视频汇聚平台EasyCVR调用rtsp地址返回的IP不正确是什么原因?
安防监控/云存储/磁盘阵列存储/视频汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等,以及厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等,能对外分发RTSP、RT…...
Spring boot开启定时任务
Cron表达式生成器 基于接口的方式 使用Scheduled 注解很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,那么可以使用接口来完成定时任务,统一将定时器信…...
package.json相关知识记录
一、相关字段 npm官方字段介绍 🍧 bin > 简单理解:指定命令的名称及路径 🍉 相当于想path中添加路径,局部安装是在./node_modules/.bin/,全局安装是在全局的bin目录 🍉 bin指定的文件必须…...
 
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
 
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
 
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
 
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
