在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项目中取出来的,可以作为小功能独立使用,如果大家有用的着,可以直接拿去使用在项目中:

//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);//解码sps字符串
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);//解码pps字符串
for(int i =0;i<result_size;i++)
{
printf("%02X ",p[i]);
if((i+1)%16==0)
{
printf("\n");
}
}
printf("\n");
return 0 ;
}
/*
程序输出如下: //这里是sps的二进制数据
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 //这里是pps的二进制数据
68 FE 3C B0
*/

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

#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协议媒体数据发包相关的细节

    最近完成了一RTSP代理网关,这是第二次开发做RTSP协议相关的开发工作了,相比11年的简单粗糙的版本,这次在底层TCP/IP通讯和RTSP协议上都有了一些新的积累,这里记录一下.基本的RTSP协议交 ...

  2. RTSP协议介绍 (转)

    1. 实 时流协议RTSP RTSP[3]协 议以客户服务器方式工作,它是一个多媒体播放控制协议,用来使用户在播放从因特网下载的实时数据时能够进行控制,如:暂停/继 续.后退.前进等.因此 RTSP ...

  3. RTSP协议

        1.RTSP与几个相关协议 RTSP(Real Time Streaming Protocol)实时流协议,是用来控制声音或影像的多媒体串流协议,并允许同时多个串流需求控制,传输时所用的网络通 ...

  4. (原)关于获取ffmpeg解析rtsp流sdp中带有sps,pps的情况

     转载请注明出处:http://www.cnblogs.com/lihaiping/p/6612511.html 今天同事准备在android下使用ffmpeg来获取rtsp流,问我如何获取获取sps ...

  5. 从wireshark数据中分析rtmp协议,并提取出H264视频流

    我写的小工具 rtmp_parse.exe 使用用法如先介绍下: -sps  [文件路径] 解析 sps 数据 文件当中的内容就是纯方本的hexstring: 如 42 E0 33 8D 68 05 ...

  6. rtsp 协议 详细讲解

    转载自:http://www.mikewootc.com/wiki/net/protocol/rtsp.html 目录: 概述 RTSP简介 协议特点 协议细节 典型的rtsp交互过程 RTSP消息格 ...

  7. RTSP协议-中文定义

    RTSP协议-中文定义 转自:http://blog.csdn.net/arau_sh/article/details/2982914 E-mail:bryanj@163.com 译者: Bryan. ...

  8. RTP/RTCP/RTSP/SIP/SDP 关系(直接看总结)

    RTP/RTCP/RTSP/SIP/SDP 关系   RTP(实时传输协议,传输层) Real-time Transport Protocol)是用于Internet上针对多媒体数据流的一种传输层协议 ...

  9. RTSP协议详解

        RTSP(Real Time Streaming Protocol)是由Real Network和Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议.RTSP对流媒体提 ...

随机推荐

  1. 2016/12/14---- C3P0

    查询查询一条记录 public UserBean findActiver(String ac) throws SQLException { QueryRunner qr = new QueryRunn ...

  2. 怎么去除google的 安全搜索

    想要避开安全搜索 更改右上角的搜索设置,将搜索语言改为英文,然后保存搜索设置 第二次进入搜索设置里找Filter explicit results前的面的勾去掉即可.

  3. VC++ excel 2 operations

    LPDISPATCH lpDisp;   //lpdispatch,接口指针 // 设置为FALSE时,加上app.Quit(); // 否则EXCEL.EXE进程会一直存在,并且每操作一次就会多开一 ...

  4. C++中四种转换类型的区别

    一.四种转换类型比较: 类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可 ...

  5. ios底层网络请求错误码

    kCFHostErrorHostNotFound = 1, kCFHostErrorUnknown = 2, // Query the kCFGetAddrInfoFailureKey to get ...

  6. iOS真机调试问题-App installation failed,The maximum number of apps for free development profiles has been reached.

    The maximum number of apps for free development profiles has been reached. 源引:http://www.jianshu.com ...

  7. PLSQL往表中插入中文乱码解决办法

    1.查看服务器端编码:select userenv('language') from dual; 2.查看第一行中PARAMETER项中为NLS_LANGUAGE 对应的VALUE项中是否和第一步得到 ...

  8. plink:将bed文件转化为ped,map文件

    用--recode命令,--out表示转化的文件的名字,本例已经命名为“filter” /plink-1.07-x86_64/plink --bfile filter --recode --out f ...

  9. 清除浮动的 why

    如果你想第三个p不被前面的浮动层所影响,就对它进行清除如果没有清除,第三个层就会移到第一个p下面 记住!!浮动是用来布局的~你看你的网页设计图,好几个版块在一条线上就是要浮动了,不需要浮动就是版块跟前 ...

  10. 前端开发必备! 20 个强大的 Sublime Text 插件

    http://www.oschina.net/translate/20-powerful-sublimetext-plugins http://www.w3cplus.com/tools/emmet- ...