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发送。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/68848.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据库】如何利用Python中的petl将PostgreSQL中所有表的外键删除,迁移数据,再重建外键

一、简介 在数据库管理中&#xff0c;外键是一种重要的约束&#xff0c;用于确保数据的一致性和完整性。然而&#xff0c;在某些情况下&#xff0c;我们可能需要删除或修改外键。本文将介绍如何使用Python中的petl库将PostgreSQL中所有表的外键删除&#xff0c;迁移数据&#…

K8S的介绍和架构

仅供入门 K8S的介绍和架构 一. 什么是kubernetes二、Kubernetes架构和组件 2.1 核心组件 2.1.1 Kubernetes Master控制组件&#xff0c;调度管理整个系统&#xff08;集群&#xff09;&#xff0c;包含如下组件: a、Kubernetes API Serverb、Kubernetes Schedulerc、Kubernet…

Linux 禁止用户或 IP通过 SSH 登录

Linux 禁止用户或 IP通过 SSH 登录 限制用户 SSH 登录 1.只允许指定用户进行登录(白名单): 在 /etc/ssh/sshd_config 配置文件中设置 AllowUsers 选项,(配置完成需要重启 SSHD 服务)格式如下: AllowUsers aliyun test@192.168.1.1 # 允许 aliyun 和从 19…

Apply AirPlay+HomeKit专栏目录

从2022年起&#xff0c;我陆续写了一些关于Airplay和HomeKit的相关文章&#xff0c;主要介绍了关于苹果认证的一些技术和如何使用&#xff0c;因为这是一个相对来说小众冷门的领域&#xff0c;网络上很多资料都找不到&#xff0c;最开始刚接触苹果物联网IOT和智能家居时&#x…

springboot自动装配原理,手写一个starter。

文章目录 springboot自动装配原理手写starter手写starter总结&#xff1a; springboot自动装配原理 口述&#xff1a; springboot自动装配的话它其实就是只需要我们添加一个starter起步依赖&#xff0c;它就能完成这个依赖组件相关Bean的自动注入&#xff0c;其实就是自动的将…

Android通过setaffinity实现绑核

有时候为了降低App算力占用&#xff0c;会把关键的线程绑定到大核中&#xff0c;下面介绍一种绑核的方式 查看绑核 查看pid :/ # ps -A | grep test u0_a15 25178 405 15950272 176544 do_epoll_wait 0 S com.test.jnites查看线程号 top -H -p 25178 25224 u0_…

SpringMVC的工作流程及入门

目录 一、概述 ( 1 ) 是什么 ( 2 ) 作用 二、工作流程 ( 1 ) 流程 ( 2 ) 步骤 三、入门实例 ( 1 ) 入门实例 ( 2 ) 静态资源处理 给我们带来的收获 一、概述 ( 1 ) 是什么 SpringMVC是一个基于Java的Web应用开发框架&#xff0c;它是Spring Framework的一部…

小程序进阶-inline、block和inline-block的区别与联系

背景介绍 每个html标签元素都有默认的元素类型&#xff0c;主要包括两大类&#xff1a;inline内联元素和block块元素。其他则称为可变元素&#xff0c;会根据上下文语境决定该元素为inline元素或者block元素。 在css里&#xff0c;有一个display的属性&#xff0c;它规定元素应…

5.bs4的基本使用

bs4是python的一个第三方库&#xff0c;用来做数据解析的 目录 1 安装bs4 2 解析本地的html文件 3 解析网上的html 4 找到指定的标签 4.1 获取页面中第一个指定标签的内容 4.2 查找页面中的第一个符合要求的内容 BeautifulSoup.find() 4.2.1 标签 4.2.2 类名 …

Linux--进程概念

1.什么是程序&#xff1f;什么是进程&#xff1f;有什么区别&#xff1f; 程序&#xff1a;是静态的概念&#xff0c;gcc xxx.c -o pro 磁盘中生成的pro文件&#xff0c;叫做程序。 进程&#xff1a;是程序的一种与运行活动&#xff0c;通俗的意思是程序跑起来了&#xff0c;系…

linux免密登录最简单--图文详解

最简单的免密登录 1.A电脑生成秘钥 ssh-keygen -t rsa 2.A电脑将秘钥传给B电脑 ssh-copy-id root192.168.1.129 #将秘钥直接传给B电脑 需要输入B电脑的密码&#xff0c;可以看到成功。 3.测试 同理&#xff1a;如果B->A也需要免密登录&#xff0c;统一的操作。 大功告…

PHP8的数组-PHP8知识详解

今天开始学习数组&#xff0c; 本文主要讲了三点&#xff1a;什么是数组、php8中数组的改进、数组函数。 一、什么是数组 在PHP8中&#xff0c;数组是非常重要的数据类型。相对于其他的数据类型&#xff0c;数组更像一种结构&#xff0c;而这种结构可以储存一系列数值。 数组…

git bash adb push 路径问题

adb push xxx.so //sdcard/DCIM/参考 https://stackoverflow.com/questions/16344985/how-do-i-pass-an-absolute-path-to-the-adb-command-via-git-bash-for-windows

【SpringSecurity】八、集成图片验证码

文章目录 1、生成图片验证码2、创建验证码过滤器3、将过滤器加入SpringSecurity过滤链4、修改登录页 SpringSecurity是通过过滤器链来完成的&#xff0c;接下来的验证码&#xff0c;可以尝试创建一个过滤器放到Security的过滤器链中&#xff0c;在自定义的过滤器中比较验证码。…

90、00后严选出的数据可视化工具:奥威BI工具

90、00后主打一个巧用工具&#xff0c;绝不低效率上班&#xff0c;因此当擅长大数据智能可视化分析的BI数据可视化工具出现后&#xff0c;自然而然地就成了90、00后职场人常用的数据可视化工具。 奥威BI工具三大特点&#xff0c;让职场人眼前一亮&#xff01; 1、零编程&…

医学影像工作站PACS系统源码,医院PACS系统源码

医学影像(PACS)系统主要进行病人信息和影像的获取、处理、存储、调阅、检索、管理&#xff0c;并通过网络向全院提供病人检查影像及诊断报告&#xff1b;各影像科室之间共享不同设备的病人检查影像及诊断报告&#xff1b;在诊断工作站上&#xff0c;调阅HIS中病人的其它信息&am…

A Review on Graph Neural Network Methods in Financial Applications

本文是与GNN有关的论文综述&#xff0c;针对《A Review on Graph Neural Network Methods in Financial Applications》的翻译。 图神经网络在金融中的应用综述 摘要1 引言2 图分类3 特征处理4 图神经网络模型5 应用6 挑战 摘要 金融数据具有多个组成部分和多个关系&#xff…

Android架构 架构和 CPU ABI - NDK

查看设备架构 adb -s emulator-5554 shell getprop ro.product.cpu.abi C:\Users\liyd>adb -s emulator-5554 shell getprop ro.product.cpu.abi x86_64C:\Users\liyd>adb -s 804c11f1 shell getprop ro.product.cpu.abi arm64-v8amumu模拟器12 C:\Users\liyd>adb …

VB合同管理系统设计与实现

摘 要 在21世纪,随着计算机科学的发展,数据库技术在人们日常工作中的应用越来越广泛,为广大用户提供了更加周到和人性化的服务。数据库技术已逐渐成为当今计算机应用的潮流。本文主要是通过制作一款数据库软件—即“合同管理系统”来介绍数据库技术在人们日常生活和工作…

ElasticSearch入门

一、基本命令_cat 1、查看节点信息 http://192.168.101.132:9200/_cat/nodes2、查看健康状况 http://192.168.101.132:9200/_cat/health3、查看主节点的信息 http://192.168.101.132:9200/_cat/master4、查看所有索引 http://192.168.101.132:9200/_cat/indices二、索引一…