0、前言
本文指在从一个H.264码流中提取出一个一段一段的NAL Unit单元
1、理论依据:
2、编码提取思路:
将码流中字节依次保存在一个数组中进行判断,如果不等一001或者0001则将读取的下一个字节存放在数组的第一成员
/*
[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}
*/
3、代码:
// MyAnalyzer.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "stdlib.h"
#include <vector>
using namespace std;
typedef unsigned char uint8;
/* 使用C++的vector容器进行保存 */
vector<uint8> vecNal;
/*
[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}
*/
static int find_nal_prefix(FILE *pFile)
{
int i = 0;
int i32Pos = 0;
uint8 ui8Prefix[3];
vecNal.clear();
for (i = 0; i < 3; i++)
{
ui8Prefix[i] = getc(pFile);
vecNal.push_back(ui8Prefix[i]);
}
/* 判断当前是否为文件尾 */
while (!feof(pFile))
{
if (ui8Prefix[i32Pos % 3] == 0 && ui8Prefix[(i32Pos+1) % 3] == 0 && ui8Prefix[(i32Pos+2) % 3] == 1)/* 此处注意(i32Pos+1) % 3计算需要加括号 */
{
vecNal.pop_back(); /* 将起始码pop出去,不属于NAL单元 */
vecNal.pop_back();
vecNal.pop_back();
break;
}
else if (ui8Prefix[i32Pos % 3] == 0 && ui8Prefix[(i32Pos+1) % 3] == 0 && ui8Prefix[(i32Pos+2) % 3] == 0)
{
if (1 == getc(pFile))
{
vecNal.pop_back();
vecNal.pop_back();
vecNal.pop_back();
break;
}
}
else
{
ui8Prefix[i32Pos%3] = getc(pFile);
vecNal.push_back(ui8Prefix[i32Pos % 3]);
i32Pos++;
}
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int i = 0;
FILE *m_inputFile = NULL;
_tfopen_s(&m_inputFile, argv[1], _T("rb"));
if (NULL != m_inputFile)
{
cout << "open:" << argv[1] << "sucess!" << endl;
}
else
{
cout << "open:" << argv[1] << "failed!" << endl;
return 0;
}
find_nal_prefix(m_inputFile); /* 第一次调用完都是0,因为码流的头部就是一个NAL的起始码 */
find_nal_prefix(m_inputFile);
for (i = 0; i < vecNal.size(); i++)
{
printf("%x ", vecNal.at(i));
}
printf("\n");
find_nal_prefix(m_inputFile);
for (i = 0; i < vecNal.size(); i++)
{
printf("%x ", vecNal.at(i));
}
fclose(m_inputFile);
system("pause");
return 0;
}
程序输出:
码流16进制文件: