文章目录

  • 第二章、FFmpeg增加RTP协议外部扩展信息解析
    • RTP协议
    • FFmpeg源码分析
    • 为什么要增加RTP协议外部信息解析

第二章、FFmpeg增加RTP协议外部扩展信息解析

第一章RTP协议深入原理介绍

RTP协议

RTP协议格式:

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

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

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

  3. CC:CSRC计数器,占4位,指示CSRC 标识符的个数。

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

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

  6. 序列号:占16位,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。
    应用场景:对视频进行无变形缩放选定要裁剪的坐标点、对应的宽高进行裁

RTP头部协议,前12位为基础字节,对应第一个结构体,如果extension为1时候,才有外部扩展信息,外部扩展信息结构对应第二个结构体,分别对应profile、length、data。

FFmpeg源码分析

第一步打开ffmpeg-5.1源码,搜素rtpdec.c文件找对应的方法

static int rtp_parse_packet_internal(RTPDemuxContext *s, AVPacket *pkt, const uint8_t *buf, int len)


从上图说明过滤的RTP协议外部扩展信息

为什么要增加RTP协议外部信息解析

1、因为一般直播、视频通话、转拉流视频选择角度会放在外部协议
判断是否有外部协议的语句

int extension = (buf[0] & 0x10) >> 4;

下面是我修改方式,主要判断是否视频角度,saveRtpData方法是我自己写的,经过验证上线过可以的,有提供rtp_parse_packet_internal源码参考

修改源码增加修改的部分可以参考,我思路把获取rtp协议的的视频角度pkt->pos传递出去,再传给上下文,后面的代码要自己去写

static int parse_rtp_extension(const uint8_t* buf,int ext_len,int len,int id){int offset=0;int extension_data=-1;int identifier = (buf[4] >> 4) & 0x0f;if(identifier==id){int extension_length = AV_RB16(buf +2);if(extension_length==1){extension_data = (buf[5] & 0x0f); // Identifierswitch (extension_data) {case 0:extension_data=0;break;case 1:extension_data=90;break;case 2:extension_data=180;break;case 3:extension_data=270;break;default: extension_data=-1;break;}if (extension_data!=-1) {return extension_data;}}}while (1) {int profile = AV_RB16(buf+offset);int length = AV_RB16(buf +offset+2);if (profile==id) {extension_data=AV_RB16(buf+offset+4);break;}offset+=4 + (length <=ext_len||offset>=len) {break;}}switch (extension_data) {case -1:extension_data=-4;break;case 0:extension_data=0;break;case 1:extension_data=90;break;case 2:extension_data=180;break;case 3:extension_data=270;break;default: extension_data=-3;break;}return extension_data;}static int parse_rtp_extensionOne(const uint8_t* buf,int ext_len,int len,int id,int*identifier_id,int*extension_len){int offset=0;int extension_data=-1;int identifier = (buf[16] >> 4) & 0x0f;*identifier_id=identifier;if(identifier==id){int extension_length = AV_RB16(buf +14);*extension_len=extension_length;if(extension_length==1){extension_data = (buf[17] & 0x0f); // Identifierswitch (extension_data) {case 0:extension_data=0;break;case 1:extension_data=90;break;case 2:extension_data=180;break;case 3:extension_data=270;break;default: extension_data=-2;break;}}else{extension_data=-3;}}else{extension_data=-4;}return extension_data;}static int saveRtpData(const uint8_t *buf,int len,int sdp_video_id){int size=0;int ext =0;int identifier_id=-1;int extension_len=-1;int rtp_video_data=-1;int extension = (buf[0] & 0x10) >> 4;if (extension) {if(sdp_video_id>0){ext = (AV_RB16(buf + 14) + 1) << 2;rtp_video_data= parse_rtp_extensionOne(buf,ext,len,sdp_video_id,&identifier_id,&extension_len);}if (access("/data/logs/prod/mg-5gcall/ffmpeg-rtp-have-extension_app.log", F_OK) != -1) {// av_log(NULL, AV_LOG_ERROR,"====yrs=====\n" );} else { // av_log(NULL, AV_LOG_ERROR,"====yrs=no====\n" );if (len30) {size=30;}else{size=len;}for (inti = 0; i pos;pkt->pos=-1;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;if(sdp_video_idpos=rtp_angle;#if 0 /* Example data */uint8_t data[] = {0x90,0xfb, 0x34,0x3c,0xe8,0x83, 0x82, 0x80, 0x98, 0x30, 0x59, 0x00, 0xbe, 0xde, 0x00, 0x01, 0x70, 0x01};int rtp_extension_data=-1;int new_ext;// 定义 RTP 扩展字段数据 // sdp_video_id = 7;//id值 // 计算 RTP 扩展字段字节数int ext_total_len =6;int new_len=len+ext_total_len;// 定义和初始化指向 RTP 包头数据的缓冲区指针 bufuint8_t *new_buf = (uint8_t *) malloc(len+ext_total_len);memcpy(new_buf, data, 12+ext_total_len);memcpy(new_buf+12+ext_total_len, buf, len-12);saveRtpData(new_buf,new_len,sdp_video_id);rtp_angle=saveRtpData(new_buf,new_len,sdp_video_id);pkt->pos=rtp_angle; av_log(NULL, AV_LOG_ERROR,"==========sdp_video_id:%d\n", sdp_video_id); av_log(NULL, AV_LOG_ERROR,"==========rtp_angle:%d\n", rtp_angle);int new_payload_type = new_buf[1] & 0x7f;/* NOTE: we can handle only one payload type */ // if (s->payload_type != new_payload_type) // return -1;intnew_seq = AV_RB16(new_buf + 2);st = s->st;new_ext= new_buf[0] & 0x10; av_log(NULL, AV_LOG_ERROR,"==========new_len:%d\n", new_len);new_len -= 12;new_buf += 12;new_len -= 4 * csrc;new_buf += 4 * csrc; if (new_len < 0)return AVERROR_INVALIDDATA; av_log(NULL, AV_LOG_ERROR,"====22======new_len:%d\n", new_len); if (new_ext) { av_log(NULL, AV_LOG_ERROR, "==============new=ext===yes=====\n"); if (new_len < 4) return -1; /* calculate the header extension length (stored as number* of 32-bit words) */ new_ext = (AV_RB16(new_buf + 2) + 1) << 2;rtp_extension_data= parse_rtp_extension(new_buf,new_ext,new_len,7);av_log(NULL, AV_LOG_ERROR,"========rtp_extension_data: %d\n", rtp_extension_data);if (new_len 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){// saveFile(sdp_video_id,-1,-1); return -1;}/* calculate the header extension length (stored as number * of 32-bit words) */ext = (AV_RB16(buf + 2) + 1) << 2;//saveFile(sdp_video_id,len,ext);if (len 0){//rtp_video_data= parse_rtp_extension(buf,ext,len,sdp_video_id);//}len -= 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); //pkt->pos=rtp_video_data;pkt->pos=rtp_angle;//pkt->pos=rtp_extension_data;} else if (st) {if ((rv = av_new_packet(pkt, len)) data, buf, len);pkt->stream_index = st->index; // pkt->pos=rtp_video_data;pkt->pos=rtp_angle; //pkt->pos=rtp_extension_data;} else {return AVERROR(EINVAL);}// now perform timestamp things....finalize_packet(s, pkt, timestamp);return rv;}