MP4Box.js 获取视频旋转信息
![MP4Box.js 获取视频旋转信息](/_ipx/s_1920x900/images//posts/get-video-rotation-by-mp4box-js-cover.jpg)
声明:本文部分内容使用 ChatGPT 生成
序言
公司的一个项目中用到 MP4Box.js
在上传视频前去解析视频的宽高,并且根据宽高的比例做一些拦截,只允许 16:9 横屏的素材。后来发现一个问题,部分竖屏的素材也被提交上来了。经过研究,发现这类视频可能是由手机拍摄的,带了旋转信息,因此 MP4Box.js
中的原始宽高有问题。
什么是 MP4Box.js
MP4Box.js 是一个支持在浏览器中处理 MP4 文件的 JS 库,可以实现获取 MP4 文件的元数据信息、分割文件、提取媒体样本等高级处理能力。
通过 MP4Box.js
可以从 videoTrack
中的 width
和 height
中获取视频的宽高,对于一般的视频都是 OK 的,但是带了旋转信息,通过 MP4Box 读出的宽高仍是旋转前的宽高,导致在一些场景下的判断会有问题。那么,如何获取到视频的旋转信息呢?
MP4Box.js 如何获取旋转信息
在 MP4 和 MOV 文件中,旋转信息通常存储在 tkhd
(Track Header Box) 或 mvhd
(Movie Header Box) 中。这个信息会影响视频轨道的显示方式。
Track Header Box (tkhd
):包含一个 matrix
的矩阵,描述视频帧的旋转。
matrix
字段中的旋转信息是通过一个 3x3 矩阵来表示的,具体可以参考 ISO/IEC 14496-12 标准。
具体实现代码:
Math.atan2(videoTrack.matrix[1], videoTrack.matrix[0]) * (180 / Math.PI)
其中,Math.atan2
是 JS 中的一个数学函数,用于计算从点 (0, 0) 到点 (x, y) 之间的直线与 x 轴正方向之间的角度,角度的单位为弧度。这个函数能够处理所有的象限,因此可以返回从 -π 到 π 之间的值。Math.atan2
函数在计算几何、游戏开发、图形编程以及需要处理极坐标转换等场景中非常有用。与 Math.atan
不同,Math.atan2
可以处理 (x, y) 都为零的情况,并根据 x 和 y 的符号确定正确的象限。
完整实现代码
function getVideoMetaInfo(file: File): Promise<any> {
return new Promise((resolve, reject) => {
const mp4boxFile = MP4Box.createFile()
mp4boxFile.onReady = function (info: any) {
if (info && info.videoTracks?.length) {
const videoTrack = info.videoTracks[0]
const result = {
duration: videoTrack.duration / videoTrack.timescale,
codec: videoTrack.codec,
fps: videoTrack.nb_samples / (videoTrack.duration / videoTrack.timescale),
width: videoTrack.video.width,
height: videoTrack.video.height,
rotation: Math.atan2(videoTrack.matrix[1], videoTrack.matrix[0]) * (180 / Math.PI),
}
resolve(result)
}
}
mp4boxFile.onError = function (info: any) {
console.error('mp4box.js error', info)
reject(info)
}
const reader = file.stream().getReader()
let offset = 0
reader.read().then(function getNextChunk({ done, value }: any) {
if (done) {
mp4boxFile.flush()
return
}
const copy = value.buffer
copy.fileStart = offset
offset += value.length
mp4boxFile.appendBuffer(copy)
reader.read().then(getNextChunk)
})
})
}
后记
在解决这个问题的过程中,我发现另一个强大的 JS 库:mediainfo.js,已经帮我们做好了这一切,并且支持解析更多格式的文件。
我基于这个库,做了一个可视化的工具页:媒体文件元数据解析,方便解析媒体文件的元数据,纯浏览器本地解析,性能优异,并且不需要读完整个文件,读完头就可以了。