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

来源: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下运行没问题)


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值