来源:http://www.w2bc.com/Article/43572

在RTSP协议的交互过程中,第二步客户端发送DESCRIBE请求之后,服务端会返回SDP内容,该SDP内容中有关于媒体和会话的描述,本篇文章主要给出如何从SDP字符串中得到H264视频信息中的sps、pps的二进制数据。

我们知道,在RTSP协议中DESCRIBE请求回复内容的SDP部分中,如果服务端的直播流的视频是H264的编码格式的话,那么在SDP中会将H264的sps、pps信息通过Base64编码成字符串发送给客户端(也就是解码器端),sps称为序列参数集,pps称为图形参数集。这两个参数中包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高,deblock滤波器等。这样解码器就可以在DESCRIBE阶段,利用这些参数初始化解码器的设置了。那么如何将SDP中的字符串还原成sps、pps的二进制数据呢。下面的部分代码是从live555项目中取出来的,可以作为小功能独立使用,如果大家有用的着,可以直接拿去使用在项目中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//main.cpp的内容
#include <stdio.h>
#include "Base64.h"
int main()
{
     /*
         RTSP 响应的SDP的内容中sprop-parameter-sets键值:
         sprop-parameter-sets=Z2QAKq2wpDBSAgFxQWKQPQRWFIYKQEAuKCxSB6CKwpDBSAgFxQWKQPQRTDoUKQNC4oJHMGIemHQoUgaFxQSOYMQ9MOhQpA0LigkcwYh6xEQmIVilsQRWUURJsogxOU4QITKUIEVlCCTYQVhBMJQhMIjGggWQJFaIGBJZBAaEnaMIDwsSWQQKCwsrRBQYOWQweO0YEBZASNAogszlAUAW7/wcFBwMQAABdwAAr8g4AAADAL68IAAAdzWU//+MAAADAF9eEAAAO5rKf//CgA==,aP48sA==;
         其中逗号前面的内容是sps的二进制数据被base64之后的结果
         而逗号后面的内容(不要分号,分号是sdp中键值对的分隔符),是pps的内容
         使用live555中的base64Decode函数分别对这两部分进行反base64解码得到的二进制数据就是h264中的sps pps 的二进制内容
         分别是以67 和 68 开头
     */
     char * sps_sdp = "Z2QAKq2wpDBSAgFxQWKQPQRWFIYKQEAuKCxSB6CKwpDBSAgFxQWKQPQRTDoUKQNC4oJHMGIemHQoUgaFxQSOYMQ9MOhQpA0LigkcwYh6xEQmIVilsQRWUURJsogxOU4QITKUIEVlCCTYQVhBMJQhMIjGggWQJFaIGBJZBAaEnaMIDwsSWQQKCwsrRBQYOWQweO0YEBZASNAogszlAUAW7/wcFBwMQAABdwAAr8g4AAADAL68IAAAdzWU//+MAAADAF9eEAAAO5rKf//CgA==" ;
     char * pps_sdp = "aP48sA==" ;
     unsigned int result_size=0;
     unsigned char * p = base64Decode(sps_sdp,result_size);
     for ( int i =0;i<result_size;i++)
     {
         printf ( "%02X " ,p[i]);
         if ((i+1)%16==0)
         {
             printf ( "\n" );
         }      
     }
     printf ( "\n\n\n" );  
     p = base64Decode(pps_sdp,result_size);
     for ( int i =0;i<result_size;i++)
     {
         printf ( "%02X " ,p[i]);
         if ((i+1)%16==0)
         {
             printf ( "\n" );
         }      
     }
     printf ( "\n" );  
     return 0 ;
}<br>
/*
程序的解码输出如下,得到的分别是3500的sps和pps内容:
67 64 00 2A AD B0 A4 30 52 02 01 71 41 62 90 3D
04 56 14 86 0A 40 40 2E 28 2C 52 07 A0 8A C2 90
C1 48 08 05 C5 05 8A 40 F4 11 4C 3A 14 29 03 42
E2 82 47 30 62 1E 98 74 28 52 06 85 C5 04 8E 60
C4 3D 30 E8 50 A4 0D 0B 8A 09 1C C1 88 7A C4 44
26 21 58 A5 B1 04 56 51 44 49 B2 88 31 39 4E 10
21 32 94 20 45 65 08 24 D8 41 58 41 30 94 21 30
88 C6 82 05 90 24 56 88 18 12 59 04 06 84 9D A3
08 0F 0B 12 59 04 0A 0B 0B 2B 44 14 18 39 64 30
78 ED 18 10 16 40 48 D0 28 82 CC E5 01 40 16 EF
FC 1C 14 1C 0C 40 00 01 77 00 00 AF C8 38 00 00
03 00 BE BC 20 00 00 77 35 94 FF FF 8C 00 00 03
00 5F 5E 10 00 00 3B 9A CA 7F FF C2 80
68 FE 3C B0
*/

其中用到的一个主要函数 base64Decode 的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "Base64.h"
#include "strDup.h"
#include <string.h>
static char base64DecodeTable[256];
static void initBase64DecodeTable() {
   int i;
   for (i = 0; i < 256; ++i) base64DecodeTable[i] = ( char )0x80;
       // default value: invalid
   for (i = 'A' ; i <= 'Z' ; ++i) base64DecodeTable[i] = 0 + (i - 'A' );
   for (i = 'a' ; i <= 'z' ; ++i) base64DecodeTable[i] = 26 + (i - 'a' );
   for (i = '0' ; i <= '9' ; ++i) base64DecodeTable[i] = 52 + (i - '0' );
   base64DecodeTable[(unsigned char ) '+' ] = 62;
   base64DecodeTable[(unsigned char ) '/' ] = 63;
   base64DecodeTable[(unsigned char ) '=' ] = 0;
}
unsigned char * base64Decode( char const * in, unsigned& resultSize,
                 Boolean trimTrailingZeros) {
   static Boolean haveInitedBase64DecodeTable = False;
   if (!haveInitedBase64DecodeTable) {
     initBase64DecodeTable();
     haveInitedBase64DecodeTable = True;
   }
   unsigned char * out = (unsigned char *)strDupSize(in); // ensures we have enough space
   int k = 0;
   int const jMax = strlen (in) - 3;
      // in case "in" is not a multiple of 4 bytes (although it should be)
   for ( int j = 0; j < jMax; j += 4) {
     char inTmp[4], outTmp[4];
     for ( int i = 0; i < 4; ++i) {
       inTmp[i] = in[i+j];
       outTmp[i] = base64DecodeTable[(unsigned char )inTmp[i]];
       if ((outTmp[i]&0x80) != 0) outTmp[i] = 0; // pretend the input was 'A'
     }
     out[k++] = (outTmp[0]<<2) | (outTmp[1]>>4);
     out[k++] = (outTmp[1]<<4) | (outTmp[2]>>2);
     out[k++] = (outTmp[2]<<6) | outTmp[3];
   }
   if (trimTrailingZeros) {
     while (k > 0 && out[k-1] == '\0' ) --k;
   }
   resultSize = k;
   unsigned char * result = new unsigned char [resultSize];
   memmove (result, out, resultSize);
   delete [] out;
   return result;
}
static const char base64Char[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
char * base64Encode( char const * origSigned, unsigned origLength) {
   unsigned char const * orig = (unsigned char const *)origSigned; // in case any input bytes have the MSB set
   if (orig == NULL) return NULL;
   unsigned const numOrig24BitValues = origLength/3;
   Boolean havePadding = origLength > numOrig24BitValues*3;
   Boolean havePadding2 = origLength == numOrig24BitValues*3 + 2;
   unsigned const numResultBytes = 4*(numOrig24BitValues + havePadding);
   char * result = new char [numResultBytes+1]; // allow for trailing '\0'
   // Map each full group of 3 input bytes into 4 output base-64 characters:
   unsigned i;
   for (i = 0; i < numOrig24BitValues; ++i) {
     result[4*i+0] = base64Char[(orig[3*i]>>2)&0x3F];
     result[4*i+1] = base64Char[(((orig[3*i]&0x3)<<4) | (orig[3*i+1]>>4))&0x3F];
     result[4*i+2] = base64Char[((orig[3*i+1]<<2) | (orig[3*i+2]>>6))&0x3F];
     result[4*i+3] = base64Char[orig[3*i+2]&0x3F];
   }
   // Now, take padding into account.  (Note: i == numOrig24BitValues)
   if (havePadding) {
     result[4*i+0] = base64Char[(orig[3*i]>>2)&0x3F];
     if (havePadding2) {
       result[4*i+1] = base64Char[(((orig[3*i]&0x3)<<4) | (orig[3*i+1]>>4))&0x3F];
       result[4*i+2] = base64Char[(orig[3*i+1]<<2)&0x3F];
     } else {
       result[4*i+1] = base64Char[((orig[3*i]&0x3)<<4)&0x3F];
       result[4*i+2] = '=' ;
     }
     result[4*i+3] = '=' ;
   }
   result[numResultBytes] = '\0' ;
   return result;
}

完整demo下载(Ubuntu Linux下运行没问题)

从RTSP协议SDP数据中获得二进制的SPS、PPS相关推荐

  1. 从RTSP协议SDP数据中获得H264中的的SPS、PPS

    1. 如何解析SDP中包含的H.264的SPS和PPS串 SDP中的H.264的SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高, ...

  2. 图像编码中的小白问题sps ,pps ,nalu ,frame ,silce ect....

    图像编码中的小白问题sps ,pps ,nalu ,frame ,silce ect.... 转载于:https://www.cnblogs.com/jingzhishen/p/5401222.htm ...

  3. RTP中H264封装NALU(SPS,PPS等)

    NAL的英文全称为Network  Abstract Layer,即网络抽象层,在H264/AVC视频编解码标准中,整个系统框架分为两个层面,视频编解码层面(VCL)和网络抽象层面(NAL).VCL负 ...

  4. RTSP协议详解(先留着,以后用到时候好找)

    原文来自: http://blog.csdn.net/chenyanxu/article/details/2728427 关于 RTSP. RTSP协议是一个非常类似HTTP协议的流控制协议.它们都使 ...

  5. RTSP协议,感觉还不错

    关于 RTSP. RTSP协议是一个非常类似HTTP协议的流控制协议.它们都使用纯文本来发送信息,而且rtsp协议的语法也和HTTP类似.Rtsp一开始这样设计,也是为了能够兼容使用以前写的HTTP协 ...

  6. RTSP协议探秘:从原理到C++实践,解锁实时流媒体传输之道

    目录标题 引言 RTSP协议基础 RTSP协议的组成与工作原理 RTSP协议的组成 RTSP协议的工作原理 RTSP协议与其他流媒体协议的比较 RTSP协议的基本功能与用途 RTSP协议详解 RTSP ...

  7. rtsp协议格式解析

    前言 网上关于rtsp的文章很多,但大多是抽象的理论介绍,从理论学习到实际上手开发往往还有一段距离.然而,没有实际开发经验的支撑,理论又很难理解到位. 本系列文章将从流媒体协议的基础原理开始,通过抓包 ...

  8. 视频【编码】原理(H.264 librtmp推流),图像编码中sps ,pps ,nalu ,frame ,silce ect

    视频编码格式:H264, VC-1, MPEG-2, MPEG4-ASP (Divx/Xvid), VP8, MJPEG 等.  音频编码格式:AAC, AC3, DTS(-HD), TrueHD, ...

  9. rtsp协议中数据的分包

    前言 RTSP视频传输推流中,数据采用数据包的形式推送到指定端口,一个完整数据包由包头和包内数据组成. 由于H.264与H.265压缩数据格式不一致,故两者相关接口数据协议也不一致. 在标准以太网通信 ...

最新文章

  1. css去掉a标签点击后的虚线框
  2. 亚马逊提出无监督虚拟增强句子表征学习框架,效果超越SimCSE
  3. 定义一个数组返回最大子数组的值(2)
  4. python3 数组重复数字,[python3] 3_01 数组中重复的数字
  5. C++ cin.sync()和cin.ignore()
  6. Android 6.0及以上版本动态申请权限,11权限
  7. 3-34Pytorch与nn库
  8. python1234出栈_Python数据结构与算法3——栈和队列
  9. cyhper study
  10. Python Lex Yacc手册
  11. EXCEL中制作省市区行政区地图
  12. BSN区块链服务网络介绍
  13. 【Unity笔记】连招动画切换方式(一)
  14. 【C语言】qsort()函数详解
  15. 明天见丨云和恩墨生态产品发布会双平台直播,三款新品即将揭晓
  16. angularjs 同步請求_AngularJS 应用请求设置同步问题~
  17. windows下的host文件在哪里,有什么作用?
  18. div+css让div内部元素均匀分布
  19. Matlab中fullfile函数在UI界面中调用
  20. matlab安装方法以及在重复弹出mathwoks software activation界面的解决办法(需要的license.lic文件内容)

热门文章

  1. Java Set常用方法总结
  2. 转帖matlab_1_图像处理imfinfo_imshow_funtion
  3. steam搬砖,适合个人操作的创业项目
  4. 全国电子设计大赛总结 (高职组)
  5. PHP查找二维数组的内容
  6. Win命令窗口设置中文chcp
  7. 《那些年啊,那些事——一个程序员的奋斗史》——64
  8. Android环境安装与配置
  9. 各种数据结构及其应用场景
  10. 白盒测试之语句覆盖、判定覆盖、条件覆盖等