您的位置:首页 > 其它

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

2015-08-19 16:18 721 查看
有这样一种需求,给你一个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
plaincopy

import android.util.Log;

/*

* Author:Vincent Luo

* Date: 20150615

* Description:参考H264标准语法实现对SPS参数的解析

*/

public class H264SPSPaser {

private static final String TAG = "H264SPSPaser";

private static int startBit = 0;

/*

* 从数据流data中第StartBit位开始读,读bitCnt位,以无符号整形返回

*/

public static short u(byte[] data,int bitCnt,int StartBit){

short ret = 0;

int start = StartBit;

for(int i = 0;i < bitCnt;i++){

ret<<=1;

if ((data[start / 8] & (0x80 >> (start%8))) != 0)

{

ret += 1;

}

start++;

}

return ret;

}

/*

* 无符号指数哥伦布编码

* leadingZeroBits = −1;

* for( b = 0; !b; leadingZeroBits++ )

* b = read_bits( 1 )

* 变量codeNum 按照如下方式赋值:

* codeNum = 2^leadingZeroBits − 1 + read_bits( leadingZeroBits )

* 这里read_bits( leadingZeroBits )的返回值使用高位在先的二进制无符号整数表示。

*/

public static short ue(byte[] data,int StartBit){

short ret = 0;

int leadingZeroBits = -1;

int tempStartBit = (StartBit == -1)?startBit:StartBit;//如果传入-1,那么就用上次记录的静态变量

for( int b = 0; b != 1; leadingZeroBits++ ){//读到第一个不为0的数,计算前面0的个数

b = u(data,1,tempStartBit++);

}

Log.d(TAG,"ue leadingZeroBits = " + leadingZeroBits + ",Math.pow(2, leadingZeroBits) = " + Math.pow(2, leadingZeroBits) + ",tempStartBit = " + tempStartBit);

ret = (short) (Math.pow(2, leadingZeroBits) - 1 + u(data,leadingZeroBits,tempStartBit));

startBit = tempStartBit + leadingZeroBits;

Log.d(TAG,"ue startBit = " + startBit);

return ret;

}

/*

* 有符号指数哥伦布编码

* 9.1.1 有符号指数哥伦布编码的映射过程

*按照9.1节规定,本过程的输入是codeNum。

*本过程的输出是se(v)的值。

*表9-3中给出了分配给codeNum的语法元素值的规则,语法元素值按照绝对值的升序排列,负值按照其绝对

*值参与排列,但列在绝对值相等的正值之后。

*表 9-3-有符号指数哥伦布编码语法元素se(v)值与codeNum的对应

*codeNum 语法元素值

* 0 0

* 1 1

* 2 −1

* 3 2

* 4 −2

* 5 3

* 6 −3

* k (−1)^(k+1) Ceil( k÷2 )

*/

public static int se(byte[] data,int StartBit){

int ret = 0;

short codeNum = ue(data,StartBit);

ret = (int) (Math.pow(-1, codeNum + 1)*Math.ceil(codeNum/2));

return ret;

}

}

只需调用如下接口即可得到宽高:

[java] view
plaincopy

int width = (H264SPSPaser.ue(sps,34) + 1)*16;

int height = (H264SPSPaser.ue(sps,-1) + 1)*16;

其中参数sps就是42开始的那一串字节流,34指的是宽开始的位置(bit位)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: