每天一点点_音视频_MP4_BOX

首先, Box 里的字节序为网络字节序,也就是大端字节序(Big-Endian),简单的说,就是一个32位的4字节整数存储方式为高位字节在内存的低端。

Box 由 header 和 body 组成,其中 header 统一指明 box 的大小和类型, body 根据类型有不同的意义和格式。

标准的box开头的4个字节(32位)为box size,该大小包括box header和box body整个box的大小,这样我们就可以在文件中定位各个box。如果size为1,则表示这个box的大小为large size,真正的size值要在largesize域上得到。(实际上只有“mdat”类型的box才有可能用到large size。)如果size为0,表示该box为文件的最后一个box,文件结尾即为该box结尾。(同样只存在于“mdat”类型的box中。

size后面紧跟的32位为box type,一般是4个字符,如“ftyp”、“moov”等,这些box type都是已经预定义好的,分别表示固定的意义。如果是“uuid”,表示该box为用户扩展类型。如果box type是未定义的,应该将其忽略。

File Type Box(ftyp)

该box有且只有1个,并且只能被包含在文件层,而不能被其他box包含。该box应该被放在文件的最开始,指示该MP4文件应用的相关信息。

“ftyp” 的body依次包括1个32位的major brand(4个字符),1个32位的minor version(整数)和1个以32位(4个字符)为单位元素的数组compatible brands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val buf = ByteArray(4)
f.inputStream().also {
it.read(buf)
val boxSize = buf.toInt()
Log.e("JIN", "size = $boxSize")
it.read(buf)
Log.e("JIN", "type = ${buf.toCharString()}")
it.read(buf)
Log.e("JIN", "major brand = ${buf.toCharString()}")
it.read(buf)
Log.e("JIN", "minor version = ${buf.toInt()}")
val compatableBrandsArraySize = boxSize - 4 * 4 // 以上的四个 四字节
(0 until (compatableBrandsArraySize / 4)).forEach {i ->
it.read(buf)
Log.e("JIN", "minor version = ${buf.toCharString()}")
}
}

代码写得很顺利,果然看着说明书一步一步弄是最简单的事情呀。

我查看了一个 MP4 文件, 它的 major brand 是 isom, 它兼容的 brand 是 isom, iso2, avc1, mp41

看这个意思, mp4 是个封装标准, 但是还有很多子规范。

明天: 每天一点点_音视频_MP4_视频数据BOX