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

Movie Box (moov)

该box包含了文件媒体的metadata信息,“moov”是一个container box,具体内容信息由子box诠释。同File Type Box一样,该box有且只有一个,且只被包含在文件层。一般情况下,“moov”会紧随“ftyp”出现。

以下是读取下一个bax的大小和类型的代码:

1
2
3
4
5
6
7

it.read(buf)
val moovBoxSize = buf.toInt()
Log.e("JIN", "size = $moovBoxSize")
it.read(buf)
Log.e("JIN", "type = ${buf.toCharString()}")

然而类型却不是 moov 而是 free, 上面说了,一般情况下 ftype 后面是 moov。

那就跳过当前的box读取下一个box吧。

我又读取了下一个box, 这个 box 是 mdat, 看来,我要读取完整个文件来看看到底这个 mp4 文件有没有 moov 的 box 了。

重构了代码:

1
2
3
4
5
6
7

f.inputStream().also {
while (it.available() > 0) {
val box = Box(it, buf)
Log.e("JIN", box.toString())
}
}

Box 对象的代码:

1
2
3
4
5
6
7
8
9
10
11
12

class Box(val size: Int, val type: String) {
constructor(inStream: InputStream, byterArray: ByteArray)
: this(inStream.read(byterArray).let { byterArray.toInt() },
inStream.read(byterArray).let { byterArray.toCharString() }) {
inStream.skip(size - 8L)
}

override fun toString(): String {
return "$type: $size"
}
}

这里, 只读取了 size 和 type, 然后跳过了其他数据。

按照大端的方式转化4个字节为 Int 的方法:

1
2
3
4
5
6
7

fun ByteArray.toInt(): Int {
val a = this[0].toUByte().toInt() * Math.pow(2.0, 8.0 * 3)
val b = this[1].toUByte().toInt() * Math.pow(2.0, 8.0 * 2)
val c = this[2].toUByte().toInt() * Math.pow(2.0, 8.0)
return (this[3].toUByte().toInt() + a + b + c).toInt()
}

这里, 除了点问题, 每个字节,要转化成无符号数,再转成 Int, 之前没有转, 因为数小没出问题。

这样打印出了这个 mp4 的所有文件级别的 box:

ftyp: 32
free: 8
mdat: 11703979
moov: 16281

这就有意思了,下一步该绘制 UI 了

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