c 使用RTP协议发送视频数据
使用RTP协议发送视频数据,要先弄清楚RTP协议的格式,自己组包发送。下面具体说明了RTP固定头的内容和组包时的值。
rtp包格式
V:2 P:0 X:0
CC:CSRC 计数,4位。表示跟在RTP固定包头后面CSRC的数目,对于本文所要实现的基本的流媒体服务器来说,没有用到混合器,该位也设为0x0。
M:如果当前 NALU为一个接入单元最后的那个NALU,那么将M位置1;或者当前RTP数据包为一个NALU的最后的那个分片时(NALU的分片在后面讲述),M位置1。其余情况下M位保持为0。
PT:负载类型 H264(96)
SQ:序号,16位。序号的起始值为随机值,此处设为0,每发送一个RTP数据包,序号值加1。
TS:时间戳,32位。同序号一样,时间戳的起始值也为随机值,此处设为0。根据RFC3984,与时间戳相应的时钟频率必须为90000HZ。
timestamp_increse=(unsigned int)(90000.0 / framerate); //+0.5);
ts_current = ts_current + timestamp_increse;
htonl(ts_current);
SSRC:同步源标示,32位。SSRC应该被随机生成,以使在同一个RTP会话期中没有任何两个同步源具有相同的SSRC识别符。此处仅有一个同步源,因此将其设为0x12345678
对于 NALU的长度小于MTU大小的包,一般采用单一NAL单元模式.对于一个原始的H.264 NALU单元常由[Start Code] [NALU Header] [NALU Payload]三部分组成,其中Start Code用于标示这是一个NALU单元的开始,必须是"00 00 00 01"或"00 00 01", NALU头仅一个字节,其后都是NALU单元内容.打包时去除"00 00 01"或"00 00 00 01"的开始码,把其他数据封包的RTP包即可。
经过测试发现,经过压缩后的一帧数据的大小一般是大于MTU的,所以不能通过单个RTP包传输一帧数据,所以我们采用FU-A来分片发送一帧数据FU indicator占一个字节,Type的值设置为29,指示该包不是完整的一帧数据,而是FU—A分片类型的RTP包。FU header中的S和E用来指示分片的开始和结束,其中R必须为0。根据这些原则就可以自己组包发送视频数据了。组包具体格式见下图。
部分代码
#ifndef _RTP_H_
#define _RTP_H_#define UDP_DEST_IP "192.168.2.1"
#define UDP_DEST_PORT 3333
#define H264 96typedef struct
{ /**//* byte 0 */ unsigned char csrc_len:4; /**//* expect 0 */ unsigned char extension:1; /**//* expect 1, see RTP_OP below */ unsigned char padding:1; /**//* expect 0 */ unsigned char version:2; /**//* expect 2 */ /**//* byte 1 */ unsigned char payload:7; /**//* RTP_PAYLOAD_RTSP */ 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 { //byte 0 unsigned char TYPE;// 5bit unsigned char NRI;//2 bit unsigned char F;//1 bit
} NALU_HEADER; /**//* 1 BYTES */ //Fragmentation
typedef struct { //byte 0 unsigned char TYPE;//:5; unsigned char NRI;//:2; unsigned char F;//;//:1;
} FU_INDICATOR; /**//* 1 BYTES */ typedef struct { //byte 0 unsigned char TYPE;//:5; unsigned char R;//:1; unsigned char E;//:1; unsigned char S;//:1;
} FU_HEADER; /**//* 1 BYTES */ int TCP_init(int port);
int UDP_init();
int RTP_send(int socketfd,char *buf,unsigned int len);
int TCP_send(int socketfd,char *buf,unsigned int len);
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "rtp.h"int UDP_init()
{int udpsocket; struct sockaddr_in server; int len =sizeof(server); server.sin_family=AF_INET; server.sin_port=htons(UDP_DEST_PORT); server.sin_addr.s_addr=inet_addr(UDP_DEST_IP); udpsocket=socket(AF_INET,SOCK_DGRAM,0); if(udpsocket==-1){fprintf(stderr,"UDP create socket error:%s\n\a",strerror(errno));exit(1);} if(connect(udpsocket, (const struct sockaddr *)&server, len) == -1)//none three handshake{printf("UDP connect error\n"); exit(1);}return udpsocket;
}
int RTP_send(int socketfd,char *buf,unsigned int len)
{static unsigned short seq_num =0;static unsigned int ts_current=0; FU_INDICATOR fu_ind; FU_HEADER fu_hdr; NALU_HEADER nalu_hdr;char* nalu_payload;int bytes=0; float framerate=25; unsigned int timestamp_increase=0; timestamp_increase=(unsigned int)(90000.0 / framerate); //+0.5); len = len -4; //delete the 00 00 00 01len=len-1;//the length of pure dataRTP_FIXED_HEADER *rtp_hdr;char sendbuf[1500]; memset(sendbuf,0,1500);rtp_hdr =(RTP_FIXED_HEADER*)&sendbuf[0]; //设置RTP HEADER, rtp_hdr->payload = H264; //负载类型号, rtp_hdr->version = 2; //版本号,此版本固定为2 rtp_hdr->marker = 0; //标志位,由具体协议规定其值。 rtp_hdr->ssrc = htonl(10); //随机指定为10,并且在本RTP会话中全局唯一 nalu_hdr.F = buf[4] & 0x80; //1 bit nalu_hdr.NRI = buf[4] & 0x60; // 2 bit nalu_hdr.TYPE = buf[4] & 0x1f;// 5 bit if(len <= 1400) {//设置rtp M 位; rtp_hdr->marker=1; rtp_hdr->seq_no = htons(seq_num ++); //序列号,每发送一个RTP包增1 ts_current=ts_current+timestamp_increase; rtp_hdr->timestamp=htonl(ts_current); memcpy(&sendbuf[12],&buf[4],len+1);send( socketfd, sendbuf, len+13, 0 );}else if(len>1400){int k=0,l=0; k=len/1400; l=len%1400;int t=0;//用于指示当前发送的是第几个分片RTP包 ts_current=ts_current+timestamp_increase; rtp_hdr->timestamp=htonl(ts_current); // There are same timestamp in one NALU while(t<=k) //there are k + l RTP packages,because index = 0 1...k{ rtp_hdr->seq_no = htons(seq_num ++); //序列号,每发送一个RTP包增1 if(!t) { rtp_hdr->marker=0; fu_ind.F=nalu_hdr.F; fu_ind.NRI=nalu_hdr.NRI; fu_ind.TYPE=28; sendbuf[12] = fu_ind.F | fu_ind.NRI | fu_ind.TYPE;fu_hdr.E=0; fu_hdr.R=0; fu_hdr.S=1; fu_hdr.TYPE=nalu_hdr.TYPE; sendbuf[13] = fu_hdr.S <<7 | fu_hdr.E <<6 | fu_hdr.R <<5 | fu_hdr.TYPE; nalu_payload=&sendbuf[14];memcpy(nalu_payload,&buf[5],1400);//去掉NALU头 bytes=1400+14; send( socketfd, sendbuf, bytes, 0 );//printf("第一个分包 ");t++; }else if(k==t){ if(l==0)break;else{rtp_hdr->marker=1; fu_ind.F=nalu_hdr.F; fu_ind.NRI=nalu_hdr.NRI; fu_ind.TYPE=28; sendbuf[12] = fu_ind.F | fu_ind.NRI | fu_ind.TYPE; fu_hdr.R=0; fu_hdr.S=0; fu_hdr.TYPE=nalu_hdr.TYPE;fu_hdr.E=1; sendbuf[13] = fu_hdr.S <<7 | fu_hdr.E <<6 | fu_hdr.R <<5 | fu_hdr.TYPE;nalu_payload=&sendbuf[14];memcpy(nalu_payload,&buf[t*1400+5],l);bytes=l+14; send( socketfd, sendbuf, bytes, 0 );//printf("最后一个分包%d ",l);t++; }}else if(t<k&&0!=t){ if(l==0&&t==k-1){rtp_hdr->marker=1; fu_ind.F=nalu_hdr.F; fu_ind.NRI=nalu_hdr.NRI; fu_ind.TYPE=28; sendbuf[12] = fu_ind.F | fu_ind.NRI | fu_ind.TYPE; fu_hdr.R=0; fu_hdr.S=0; fu_hdr.TYPE=nalu_hdr.TYPE;fu_hdr.E=1; sendbuf[13] = fu_hdr.S <<7 | fu_hdr.E <<6 | fu_hdr.R <<5 | fu_hdr.TYPE;}else{rtp_hdr->marker=0; fu_ind.F=nalu_hdr.F ; fu_ind.NRI=nalu_hdr.NRI; fu_ind.TYPE=28; sendbuf[12] = fu_ind.F | fu_ind.NRI | fu_ind.TYPE; fu_hdr.R=0; fu_hdr.S=0; fu_hdr.E=0; fu_hdr.TYPE=nalu_hdr.TYPE; sendbuf[13] = fu_hdr.S <<7 | fu_hdr.E <<6 | fu_hdr.R <<5 | fu_hdr.TYPE;}nalu_payload=&sendbuf[14];memcpy(nalu_payload,&buf[t*1400+5],1400);bytes=1400+14;send( socketfd, sendbuf, bytes, 0 );//printf("中间分包"); t++; } }}return 0;
}
c 使用RTP协议发送视频数据相关推荐
- Java做rtp解包封包_基于RTP的H视频数据打包解包类DoubleLi博客园.pdf
基于RTP的H视频数据打包解包类DoubleLi博客园 15- 10-30 基于RTP的H264视频数据打包解包类 - DoubleLi - 博客园 DoubleLi 博客园 :: 首页 :: 博问 ...
- EasyGBS中基于 RTP 的音视频数据 PS 封装
在国标GB28181协议中,视频传输基本都由两个模块构成,EasyGBS包含两个模块:信令服务和流媒体服务.本节主要为大家解释下流媒体服务中关于音视频数据的PS封装. PS封装介绍: PS是Progr ...
- 【FFMPEG】基于RTP的H264视频数据打包解包类
最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包.解包的文档和代码.功夫不负有心人,找到不少有价值的文档和代码.参考这些资料,写了H264 RTP打包类.解包类,实现 ...
- wireshark提取视频数据之RTP包中提取H264和H265
wireshark提取视频数据之RTP包中提取H264和H265 文章目录 wireshark提取视频数据之RTP包中提取H264和H265 1 背景 2 提取前工作 3 H264视频从RTP包中提取 ...
- android 与后台实时视频,Android实时监控项目第四篇:后台线程发送预览帧视频数据...
还记得上篇提到的setPreviewCallback(Camera.PreviewCallback cb)函数吗?我们在开始预览帧视频之前,调用的它,这里要注意其内部的Camera.PreviewCa ...
- H264视频传输、编解码----RTP协议对H264数据帧拆包、打包、解包过程
H264帧需要通过RTP协议进行传输,这其中就涉及到H264数据帧的封包.拆包和解包等过程. RTP协议格式 下面是 RFC 3550 中规定的 RTP 头的结构: 0 1 2 3 40 1 2 3 ...
- 流媒体服务器之rtp协议,rtcp协议,rtsp协议,sdp协议,sip协议简析
0.前言 流媒体服务器做音视频媒体传输主要就两件事:媒体回话协商,媒体数据传输:下面这几种协议就围绕着这两个需求而产生. 1.rtp协议 rtp的全称是实时传输协议RTP(Real-time Tran ...
- 从WebRtc学习RTP协议
文章目录 TCP为何不适用于实时音视频 UDP->RTP RTP协议结构 Jittbuffer RTP扩展头 RTP填充数据 参考 TCP为何不适用于实时音视频 可靠性是以牺牲实时性为代价的.按 ...
- 基于RTP协议的IP电话QoS监测及提高策略
基于RTP协议的IP电话QoS监测及提高策略 本文转自 http://jxic.jiangxi.gov.cn/Html/2008321143656-1.html 1. 概述 随着Internet和多 ...
最新文章
- Linux文件系统映像:Initranfs 和 Initrd
- 算法提高课-搜索-DFS之搜索顺序-AcWing 1116. 马走日:dfs
- c语言 判断一个图是否全连通_C语言:程序运行流程图与顺序结构语句
- AI基础:机器学习简易入门
- abp框架java,【Net】ABP框架学习之正面硬钢
- 使用frp进行内网穿透的实例
- nginx 常用命令 保持启动 重载 开机启动等
- 局网满猿关不住,一波码农出墙来。
- 服务器需不需要虚拟内存,服务器要不要虚拟内存
- oracle 表复制 long,关于oracle的数据库的数据Long和Number的转化字段
- jmeter学习指南之中文乱码
- 新建SVN Repository
- 如何用PS制作1寸证件照
- iOS 实时录音和播放
- 业绩爆发,押注“泛半导体”,TCL押对了吗?
- liunx开发板使用交叉网线连接电脑,通过电脑连接外网的方法
- Linux TCP Timestamps 没鸟用
- patreon cg人物插画作品合集分享
- html画流程图插件,基于SVG的流程图插件Flowchart.js
- 华为机试真题 Java 实现【数字涂色】