经过几天日夜,对照 flv_video_file_format_spec_v10_1.pdf,用C写了个f4v文件分析工具。也适应mp4文件分析。
原始文件为 sky.f4v 由ffmpeg生成(ffmpeg -i sky.mov sky.f4v)
链接: https://pan.baidu.com/s/1asrSPJZq1Zv4zQaYqgDsRg 密码: frec
flv.exe (./flv sky.f4v)运行环境64位windows10,cygwin64
链接:https://pan.baidu.com/s/1o5dpI-Akhuat4uykxI9xWQ 密码:2jrr
打印出的BOX层级如下:
+ ftyp + free + mdat + moov + mvhd + trak + tkhd + edts + elst + mdia + mdhd + hdlr + minf + vmhd + dinf + dref + url + stbl + stsd + avc1 + avcC + stts + stss + ctts + stsc + stsz + stco + trak + tkhd + edts + elst + mdia + mdhd + hdlr + minf + smhd + dinf + dref + url + stbl + stsd + mp4a + stts + stsc + stsz + stco + sgpd + sbgp + udta
完整打印附在文件最后,结合网上的资料,写一点个人理解:
EDTS
moov . trak . edts . elst
设置该trak的起始时间
http://blog.jianchihu.net/mp4-elst-box.html
STTS
moov . trak . mdia . minf . stbl . stts
SampleCount = 313
SampleDelta = 512
Sample个数为313,也就是313帧,30帧每秒来算,视频时间为10秒,与mdhd中的10秒吻合(Duration / TimeScale = 160256 / 15360)
SampleDelta * SampleCount = 512 * 313 = 160256 等于mdhd中的Duration
STSS
moov . trak . mdia . minf . stbl . stss
记录关键帧,可以理解为I帧
SyncTable[0] = 1
SyncTable[1] = 251
有两个关键帧,分别是第1和第251。
CTTS
moov . trak . mdia . minf . stbl . ctts
记录每帧的PTS与DTS的差值,打印一共有310相,其中有3项的SampleCount为2,其它项SampleCount均为1,310 + 3 = 313 也就是视频总帧数。
STSC
moov . trak . mdia . minf . stbl . stsc
Sample到Chunk的映射表
(1,2,1) (2,1,1)
这个f4v的stsc中只有两项,意思是,前2个Sample组成1个Chunk,从第2个Chunk开始到最后,每个Chunk只有1个Sample。这样可计算得Chunk总数为 312,与stco中记录个数相等。
STSZ
moov . trak . mdia . minf . stbl . stsz
记录每个Sample字节数,一共313项,等于Sample个数。
STCO
moov . trak . mdia . minf . stbl . stco
记录每个chunk在整个文件中的起始位置,由chunk的起始位置 加上 同一个chunk中前面的Sample字节数,就是当前Sample在文件中的起始位置。如果chunk只有一个Sample,那么该Sample的起始位置就是这个chunk的起始位置。
sgpd与sbgp
这两个BOX网上资料很少,查了ffmpeg和vlc源代码,只有解析,没有看到如何使用这两个BOX中的值,以后有机会更多了解后再补充。
+ ftyp: fileOffset = 0x00000000, size = 0x0000001c + MajorBrand = f4v + MinorVersion = + CompatibleBrands = isom + CompatibleBrands = iso2 + CompatibleBrands = avc1 + free: fileOffset = 0x0000001c, size = 0x00000008 + mdat: fileOffset = 0x00000024, size = 0x004d5715 + moov: fileOffset = 0x004d5739, size = 0x00003175 + mvhd: fileOffset = 0x004d5741, size = 0x0000006c + Version = 0 + Flags = 0 + CreationTime = 0x00000000 + ModificationTime = 0x00000000 + TimeScale = 1000 + Duration = 10435 + Rate = 0x00010000 + Volume = 0x0100 + Matrix = {0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000} + NextTrackID = 3 + trak: fileOffset = 0x004d57ad, size = 0x000015ca + tkhd: fileOffset = 0x004d57b5, size = 0x0000005c + Version = 0 + Flags = 3 + CreationTime = 0x00000000 + ModificationTime = 0x00000000 + TrackID = 1 + Duration = 10434 + Layer = 0x0000 + AlternateGroup = 0x0000 + Volume = 0x0000 + TransformMatrix = {0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000} + Width = 1920 + Height = 1080 + edts: fileOffset = 0x004d5811, size = 0x00000030 + elst: fileOffset = 0x004d5819, size = 0x00000028 + Version = 0 + Flags = 0 + EntryCount = 2 + EditListEntryTable[0] + SegmentDuration = 66 + MediaTime = -1 + MediaRateInteger = 1 + MediaRateFraction = 0 + EditListEntryTable[1] + SegmentDuration = 10434 + MediaTime = 1024 + MediaRateInteger = 1 + MediaRateFraction = 0 + mdia: fileOffset = 0x004d5841, size = 0x00001536 + mdhd: fileOffset = 0x004d5849, size = 0x00000020 + Version = 0 + Flags = 0 + CreationTime = 0x00000000 + ModificationTime = 0x00000000 + TimeScale = 15360 + Duration = 160256 + Language = und + hdlr: fileOffset = 0x004d5869, size = 0x0000002d + Version = 0 + Flags = 0 + Predefined = 0 + HandlerType = Video + Name = VideoHandler + minf: fileOffset = 0x004d5896, size = 0x000014e1 + vmhd: fileOffset = 0x004d589e, size = 0x00000014 + Version = 0 + Flags = 1 + GraphicsMode = 0 + OpColor = (0, 0, 0) + dinf: fileOffset = 0x004d58b2, size = 0x00000024 + dref: fileOffset = 0x004d58ba, size = 0x0000001c + Version = 0 + Flags = 0 + EntryCount = 1 + url : fileOffset = 0x004d58ca, size = 0x0000000c + Version = 0