如何从RTP包的AP类型包,获取h265的PPS、SPS、VPS信息

2023-12-29 23:52

本文主要是介绍如何从RTP包的AP类型包,获取h265的PPS、SPS、VPS信息,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ffmpeg播放rtp流,为了降低首开延迟,需要在SDP文件中指定PPS、SPS、VPS信息。抓包后发现wireshark无法解析AP包。需要自己进行AP包解析。RTP协议AP包格式如下:

根据如上信息,我们可以解析AP包,效果如下

  • 40 01,type=32,VPS(视频参数集)
  • 42 01,type=33,SPS(序列参数集)
  • 44 01,type=34,PPS(图像参数集)
  • 4E 01, type=39,SEI(补充增强信息)
  • 26 01,type=19,可能有RADL图像的IDR图像的SS编码数据 IDR
  • 02 01, type=01,被参考的后置图像,且非TSA、非STSA的SS编码数据
  • 46 01,type=35,分隔符,没用。

下图中红色部分是分隔符,橙色是VPS,黑色是SPS,黄色为PPS

SDP中的VPS等信息需要转换成base64。使用下面的函数可转换
#include <stdio.h>
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
#include <string>
#include <string.h>
#include <iostream>


#define AV_BASE64_SIZE(x)  (((x)+2) / 3 * 4 + 1)
#   define AV_RB32(x)                                \
    (((uint32_t)((const uint8_t*)(x))[0] << 24) |    \
               (((const uint8_t*)(x))[1] << 16) |    \
               (((const uint8_t*)(x))[2] <<  8) |    \
                ((const uint8_t*)(x))[3])
using namespace std;
char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
{
    static const char b64[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    char *ret, *dst;
    unsigned i_bits = 0;
    int i_shift = 0;
    int bytes_remaining = in_size;

    if (in_size >= UINT_MAX / 4 ||
        out_size < AV_BASE64_SIZE(in_size))
        return NULL;
    ret = dst = out;
    while (bytes_remaining > 3) {
        i_bits = AV_RB32(in);
        in += 3; bytes_remaining -= 3;
        *dst++ = b64[ i_bits>>26        ];
        *dst++ = b64[(i_bits>>20) & 0x3F];
        *dst++ = b64[(i_bits>>14) & 0x3F];
        *dst++ = b64[(i_bits>>8 ) & 0x3F];
    }
    i_bits = 0;
    while (bytes_remaining) {
        i_bits = (i_bits << 8) + *in++;
        bytes_remaining--;
        i_shift += 8;
    }
    while (i_shift > 0) {
        *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];
        i_shift -= 6;
    }
    while ((dst - ret) & 3)
        *dst++ = '=';
    *dst = '\0';

    return ret;
}

static int doLog = 0;
void hexDump(uint8_t* data,int len){
  if(doLog == 0)
    return;
  printf("[%d]",len);
  int pos = 0;
  uint8_t d = 0;
  while(pos<len){
    d = *(data+pos);
    printf("0x%02x,",(int)d);
    pos++;
  }
  printf("[%d]\n",len);
}
//sprop-vps=QAEMAf//AWAAAAMAkAAAAwAAAwBalZgJ; sprop-sps=QgEBAWAAAAMAkAAAAwAAAwBaoAeCAIh95ZWaSTK8BacIAAADAAgAAAMA8EA=; sprop-pps=RAHBcrRiQA==
//sprop-vps=DAH//wFgAAADALAAAAMAAAMAWqwJ; sprop-sps=AQFgAAADALAAAAMAAAMAWqAPCAPBY2uSRS9NQEBAQCA=; sprop-pps=wPLOcDs0
void getXPSfromAP(uint8_t* ap){
  int pos = 0;
  while(true){
    uint16_t hdr = (ap[pos+2]<<8)|(ap[pos+3]);
    int typ = (hdr>>9)&0x3f;
    int siz = (ap[pos+0]<<8)|(ap[pos+1])-2;
    switch(typ){
      case 32:
      { 
        char str_vps[100]={0};
        uint8_t* vps = (uint8_t*)malloc(siz);
        memcpy(vps,ap+pos+4,siz);
        av_base64_encode(str_vps,100,vps,siz);
        cout<<"sprop-vps="<<str_vps;
        hexDump(vps,siz);
        free(vps);
        break;
      }
      case 33:
      { 
        char str_sps[100]={0};
        uint8_t* sps = (uint8_t*)malloc(siz);
        memcpy(sps,ap+pos+4,siz);
        av_base64_encode(str_sps,100,sps,siz);
        cout<<"; sprop-sps="<<str_sps;
        hexDump(sps,siz);
        free(sps);
        break;
      }
      case 34:
      { 
        char str_pps[100]={0};
        uint8_t* pps = (uint8_t*)malloc(siz);
        memcpy(pps,ap+pos+4,siz);
        av_base64_encode(str_pps,100,pps,siz);
        cout<<"; sprop-pps="<<str_pps<<endl;
        hexDump(pps,siz);
        free(pps);
        return;
        break;
      }
      default:
        break;
    }
    pos += 4;
    pos += siz;
  }
}
int main(int argc, char *argv[]) {
  if(argc>=2){
    doLog = atoi(argv[1]);
  }
 
  uint8_t in[]={0x67, 0x42,0xc0,0x14,0xf4,0x0b,0x04,0xb4,0x20,0x00,0x00,0x03,0x00,0x20,0x00,0x00,0x03,0x03,0xd1,0xe2,0x85,0x54};
    char str_sps[100]={0};
    av_base64_encode(str_sps,100,in,22);
    cout<<"sps'sbasecode:"<<str_sps<<endl;
    uint8_t pps[]={0x68 ,0xce ,0x04 ,0xf2};
  char str_sps2[100]={0};
    av_base64_encode(str_sps2,100,pps,4);
    cout<<"pps'sbasecode:"<<str_sps2<<endl;
 
  uint8_t ap[] = {0x00,0x17,0x40,0x01,0x0c,0x01,0xff,0xff,0x01,0x60,0x00,0x00,0x03,0x00,0xb0,0x00,0x00,0x03,0x00,0x00,0x03,0x00,0x5a,0xac,0x09,0x00,0x22,0x42,
    0x01,0x01,0x01,0x60,0x00,0x00,0x03,0x00,0xb0,0x00,0x00,0x03,0x00,0x00,0x03,0x00,0x5a,0xa0,0x0f,0x08,0x03,0xc1,0x63,0x6b,0x92,0x45,0x2f,
    0x4d,0x40,0x40,0x40,0x40,0x20,0x00,0x08,0x44,0x01,0xc0,0xf2,0xce,0x70,0x3b,0x34,0x00,0x09,0x4e,0x01,0xe5,0x04,0x00,0x00,0x70,0x00,0x80,0x00,
    0x1e,0x4e,0x01,0x89,0x18,0x3a,0x98,0x75,0x30,0x1d,0x4c,0x0b,0xb8,0x7d,0x00,0x40,0x74,0x3d,0x13,0x40,0x42,0x00,0x00,0x04,0xb0,0x00,0x00,0x03,0x00,0xc8,0x80};
  getXPSfromAP(ap);
  return 0;
}
 

这篇关于如何从RTP包的AP类型包,获取h265的PPS、SPS、VPS信息的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/551085

相关文章

C#如何在Excel文档中获取分页信息

《C#如何在Excel文档中获取分页信息》在日常工作中,我们经常需要处理大量的Excel数据,本文将深入探讨如何利用Spire.XLSfor.NET,高效准确地获取Excel文档中的分页信息,包括水平... 目录理解Excel中的分页机制借助 Spire.XLS for .NET 获取分页信息为什么选择 S

springboot3.x使用@NacosValue无法获取配置信息的解决过程

《springboot3.x使用@NacosValue无法获取配置信息的解决过程》在SpringBoot3.x中升级Nacos依赖后,使用@NacosValue无法动态获取配置,通过引入SpringC... 目录一、python问题描述二、解决方案总结一、问题描述springboot从2android.x

springboot的controller中如何获取applicatim.yml的配置值

《springboot的controller中如何获取applicatim.yml的配置值》本文介绍了在SpringBoot的Controller中获取application.yml配置值的四种方式,... 目录1. 使用@Value注解(最常用)application.yml 配置Controller 中

MyBatis中的两种参数传递类型详解(示例代码)

《MyBatis中的两种参数传递类型详解(示例代码)》文章介绍了MyBatis中传递多个参数的两种方式,使用Map和使用@Param注解或封装POJO,Map方式适用于动态、不固定的参数,但可读性和安... 目录✅ android方式一:使用Map<String, Object>✅ 方式二:使用@Param

C# WebAPI的几种返回类型方式

《C#WebAPI的几种返回类型方式》本文主要介绍了C#WebAPI的几种返回类型方式,包括直接返回指定类型、返回IActionResult实例和返回ActionResult,文中通过示例代码介绍的... 目录创建 Controller 和 Model 类在 Action 中返回 指定类型在 Action

golang实现nacos获取配置和服务注册-支持集群详解

《golang实现nacos获取配置和服务注册-支持集群详解》文章介绍了如何在Go语言中使用Nacos获取配置和服务注册,支持集群初始化,客户端结构体中的IpAddresses可以配置多个地址,新客户... 目录golang nacos获取配置和服务注册-支持集群初始化客户端可选参数配置new一个客户端 支

python中的鸭子类型详解

《python中的鸭子类型详解》鸭子类型是Python动态类型系统的灵魂,它通过强调“行为”而非“类型”,赋予了代码极大的灵活性和表现力,本文给大家详细介绍python中的鸭子类型,感兴趣的朋友一起看... 目录1. 核心思想:什么是鸭子类型?2. 与“传统”静态类型语言的对比3. python 中无处不在

Java枚举类型深度详解

《Java枚举类型深度详解》Java的枚举类型(enum)是一种强大的工具,它不仅可以让你的代码更简洁、可读,而且通过类型安全、常量集合、方法重写和接口实现等特性,使得枚举在很多场景下都非常有用,本文... 目录前言1. enum关键字的使用:定义枚举类型什么是枚举类型?如何定义枚举类型?使用枚举类型:2.

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

Java发送SNMP至交换机获取交换机状态实现方式

《Java发送SNMP至交换机获取交换机状态实现方式》文章介绍使用SNMP4J库(2.7.0)通过RCF1213-MIB协议获取交换机单/多路状态,需开启SNMP支持,重点对比SNMPv1、v2c、v... 目录交换机协议SNMP库获取交换机单路状态获取交换机多路状态总结交换机协议这里使用的交换机协议为常