H264数据包格式
H264数据是通过连续的00 00 01
或00 00 00 01
进行分隔的,分隔数据之后的一个字节包含三个方面,分别为
- 第1位禁止位,值为1表示语法出错
- 第2~3位为参考级别
- 第4~8为是nal单元类型
现给出一段代码,进行数据分析:
#include <stdio.h>
#include <windows.h>
typedef enum {
NALU_TYPE_SLICE = 1,
NALU_TYPE_DPA = 2,
NALU_TYPE_DPB = 3,
NALU_TYPE_DPC = 4,
NALU_TYPE_IDR = 5,
NALU_TYPE_SEI = 6,
NALU_TYPE_SPS = 7,
NALU_TYPE_PPS = 8,
NALU_TYPE_AUD = 9,
NALU_TYPE_EOSEQ = 10,
NALU_TYPE_EOSTREAM = 11,
NALU_TYPE_FILL = 12,
} NaluType;
typedef enum {
NALU_PRIORITY_DISPOSABLE = 0,
NALU_PRIRITY_LOW = 1,
NALU_PRIORITY_HIGH = 2,
NALU_PRIORITY_HIGHEST = 3
} NaluPriority;
void printfH264(int j, int i, int nLen, int nFrameType)
{
printf("%d %d", j, i);
int nForbiddenBit = (nFrameType>>7) & 0x1;//第1位禁止位,值为1表示语法出错
int nReference_idc = (nFrameType>>5) & 0x03;//第2~3位为参考级别
int nType = nFrameType & 0x1f;//第4~8为是nal单元类型 0x1f=31
printf(" ");
switch(nReference_idc){
case NALU_PRIORITY_DISPOSABLE://可丢弃
printf("DISPOS");
break;
case NALU_PRIRITY_LOW:
printf("LOW");
break;
case NALU_PRIORITY_HIGH:
printf("HIGH");
break;
case NALU_PRIORITY_HIGHEST:
printf("HIGHEST");
break;
}
//4-8
printf(" ");
switch(nType)
{
case NALU_TYPE_SLICE:
printf("不分区,非IDR图像的片");
break;
case NALU_TYPE_DPA://片分区A
printf("DPA");
break;
case NALU_TYPE_DPB://片分区B
printf("DPB");
break;
case NALU_TYPE_DPC://片分区C
printf("DPC");
break;
case NALU_TYPE_IDR: // IDR图像中的片 I帧=5
printf("IDR");
break;
case NALU_TYPE_SEI:// 补充增强信息单元(SEI)
printf("SEI");
break;
case NALU_TYPE_SPS:
printf("SPS");
break;
case NALU_TYPE_PPS:
printf("PPS");
break;
case NALU_TYPE_AUD:// 序列结束
printf("AUD");
break;
case NALU_TYPE_EOSEQ://序列结束
printf("EOSEQ");
break;
case NALU_TYPE_EOSTREAM://码流借宿
printf("EOSTREAM");
break;
case NALU_TYPE_FILL://填充
printf("FILL");
break;
case 24:
printf("STAP-A 单一时间的组合包");
break;
case 25:
printf("STAP-B 单一时间的组合包");
break;
case 26:
printf("MTAP16 多个时间的组合包");
break;
case 27:
printf("MTAP24 多个时间的组合包");
break;
case 28:
printf("FU-A 分片的单元");
break;
case 29:
printf(" FU-B 分片的单元");
break;
default:
printf("没有定义 %d", nType);
break;
}
printf(" %d\r\n", nLen);
}
int GetLen(int nPos, int nTotalSize, BYTE* btData)
{
int nStart = nPos;
while (nStart < nTotalSize)
{
if (btData[nStart] == 0x00 && btData[nStart + 1] == 0x00 && btData[nStart + 2] == 0x01)
{
return nStart - nPos;
}
else if (btData[nStart] == 0x00 && btData[nStart + 1] == 0x00 && btData[nStart + 2] == 0x00 && btData[nStart + 3] == 0x01)
{
return nStart - nPos;
}
else
{
nStart++;
}
}
return nTotalSize - nPos;//最后一帧。
}
int _tmain(int argc, _TCHAR* argv[])
{
BYTE *btData = NULL;
DWORD dwFileSize = 0;
HANDLE hFile = CreateFile(L"D:\\video.h264", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE){
dwFileSize = GetFileSize(hFile, NULL);
btData = new BYTE[dwFileSize];
memset(btData, 0, dwFileSize);
DWORD dwRead = 0;
ReadFile(hFile, btData, dwFileSize, &dwRead, NULL);
CloseHandle(hFile);
}
int j = 0;//多少帧
int i = 0;//偏移量
while (i < dwFileSize - 4)
{
if (btData[i] == 0x00 && btData[i + 1] == 0x00 && btData[i + 2] == 0x01)
{
int nLen = GetLen(i + 3, dwFileSize, btData);
printfH264(j, i, nLen, btData[i + 3]);
j++;
i += 3;
}
else if (btData[i] == 0x00 && btData[i + 1] == 0x00 && btData[i + 2] == 0x00 && btData[i + 3] == 0x01)
{
int nLen = GetLen(i + 4, dwFileSize, btData);
printfH264(j, i, nLen, btData[i + 4]);
j++;
i += 4;
}
else{
i++;
}
}
if (btData){
delete[] btData;
}
return 0;
}