一句话
手机的摄像头传感器是横向固定在机身里的。你竖着拿手机录像,传感器录下的仍然是横向画面;手机只是往文件里写一个标记:“显示时转 90°”。手机上每个播放器都认这个标记。别处的一些软件——旧的剪辑软件、某些网页播放器、某些上传流程——不认它或者把它抹掉了,结果就是视频侧着播。把标记写回去是一次元数据编辑:不管文件多大都只要零点几秒,什么都不重新编码。
这个标记到底是什么
MP4 或 MOV 文件是一棵盒子树。描述一条视频轨如何呈现的那个盒子叫 tkhd(track header),里面有一个 3 × 3 的变换矩阵——九个数、36 字节——播放器在画每一帧之前都先套上它。没旋转的视频,矩阵是单位阵。竖着拍的视频,矩阵是一个 90° 旋转。文件里的像素是横的,矩阵说“把它们转过来”。安卓把同样的信息写成一个单独的 rotation 值;ffmpeg 把两者都报告为流元数据里的 rotate: 90。
这个设计是有意的。录像时真的去转动像素,意味着每一帧都要在编码器里多跑一整遍,还是靠电池。写九个数不花任何代价。这和照片里 EXIF 方向标记是同一个思路,也以同一种方式出问题:任何不读这个标记的消费方,显示的就是原始方向。
谁把它弄丢的
- 竖屏视频出现之前写的桌面剪辑软件和播放器。 VLC 和 QuickTime 多年前就认这个矩阵;某些企业视频系统和旧版 Windows Media Player 不认。
- 复制视频流但重建容器的转码器。 一个号称“不重编码、无损”的工具,仍然可能写一个带单位矩阵的全新
tkhd。像素活下来了,指令没有。 - 某些网站上传。 上传时重新封装的网站可能丢掉标记;上传时重新编码的网站通常会把旋转正确地烤进去。
- 拼接。 把一段竖屏和一段横屏拼成一个文件,合并后的轨只有一个矩阵,两半里必有一半是错的。
两种修法,一种是免费的
重写矩阵。 把 tkhd 矩阵(或旋转字段)改成让视频正确显示的值。这是往一个可能好几 GB 的文件里写几十个字节;视频流和音频流原样拷过去。半秒钟,不掉画质,体积不变。这是视频旋转的默认做法:在你的设备上读文件,写入修正后的头,把文件还给你。因为什么都不解码,4 GB 的录像和 4 MB 的一样快。
重编码,把旋转烤进去。 解码每一帧,转动像素,再编码。只有在消费方确定不认矩阵、而你又改不了消费方的时候才需要——数字标牌播放器、老旧的内容系统。耗时和视频一样长(没有硬件编码器还更长),而且掉一代画质。视频旋转把它作为第二个选项,用浏览器的 WebCodecs 编码器完成,界面上写明了,因为这是贵的那条路。
“免费”的修法有时为什么不管用
如果视频只在一个程序里侧着,在别处都正常,那是这个程序不认矩阵,重写也没用——只能烤进去。如果到处都侧着,那是矩阵丢了,重写就是解法。一个快速测试:在现行浏览器里打开文件(Chrome、Safari、Firefox 都认这个标记)。浏览器里侧着 → 矩阵错了或丢了 → 重写。浏览器里正常、那个程序里侧着 → 程序的问题 → 烤进去。