如何获取播放H264原始数据文件的宽高信息(from SPS PPS)

有这样一种需求,给你一个h264原始数据文件,让你直接播放出来,如何实现?

思路是这样的,H264原始数据格式都是 0x00000001后面跟0x67 0x68 0x65 0x41这样的数据,解码需要一个完整的NAL数据单元,我们需要将每个0x00000001以及下一个0x00000001之前的数据读出来,交给解码器解码。

读文件我就不啰嗦了,本文主要讲解如何从SPS获取视频长宽,SPS即0x67开头数据,读到0x00000001 后一个字节是0x67的后面跟的数据就是SPS了。我们看一个封包里面sps的结构:


我们可以看到 最下面的42开始就是0x67后面的SPS数据了,看H264的官方文档可以知道,SPS里面的参数都是按照bit的形式存储的。

我自己写了一个解析SPS的类,代码如下:

[java]  view plain copy
  1. import android.util.Log;  
  2.   
  3. /* 
  4.  * Author:Vincent Luo 
  5.  * Date: 20150615 
  6.  * Description:参考H264标准语法实现对SPS参数的解析 
  7.  */  
  8. public class H264SPSPaser {  
  9.     private static final String TAG = "H264SPSPaser";  
  10.     private static int startBit = 0;  
  11.     /* 
  12.      * 从数据流data中第StartBit位开始读,读bitCnt位,以无符号整形返回 
  13.      */  
  14.     public static short u(byte[] data,int bitCnt,int StartBit){  
  15.         short ret = 0;  
  16.         int start = StartBit;  
  17.         for(int i = 0;i < bitCnt;i++){  
  18.             ret<<=1;  
  19.             if ((data[start / 8] & (0x80 >> (start%8))) != 0)  
  20.             {  
  21.                 ret += 1;  
  22.             }  
  23.             start++;  
  24.         }  
  25.         return ret;  
  26.     }  
  27.     /* 
  28.      * 无符号指数哥伦布编码 
  29.      * leadingZeroBits = −1; 
  30.      * for( b = 0; !b; leadingZeroBits++ ) 
  31.      *    b = read_bits( 1 ) 
  32.      * 变量codeNum 按照如下方式赋值: 
  33.      * codeNum = 2^leadingZeroBits − 1 + read_bits( leadingZeroBits ) 
  34.      * 这里read_bits( leadingZeroBits )的返回值使用高位在先的二进制无符号整数表示。 
  35.      */  
  36.     public static short ue(byte[] data,int StartBit){  
  37.         short ret = 0;  
  38.         int leadingZeroBits = -1;  
  39.         int tempStartBit = (StartBit == -1)?startBit:StartBit;//如果传入-1,那么就用上次记录的静态变量  
  40.          forint b = 0; b != 1; leadingZeroBits++ ){//读到第一个不为0的数,计算前面0的个数  
  41.              b = u(data,1,tempStartBit++);  
  42.          }  
  43.          Log.d(TAG,"ue leadingZeroBits = " + leadingZeroBits + ",Math.pow(2, leadingZeroBits) = " + Math.pow(2, leadingZeroBits) + ",tempStartBit = " + tempStartBit);  
  44.          ret = (short) (Math.pow(2, leadingZeroBits) - 1 + u(data,leadingZeroBits,tempStartBit));  
  45.          startBit = tempStartBit + leadingZeroBits;  
  46.          Log.d(TAG,"ue startBit = " + startBit);  
  47.         return ret;  
  48.     }  
  49.     /* 
  50.      * 有符号指数哥伦布编码 
  51.      * 9.1.1 有符号指数哥伦布编码的映射过程 
  52.      *按照9.1节规定,本过程的输入是codeNum。 
  53.      *本过程的输出是se(v)的值。 
  54.      *表9-3中给出了分配给codeNum的语法元素值的规则,语法元素值按照绝对值的升序排列,负值按照其绝对 
  55.      *值参与排列,但列在绝对值相等的正值之后。 
  56.      *表 9-3-有符号指数哥伦布编码语法元素se(v)值与codeNum的对应 
  57.      *codeNum 语法元素值 
  58.      *  0       0 
  59.      *  1       1 
  60.      *  2       −1 
  61.      *  3       2 
  62.      *  4       −2 
  63.      *  5       3 
  64.      *  6       −3 
  65.      *  k       (−1)^(k+1) Ceil( k÷2 ) 
  66.      */  
  67.     public static int se(byte[] data,int StartBit){  
  68.         int ret = 0;  
  69.         short codeNum = ue(data,StartBit);  
  70.         ret = (int) (Math.pow(-1, codeNum + 1)*Math.ceil(codeNum/2));  
  71.         return ret;  
  72.     }  
  73. }  
只需调用如下接口即可得到宽高:

[java]  view plain copy
  1. int width = (H264SPSPaser.ue(sps,34) + 1)*16;  
  2. int height = (H264SPSPaser.ue(sps,-1) + 1)*16;  
其中参数sps就是42开始的那一串字节流,34指的是宽开始的位置(bit位)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值