H.264的码流封装格式
Annex-B字节流格式(大部分是这种):
大部分编码器的默认输出格式;
每个NAL Unit以规定格式的起始码分割;
起始码:0x 00 00 00 01 或0x 00 00 01
RTP数据包格式:
直接封装NAL Unit,无起始码
每个NAL Unit之前以几个字节表示NAL Unit的长度
NAL Unit字节流格式
标准协议文档:“Annex B - Byte stream format”
描述符:f(n) – n位定长编码
语法元素:
leading_zero_8bits:前缀0,值为0x00,仅在第一个NAL Unit中出现;
zero_byte:0字节;
start_code_prefix_one_3bytes:固定值0x 00 00 01,标记一个NAL Unit的起始位置;
trailing_zero_8bits:后缀0;
查找start_code_prefix之间的数据,是为一个NAL Unit的有效数据;
如:“00 00 00 01 67 42 00 1E E8 58 58 98 80 00 00 00 01 68 C8 ……”
该NAL Unit的实际内容:“67 42 00 1E E8 58 58 98 80”
start_code_prefix:0x00 00 00 01或0x 00 00 01
码流信息提取程序
思路:循环读取字节然后检测是否为00 00 00或00 00 01若是则删除,若不是则存入有效值
int CStreamFile::find_nal_prefix()//提取NAL有效信息
{
UINT8 prefix[3] = { 0 };
UINT8 fileByte;//读进来的字节数值
/*
[0][1][2] = {0 0 0} -> [1][2][0] ={0 0 0} -> [2][0][1] = {0 0 0}
getc() = 1 -> 0 0 0 1
[0][1][2] = {0 0 1} -> [1][2][0] ={0 0 1} -> [2][0][1] = {0 0 1}
*/
m_nalVec.clear();
int pos = 0, getPrefix = 0;
for (int idx = 0; idx < 3; idx++)
{
prefix[idx] = getc(m_inputFile);
m_nalVec.push_back(prefix[idx]);//将读到的内容push到vector
}
while (!feof(m_inputFile))
{
if ((prefix[pos % 3] == 0) && (prefix[(pos + 1) % 3] == 0) && (prefix[(pos + 2) % 3] == 1))
{
//0x 00 00 01 found
getPrefix = 1;
m_nalVec.pop_back();//将起始码从容器中移出来
m_nalVec.pop_back();
m_nalVec.pop_back();
break;
}
else if ((prefix[pos % 3] == 0) && (prefix[(pos + 1) % 3] == 0) && (prefix[(pos + 2) % 3] == 0))
{
if (1 == getc(m_inputFile))
{
//0x 00 00 00 01 found
getPrefix = 2;
m_nalVec.pop_back();//将起始码从容器中移出来
m_nalVec.pop_back();
m_nalVec.pop_back();
break;
}
}
else
{
fileByte = getc(m_inputFile);//获取一个字节
prefix[(pos++) % 3] = fileByte;//将获取到的字节存到prefix(有点像循环缓冲区)
m_nalVec.push_back(fileByte);//将非起始码字节送进vector容器
}
}
return getPrefix;
}
运行结果: