首先, 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