UDP-RTP协议解析

article/2025/9/21 1:29:23

一、RTP协议

    数据传输协议RTP,用于实时传输数据。RTP报文由两部分组成:报头和有效载荷

二、RTP的会话过程

    当应用程序建立一个RTP会话时,应用程序将确定一对目的传输地址。目的传输地址由一个网络地址和一对端口组成,有两个端口:一个给RTP包,一个给RTCP包,使得RTP/RTCP数据能够正确发送。RTP数据发向偶数的UDP端口,而对应的控制信号RTCP数据发向相邻的奇数UDP端口(偶数的UDP端口+1),这样就构成一个UDP端口对。 RTP的发送过程如下,接收过程则相反

  • RTP协议从上层接收流媒体信息码流(如H.263),封装成RTP数据包
  • RTCP从上层接收控制信息,封装成RTCP控制包
  • RTP将RTP 数据包发往UDP端口对中偶数端口;RTCP将RTCP控制包发往UDP端口对中的接收端口

三、RTP Header解析

前12字节是固定的,CSRC可以有多个或者0个

    1)V:RTP协议的版本号,占2位,当前协议版本号为2

    2)P:填充标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分

    3)X:扩展标志,占1位,如果X=1,则在RTP报头后跟有一个扩展报头

    4)CC:CSRC计数器,占4位,指示CSRC标识符个数

    5)M:标志,占1位,不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。

    6)PT(payload type):有效荷载类型,占7位,用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等,在流媒体中大部分是用来区分音频流和视频流,这样便于客户端进行解析。

    7)序列号:占16位,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。这个字段当下层的承载协议用UDP的时候,网络状况不好的时候可以用来检查丢包。当出现网络抖动的情况可以用来对数据进行重新排序。序列号的初始值是随机的,同时音频包和视频包的sequence是分别计数的。

    8)时戳(Timestamp):占32位,必须使用90kHZ时钟频率(程序中的90000)。时戳反映了该RTP报文的第一个八位组的采样时刻。接受者使用时戳来计算延迟和延迟抖动,并进行同步控制。可以根据RTP包的时间戳来获得数据包的时序。

    9)同步信源(SSRC)标识符:占32位,用于标识同步信源。同步信源是指产生媒体流的信源,他通过RTP报头中的一个32为数字SSRC标识符来标识,而不依赖网络地址,接收者将根据SSRC标识符来区分不同的信源,进行RTP报文的分组。

    10)提供信源(CSRC)标识符:每个CSRC标识符占32位,可以有0~15个CSRC。每个CSRC标识了包含在RTP报文有效载荷中的所有提供信源。

提供信源用来标识对一个RTP混合器产生的新包有贡献的所有RTP包的源。是指当混合器接收到一个或多个同步信源的RTP报文后,经过混合处理产生一个新的组合RTP报文,并把混合器作为组合RTP报文的SSRC,将原来所有的SSRC都作为CSRC传送给接收者,是接受者知道组成组合报文的各个SSRC
 

把前两字节 80 e0 换成二进制如下

1000 0000 1110 0000

按顺序解释如下:

10               是V;

0                 是P;

0                 是X;

0000           是CC;

1                 是M;

110 0000    是PT;

四、RTP载荷H264码流:红色RTP协议头,黄色H264码流

RTP头后是RTP载荷,RTP载荷第一个字节格式跟NALU头一样:

F和NRI也跟NALU头一样,只有Type有些不一样:拓展24 – 31

0     没有定义

 1-23  NAL单元   单个 NAL 单元包.

  24    STAP-A   单一时间的组合包

  25    STAP-B   单一时间的组合包

  26    MTAP16   多个时间的组合包

  27    MTAP24   多个时间的组合包

  28    FU-A     分片的单元

  29    FU-B     分片的单元

  30-31 没有定义

1)   单个NAL单元包:荷载中只包含一个NAL单元。NAL头类型域等于原始 NAL单元(NALU)类型,即Type在范围1到23之间。

2)组合包:本类型用于聚合多个NAL单元到单个RTP荷载中。本包有四种版本,单时间聚合包类型A(STAP-A)单时间聚合包类型B(STAP-B),多时间聚合包类型(MTAP)16位位移(MTAP16),多时间聚合包类型(MTAP)24位位移(MTAP24)。赋予STAP-A,STAP-B,MTAP16,MTAP24的NAL单元类型号(Type)分别是24 25 26 27

3)分片包:用于分片单个NAL单元到多个RTP包。现存两个版本FU-A,FU-B,用NAL单元类型(Type)28 29标识

常用的打包时的分包规则:如果小于MTU采用单个NAL单元包,如果大于MTU就采用FUs分片方式

五、雷神博客

原理

    MPEG-TS封装格式数据打包为RTP/UDP协议然后发送出去的流程如下图所示。图中首先每7个MPEG-TS Packet打包为一个RTP,然后每个RTP再打包为一个UDP。其中打包RTP的方法就是在MPEG-TS数据前面加上RTP Header,而打包RTP的方法就是在RTP数据前面加上UDP Header
 

    有关MPEG-TS、RTP、UDP的知识不再详细介绍,可以参考相关的文档了解其中的细节信息。本文记录的程序是一个收取流媒体的程序,因此本文程序的流程和上述发送MPEG-TS的流程正好是相反的。该程序可以通过Socket编程收取UDP包,解析其中的RTP包的信息,然后再解析RTP包中MPEG-TS Packet的信息
代码

#include <stdio.h>
#include <winsock2.h>#pragma comment(lib, "ws2_32.lib") #pragma pack(1)/** [memo] FFmpeg stream Command:* ffmpeg -re -i sintel.ts -f mpegts udp://127.0.0.1:8880* ffmpeg -re -i sintel.ts -f rtp_mpegts udp://127.0.0.1:8880*/typedef struct RTP_FIXED_HEADER{/* byte 0 */unsigned char csrc_len:4;       /* expect 0 */unsigned char extension:1;      /* expect 1 */unsigned char padding:1;        /* expect 0 */unsigned char version:2;        /* expect 2 *//* byte 1 */unsigned char payload:7;unsigned char marker:1;        /* expect 1 *//* bytes 2, 3 */unsigned short seq_no;            /* bytes 4-7 */unsigned  long timestamp;        /* bytes 8-11 */unsigned long ssrc;            /* stream number is used here. */
} RTP_FIXED_HEADER;typedef struct MPEGTS_FIXED_HEADER {unsigned sync_byte: 8; unsigned transport_error_indicator: 1; unsigned payload_unit_start_indicator: 1;unsigned transport_priority: 1; unsigned PID: 13;unsigned scrambling_control: 2;unsigned adaptation_field_exist: 2;unsigned continuity_counter: 4;
} MPEGTS_FIXED_HEADER;int simplest_udp_parser(int port)
{WSADATA wsaData;WORD sockVersion = MAKEWORD(2,2);int cnt=0;//FILE *myout=fopen("output_log.txt","wb+");FILE *myout=stdout;FILE *fp1=fopen("output_dump.ts","wb+");if(WSAStartup(sockVersion, &wsaData) != 0){return 0;}SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(serSocket == INVALID_SOCKET){printf("socket error !");return 0;}sockaddr_in serAddr;serAddr.sin_family = AF_INET;serAddr.sin_port = htons(port);serAddr.sin_addr.S_un.S_addr = INADDR_ANY;if(bind(serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR){printf("bind error !");closesocket(serSocket);return 0;}sockaddr_in remoteAddr;int nAddrLen = sizeof(remoteAddr); //How to parse?int parse_rtp=1;int parse_mpegts=1;printf("Listening on port %d\n",port);char recvData[10000];  while (1){int pktsize = recvfrom(serSocket, recvData, 10000, 0, (sockaddr *)&remoteAddr, &nAddrLen);if (pktsize > 0){//printf("Addr:%s\r\n",inet_ntoa(remoteAddr.sin_addr));//printf("packet size:%d\r\n",pktsize);//Parse RTP//if(parse_rtp!=0){char payload_str[10]={0};RTP_FIXED_HEADER rtp_header;int rtp_header_size=sizeof(RTP_FIXED_HEADER);//RTP Headermemcpy((void *)&rtp_header,recvData,rtp_header_size);//RFC3551char payload=rtp_header.payload;switch(payload){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9:case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18: sprintf(payload_str,"Audio");break;case 31: sprintf(payload_str,"H.261");break;case 32: sprintf(payload_str,"MPV");break;case 33: sprintf(payload_str,"MP2T");break;case 34: sprintf(payload_str,"H.263");break;case 96: sprintf(payload_str,"H.264");break;default:sprintf(payload_str,"other");break;}unsigned int timestamp=ntohl(rtp_header.timestamp);unsigned int seq_no=ntohs(rtp_header.seq_no);fprintf(myout,"[RTP Pkt] %5d| %5s| %10u| %5d| %5d|\n",cnt,payload_str,timestamp,seq_no,pktsize);//RTP Datachar *rtp_data=recvData+rtp_header_size;int rtp_data_size=pktsize-rtp_header_size;fwrite(rtp_data,rtp_data_size,1,fp1);//Parse MPEGTSif(parse_mpegts!=0&&payload==33){MPEGTS_FIXED_HEADER mpegts_header;for(int i=0;i<rtp_data_size;i=i+188){if(rtp_data[i]!=0x47)break;//MPEGTS Header//memcpy((void *)&mpegts_header,rtp_data+i,sizeof(MPEGTS_FIXED_HEADER));fprintf(myout,"   [MPEGTS Pkt]\n");}}}else{fprintf(myout,"[UDP Pkt] %5d| %5d|\n",cnt,pktsize);fwrite(recvData,pktsize,1,fp1);}cnt++;}}closesocket(serSocket); WSACleanup();fclose(fp1);return 0;
}

结果

    本程序输入为本机的一个端口号,输出为UDP/RTP/MPEG-TS的解析结果。程序开始运行后,可以使用推流软件向本机的udp://127.0.0.1:8880地址进行推流。例如可以使用VLC Media Player的“打开媒体”对话框中的“串流”功能(位于“播放”按钮旁边的小三角按钮的菜单中)。在该功能的对话框中添加一个“RTP / MPEG Transport Stream”的新目标
    也可以使用FFmpeg对本机的8880端口进行推流。下面的命令可以推流UDP封装的MPEG-TS

ffmpeg -re -i sintel.ts -f rtp_mpegts udp://127.0.0.1:8880

    推流之后,本文的程序会通过Socket接收到UDP包并且解析其中的数据。解析的结果如下图所示

CSDN下载地址: http://download.csdn.net/detail/leixiaohua1020/9422409


http://chatgpt.dhexx.cn/article/AC81usf3.shtml

相关文章

UDP 理解

这里需要指出的一点是&#xff0c;伪首部完全是虚拟的&#xff0c;它并不会和用户数据报一起被发送出去&#xff0c;只是在校验和的计算过程中会被使用到&#xff0c;伪首部主要来自于运载UDP报文的IP数据报首部&#xff0c;将源IP地址和目的IP地址加入到校验和的计算中可以验证…

关于TCP/UDP

目录 1、TCP协议 1.1 TCP协议格式 1.2 TCP协议原理 2、UDP协议 在学习TCP/UDP之前先来了解以下整体的通信传输&#xff0c;它是一个向下封装、向上分用的过程&#xff1a; 这是TCP/IP四层模型&#xff0c;所以要想实现通讯&#xff0c;通过TCP建立和断开连接是至关重要的&a…

UDP详解

1、UDP数据包格式 UDP 是User Datagram Protocol的简称&#xff0c; 中文名是用户数据报协议&#xff0c;是OSI&#xff08;Open System Interconnection&#xff0c;开放式系统互联&#xff09; 参考模型中一种无连接的传输层协议&#xff0c;提供面向事务的简单不可靠信息传…

TCPUDP相关介绍

TCP and UDP TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是面向连接的协议&#xff0c;也就是说&#xff0c;在收发数据前&#xff0c;必须和对方建立可靠的连接。 一个TCP连接必须要经过三次握手才能建立起来。断开连接需要四次挥手才…

TCPUDP

TCP&#xff1a;面向连接的服务&#xff0c;可靠的进程到进程的通信协议。&#xff08;因为TCP里面封装了端口号&#xff0c;端口号就意味着一个服务&#xff0c;进程&#xff09;&#xff1b;应用场景&#xff1a;如&#xff1a;文件传输&#xff1b;HTTP应用层协议 UDP&…

TCP/UDP

Tcp / ip : 应用层、传输层、网络层、网络接口层 查看本机ip&#xff1a; windons r &#xff08;进入交互换环境&#xff09;ipconfigping 本机ip 查看本机网络有无问题 端口&#xff1a; 知名端口(固定端口)&#xff1a;0—1023动态端口&#xff1a;程序可以设置的端口 1…

UDP协议的详细解析

UDP数据报 一、UDP的概述&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09; UDP是传输层的协议&#xff0c;功能即为在IP的数据报服务之上增加了最基本的服务&#xff1a;复用和分用以及差错检测。 UDP提供不可靠服务&#xff0c;具有TCP所没有的优…

UDP协议详解

一、UDP协议概述 传输层另一个重要的协议就是用户数据报协议 UDP。UDP 只在 IP 的数据报服务之上增加了很少一点的功能&#xff0c;这就是复用和分用的功能以及差错检测的功能。 <注> UDP(User Datagram Protocol&#xff0c;用户数据报协议) UDP的主要特点是&#xff1a…

截图文字识别工具

tkinter程序源码&#xff1a;初识Python&#xff0c;如有不足请多指教。 import tkinter as tk import keyboard # 安装&#xff1a; pip install keyboard from PIL import ImageGrab # pip install pillow import time from aip import AipOcr # pip install baidu-a…

电脑截图如何快速识别文字?3分钟教会你快速截图识别怎么做

电脑截图已经成为我们日常生活中的常见操作&#xff0c;无论是工作还是学习&#xff0c;我们都有可能需要截取电脑屏幕上的某个区域进行保存或分享。但是&#xff0c;有时候我们需要识别截图中的文字内容&#xff0c;这时候该怎么办呢&#xff1f;接下来&#xff0c;本文将为大…

python截图识别文字_10几行代码,用python打造实时截图识别OCR|python基础教程|python入门|python教程...

https://www.xin3721.com/eschool/pythonxin3721/ 你一定用过那种“OCR神器”&#xff0c;可以把图片中的文字提取出来&#xff0c;极大的提高工作效率。 &#xff01; 今天&#xff0c;我们就来做一款实时截图识别的小工具。顾名思义&#xff0c;运行程序时&#xff0c;可以…

chrome拓展 --截屏文字识别

文章目录 场景源代码功能实现点击在页面上出现裁剪框百度云文字识别复制选中 参考 场景 因为学习通题目都加密了复制过来也无法进行搜题 无奈写了这个插件 为什么使用插件的形式 而不是脚本 &#xff1f; 使用了html2canvas结果是比的是dom文字变成了加密过的 无法识别 于是使用…

微信怎么识别图片文字?其实操作很简单

微信作为中国最流行的社交媒体应用程序之一&#xff0c;已经成为人们分享照片和信息的主要平台之一。在微信中&#xff0c;用户可以轻松地将照片上传到朋友圈或与朋友共享。然而&#xff0c;在某些情况下&#xff0c;这些照片上可能有一些重要的文字信息&#xff0c;这些信息需…

电脑截图怎么识别文字?识别原理又是什么?

在日常工作和生活中&#xff0c;我们经常需要从图片或截图中提取文字&#xff0c;但是手动输入费时费力&#xff0c;因此电脑截图文字识别技术应运而生。本文将介绍电脑截图文字识别的原理和方法。 OCR技术的原理 OCR是一种光学字符识别技术&#xff0c;其原理是将图片中的文字…

C# 通用OCR识别 文字识别 中文识别

软件说明 基于以下两个开源项目&#xff0c;做了再次封装 https://github.com/paddlepaddle/PaddleOCR PaddleOCRSharp: 本项目是一个基于PaddleOCR的C代码修改并封装的.NET的OCR工具类库。包含文本识别、文本检测、基于文本检测结果的统计分析的表格识别功能&#xff0c;同…

手把手教截图识别文字

点击上方 毛利学python&#xff0c;选择置顶或星标 第一时间送达Python 技术干货&#xff01; 最近不想打字&#xff0c;直接截图然后识别出来文字&#xff0c;不就可以不用打吗&#xff1f;我就是太懒了。 keyboard 这个库让你可以控制和监控输入设备。 对于每一种输入设备&a…

屏幕可以截图识别文字?我来教你

我们经常浏览一些网页的时候&#xff0c;看到一些优美的文字&#xff0c;想将它复制下来&#xff0c;却发现粘贴的时候都是一些乱码之类的&#xff0c;以前我估计你们大多数的人都会选择用手抄&#xff0c;但是今天我来了&#xff0c;我给大家介绍一个非常有用的一个方法&#…

python截图识别文字_Python技术:截图文字识别工具

#01 截图文字识别工具 有时候在海报上面&#xff0c;图片上面&#xff0c;或者PDF文档中&#xff0c;经常出现一些唯美的文字。这个时候想要复制下来才发现不能复制。因为有的是图片&#xff0c;有的是PDF。 可以使用Python制作一个小工具&#xff0c;来识别图片上的文字。但…

这几个截图文字识别软件可以自动识别文字

从事新媒体行业的朋友&#xff0c;是不是经常在电脑桌面上或者在浏览也中临时截图识别文字呢&#xff1f;尤其是为了方便&#xff0c;直接识别图片转为文字的话&#xff0c;我们就可以节省了很多打字的时间。那你们知道怎么截图文字识别吗&#xff1f;今天我来教你们3个非常简单…

图片截图识别文字怎么操作?这两个方法不要错过

现如今&#xff0c;图片截图识别文字是一项非常有用的技术。很多小伙伴平时在工作或者生活中都会保存很多图片格式的资料文件把。如果遇到需要讲内容图区到文档中编辑的话&#xff0c;识别技术就可以帮助我们快速识别图片中的文字&#xff0c;从而节省大量的时间。那么图片截图…