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

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_startcodeff_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中&#xff0c;rtpenc是一个用于将音视频数据封装成RTP&#xff08;Real-time Transport Protocol&#xff09;数据包并发送到网络上的编码器。RTP是一种用于实时传输音视频数据的协议&#xff0c;常用于视频会议、流媒体等场景。 rtpenc可以将音视频数据封装成R…...

【链表OJ】相交链表 环形链表1

前言: &#x1f4a5;&#x1f388;个人主页:​​​​​​Dream_Chaser&#xff5e; &#x1f388;&#x1f4a5; ✨✨刷题专栏:http://t.csdn.cn/UlvTc ⛳⛳本篇内容:力扣上链表OJ题目 目录 一.leetcode 160. 相交链表 1.问题描述: 2.解题思路: 二.leetcode 141.环形链表 …...

DevOps之自动化测试

什么是自动化测试&#xff1f; 明确一下自动化测试不是什么。自动化测试不是指自动化生成测试代码&#xff0c;而是自动化地执行由开发人员或测试人员编写的测试代码。正如下面这句谚语&#xff1a;“绝不要手工去做任何可以被自动化处理的事情。——Curt Hibbs” 之前是由人…...

Java 程序打印 OpenCV 的版本

我们可以使用 Java 程序来使用 OpenCV。 OpenCV 的使用需要动态库的加载才可以。 加载动态库 到 OpenCV 的官方网站上下载最新的发布版本。 Windows 下载的是一个可执行文件&#xff0c;没关系&#xff0c;这个可执行文件是一个自解压程序。 当你运行以后会提示你进行解压。…...

ChatGPT⼊门到精通(2):ChatGPT 能为我们做什么

⼀、雇佣免费的⼲活⼩弟 有了ChatGPT后&#xff0c;就好⽐你有了好⼏个帮你免费打⼯的「⼩弟」&#xff0c;他们可以帮你做很多 ⼯作。我简单总结⼀些我⽬前使⽤过的⽐较好的基于ChatGPT的服务和应⽤。 1、总结、分析 当我们在阅读⼀些⽂章和新闻的时候&#xff0c;有的⽂章写…...

线程和进程的区别是什么?

线程(Thread)和进程(Process)是操作系统中两个重要的概念,用于管理程序的执行。它们有以下区别: 定义:进程:进程是程序的一个执行实例,它包含了程序的代码、数据以及执行上下文。进程是操作系统分配资源和调度的基本单位。线程:线程是进程的子执行单元,一个进程可以…...

力扣27.移除元素

27. 移除元素 提示 简单 1.9K 相关企业 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序…...

指针(个人学习笔记黑马学习)

1、指针的定义和使用 #include <iostream> using namespace std;int main() {int a 10;int* p;p &a;cout << "a的地址为&#xff1a;" << &a << endl;cout << "a的地址为&#xff1a;" << p << endl;…...

vue 路由动态加载

在 Vue.js 中&#xff0c;可以使用 webpack 的动态导入语法来实现路由动态加载。下面是一个简单的示例&#xff1a; const Home () > import(/* webpackChunkName: "home" */ ./views/Home.vue); const About () > import(/* webpackChunkName: "about…...

电脑识别不了固态硬盘怎么办?

在使用固态硬盘时&#xff0c;可能会出现电脑无法识别的情况&#xff0c;这时我们就无法使用固态硬盘中的数据。那么&#xff0c;电脑识别不了固态硬盘怎么办&#xff1f; 为什么电脑识别不了固态硬盘&#xff1f; 一般来说&#xff0c;电脑识别不了固态硬盘是因为以下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单选按钮,点击可以选中,再次点击可以取消

一、实现效果&#xff1a; 二、代码实现&#xff1a; 不适用官方的change方法&#xff0c;自己定义点击方法。 动态判断定义的值是否等于遍历的值进行回显&#xff0c;如果和上一次点击的值一样&#xff0c;就把定义的值改为null <template><view><radio-group&…...

【Qt专栏】实现单例程序,禁止程序多开的几种方式

目录 一&#xff0c;简要介绍 二&#xff0c;实现示例&#xff08;Windows&#xff09; 1.使用系统级别的互斥机制 2.通过共享内存&#xff08;进程间通信-IPC&#xff09; 3.使用命名互斥锁&#xff08;不推荐&#xff09; 4.使用文件锁 5.通过网络端口检测 一&#xf…...

力扣26. 删除有序数组中的重复项

给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff0c;你需要做…...

【机器学习】鸢尾花分类-逻辑回归示例

这段代码是一个完整的示例&#xff0c;展示了如何使用逻辑回归对鸢尾花数据集进行训练、保存模型&#xff0c;并允许用户输入数据进行预测。以下是对这段代码的总结&#xff1a;功能&#xff1a; 这段代码演示了如何使用逻辑回归对鸢尾花数据集进行训练&#xff0c;并将训练好的…...

Flink CDC介绍

1.CDC概述 CDC&#xff08;Change Data Capture&#xff09;是一种用于捕获和处理数据源中的变化的技术。它允许实时地监视数据库或数据流中发生的数据变动&#xff0c;并将这些变动抽取出来&#xff0c;以便进行进一步的处理和分析。 传统上&#xff0c;数据源的变化通常通过…...

Java集合sort排序报错UnsupportedOperationException处理

文章目录 报错场景排查解决UnmodifiableList类介绍 报错场景 我们使用的是PostgreSQL数据库&#xff0c;存储业务数据&#xff0c;业务代码使用的是Spring JPA我们做的是智慧交通信控平台&#xff0c;有个功能是查询展示区域的交通态势&#xff0c;需要按照不同维度排序展示区…...

安防监控/磁盘阵列存储/视频汇聚平台EasyCVR调用rtsp地址返回的IP不正确是什么原因?

安防监控/云存储/磁盘阵列存储/视频汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RT…...

Spring boot开启定时任务

Cron表达式生成器 基于接口的方式 使用Scheduled 注解很方便&#xff0c;但缺点是当我们调整了执行周期的时候&#xff0c;需要重启应用才能生效&#xff0c;这多少有些不方便。为了达到实时生效的效果&#xff0c;那么可以使用接口来完成定时任务&#xff0c;统一将定时器信…...

package.json相关知识记录

一、相关字段 npm官方字段介绍 &#x1f367; bin   >   简单理解&#xff1a;指定命令的名称及路径   &#x1f349; 相当于想path中添加路径&#xff0c;局部安装是在./node_modules/.bin/&#xff0c;全局安装是在全局的bin目录   &#x1f349; bin指定的文件必须…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

Windows 下端口占用排查与释放全攻略

Windows 下端口占用排查与释放全攻略​ 在开发和运维过程中&#xff0c;经常会遇到端口被占用的问题&#xff08;如 8080、3306 等常用端口&#xff09;。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口&#xff0c;帮助你高效解决此类问题。​ 一、准…...