标签:
杂谈 |
分类: 音视频 |
-
计算 AVCDecoderConfigurationR
ecord 得到 CodecPrivateData 数据(只有第一帧需要); - 计算 NALUs 得到帧数据。
计算 AVCDecoderConfigurationR
H.264 视频流的 CodecPrivateData 实际上就是 AVCDecoderConfigurationR
注意!FLV 文件中第一个 VIDEOTAG 的 VIDEODATA 的 AVCVIDEOPACKET 的 Data 总是
AVCDecoderConfigurationR
AVCDecoderConfigurationR
aligned(8) class AVCDecoderConfigurationR
unsigned int(8) configurationVersion =
1;
unsigned int(8) AVCProfileIndication;
unsigned int(8) profile_compatibility;
unsigned int(8) AVCLevelIndication;
bit(6) reserved = ‘111111’b;
unsigned int(2) lengthSizeMinusOne;
bit(3) reserved = ‘111’b;
unsigned int(5)
numOfSequenceParameterSe
for (i=0; i< numOfSequenceParameterSe
unsigned int(16) sequenceParameterSetLeng
bit(8*sequenceParameterSetLeng
}
unsigned int(8)
numOfPictureParameterSet
for (i=0; i< numOfPictureParameterSet
unsigned int(16)
pictureParameterSetLengt
bit(8*pictureParameterSetLengt
}
}
下面蓝色的部分就是 FLV 文件中的 AVCDecoderConfigurationR
00000130h: 00 00 00 17 00 00 00 00
00000140h:
00000150h:
根据 AVCDecoderConfigurationR
-
configurationVersion =
01 -
AVCProfileIndication =
4D -
profile_compatibility =
40 -
AVCLevelIndication =
15 -
lengthSizeMinusOne =
FF <- 非常重要,是 H.264 视频中 NALU 的长度,计算方法是 1 + (lengthSizeMinusOne & 3) -
numOfSequenceParameterSe
ts = E1 <- SPS 的个数,计算方法是 numOfSequenceParameterSe ts & 0x1F -
sequenceParameterSetLeng
th = 00 0A <- SPS 的长度 -
sequenceParameterSetNALU
nits = 67 4D 40 15 96 53 01 00 4A 20 <- SPS -
numOfPictureParameterSet
s = 01 <- PPS 的个数 -
pictureParameterSetLengt
h = 00 05 <- PPS 的长度 -
pictureParameterSetNALUn
its = 68 E9 23 88 00 <- PPS
因此 CodecPrivateData 的字符串表示就是
但是设置 MediaStreamAttributeKeys
也就是说,Silverlight 的 H.264 解码器会读取第一帧前面的 CodecPrivateData 数据来进行配置。
因为 CodecPrivateData 数据已经包含视频流的解码器参数(包括视频的宽高),所以就不需要设置
MediaStreamAttributeKeys
计算 NALU 得到帧数据
FLV 文件中 VIDEOTAG 的 VIDEODATA 的 AVCVIDEOPACKET 的 Data 不是原始视频帧数据,而是一个或更多个 NALU 数据片段。在这篇文章中,你认为 H.264 视频帧数据是由多个 NALU 组成的。当然实际上并不是这样,关于这部分的概念请自行 Google,本文将不做讨论。
下面是 FLV 文件中 VIDEOTAG 的 VIDEODATA 的 AVCVIDEOPACKET 的 Data 属性的数据(第一帧数据)。
- 红色的部分是 NALU 数据的长度,而红色部分的长度则由 lengthSizeMinusOne 决定。
- 蓝色的部分是 NALU 数据部分。
- 删除的部分是废弃的数据。
00000300h: 00 00 00 00 00 17 01 00 00
22
00000310h:
00000320h:
00000330h:
00000340h:
00000350h:
00000360h:
00000370h:
00000380h:
00000390h:
000003a0h:
000003b0h:
000003c0h:
000003d0h:
000003e0h:
000003f0h:
帧数据是将多个 NALU 使用 byte[] {00, 00, 01} 连接的字节数组。
byte[] = {
00,00,01,65,88,
80,40,05,B7,95,53,67,FF,84,6C,07,EB,00,F8,45,FB,
F9,15,71,0D,A4,C5,2C,00,00,03,00,00,03,00,3F,2B,
5B,06,57,48,29,F4,08,00,00,0A,10,02,D0,7A,FE,
00,00,01,65,01,22,22,01,00,17,B7,95,53,67,FF,84,
6C,07,EB,00,F8,45,FB,F9,15,71,0D,A4,C5,2C,00,E8,
F3,37,75,43,90,00,00,03,00,15,EF,AA,A8,53,86,01,
DD,57,60,00,00,03,01,59,0C,F4,3C,
00,00,01,65,
00,90,88,80,40,05,B7,95,53,67,FF,84,6C,07,EB,00,
F8,45,FB,F9,15,71,0D,A4,C5,2C,00,00,03,00,00,03,
00,3F,2B,5B,06,57,48,29,F4,08,00,00,0A,10,02,D0,
7A,FE,
00,00,01,65,00,D8,88,80,40,05,B7,95,53,
67,FF,84,6C,07,EB,00,F8,45,FB,F9,15,71,0D,A4,C5,
2C,00,E8,F3,37,75,43,90,00,00,03,00,15,EF,AA,A8,
53,86,01,DD,57,60,00,00,03,01,59,0C,F4,3C
};
如果是第一帧数据,那么前面还要加上 CodecPrivateData 数据。
byte[] = {
00,00,01,67,4D,40,15,96,53,01,00,4A,20,
00,00,01,68,E9,23,88,00,
00,00,01,65,88,
80,40,05,B7,95,53,67,FF,84,6C,07,EB,00,F8,45,FB,
F9,15,71,0D,A4,C5,2C,00,00,03,00,00,03,00,3F,2B,
5B,06,57,48,29,F4,08,00,00,0A,10,02,D0,7A,FE,
00,00,01,65,01,22,22,01,00,17,B7,95,53,67,FF,84,
6C,07,EB,00,F8,45,FB,F9,15,71,0D,A4,C5,2C,00,E8,
F3,37,75,43,90,00,00,03,00,15,EF,AA,A8,53,86,01,
DD,57,60,00,00,03,01,59,0C,F4,3C,
00,00,01,65,
00,90,88,80,40,05,B7,95,53,67,FF,84,6C,07,EB,00,
F8,45,FB,F9,15,71,0D,A4,C5,2C,00,00,03,00,00,03,
00,3F,2B,5B,06,57,48,29,F4,08,00,00,0A,10,02,D0,
7A,FE,
00,00,01,65,00,D8,88,80,40,05,B7,95,53,
67,FF,84,6C,07,EB,00,F8,45,FB,F9,15,71,0D,A4,C5,
2C,00,E8,F3,37,75,43,90,00,00,03,00,15,EF,AA,A8,
53,86,01,DD,57,60,00,00,03,01,59,0C,F4,3C
};