注意点:为什么 VS Code 打不开某些 MP4?远程开发机视频预览、编码、端口转发原理总结

为什么 VS Code 打不开某些 MP4?远程开发机视频预览、编码、端口转发原理总结

最近在远程开发机上处理一批视频数据,遇到了一个很典型的问题:

文件明明是 .mp4,但是在 VS Code 里打开后,播放器显示 0:00,一直转圈,无法播放。

后面排查发现,这个问题并不是文件损坏,也不是 VS Code 插件没装好,而是涉及到几个概念:

  • MP4 容器和视频编码不是一回事
  • VS Code / 浏览器支持的视频编码有限
  • Remote SSH 下本地浏览器为什么能访问远程开发机文件
  • H.264、H.265、mpeg4/mp4v 的兼容性差异
  • I/P/B 帧是什么
  • 如何把视频转成 VS Code 可播放格式

下面做一个完整总结。


1. 先说背景

视频文件在远程开发机上,例如:

text 复制代码
videos/

里面有很多 .mp4 文件。

一开始文件名是 UUID 风格,比如:

text 复制代码
00051b97-5da9-451b-8b60-0bb19f73534d.mp4
00b55c86-0e9c-4c74-a7fa-9b85a13a8dc3.mp4
...

为了方便浏览,先按文件名排序并加了编号前缀:

text 复制代码
0001. 00051b97-5da9-451b-8b60-0bb19f73534d.mp4
0002. 00b55c86-0e9c-4c74-a7fa-9b85a13a8dc3.mp4
0003. 00b93f10-c2da-48f9-96de-45b956b6ce33.mp4
...
0983. ffe79969-b0ba-4b79-8a5b-86e1589ea717.mp4

这里用 0001.0002. 这种四位补零编号,是为了让文件管理器按字典序排序时也能保持正确顺序。

如果只写:

text 复制代码
1.
2.
10.
100.

很多文件管理器按字符串排序时会变成:

text 复制代码
1.
10.
100.
101.
2.

所以补零是必要的。


2. 为什么 VS Code 不能直接播放这些 MP4?

一开始直接在 VS Code 里点开原始视频,看到的现象是:

text 复制代码
播放器显示 0:00
一直转圈
无法播放

排查后发现,原始视频虽然后缀是 .mp4,但内部编码是:

text 复制代码
codec_name=mpeg4
codec_tag_string=mp4v

例如用 ffprobe 查看:

bash 复制代码
ffprobe -v error -show_streams -show_format "videos/0003.xxx.mp4"

可以看到类似信息:

text 复制代码
codec_name=mpeg4
codec_long_name=MPEG-4 part 2
codec_tag_string=mp4v
width=3840
height=2160
duration=78.9

关键点是:

text 复制代码
mpeg4 / mp4v

这不是浏览器/VS Code WebView 最稳定支持的编码。

VS Code 的视频预览能力本质上依赖类似浏览器内核的播放能力。浏览器最常见、最稳定支持的是:

text 复制代码
MP4 容器 + H.264/AVC 编码 + yuv420p 像素格式

也就是:

text 复制代码
codec_name=h264
codec_tag_string=avc1

所以问题不是 .mp4 文件坏了,而是:

text 复制代码
文件后缀是 mp4,但里面的视频编码 VS Code/浏览器不支持。

3. MP4 不是编码,它只是容器

这是最容易混淆的地方。

很多人以为:

text 复制代码
.mp4 = 一种视频格式

更准确地说:

text 复制代码
MP4 是容器格式,不是视频编码。

可以把 MP4 理解成一个盒子:

text 复制代码
MP4 文件 = 盒子
H.264 / H.265 / mpeg4 / 音频 / 字幕 / 时间戳 = 盒子里的内容

所以一个 .mp4 文件里面可以装不同编码的视频流:

text 复制代码
MP4 + H.264 / AVC
MP4 + H.265 / HEVC
MP4 + MPEG-4 Part 2 / mp4v
MP4 + AV1

后缀都是:

text 复制代码
.mp4

但里面的视频编码可以完全不同。

这就是为什么有些 MP4 能播放,有些 MP4 不能播放。

真正决定能不能播放的是:

text 复制代码
容器 + 视频编码 + 像素格式 + 播放器支持情况

而不是单纯看 .mp4 后缀。


4. 为什么 MP4 里面会是 HEVC/H.265 编码?

因为编码视频的人、设备或者软件可以自由选择:

text 复制代码
容器:MP4
编码:H.265 / HEVC

最终文件依然是:

text 复制代码
xxx.mp4

但内部视频流可能是:

text 复制代码
codec_name=hevc
codec_tag_string=hvc1 或 hev1

这是完全正常的。

类似地,这批原始视频是:

text 复制代码
容器:MP4
编码:mpeg4 / mp4v

转码后的预览视频是:

text 复制代码
容器:MP4
编码:H.264 / avc1

它们后缀都是 .mp4,但兼容性完全不同。


5. H.264 和 H.265 都能播放吗?

不一定。

H.264 / AVC

H.264 是目前兼容性最好的编码之一。

一般来说:

text 复制代码
Chrome
Edge
Safari
VS Code WebView
大多数视频播放器

都比较稳定支持:

text 复制代码
MP4 + H.264/avc1 + yuv420p

所以如果目标是浏览器或 VS Code 播放,H.264 是最稳妥的选择。


H.265 / HEVC

H.265 压缩率更高,同等画质下文件更小。

但是兼容性比 H.264 差很多。

例如:

text 复制代码
Safari 对 H.265 支持较好
Chrome/Edge 在不同系统上支持情况不稳定
Linux 浏览器环境经常不能直接播
VS Code WebView 不建议依赖 H.265

所以如果目标是:

text 复制代码
在 VS Code 里直接看

更推荐:

text 复制代码
H.264

而不是 H.265。


6. I/P/B 帧是什么?H.264/H.265 都有吗?

H.264 和 H.265 都支持:

text 复制代码
I 帧
P 帧
B 帧

但注意:

text 复制代码
支持 ≠ 视频里一定都有

视频里到底有没有 B 帧,取决于编码参数。


I 帧

I 帧可以理解为一张完整图片。

特点:

text 复制代码
不依赖其它帧
可以单独解码
适合随机定位和拖进度条
体积相对较大

播放器拖进度时,一般需要从最近的 I 帧开始解码。


P 帧

P 帧依赖前面的帧。

特点:

text 复制代码
参考之前的 I/P 帧
只记录变化部分
比 I 帧更省空间

B 帧

B 帧可以参考前后的帧。

特点:

text 复制代码
参考前面的帧
也参考后面的帧
压缩率更高
解码顺序和显示顺序可能不同
会增加一点复杂度和延迟

这次转码后的 H.264 视频抽样检查结果是:

text 复制代码
codec=h264
tag=avc1
pix_fmt=yuv420p
size=1920x1080
has_b_frames=2

说明转码后的视频是:

text 复制代码
MP4 容器
H.264/avc1 编码
yuv420p 像素格式
包含 B 帧

这类视频在 VS Code 和浏览器里播放兼容性更好。


7. 如何把原始视频转成 VS Code 可播放格式?

解决方式是把原始视频转成:

text 复制代码
MP4 + H.264/avc1 + yuv420p

示例命令:

bash 复制代码
ffmpeg -i input.mp4 \
  -c:v libx264 \
  -pix_fmt yuv420p \
  -preset veryfast \
  -crf 26 \
  -movflags +faststart \
  output.mp4

参数解释:

text 复制代码
-c:v libx264        使用 H.264 编码
-pix_fmt yuv420p    使用浏览器兼容性最好的像素格式
-preset veryfast    转码速度较快
-crf 26             控制质量和文件大小,数值越小质量越高、文件越大
-movflags +faststart 把 moov 元数据放到文件前面,方便浏览器快速读取时长并开始播放

为了不破坏原始数据,建议不要覆盖原始视频,而是输出到新目录:

text 复制代码
videos_h264_preview/

原始视频保留在:

text 复制代码
videos/

转码后用于 VS Code 播放的是:

text 复制代码
videos_h264_preview/

8. 为什么在远程开发机上,浏览器还能看到视频?

这里涉及 VS Code Remote SSH 的端口转发。

文件和脚本都在远程开发机上,但本地浏览器可以打开类似地址:

text 复制代码
http://127.0.0.1:5500/video_player.html

这是因为 VS Code Remote SSH 帮我们做了端口转发。

整体链路是:

text 复制代码
本地浏览器
   ↓
访问本地 127.0.0.1:5500
   ↓
VS Code / SSH 端口转发
   ↓
远程开发机上的 Live Server
   ↓
读取远程磁盘文件
   ↓
视频数据通过 SSH 隧道传回本地浏览器
   ↓
本地浏览器解码播放

也就是说:

text 复制代码
文件在远程
HTTP 服务在远程
浏览器在本地
中间靠 VS Code Remote SSH 端口转发

本地浏览器并不是直接读远程磁盘,而是通过 HTTP 请求远程服务。


9. 为什么复制链接到另一个浏览器也能打开?

因为 VS Code 不关心你用哪个浏览器。

它做的事情只是:

text 复制代码
在本地监听 127.0.0.1:5500
并把这个端口转发到远程开发机

所以只要 VS Code 的端口转发还在,本地任何浏览器访问:

text 复制代码
http://127.0.0.1:5500/video_player.html

都能打开。

例如:

text 复制代码
Chrome -> 127.0.0.1:5500 -> VS Code SSH 隧道 -> 远程开发机
Edge   -> 127.0.0.1:5500 -> VS Code SSH 隧道 -> 远程开发机
Firefox-> 127.0.0.1:5500 -> VS Code SSH 隧道 -> 远程开发机

VS Code 不需要知道具体是哪个浏览器。

它只是修了一条隧道,谁访问这个本地端口,谁就能通过隧道去远程拿文件。


10. 如果关闭或删除 VS Code,还能播放吗?

如果当前依赖的是 VS Code Remote SSH 自动端口转发,那么关闭 VS Code 后大概率不能继续播放。

因为:

text 复制代码
VS Code 关闭
↓
SSH 隧道断开
↓
本地 127.0.0.1:5500 不再连接远程开发机
↓
浏览器刷新后打不开

如果不想依赖 VS Code,也可以自己手动建立 SSH 隧道:

bash 复制代码
ssh -L 5500:127.0.0.1:5500 user@remote-host

然后在远程开发机上启动 HTTP 服务:

bash 复制代码
python -m http.server 5500

本地浏览器访问:

text 复制代码
http://127.0.0.1:5500/video_player.html

这样就不依赖 VS Code,而是自己维护 SSH 端口转发。


11. 我最后采用的方案

最终采用的方案是:

  1. 原始视频保留不动:

    text 复制代码
    videos/
  2. 转码生成 VS Code/浏览器兼容版本:

    text 复制代码
    videos_h264_preview/
  3. 转码目标格式:

    text 复制代码
    MP4 + H.264/avc1 + yuv420p
  4. 创建一个 video_player.html 页面,用来批量浏览视频。

  5. 播放器支持:

    text 复制代码
    播放
    暂停
    从头播放
    0.5x / 1x / 2x 倍速
    快进快退
    上一个/下一个
    搜索文件名
    缩放
    全屏
  6. 后台批量转码:

    bash 复制代码
    python convert_videos_to_h264_preview.py --crf 26 --preset veryfast
  7. 转码完成后,在 VS Code 中打开转码后的文件或播放器页面即可播放。


12. 总结

这次问题的核心可以总结成几句话:

text 复制代码
MP4 只是容器,不代表一定能播放。
真正决定能不能播放的是内部视频编码。
text 复制代码
原始视频是 MP4 + mpeg4/mp4v,VS Code/浏览器不稳定支持,所以显示 0:00 并一直转圈。
text 复制代码
转成 MP4 + H.264/avc1 + yuv420p 后,VS Code/浏览器就能正常播放。
text 复制代码
H.264 兼容性最好,适合 VS Code/浏览器预览。
H.265 压缩率更高,但浏览器和 VS Code 支持不稳定。
text 复制代码
H.264/H.265 都支持 I/P/B 帧,但具体视频里有没有 B 帧取决于编码参数。
text 复制代码
Remote SSH 场景下,本地浏览器之所以能看远程视频,是因为 VS Code 做了端口转发。
文件在远程,浏览器在本地,数据通过 SSH 隧道传回来。

最终,如果目标是数据预览、标注、快速检查,推荐格式是:

text 复制代码
MP4 容器
H.264/avc1 编码
yuv420p 像素格式
+faststart

这是目前在 VS Code、浏览器和大多数环境里最稳的组合。