在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. dubbox新特性介绍

    dubbx是当当网对原阿里dubbo2.x的升级,并且兼容原有的dubbox.其中升级了zookeeper和spring版本,并且支持restfull风格的远程调用. dubbox git地址:  h ...

  2. 关于网站高性能中磁盘cpu以及内存对网站性能的影响

    之前和同事聊天的时候,提到了这个硬件方面(包括内存,cpu,以及硬盘的存储选择),个人认为可以从这几个方面来提高底层硬件的性能,从而提高网站的整体吞吐量和速度. 一.主机: (1).CPU:决定处理的 ...

  3. XidianOJ 1120 Gold of Orz Pandas

    题目描述 Orz Panda is addicted to one RPG game. To make his character stronger, he have to fulfil tasks ...

  4. MySQL相关操作知识

    1.解决客户端联不上MySQL服务器的问题: GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '' WITH GRANT OPTION; ...

  5. VC++ CButton::SetCheck 的使用方法

    CButton::SetCheck void SetCheck(int nCheck); 参数 nCheck 指定检查状态. 此参数可以是下列值之一: 值                        ...

  6. WebForm 简单控件、复合控件

    简单控件: Label:被编译成span 样式表里设置lable的高度:  display:inline-block; Text  --文本 ForeColor  --字体颜色 Visible  -- ...

  7. BackgroundWorker控件

    在我们的程序中,经常会有一些耗时较长的运算,为了保证用户体验,不引起界面不响应,我们一般会采用多线程操作,让耗时操作在后台完成,完成后再进行处理或给出提示,在运行中,也会时时去刷新界面上的进度条等显示 ...

  8. eclipse tomcat maven热部署

    1.  tomcat插件 如果是Kepler的话,已经自带了tomcat插件,如果没有,到http://www.eclipsetotale.com/tomcatPlugin.html下载安装或在线安装 ...

  9. scala学习:apply方法

    摘抄两段话: 在明确了方法调用的接收者的情况下,若方法只有一个参数时,调用的时候就可以省略点及括号.如 " to ",实际完整调用是 ".to()".但 &qu ...

  10. 如何用Jquery实现 ,比如点击图片之后 ,该图片变成向下的箭头,再点击向下箭头的图片 又变成原始图片呢

    <!DOCTYPE html><html><head><meta charset="utf-8" /><title>切换 ...