搜索了一下午,如果视频源非切片的话最好的方式还是方案2
下面是我的一个不成熟想法
由于我用的是ffmpeg来开发,其他分辨率的流可以seek 到正在播放的流后面一点的关键帧,然后通过side_data 通知解码器播放的数据变化了,然后重新开启一个新的解码器
A---->read--------------->
| pkt = A.pts< B.pts ?A.pkt:B.pkt |---->cache---->decoder----->render
B->seek(a.pts+2s)--read-->
这样整个播放器就会需要所有模块自己处理切换事件
1
royzxq 2020-01-08 14:45:22 +08:00
方案 1 是 B 站 3 年前的解决方案,高切低几乎无感知但是低切高会感知到并且有一丝卡顿。
|
2
royzxq 2020-01-08 14:46:20 +08:00 1
要么看看 MEPG-DASH, 现在 B 站的无感知切换应该和这个有很大关系。
|
3
fgodt OP @royzxq 非常感谢,网页上的用 DASH 是可以实现的,他们用的 MSE 接口。不过我正在写原生平台的播放器,感觉要实现 DASH 的方法就只能方案 2
|
4
wanguorui123 2020-01-08 14:58:43 +08:00 1
把不同分辨率的视频切片成 TS 格式,播放器切换后切到其他清晰度的 TS 分片上,可以无缝切换清晰度。
|
5
fgodt OP @wanguorui123 这样的话就要求视频源必须处理成 ts 切片,如果用户的视频源是 mp4 mkv 就无法切换
|
6
hardwork 2020-01-08 21:09:59 +08:00 via Android
用 2 肯定可行,原理上没啥问题,剩下的都是特定场景的有特定业务场景吧,点播
|
7
hardwork 2020-01-08 21:16:08 +08:00 via Android 1
用 2 肯定可行,原理上没啥问题,剩下的都是业务逻辑。收到切换事件后开始并行解码目标分辨率,然后保证无缝接入渲染队列,再把原分辨率解码停了,具体实现还是看你整个架构
|
8
fgodt OP @hardwork 是的必须要让每个模块都支持动态切换,其实 pc 两个播放器也能搞定,但是 Android 这样的设备就比较吃力
|
9
hardwork 2020-01-08 21:53:22 +08:00 1
没看清楚,我好像说的是方案 1
看了看你说的方案 2,意思是想要解码前在关键帧处拼成一段码流,这样完全没有两个并行解码了,是这个意思吧. 不想要并行解码那么先停掉第一个解码器,再开启第二个解码器就可以了,事实也确实应该这么做,并行逻辑反而复杂了,当然这个切换期间保证渲染 buffer 不要耗尽,保证接缝处时间戳连续就可以了. 除非是带 startcode 的 h264 码流,且 idr 帧前是有 sps,pps 的这种你可以接起来送到解码器,否则像 mp4,mkv 不同分辨率的还是要重开解码器的 |
10
fgodt OP @hardwork 是的如果要完美支持的话就应该就只能这样操作。
根据你最后这种思路,还有一种想法如果我把 sps pps 放到 pkt 再传给解码器不知道 ffmpeg 里的 codec 支不支持这种操作。支持的话我人为的将 mp4 等容器的数据封装成 NAl 的数据,切换时附上 sps pps 是不是就无需重新开解码器了 |
11
mxT52CRuqR6o5 2020-01-09 09:39:27 +08:00 via Android 1
爱奇艺似乎是切片,然后通过 js 把文件流推给播放器
|
12
fgodt OP @mxT52CRuqR6o5 是的网页的播放器都是通过 ts 或者 dash 切片传给浏览器,这样确实可以无缝
|