MPEG-DASH 的好处有哪些?浏览器是如何加载普通.mp4 的?

2022-11-30 14:07:16 +08:00
 Loserzhu

需求大部分是类似于游戏播片那种 2-3 min 的短视频。

听说很多年前播放 mp4 只能等下载完了才能播放,所以都用 flash?(有没有年长的讲讲这段历史) 而现在 chrome 在播放 mp4 时是逐渐下载的。如果手动拖动进度条,加载的时间也不长。但是跳回已播放的部分貌似又要重新下载(至少从 network 上看是新请求)。这个是需要 server 配置还是浏览器的 feature ?

最近在比较 DASH 技术和普通的 mp4 link 。非视频内容为主的业务,是不是不用把视频切成 ts/fmp4 这种的了?

1368 次点击
所在节点    程序员
10 条回复
tool2d
2022-11-30 14:40:50 +08:00
DASH 就是一堆不同分辨率 mp4 的合集嘛。

不使用单一 mp4 还是有好处的,比如手机用移动流量看视频,高清 MP4 特别费流量。直接扔一个 mp4, 用户满意度就不会很高。
okakuyang
2022-11-30 14:43:25 +08:00
现在主要是两个阵营,chrome like 和 safari like 。
chrome 播放 mp4 一般发起一个请求下载整个文件的数据。
一边接收数据一边解析,如果达到可以播放的缓冲就开始播放。
快进的话会从视频帧对应文件位置请求。

safari like 播放 mp4 有两种模式,其中一种和 chrome 类似,只需要一个请求就开始播放。
但是这种模式出现的时机比较苛刻。

另外一种是彻底的 safari 模式。播放视频时候需要请求非常多次。
第一次会请求两个字节,要求服务器返回 mp4 文件长度。
接下来会:
第二次请求会请求文件全长度(服务器不一定会返回全部长度,可能只会传输几 M )
第二次请求文件尾部几 MB 字节 (服务器应该返回这部分的全部长度)
因为 mp4 文件结构中视频信息在文件尾部,所以要先请求到这部分数据解析后播放。
之后 safari 会重复多次请求,一边播放一边请求接下来要播放的部分。

不同平台 webview 处理逻辑差异:例如 windows10 上的 webview 就会有不同的反应,有时候两种模式都可能会出现。
Mohanson
2022-11-30 14:50:32 +08:00
以前 mp4 文件的元数据放在文件末尾, 现在可以将元数据放到文件开头. 只要下载了元数据 mp4 就可以开始播放.

用 ffmpeg 带以下参数转码下视频, 就能在大多数播放器上播放(包括各种浏览器)

-c:v libx264 -c:a aac -pix_fmt yuv420p -ac 2 -movflags faststart

-pix_fmt yuv420p 是因为 chrome 只支持 yuv420p 像素格式, -ac 2 是因为 chrome android 只支持双声道 -movflags faststart 是把 mp4 元信息挪到开头, 可以尽快开始播放
hello2090
2022-11-30 14:56:51 +08:00
mp4 快速播放就是上面说的,把 moov atom 放到文件前面,那里面存了每一帧的位置和大小。主要区别是 mepg dash ,hls, flv 能播放 live 啊,也就是流。流是不可能先给你一个 moov atom 的。
Loserzhu
2022-11-30 20:00:12 +08:00
感谢各位的回复
edis0n0
2022-11-30 21:48:55 +08:00
@Mohanson 不重编码的情况下能将元数据放到文件开头吗
Mohanson
2022-11-30 21:53:35 +08:00
@edis0n0 可以的, -c:v libx264 -c:a aac 替换成 -c copy
hello2090
2022-12-01 06:34:16 +08:00
@edis0n0 可以的,FFMPEG 的那个命令-movflags faststart 应该就可以。
Loserzhu
2022-12-01 11:24:39 +08:00
@hello2090 还有个问题想请教。像 hls ,每个 media chunk 都很小,浏览器可以缓存。如果是 mp4 ,浏览器会缓存吗?我从 network 面板上看不出,感觉每次加载、拖动进度条再跳回已经加载的,这些操作都是重新请求了 server 。。
hello2090
2022-12-01 14:07:11 +08:00
@Loserzhu 我已经很久没做这个了,而且这和浏览器相关吧,所以我不了解。但你 SEEK, 也就是在进度条点击的时候,是 SEEK 到下一个 /或者上一个 KEY FRAME 的,至少本地的视频播放器是这样的。比如说电影一开头你就点到 1 小时那个地方,代码里会请求 SEEK(1 小时),这样 FFMPEG 内部会把读的指针设置好,这样你下一个 readframe 读出来的就是 1 小时附近的内容了。

你缓冲文件可以啊,你要取下一个文件之前看看本地有没有,本地有就用本地的,不要 REQUEST SERVER. 但我觉得视频播放器,那就是读一帧显示一帧,你把解好的帧存起来我是没见过。这个东西难做吧,视频播放器是一个 WHILE 循环,把数据读出来,放到解码器里,返回一个 VIDEO FRAME, 显示在屏幕上,有的时候你要放好几段数据解码器才会解出一个 VIDEO FRAME 的,而且你也是解出来了,才知道这帧的 TIMESTAMP 。

哦对,我想一般播放器是两个线程,一个声音,一个图像,因为声音是连续的,所以一般声音是基准。每放一点声音,比如说到了 1:20:30 了,看一下有没有图像在这之前的,有就把图像也显示出来,因为声音的 STEP 小,检查会比较频繁,所以每帧图像都会被显示出来。

所以实现肯定是可以的,但这个也很 TRICKY, 比如说你现在到 1:20:30 了,你缓存了 1:20:25 和 1:20:27 的图像,当然你要把他们显示出来,那中间会不会还有别的图像?有些是可变 FPS 的吧,所以可能你缓存的两帧之间有一帧漏掉了,你要调用 DECODE 把他拿出来,但是我说了你也不知道那块数据能解出 1:20:26 的图像,当然这也是有办法做的,只要你播放过你总能记录下来,但其实我觉得挺麻烦的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/899067

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX