H.264码流结构

H.264的码流封装格式

在H.264进行编码之后,生成的数据都封装为NAL Unit,多个NAL Unit串在一起形成总的输出码流。

  • 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”
H.264码流结构
H.264码流结构
NAL Unit提取方法

  • 查找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

实践:从码流中读取NAL Unit

// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
typedef unsigned char uint8;

static int find_nal_prefix(ifstream& pfile,vector<uint8> &nalBytes) {
	/*
		00 00 00 01 x x x x x 00 00 00 01
	*/
	uint8 prefix[3] = { 0 };
	/*
		[0][1][2] = {0 0 0}-> [1][2][0]={0 0 0} -> [2][0][1]={0 0 0}->...
		getc()=1
	*/
	nalBytes.clear();
	uint8 x,pos=0;
	int getprefix = 0;
	for (int idx = 0; idx < 3; idx++) {
		x = pfile.get();
		prefix[idx] = x;
		nalBytes.push_back(x);
	}
	while ((x = pfile.get()) != EOF) {
		//cout << x << endl;
		if (prefix[pos %3]==0&& prefix[(pos+1) % 3] == 0&& prefix[(pos + 2) % 3] == 1) {
		 //0x 00 00 01 found
			getprefix = 1;
			nalBytes.pop_back();
			nalBytes.pop_back();
			nalBytes.pop_back();
			break;
		}
		else if (prefix[pos % 3] == 0 && prefix[(pos + 1) % 3] == 0 && prefix[(pos + 2) % 3] == 0) {
			//0x 00 00 00 found
			if (x == 1) {
				//0x 00 00 00 01 found
				getprefix = 2;
				nalBytes.pop_back();
				nalBytes.pop_back();
				nalBytes.pop_back();
				//nalBytes.pop_back();  还没push
				break;
			}
		}
		else {
			prefix[(pos++) % 3] = x;
			nalBytes.push_back(x);
		}
	}
	return getprefix;
}

//void Oc2Hex(int a){
//	char buffer[33];
//	sprintf_s(buffer, "%x", a);
//	cout << buffer << endl;
//}

int main(int argc,char* argv[])
{
	int *p1 = new int[10];
	int *p2 = new int[10]();

	ifstream inFile;
	inFile.open(argv[1], ios::in | ios::binary);
	if (!inFile) {  //条件成立,则说明文件打开成功
		cout << "Error:opening input file failed!" << endl;
		return 0;
	}
	else
		cout << "opening input file success!" << endl;
	
	int x;
	vector<uint8> nalBaytes;
	auto ou = find_nal_prefix(inFile,nalBaytes);
	ou = find_nal_prefix(inFile, nalBaytes);
	for (auto i : nalBaytes)
		printf("%x\t", i);
	printf("\n");
	ou = find_nal_prefix(inFile, nalBaytes);
	for (auto i : nalBaytes)
		printf("%x\t", i);
	printf("\n");
	ou = find_nal_prefix(inFile, nalBaytes);
	for (auto i : nalBaytes)
		printf("%x\t", i);
	printf("\n");
	inFile.close();
    return 0;
}

上一篇:Cat 1模组|广和通L610 LTE Cat 1模组国内首款具备规模出货资质!


下一篇:【H264】码流结构详解