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

音视频入门基础:RTP专题(10)——FFmpeg源码中,解析RTP header的实现

一、引言

由《音视频入门基础:RTP专题(9)——FFmpeg接收RTP流的原理和内部实现》可以知道,FFmpeg接收RTP流时,其源码内部会调用rtp_read函数。而rtp_read函数内部会通过recvfrom函数接收基于UDP的RTP音视频数据。一般情况下,每通过一次recvfrom函数接收到数据算一个RTP packet。然后FFmpeg会通过rtp_parse_packet_internal函数解析该RTP packet。

二、rtp_parse_packet_internal函数的定义

rtp_parse_packet_internal函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/rtpdec.c中:

static int rtp_parse_packet_internal(RTPDemuxContext *s, AVPacket *pkt,const uint8_t *buf, int len)
{unsigned int ssrc;int payload_type, seq, flags = 0;int ext, csrc;AVStream *st;uint32_t timestamp;int rv = 0;csrc         = buf[0] & 0x0f;ext          = buf[0] & 0x10;payload_type = buf[1] & 0x7f;if (buf[1] & 0x80)flags |= RTP_FLAG_MARKER;seq       = AV_RB16(buf + 2);timestamp = AV_RB32(buf + 4);ssrc      = AV_RB32(buf + 8);/* store the ssrc in the RTPDemuxContext */s->ssrc = ssrc;/* NOTE: we can handle only one payload type */if (s->payload_type != payload_type)return -1;st = s->st;// only do something with this if all the rtp checks pass...if (!rtp_valid_packet_in_sequence(&s->statistics, seq)) {av_log(s->ic, AV_LOG_ERROR,"RTP: PT=%02x: bad cseq %04x expected=%04x\n",payload_type, seq, ((s->seq + 1) & 0xffff));return -1;}if (buf[0] & 0x20) {int padding = buf[len - 1];if (len >= 12 + padding)len -= padding;}s->seq = seq;len   -= 12;buf   += 12;len   -= 4 * csrc;buf   += 4 * csrc;if (len < 0)return AVERROR_INVALIDDATA;/* RFC 3550 Section 5.3.1 RTP Header Extension handling */if (ext) {if (len < 4)return -1;/* calculate the header extension length (stored as number* of 32-bit words) */ext = (AV_RB16(buf + 2) + 1) << 2;if (len < ext)return -1;// skip past RTP header extensionlen -= ext;buf += ext;}if (s->handler && s->handler->parse_packet) {rv = s->handler->parse_packet(s->ic, s->dynamic_protocol_context,s->st, pkt, &timestamp, buf, len, seq,flags);} else if (st) {if ((rv = av_new_packet(pkt, len)) < 0)return rv;memcpy(pkt->data, buf, len);pkt->stream_index = st->index;} else {return AVERROR(EINVAL);}// now perform timestamp things....finalize_packet(s, pkt, timestamp);return rv;
}

该函数的作用是:解析一个RTP packet。该函数的前半部分实现了解析该RTP packet的RTP header的功能。

形参s:既是输入型参数也是输出型参数,指向一个RTPDemuxContext类型变量。RTPDemuxContext结构体声明如下,存贮RTP解复用的上下文信息:

struct RTPDemuxContext {AVFormatContext *ic;AVStream *st;int payload_type;uint32_t ssrc;uint16_t seq;uint32_t timestamp;uint32_t base_timestamp;int64_t  unwrapped_timestamp;int64_t  range_start_offset;int max_payload_size;/* used to send back RTCP RR */char hostname[256];int srtp_enabled;struct SRTPContext srtp;/** Statistics for this stream (used by RTCP receiver reports) */RTPStatistics statistics;/** Fields for packet reordering @{ */int prev_ret;     ///< The return value of the actual parsing of the previous packetRTPPacket* queue; ///< A sorted queue of buffered packets not yet returnedint queue_len;    ///< The number of packets in queueint queue_size;   ///< The size of queue, or 0 if reordering is disabled/*@}*//* rtcp sender statistics receive */uint64_t last_rtcp_ntp_time;int64_t last_rtcp_reception_time;uint64_t first_rtcp_ntp_time;uint32_t last_rtcp_timestamp;int64_t rtcp_ts_offset;/* rtcp sender statistics */unsigned int packet_count;unsigned int octet_count;unsigned int last_octet_count;int64_t last_feedback_time;/* dynamic payload stuff */const RTPDynamicProtocolHandler *handler;PayloadContext *dynamic_protocol_context;
};

形参pkt:输出型参数。执行rtp_parse_packet_internal函数后,pkt会得到从该RTP packet解析出来的信息。

形参buf:输入型参数,存放需要被解析的该RTP packet数据的缓冲区。

形参len:输入型参数,该RTP packet的字节数。

返回值:返回非负数表示成功,返回负数表示失败。

三、rtp_parse_packet_internal函数中,解析RTP header的实现

rtp_parse_packet_internal函数中,首先通过下面语句将RTP header中的CSRC count字段读取出来:

    csrc         = buf[0] & 0x0f;

将RTP header中的extension字段读取出来:

    ext          = buf[0] & 0x10;


 

将RTP header中的payload type(有效载荷类型)字段读取出来:

    payload_type = buf[1] & 0x7f;

判断RTP header中的marker字段值的值是否为1,如果为1,设置局部变量flags:

    if (buf[1] & 0x80)flags |= RTP_FLAG_MARKER;

将RTP header中的sequence number(序列号)字段读取出来。关于AV_RB16宏定义的用法可以参考:《FFmpeg源码:AV_RB32、AV_RB16、AV_RB8宏定义分析》:

    seq       = AV_RB16(buf + 2);
//...s->seq = seq;

将RTP header中的timestamp(时间戳)字段读取出来:

    timestamp = AV_RB32(buf + 4);

将RTP header中的synchronization source (SSRC) identifier字段读取出来:

    ssrc      = AV_RB32(buf + 8);/* store the ssrc in the RTPDemuxContext */s->ssrc = ssrc;

判断RTP header中的padding属性的值是否为1,如果为1,表示RTP packet末端会附加填充字节:

    if (buf[0] & 0x20) {int padding = buf[len - 1];if (len >= 12 + padding)len -= padding;}

RTP header中的RTP Fixed Header(RTP header中的固定长度部分)固定占12字节,RTP Fixed Header之后紧接着的是contributing source(CSRC) identifiers,让指针buf移动到contributing source(CSRC) identifiers之后,使得可以读取之后的数据:

    len   -= 12;buf   += 12;len   -= 4 * csrc;buf   += 4 * csrc;if (len < 0)return AVERROR_INVALIDDATA;

如果RTP header中存在RTP Header Extension,跳过RTP Header Extension的读取:

    /* RFC 3550 Section 5.3.1 RTP Header Extension handling */if (ext) {if (len < 4)return -1;/* calculate the header extension length (stored as number* of 32-bit words) */ext = (AV_RB16(buf + 2) + 1) << 2;if (len < ext)return -1;// skip past RTP header extensionlen -= ext;buf += ext;}

相关文章:

音视频入门基础:RTP专题(10)——FFmpeg源码中,解析RTP header的实现

一、引言 由《音视频入门基础&#xff1a;RTP专题&#xff08;9&#xff09;——FFmpeg接收RTP流的原理和内部实现》可以知道&#xff0c;FFmpeg接收RTP流时&#xff0c;其源码内部会调用rtp_read函数。而rtp_read函数内部会通过recvfrom函数接收基于UDP的RTP音视频数据。一般…...

1.1 go环境搭建及基本使用

golang下载地址&#xff1a; Download and install - The Go Programming Language (google.cn) 验证安装是否成功&#xff1a; go version 查看go环境 go env 注意&#xff1a;Go1.11版本之后无需手动配置环境变量,使用go mod 管理项目&#xff0c;也不需要把项目放到GO…...

Flask flash() 消息示例

目录 安装 Flask 入门:Flask flash() 基本示例 进阶:使用 Flask-WTF Flash 登录结果消息 详解:get_flashed_messages() 详解:flash() 消息的完整生命周期 Flask 提供 flash() 用于向 用户传递临时消息,通常用于: • 表单提交成功或失败 • 用户登录、注册、退出提…...

Gemini 2.0助力科学突破,AI联合科学家系统登场

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

京东外卖骑手全部缴纳五险一金

刘强东这步棋&#xff0c;直击700万骑手软肋&#xff1f; 今天&#xff0c;京东突然甩出一张底牌&#xff1a;自2025年3月1日起&#xff0c;外卖全职骑手全员缴纳五险一金&#xff0c;兼职骑手配套意外医疗双保险。 消息一出&#xff0c;直接炸了外卖江湖。要知道&#xff0c…...

oracle apex post接口

日常记录 使用到了apex_json方式接收 、、、1 首先&#xff0c;接口通过body传递过来&#xff0c;成功接收到&#xff0c; 数据格式为 JSON_OBJECT_T l_json : JSON_OBJECT_T.parse(:body); 这里我用参数接收到 然后 里面是包含了 "data" 我用 继续接收到这个 l…...

百度云DeepSeek一体机:百舸、千帆和一见介绍及区别对比

百度智能云DeepSeek一体机百舸、千帆和一见&#xff0c;搭载昆仑芯等国产自研算力芯片&#xff0c;可支持在单机环境下一键部署DeepSeek R1/V3全系列模型。百度云服务器网bdyfwq.com分享百度智能云官方发布的百舸DeepSeek一体机、千帆DeepSeek一体机和一见DeepSeek一体机配置介…...

k8s集群内的pod连接集群外部的mysql, k8s集群内部服务如何连接集群外部mysql? 一文搞明白

一、为什么不将mysql服务部署到k8s集群中使用呢&#xff1f; 1.有状态服务在K8s中的管理比较复杂&#xff0c;特别是持久化存储的问题。虽然K8s有StatefulSet和PV/PVC&#xff0c;但配置和维护起来需要更多工作,同时以下问题仍需解决&#xff1a;-存储可靠性&#xff1a;如果使…...

C#使用Semantic Kernel:接入本地deepseek-r1

安装Ollama 1.下载Ollama 访问Ollama官网&#xff08;https://ollama.com&#xff09;&#xff0c;选择适合你操作系统的版本进行下载。 对于Linux用户&#xff0c;可以通过以下命令安装&#xff1a; curl -fsSL https://ollama.com/install.sh | sudo bash sudo system…...

【算法】直接插入排序、折半插入排序、希尔排序

1 直接插入排序 时间复杂度&#xff1a;O(N^2) 空间复杂度&#xff1a;O(1) 稳定性&#xff1a;稳定 元素集合越接近有序&#xff0c;直接插入排序算法的时间效率越高 1.1直接插入排序思想 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff…...

使用API有效率地管理Dynadot域名,为域名部署DNS安全拓展(DNSSEC)

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…...

【排版教程】如何在Word/WPS中优雅的插入参考文献

材料展示 随便选取一段综述内容&#xff0c;以及对应的参考文献&#xff0c;如下图所示&#xff1a; 1 参考文献编辑 首先对参考文献部分进行编辑&#xff0c;将其设置自动编号 在段落中&#xff0c;选择悬挂缩进 在编号中&#xff0c;设置自定义编号&#xff0c;然后按照…...

神经形态视觉的实时动态避障系统:突破传统SLAM的响应延迟瓶颈

引言&#xff1a;机器人感知的实时性挑战 斯坦福机器人实验室采用异步脉冲神经网络处理DVS事件相机数据后&#xff0c;动态障碍物响应延迟从34ms降至0.9ms。在20m复杂场景避障测试中&#xff0c;基于神经形态芯片的路径规划系统将SLAM更新频率提升至10kHz&#xff0c;较传统GP…...

python绘图之密集散点图

密集散点图主要目的是生成一个可视化图表&#xff0c;展示 insurance 数据集中 bmi&#xff08;身体质量指数&#xff09;和 charges&#xff08;医疗费用&#xff09;之间的关系&#xff0c;并通过不同的维度对数据进行分组和区分&#xff0c;以便更清晰地观察数据的分布和特征…...

Linux操作系统4-进程间通信5(共享内存实现两个进程通信)

上篇文章&#xff1a;Linux操作系统4-进程间通信4&#xff08;共享内存原理&#xff0c;创建&#xff0c;查看&#xff0c;命令&#xff09;-CSDN博客 本篇Gitee仓库&#xff1a;myLerningCode/l24 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com) 本篇重…...

sam2 windows 编译安装

目录 1. pip install sam2 2. 编译安装 1. pip install sam2 运行报错&#xff1a; cannot import name _C from sam2 (E:\project\smpl\render_blender\linux\GroundedSAM2_SMPL\sam2\__init__.py) 2. 编译安装 cd E:\project\sam2\sam2-main set DISTUTILS_USE_SDK1 py…...

RFID测温技术:电力设备安全监测的新利器

在当今高度依赖电力的现代化社会中&#xff0c;稳定且可靠的电力供应是社会运转的基石。电力设备作为电力系统的关键核心&#xff0c;其运行状态直接关乎电力供应的品质。然而&#xff0c;电力设备长期运行过程中&#xff0c;受到诸如过载、接触不良以及环境因素等多重影响&…...

(一)趣学设计模式 之 单例模式!

目录 一、啥是单例模式&#xff1f;二、为什么要用单例模式&#xff1f;三、单例模式怎么实现&#xff1f;1. 饿汉式&#xff1a;先下手为强&#xff01; &#x1f608;2. 懒汉式&#xff1a;用的时候再创建&#xff01; &#x1f634;3. 枚举&#xff1a;最简单最安全的单例&a…...

自动化办公|xlwings生成图表

在日常的数据分析和报告生成中&#xff0c;Excel图表是一个非常重要的工具。它能够帮助我们直观地展示数据&#xff0c;发现数据中的规律和趋势。然而&#xff0c;手动创建和调整图表往往耗时且容易出错。幸运的是&#xff0c;借助Python的xlwings库&#xff0c;我们可以自动化…...

Docker基于Ollama本地部署大语言模型

一、Ollama介绍 Ollama 是一个开源的大型语言模型&#xff08;LLM&#xff09;平台&#xff0c;旨在简化大型语言模型在本地环境中的运行、管理和交互。通过Ollama&#xff0c;用户可以轻松加载和使用各种预训练的语言模型&#xff0c;执行诸如文本生成、翻译、代码编写、问答…...

Pytorch实现之GIEGAN(生成器信息增强GAN)训练自己的数据集

简介 简介:在训练数据样本之前首先利用VAE来推断潜在空间中不同类的分布,用于后续的训练,并使用它来初始化GAN。与ACGAN和BAGAN不同的是,提出的GIEGAN有一个分类器结构,这个分类器主要判断生成的图像或者样本图像属于哪个类,而鉴别器仅判断图像是来自于生成器还是真实样…...

centos9安装k8s集群

以下是基于CentOS Stream 9的Kubernetes 1.28.2完整安装流程&#xff08;containerd版&#xff09;&#xff1a; 一、系统初始化&#xff08;所有节点执行&#xff09; # 关闭防火墙 systemctl disable --now firewalld# 关闭SELinux sed -i "s/SELINUXenforcing/SELINU…...

pytest下allure

import pytestdef test_case01():用例01~print(用例01)class Test_mokuai01:def test_case02(self):用例02~print(用例02)if __name____main__:#pytest.main([-vs,test_sample-2.py])pytest.main([-vs,test_sample-2.py,--allure-dir,./result2])#生成allure报告&#xff0c;参…...

JVM预热

阿里电商平台每年的各种大促活动&#xff0c;对于Java技术来说&#xff0c;其中重要一个操作环节就是预热操作。 目录 预热是什么&#xff1f;为什么要预热&#xff1f; java 程序不预热和预热的调用对比 预热是什么&#xff1f; 预热是指&#xff0c;在 JVM 启动后&#xff0…...

【JavaWeb12】数据交换与异步请求:JSON与Ajax的绝妙搭配是否塑造了Web的交互革命?

文章目录 &#x1f30d;一. 数据交换--JSON❄️1. JSON介绍❄️2. JSON 快速入门❄️3. JSON 对象和字符串对象转换❄️4. JSON 在 java 中使用❄️5. 代码演示 &#x1f30d;二. 异步请求--Ajax❄️1. 基本介绍❄️2. JavaScript 原生 Ajax 请求❄️3. JQuery 的 Ajax 请求 &a…...

Ubuntu 查看mysql用户和数据库

在Ubuntu系统中&#xff0c;你可以使用以下MySQL命令来查看用户和数据库的信息。请确保你已经安装了MySQL服务器&#xff0c;并且你具有足够的权限&#xff08;如root用户权限&#xff09;来执行这些命令。 查看所有数据库 要查看MySQL服务器上的所有数据库&#xff0c;可以使…...

数据库服务器和应用服务器的区别是什么?

在当今的互联网社会中&#xff0c;各个行业中的业务都离不来网络科技&#xff0c;而作为互联网基础设施的服务器&#xff0c;受到了各大行业的广泛应用&#xff0c;同时根据所承担职责的不同&#xff0c;可以将服务器分为数据库服务器和应用服务器&#xff0c;本文就来概括一下…...

初级银行从业考试真题

2023 年 6 月初级银行从业考试真题 法律法规 单选题 1.按照《中华人民共和国反洗钱法》的规定,金融机构所建立的客户身份资料和客户交易信息在业务关系或交易结束后至少 保存期限为()年。 A.5 B.3 C.10 D.2 参考答案:A 2.物价稳定是要保持()的大体稳定,避免出现高…...

普通转录组RNASeq生物信息流程

探序基因肿瘤研究院 整理 比对工具&#xff1a;HISAT2&#xff0c;下载源代码编译安装或者二进制文件 定量工具&#xff1a;feactureCounts&#xff0c;下载地址&#xff1a;The Subread package 参考基因组&#xff1a;NCBI的GCF_000001405.40_GRCh38.p14_genomic.fna.g…...

nginx容器配置fastapi服务失败

问题描述&#xff1a; Linux虚拟机中启动了一个fastapi服务器&#xff08;8000端口&#xff09;&#xff0c;希望能通过nginx容器设置代理使得前端代码可以调用这个接口&#xff0c;但是访问时报错&#xff08;状态码&#xff1a;502&#xff09;。nginx配置如下&#xff1a; l…...