Android短视频SDK转场特效的音视频同步分析
在短视频的应用场景中,经常存在用户拍摄的两个或者多个视频生成一个视频的需求,为了达到两个视频平滑过渡,就需要在两个视频中间添加转场效果。由于导入视频的帧率、码率等参数都不一致,如何保证在添加完转场效果后音视频同步?
本文主要介绍转场效果的实现及如何保证最终合成视频的音视频同步,同时简单介绍一下转场滤镜。
视频转场涉及基本的视频转码相关,关于转码相关不是此篇文章的重点,可参考Android短视频SDK转码实践
一. 转场功能介绍
市面上的转场基本分为三类:
-
片头片尾转场:即只作用在一个视频上。
此种和普通的时间滤镜添加区别不大,并不复杂,本文不再赘述 -
非重叠转场:转场接替作用在第一个视频的最后和第二个视频的开始,两个视频是顺次拼接。
transition_blur
比如持续1s的blur转场,blur滤镜 在第一个视频的最后0.5s开始,直到结束,作用是由清晰变模糊;在第二个视频的开始作用,持续0.5s,作用是由模糊变清晰。效果如下:
-
重叠转场:转场叠加作用在第一个视频的最后和第二个视频的开始,两个视频有一个转场时间的重叠区。
transition_fadesinout
比如持续1s的 淡入淡出转场,淡入淡出滤镜接收两个视频输入源,并且从第一个视频的最后1s开始作用,即在第一个视频的最后1s需要同时启动第二个视频的解码,并将解码后的数据输入到滤镜中,在转场的持续时间内是同时叠加了两个视频数据。效果如下:
二. 转场方案介绍
转场是在时间上对多个视频做转码和拼接。
我们采取的方案如如下图所示,依次对待拼接文件做解码,输出音频采样和视频像素数据到编码器,经过muxer最终将不同帧率、码率的视频生成统一格式的文件。
上图中AVMediaCapture为demuxer和decoder的封装。
如第一章节的介绍转场同一时间最多作用在两个视频上,因此只需要创建两个AVMediaCapture的实例,第一个视频解码结束后,第三个视频可以使用第一个视频创建的AVMediaCapture,依次类推,避免反复创建造成资源浪费。如下图所示:
AVMediaCapture
而对于AVMediaCapture中的解码器(硬解为例),也不需要反复创建,我们来看官网上关于MediaCodec的生命周期:
MediaCodec_states
如上图所示,当一个文件解码完成以后,通过reset接口使解码器处于Uninitialized状态,当对第二个文件进行解码时,只需要重新configure,start即可。
三. 转场中的音视频pts 计算
3.1 非重叠转场
在两个视频之间添加持续时间 trans_t 的转场滤镜,滤镜在第一个视频 [dur_0 - trans_t / 2.0f] 开始作用,直到第一个视频结束,然后继续在第二个视频的开始作用,持续 [trans_t / 2.0f]。
pts 依次是之前视频时长的累加,公式如下:
vTrack_1 和 aTrack_1 开始点的 pts : [0 + dur_0];
vTrack_2 和 aTrack_2 开始点的 pts : [dur_0 + dur_1]。
vTrack_n 和 aTrack_n 开始点的 pts : [dur_0 + dur_1 + ... + dur_n]。
3.2 重叠转场
在两个视频之间添加持续时间 trans_t 的转场滤镜,滤镜是同时作用在两个视频上的,因此滤镜在第一个视频的 [dur_0 - 1.0f] 时开始作用,直到第一个视频结束,同时开始第二个视频的解码,并作为滤镜的第二视频输入源。
pts 的计算需要将转场的作用时间裁剪掉,公式如下:
vTrack_1 和 aTrack_1 开始点的 pts: [0 + dur_0 - trans_t];
vTrack_2 和 aTrack_2 开始点的 pts: [dur_0 + dur_1 - 2 * trans_t]。
vTrack_n 和 aTrack_n 开始点的 pts: [dur_0 + dur_1 + ... + dur_n - n * trans_t]
四. 转场中的音视频同步
因为采用的是pull的方式从解码向编码输入数据,因此在添加重叠场景的转场时,在转场的时间段内,同时存在2个音频轨道和2个视频轨道,就需要考虑四个轨道的同步问题
- 单个视频的音视频解码同步
重叠场景的转场,若音视频 demuxer 相差很大,比如第一个视频的音频已经 demuxer 结束,但是第一个视频的视频还在继续处理,因为同时开启了第二个视频的 demuxer ,所以会有累加的音视频不同步的情况。
transition_avsync
如上图所示,在 decoder 之后添加AVSync模块以解决此种情况的不同步问题,AVSync模块采用视频驱动音频的同步模式,即,对音频做缓存,以视频帧驱动音频帧向下传递,threshold 不超过100ms。
-
两个视频之间的视频解码同步
重叠场景下,转场滤镜需要同时输入两个视频源,若第一个视频解码速度快,但是第二个视频的解码速度慢,会造成某一帧数据中只有第一个视频,并没有第二个视频,或者滤镜已经持续了0.8s了,第二个视频才有了输入,造成整体的转场效果较差。
transition_vsync
为了解决此种问题,加入 VTracks_Sync 同步模块, Vtracks_Sync 保证两个视频的 pts 的diff在100ms之内,若 vtrack_0_pts – vtrack_1_pts > 100ms,
则对 vtrack_0 的 demuxer 做暂停,反之对 vtrack_1 的 demuxer 做暂停,以达两个视频源的同步
五. 转场滤镜
重叠转场的渐变滤镜,基本方案为
以vtrack_0 为滤镜的主视频输入源 sTexture ,以 vtrack_1 为滤镜第二个视频输入源 vTexture1 ,在 shader 中通过修改渐变因子,以达到不同输入源的比重不同。
以最简单的淡入淡出滤镜为例,offset 为渐变因子,例如持续时间为1s的转场,则offset在1s内从0渐变到1,作用到视频帧的单位值计算公式:
[offset_maxvalue / offset_maxcount]
offset_maxvalue为渐变因子的最大值,即1
offset_maxcount为作用帧数,以帧率是20为例,1s的转场,offset_maxcount即为20。
void main()
{
vec4 video = texture2D(sTexture, vTextureCoord);
vec4 screen = texture2D(vTexture1, vTextureCoord);
gl_FragColor = mix(video, screen, offset);
}";
mix是对video和screen做线性混淆,即gl_FragColor = video(1- offset) + (screen * offset)
转载请注明:
作者金山视频云,首发简书 Jianshu.com
Android短视频SDK:https://github.com/ksvc/KSYMediaEditorKit_Android
有关音视频的更多精彩内容,请参考https://github.com/ksvc
金山云SDK相关的QQ交流群:
- 视频云技术交流群:574179720
- 视频云Android技术交流:620036233