zoukankan      html  css  js  c++  java
  • 从RTSP协议SDP数据中获得二进制的SPS、PPS

    在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("
    ");
    		}		
    	}
    	printf("
    
    
    ");	
    	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("
    ");
    		}		
    	}
    	printf("
    ");	
    	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] == '') --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 ''
    
      // 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] = '';
      return result;
    }
    

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

  • 相关阅读:
    Spring3整合Quartz实现定时作业
    伪静态URLRewrite学习笔记
    VC 获取系统特殊文件夹的路径如:系统目录,桌面等
    正反向代理
    过虚拟机检测
    PDB符号文件信息
    Win64 驱动内核编程-33.枚举与删除对象回调
    Windows 反调试技术——OpenProcess 权限过滤
    Win10如何开启蓝屏记录?Win10开启蓝屏信息记录的方法
    Win7 x64下进程保护与文件保护(ObRegisterCallbacks)
  • 原文地址:https://www.cnblogs.com/wangqiguo/p/4556391.html
Copyright © 2011-2022 走看看