如何从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

相关文章

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

【北交大信息所AI-Max2】使用方法

BJTU信息所集群AI_MAX2使用方法 使用的前提是预约到相应的算力卡,拥有登录权限的账号密码,一般为导师组共用一个。 有浏览器、ssh工具就可以。 1.新建集群Terminal 浏览器登陆10.126.62.75 (如果是1集群把75改成66) 交互式开发 执行器选Terminal 密码随便设一个(需记住) 工作空间:私有数据、全部文件 加速器选GeForce_RTX_2080_Ti

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

Mysql BLOB类型介绍

BLOB类型的字段用于存储二进制数据 在MySQL中,BLOB类型,包括:TinyBlob、Blob、MediumBlob、LongBlob,这几个类型之间的唯一区别是在存储的大小不同。 TinyBlob 最大 255 Blob 最大 65K MediumBlob 最大 16M LongBlob 最大 4G

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla