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

  • 相关阅读:
    IDEAL葵花宝典:java代码开发规范插件 GenerateAllSetter、ECtranslation、translation、插件
    IDEAL葵花宝典:java代码开发规范插件 checkstyle、visualVM、PMD 插件
    IDEAL葵花宝典:java代码开发规范插件:GsonFormat插件将JSONObject格式的String 解析成实体
    IDEAL葵花宝典:java代码开发规范插件 FindBugs-IDEA
    IDEAL葵花宝典:java代码开发规范插件 p3c
    IDEAL葵花宝典:java代码开发规范插件 (maven helper)解决maven 包冲突的问题
    分享知识-快乐自己:IDEA下maven编译打包Java项目成jar包但是resource下配置文件无法编译
    分享知识-快乐自己:intellij Idea报错Could not autowire. No beans of...
    Linux apt-get error
    Erlang官方站点
  • 原文地址:https://www.cnblogs.com/wangqiguo/p/4556391.html
Copyright © 2011-2022 走看看