从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下运行没问题)
从RTSP协议SDP数据中获得二进制的SPS、PPS相关推荐
- 从RTSP协议SDP数据中获得H264中的的SPS、PPS
1. 如何解析SDP中包含的H.264的SPS和PPS串 SDP中的H.264的SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高, ...
- 图像编码中的小白问题sps ,pps ,nalu ,frame ,silce ect....
图像编码中的小白问题sps ,pps ,nalu ,frame ,silce ect.... 转载于:https://www.cnblogs.com/jingzhishen/p/5401222.htm ...
- RTP中H264封装NALU(SPS,PPS等)
NAL的英文全称为Network Abstract Layer,即网络抽象层,在H264/AVC视频编解码标准中,整个系统框架分为两个层面,视频编解码层面(VCL)和网络抽象层面(NAL).VCL负 ...
- RTSP协议详解(先留着,以后用到时候好找)
原文来自: http://blog.csdn.net/chenyanxu/article/details/2728427 关于 RTSP. RTSP协议是一个非常类似HTTP协议的流控制协议.它们都使 ...
- RTSP协议,感觉还不错
关于 RTSP. RTSP协议是一个非常类似HTTP协议的流控制协议.它们都使用纯文本来发送信息,而且rtsp协议的语法也和HTTP类似.Rtsp一开始这样设计,也是为了能够兼容使用以前写的HTTP协 ...
- RTSP协议探秘:从原理到C++实践,解锁实时流媒体传输之道
目录标题 引言 RTSP协议基础 RTSP协议的组成与工作原理 RTSP协议的组成 RTSP协议的工作原理 RTSP协议与其他流媒体协议的比较 RTSP协议的基本功能与用途 RTSP协议详解 RTSP ...
- rtsp协议格式解析
前言 网上关于rtsp的文章很多,但大多是抽象的理论介绍,从理论学习到实际上手开发往往还有一段距离.然而,没有实际开发经验的支撑,理论又很难理解到位. 本系列文章将从流媒体协议的基础原理开始,通过抓包 ...
- 视频【编码】原理(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, ...
- rtsp协议中数据的分包
前言 RTSP视频传输推流中,数据采用数据包的形式推送到指定端口,一个完整数据包由包头和包内数据组成. 由于H.264与H.265压缩数据格式不一致,故两者相关接口数据协议也不一致. 在标准以太网通信 ...
最新文章
- css去掉a标签点击后的虚线框
- 亚马逊提出无监督虚拟增强句子表征学习框架,效果超越SimCSE
- 定义一个数组返回最大子数组的值(2)
- python3 数组重复数字,[python3] 3_01 数组中重复的数字
- C++ cin.sync()和cin.ignore()
- Android 6.0及以上版本动态申请权限,11权限
- 3-34Pytorch与nn库
- python1234出栈_Python数据结构与算法3——栈和队列
- cyhper study
- Python Lex Yacc手册
- EXCEL中制作省市区行政区地图
- BSN区块链服务网络介绍
- 【Unity笔记】连招动画切换方式(一)
- 【C语言】qsort()函数详解
- 明天见丨云和恩墨生态产品发布会双平台直播,三款新品即将揭晓
- angularjs 同步請求_AngularJS 应用请求设置同步问题~
- windows下的host文件在哪里,有什么作用?
- div+css让div内部元素均匀分布
- Matlab中fullfile函数在UI界面中调用
- matlab安装方法以及在重复弹出mathwoks software activation界面的解决办法(需要的license.lic文件内容)