HTML5 video 旋转异常的根本原因是浏览器仅通过元数据(如 MP4 的 rotation flag)校正角度,而非 CSS transform;应优先用 FFmpeg 写入 rotate metadata,canvas 渲染仅作兜底。

video 标签旋转后黑边或裁切异常
HTML5 的 元素本身不支持原生角度设置,强行用 CSS transform: rotate() 会触发渲染层重排,导致视频区域外溢、黑边、控件错位。常见表现是旋转 90° 后画面被截断,或全屏时比例崩坏。
真正可控的旋转必须在解码/渲染前完成——也就是靠视频元数据(rotation flag)或转码预处理。浏览器只会在识别到 MP4 文件中 tkhd 或 avcC box 内的旋转标志时,自动校正显示角度。
- 用
ffprobe -v quiet -show_entries stream_tags=rotate -of default=nw=1 input.mp4查看原始旋转标记 - 若输出为
rotate=90,但播放时未生效,说明浏览器未读取该 tag(Safari 支持较好,Chrome 对某些封装可能忽略) - 不要依赖
transform做“视觉旋转”,它不改变 video 尺寸计算逻辑,video.videoWidth/video.videoHeight仍返回原始值
用 FFmpeg 强制写入 rotation metadata
很多手机直出视频(尤其是 iOS 拍摄的竖屏视频)只靠 Exif 或 QuickTime 元数据记录方向,而没在标准 box 中写入 rotation flag,导致 Web 播放器无法识别。FFmpeg 可以重写这个标记:
ffmpeg -i input.mp4 -c:v copy -c:a copy -metadata:s:v:0 rotate=90 output.mp4
注意:-c:v copy 表示不重编码,仅修改容器层元数据,秒级完成。但部分安卓设备拍摄的 HEVC 视频可能因 hvcC box 结构特殊,需先解复用再重写:
立即学习“前端免费学习笔记(深入)”;
- 先用
ffprobe -v quiet -show_entries stream=codec_name,width,height -of csv=p=0 input.mp4确认编码格式 - 若为
hevc且旋转无效,改用ffmpeg -i input.mp4 -c:v libx265 -c:a copy -metadata:s:v:0 rotate=90 output.mp4 - 加
-vf "transpose=1"是重编码旋转画面像素,和 metadata 旋转是两回事,别混用
JavaScript 动态检测并修正 canvas 渲染
当必须运行时旋转(如实时摄像头流、WebRTC 远程视频),CSS transform 不可靠,得用 手动绘制并翻转帧:
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const video = document.getElementById('myVideo');
// 监听 loadedmetadata,获取原始宽高
video.addEventListener('loadedmetadata', () => {
if (video.videoWidth < video.videoHeight) {
// 判定为竖屏源,需横置渲染
canvas.width = video.videoHeight;
canvas.height = video.videoWidth;
}
});
function drawRotated() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(Math.PI / 2); // 顺时针90°
ctx.drawImage(video, -video.videoHeight / 2, -video.videoWidth / 2, video.videoHeight, video.videoWidth);
ctx.restore();
}
关键点:
- 必须在
loadedmetadata后设置 canvas 尺寸,否则video.videoWidth为 0 -
drawImage参数顺序和坐标偏移要匹配旋转中心,否则画面偏移 - 频繁
requestAnimationFrame调用drawRotated有性能开销,移动端慎用
移动端 Safari 的 rotation 兼容陷阱
iOS Safari 对 rotation metadata 的解析最严格:只认 MP4 容器中 moov.udta.meta.ilst.rotat 或 tkhd 中的整型值(0/90/180/270),且要求 rotate tag 必须在视频流轨道(s:v:0)上,音频流写无效。
常见失效场景:
- 用
ffmpeg -i in.mp4 -metadata rotate=90 out.mp4(写到了全局,而非流级别)→ 失效 - 视频是 MOV 封装 → Safari 可能不读取,转成 MP4 再写 tag
- 用
exiftool -Rotation=90 in.mp4→ 写的是 Exif,非 QuickTime 标准,Safari 忽略
验证是否生效:在 iOS Safari 中打开视频,右键「检查元素」→ 查看 的 clientWidth/clientHeight 是否已按旋转后尺寸返回(比如原始 1080×1920 的竖屏视频,加载后 clientWidth > clientHeight 才算成功)。
真正在生产环境做角度校正,优先走 FFmpeg 预处理 + metadata 写入,JS canvas 方案只作为兜底。别指望 CSS transform 能绕过浏览器对视频原始朝向的底层处理逻辑。










