• 请不要在回答技术问题时复制粘贴 AI 生成的内容
fgodt
V2EX  ›  程序员

关于播放器无缝切换清晰度

  •  
  •   fgodt ·
    FgoDt · Jan 8, 2020 · 5225 views
    This topic created in 2346 days ago, the information mentioned may be changed or developed.
    最近在自己实现播放器,有一个无缝切换清晰度的功能不知道怎么实现,希望有大佬给点指导
    我能想到的实现有两种
    1. 两个播放器并行,一个前台播放一个后台 seek 到前台播放器附近然后解码,等后台和前台 pts 相同再显示。这样的话必定有一段时间有两个播放器并行,开销很大
    2. 两个流,一个流正在解码播放,另一个要切换的流先 seek 再读取等到关键帧与播放的 pts 相同时切换解码器。这种方式我感觉过于复杂,而且不太好完美实现
    希望有大佬指点下
    Supplement 1  ·  Jan 8, 2020

    搜索了一下午,如果视频源非切片的话最好的方式还是方案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-->
    

    这样整个播放器就会需要所有模块自己处理切换事件

    13 replies    2020-01-09 10:14:01 +08:00
    royzxq
        1
    royzxq  
       Jan 8, 2020
    方案 1 是 B 站 3 年前的解决方案,高切低几乎无感知但是低切高会感知到并且有一丝卡顿。
    royzxq
        2
    royzxq  
       Jan 8, 2020   ❤️ 1
    要么看看 MEPG-DASH, 现在 B 站的无感知切换应该和这个有很大关系。
    fgodt
        3
    fgodt  
    OP
       Jan 8, 2020
    @royzxq 非常感谢,网页上的用 DASH 是可以实现的,他们用的 MSE 接口。不过我正在写原生平台的播放器,感觉要实现 DASH 的方法就只能方案 2
    wanguorui123
        4
    wanguorui123  
       Jan 8, 2020   ❤️ 1
    把不同分辨率的视频切片成 TS 格式,播放器切换后切到其他清晰度的 TS 分片上,可以无缝切换清晰度。
    fgodt
        5
    fgodt  
    OP
       Jan 8, 2020
    @wanguorui123 这样的话就要求视频源必须处理成 ts 切片,如果用户的视频源是 mp4 mkv 就无法切换
    hardwork
        6
    hardwork  
       Jan 8, 2020 via Android
    用 2 肯定可行,原理上没啥问题,剩下的都是特定场景的有特定业务场景吧,点播
    hardwork
        7
    hardwork  
       Jan 8, 2020 via Android   ❤️ 1
    用 2 肯定可行,原理上没啥问题,剩下的都是业务逻辑。收到切换事件后开始并行解码目标分辨率,然后保证无缝接入渲染队列,再把原分辨率解码停了,具体实现还是看你整个架构
    fgodt
        8
    fgodt  
    OP
       Jan 8, 2020
    @hardwork 是的必须要让每个模块都支持动态切换,其实 pc 两个播放器也能搞定,但是 Android 这样的设备就比较吃力
    hardwork
        9
    hardwork  
       Jan 8, 2020   ❤️ 1
    没看清楚,我好像说的是方案 1

    看了看你说的方案 2,意思是想要解码前在关键帧处拼成一段码流,这样完全没有两个并行解码了,是这个意思吧.

    不想要并行解码那么先停掉第一个解码器,再开启第二个解码器就可以了,事实也确实应该这么做,并行逻辑反而复杂了,当然这个切换期间保证渲染 buffer 不要耗尽,保证接缝处时间戳连续就可以了.

    除非是带 startcode 的 h264 码流,且 idr 帧前是有 sps,pps 的这种你可以接起来送到解码器,否则像 mp4,mkv 不同分辨率的还是要重开解码器的
    fgodt
        10
    fgodt  
    OP
       Jan 8, 2020
    @hardwork 是的如果要完美支持的话就应该就只能这样操作。
    根据你最后这种思路,还有一种想法如果我把 sps pps 放到 pkt 再传给解码器不知道 ffmpeg 里的 codec 支不支持这种操作。支持的话我人为的将 mp4 等容器的数据封装成 NAl 的数据,切换时附上 sps pps 是不是就无需重新开解码器了
    mxT52CRuqR6o5
        11
    mxT52CRuqR6o5  
       Jan 9, 2020 via Android   ❤️ 1
    爱奇艺似乎是切片,然后通过 js 把文件流推给播放器
    fgodt
        12
    fgodt  
    OP
       Jan 9, 2020
    @mxT52CRuqR6o5 是的网页的播放器都是通过 ts 或者 dash 切片传给浏览器,这样确实可以无缝
    fgodt
        13
    fgodt  
    OP
       Jan 9, 2020
    @hardwork 非常感谢大佬的提示,我做了一个简单的验证在两个文件都是 264 编码的情况下无论分辨率和码率都可以通过 NAl 的封装来达到无缝切换的效果。264 的解码器似乎都支持改变 sps pps
    由此我还有一个猜想 如果都是 AAC 的流我们使用 ADTS 的流是否也可以任意改变呢?
    希望这里的提示对其他还在困惑的人有帮助
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   4065 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 05:22 · PVG 13:22 · LAX 22:22 · JFK 01:22
    ♥ Do have faith in what you're doing.