Hi,你们好,我是承香墨影!html
开门见山,开篇名义。今天来聊聊如何将多段视频,拼接成一个完整而连续的视频,而后无缝进行播放。git
这样的需求应该不算偏门吧?程序员
最简单的就是一些视频 App,会将大段的视频切割成小段的视频进行播放,还有一些在播放视频以前,会插播一段广告,这些需求均可以被本文的内容覆盖到。github
说到多个视频拼接来讲,若是你了解过 Google 出的 ExoPlayer 的话,它其内正好有一个 ConcatenatingMediaSource
能够来完成多个视频源的拼接工做,而且 Api 很好用,基本上算是无缝拼接。安全
不过呢,ExoPlayer 是依赖 MediaCodec
的,除了 Api Level 的限制以外(Api Level 16+),它对设备硬件也是有要求的,在一些低端机上,你会碰到一些莫名其妙的卡顿、马赛克、花屏等问题。而正是由于封装的太好了,若是你想自行添加软解,很遗憾,不太简单。而 Github 上 extensions 中,对 ffmpeg 的支持,也只是仅限于 Audio,对 Video 没有这个支持。bash
本文是基于另一个很火的开源播放器:IJKPlayer,来看看如何去拼接视频。服务器
IJKPlayer 是一个基于 FFmpeg 的轻量级 Android/iOS 视频播放器,被 Bilibili 开源出来,算是国内很火的一款开源播放器了,不少 App 都在用。tcp
由于背靠 FFmpeg,因此你在视频编码解码上碰到的大部分问题,IJKPlayer 均可以帮你解决,是一款很是好用的播放器。ide
IJKPlayer 自己已经很好用了,你若是想播放多段视频源的话,想要挨个的顺序播放,在要求不高或者自己有转场效果的前提条件下,也不是不能够。可若是是须要那种无缝的衔接,使用这种方式你会发现会有短暂的黑屏,由于加载新的视频源须要经历一小段时间,这种黑屏的现象在越差的设备上,越明显。学习
对此,我这里推荐的解决方案,就是使用 FFmpeg 的 concat 协议。
concat 是 FFmpeg 提供的一个虚级联脚本分解器(如下简称 concat 协议),它是以一段有规则的脚本文件的形式存在的。可使用 concat 定义一个视频播放列表,FFmpeg 在播放的时候,会根据你定义的顺序,一个接一个的解析进行播放,就好像他们自己就是一个视频源同样。
这么解释可能有点不清晰,不过若是你了解 .m3u8
的格式,你对 concat 的理解应该就不难,它们都是定义了一个视频列表,交由播放器的解码器去顺序播放。
具体的信息,能够去 FFmpeg 的官方文档中,查阅对应的内容。
FFmpeg Doc:
https://ffmpeg.org/ffmpeg-formats.html#concat
想要使用 concat 协议,首先须要定义一个待解析的文件。它必须是以 .ffcat
或者 .ffconcat
后缀结尾,而且文件的内容头,必须标记当前 concat 的版本号。
其内有两个可配置的选项:
下面举个官方的例子来看看一个完整的 .ffcat
文件,应该是什么样子的。
ffconcat version 1.0
# my first filename
file /mnt/share/file-1.wav
duration 20.0
# my second filename including whitespace
file '/mnt/share/file 2.wav'
# my third filename including whitespace plus single quote
file '/mnt/share/file 3'\''.wav' 复制代码
在使用 IJKPlayer 的时候,会有一些设置是经过 setOption()
方法进行设置的,若是须要支持 concat 协议,同时也须要有对应的设置。
这里主要关注两点:
为了让 IJKPlayer 能支持 concat 协议,你须要将 concat 配置到它的白名单协议里,主要是为了添加 ffconcat 和 concat 两个。
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "protocol_whitelist", "rtmp,concat,ffconcat,file,subfile,http,https,tls,rtp,tcp,udp,crypto");
复制代码
而 safe 主要是为了指定容许一些不安全的路径,默认值是 1 ,会拒绝一些不安全的文件路径。固然,什么是安全路径?你能够自行测试或者查阅文档,这里直接将它设置为 0 ,就能够将其安全监测关掉。
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT,"safe",0);
复制代码
到此,基本上就说清楚关键点了,直接将这个 .ffcat
文件,丢给 IJKPlayer 就能够正常的顺序播放了。
concat 相关的内容很是的少,若是你在实际操做过程当中,碰到问题,仍是建议关注一下 Logcat 的输出信息,看看出错的缘由。固然,通读一遍 FFmpeg 的 concat 文档,也是有帮助的。
前面提到的,concat 文件中,file
后面跟随的文件路径,必须是一个安全路径,那什么是安全路径?
根据 concat 的文档描述,安全路径必须是一个相对路径,而且只不包含特殊符号,只包含(字母。数字、句点、下划线)等字符,而且路径开始的时候,不包含句点“.”,则认为是一个安全路径。
例如 :
file a.mp4
复制代码
则认为是当前 .ffcat 文件所在目录下的 a.mp4
文件,这是一个安全路径。
相反的,例如 :"https://"、"file://"、"./" 这种视频源路径,均会视为不安全路径。
FFmpeg 只是接受一个 concat 协议格式的数据流,具体它是在本地仍是在远端的服务器上,实际上是不影响的。
file 后面跟随的视频源的地址,concat 并不强制要求须要都在同一个地方。
ffconcat version 1.0
file /sdcard/a.mp4
file http://down4.xxx.com/hash/c644d9e118417e56d91cba3dc467ab9b.mp4
复制代码
例如这样一个 .ffcat
文件,它是合法可播放的。
concat 要求拼接的视频必须具备相同的流(相同的码率和时间基准等),因此若是先后两个视频源这些参数不一致,是可能致使闪一下黑屏的。
这个问题,我在很是差的电视盒子上作过测试,若是文件流保持一致,是能够作到无缝衔接。因此若是你也碰到这样的状况,不要怀疑 FFmpeg 的 concat 的问题,从新用 FFmpeg 转码一下你的视频文件再试试吧。
https://github.com/alwaystest/Blog/issues/58
https://www.jianshu.com/p/ea794a357b48
今天在公众号后台回复成长『成长』,将会获得我整理的一些学习资料,也能回复『加群』,一块儿学习进步。
推荐阅读: