现如今互联网最火的两大领域一个是人工智能,另一个就是以抖音、火山小视频为首的短视频APP。我们在使用这些短视频APP的时候又一个很好的体验就是从一个视频的播放从一个界面跳转到另外一个页面的时候视频总是能无缝衔接,不会出现重新加载播放的现象。所以今天我们就来聊音视频的无缝衔接播放的问题。
对于音视频的无缝续播主要是两个方面:
一个是界面切换时的无缝续播,另外一个切换视频播放源时的无缝续播。
界面切换无缝续播
对于界面切换时的无缝续播,业界大致有两种解决方案:
其中一种解决方案是替换播放器渲染的surfaceView的方式,另外一种解决方案是使用移动播放器View的方式,也就是将播放器的渲染View从原先的布局中移除掉,然后插入到要显示的布局中。
对于使用切换surfaceView的原理是解码器动态关联不同的渲染视图(RenderView),比如使用MediaPlayer动态关联SurfaceView,就如同一个电脑主机不断连接不同的显示器。典型的开源项目是 (GSYVideoPlayer)https://github.com/CarGuo/GSYVideoPlayer
但是这种方案有一个状态同步的问题,比如说目前播放器是暂停的,那么切换surfaceView的时候需要将暂停时的那一帧图像绘制到新的surfaceView上,播放完毕也是同理。比如有这样的一个需求,一个RecyclerView的视频播放列表,点击跳转到了详情页的时候就把播放器的surfaceView切换到了详情页的surfaceView,那么当详情页播放完毕之后,当用户点击返回按钮时,需要重新把surfaceView设置成RecyclerView条目中的surfaceView,那么这时就需要将视频的最后一帧图像渲染到新的surfaceView上。总的来说就是需要保证播放器的surfaceView在切换前和切换后显示的图像内容是一样的。这个是一个重难点。
至于使用移动View的方式进行界面无缝续播的方案,可能会导致View缺失的问题,导致播放界面可能会出现空白,特别是列表播放的需求情景。需要精确地管理播放器View当前所在的布局,而且在不同的Activity或者Fragment随意移动穿插View,处理不好的话可能会出现内存泄露的问题。这种解决方案的开源项目代表有(JiaoZiVideoPlayer)https://github.com/lipangit/JiaoZiVideoPlayer
对于以上两种方案,一句话总结就是:如果播放器逻辑层和视频帧渲染层分离管理得当的话,一个就是管理View的问题,另外一个就是管理渲染状态的问题。
码流切换无缝续播
对于无缝切换码流主要分为单个播放器和多个播放器的方案:
单个播放器的方案:
点击切换码流时,不销毁播放器,只是暂停解码。开始请求新的url中数据,然后将重新下载到的流媒体数据送给解码器,重新启动解码,然后渲染输出。达到无缝切换的效果。
多个播放器的方案:
在点击切换码流的时候,让原来的播放器继续工作,然后新开一个播放器后台异步准备新的播放源,准备完毕后,使用新的播放器seek到原来的播放器播放的时间位置,最后显示新的播放器,隐藏并销毁原来的旧播放器,以达到无缝切换的效果。
但是对于很多播放器来说一般都是不能seek到非关键帧的位置的,一旦播放的视频两个关键帧之间相差好几秒,而要seek的位置又刚好不是关键帧的位置时,可能就会看到有明显的跳帧感觉。所以说如果要达到比较好的码流切换无缝衔接续播的效果的话可能需要在解码阶段做一些处理比较合适。
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/yinshipin/20059.html