该 Box 则包含了真实 H264 码流的SPS PPS等信息。
这里就直接分析字段值
名称 | 实际值(16进制) | 具体值(10进制 / ASCII) | 字段默认值 |
---|---|---|---|
Box length | 00 00 00 2F | 47 | Header 和 Data部分长度 |
Box type | 61 76 63 43 | “avcC” | box 属性值,通常是固定值 |
configuration version | 01 | 1 | 保留位默认0x01 |
avc profile indication | 4D | 77 | H.264编码配置:0x64表示Baseline,0x4D表示Main |
profile compatibility | 40 | ||
avc level indication | 29 | 0 | H.264编码级别 |
reserved | FF | 0b111111 | (6bit)默认都是1 |
length size minus one | FF | 0b11 | (2 bit)读出的每个packet的前几字节代表数据大小 |
reserved | E1 | 0b111 | (3 bit) |
number of sps | E1 | 0b00001 | (5 bit)sps的个数,一般情况是1 |
sps length | 00 18 | 24 | |
sps | 红框部分 | ||
reserved | 01 | 0b000 | (3 bit) |
number of pps | 01 | 0b00001 | (5 bit)pps的个数,一般情况是1 |
pps length | 00 04 | 4 | |
pps | 黑框部分 |
因为上面有些字段出现了 bit 部分,所以我们得弄个专门对bit操作的工具。
// TimeBufferBitStream.h
class TimeBufferBitStream {
private:
void *Buffer;
int len; // Byte
int index=0;
unsigned char BitIndex;
public:
TimeBufferBitStream(void *b, int len);
unsigned char GetBit();
bool IsEnd();
unsigned char GetUChar();
};
// TimeBufferBitStream.cpp
TimeBufferBitStream::TimeBufferBitStream(void *b, int len)
:Buffer(b), len(len), index(0), BitIndex(0)
{
}
unsigned char TimeBufferBitStream::GetBit() {
// if(index >= len) return 0;
unsigned char* b = (unsigned char *)Buffer;
unsigned char ret = b[index]>>(7-BitIndex++)&1;
if(BitIndex==8) {
index++;
BitIndex = 0;
}
return ret;
}
bool TimeBufferBitStream::IsEnd() {
return index>=len;
}
unsigned char TimeBufferBitStream::GetUChar() {
if(len < 1 ) return 0;
if(index==len && BitIndex>0) return 0;
unsigned char* b = (unsigned char *)Buffer;
// 如果上次读取当前字节的一点bit 则这次读取的Char为上次没读取完的Char
if(BitIndex) {
BitIndex = 0;
}
return b[index++];
}
具体Box的定义:
// BaseBox.h
// ...
// 其他 Box 的定义
class TimeAVCCBox : public BaseBox{
public:
unsigned char configuration_version = 0; // 1 保留位默认0x01
unsigned char avc_profile_indication = 0; // 1 保留位默认0x01 0x64即100表示Baseline 0x4D即77表示Main
unsigned char profile_compatibility = 0; // 1
unsigned char avc_level_indication = 0; // 1 H.264编码级别
unsigned char reserved = 0; // 6bit 默认填1
unsigned char length_size_minus_one = 0; // 2bit 读出的每个packet的前几字节代表数据大小
unsigned char reserved2 = 0; // 3bit 默认填1
unsigned char number_of_sps = 0; // 5bit sps的个数,一般情况是1
unsigned short sps_length = 0; // 2 sps 长度
void * sps = nullptr; // sps实际内容
unsigned char reserved3 = 0; // 3bit 默认填1
unsigned char number_of_pps = 0; // 5bit sps的个数,一般情况是1
unsigned short pps_length = 0; // 2 sps 长度
void * pps = nullptr; // sps实际内容
TimeAVCCBox(BoxHeader h);
TimeAVCCBox(BoxHeader h, Timebyte * d): BaseBox(h, d){};
void PrintDataInfo() override;
};
实现
TimeAVCCBox::TimeAVCCBox(BoxHeader h) : BaseBox(h) {
if (h.GetDataSize()) {
data = new Timebyte[h.GetDataSize()];
}
}
void TimeAVCCBox::PrintDataInfo() {
printf("===========================\n");
h.to_string();
TimeBufferBitStream timeBufferBitStream(data, h.GetSize() - 8);
configuration_version = timeBufferBitStream.GetUChar();
avc_profile_indication = timeBufferBitStream.GetUChar();
profile_compatibility = timeBufferBitStream.GetUChar();
avc_level_indication = timeBufferBitStream.GetUChar();
reserved = timeBufferBitStream.GetUChar();
reserved2 = timeBufferBitStream.GetUChar();
sps_length = timeBufferBitStream.GetUChar() << 8 | timeBufferBitStream.GetUChar();
printf("sps: ");
for (int i = 0; i < sps_length; ++i) {
printf("%d ", timeBufferBitStream.GetUChar());
}
printf("\n");
reserved3 = timeBufferBitStream.GetUChar();
pps_length = timeBufferBitStream.GetUChar() << 8 | timeBufferBitStream.GetUChar();
printf("pps: ");
for (int i = 0; i < pps_length; ++i) {
printf("%d ", timeBufferBitStream.GetUChar());
}
printf("\n");
}
完善一下Avc1 Box
// TimeAvc1.cpp
// ...
void TimeAvc1::AnalyzeBoxHeader(BoxHeader header, size_t offset) {
// 如果是avc/h.264编码则构造Avcc Box
// 如果是MPEG-4编码则构造Esds Box
// 如果是MPEG-4编码则构造Hvcc Box
if (header.GetType() == AVCC) {
TimeAVCCBox avccBox(header, data + offset + 8);
avccBox.PrintDataInfo();
}
}
运行结果