在录制短视频的过程中,为了使你的短视频更有特色和看点,往往需要加入其他的素材、比如贴纸、美颜、背景音、MV等,本文介绍在短视频录制过程中添加MV的实现方案。
1. 功能介绍
短视频中添加MV,即在原视频的基础上添加、视频、音频、滤镜等组合因素,从而生成类似歌曲MV唱片的效果。
以下效果视频是通过金山云短视频生成的:
市面上大部分短视频的MV功能包含以下两个基本点:
- 有自己独立的资源包,资源包中包含添加的音视频元素及配置文本;
- 用户通过修改配置文件来调出不同效果的MV。
金山云短视频提供在录制过程中添加MV的功能,我们致力于可以让用户方便快捷的自定义MV效果,并快速添加到正在录制的视频中。
金山云短视频MV可实现的功能有:
- 支持录制任意时间段添加和删除MV,且支持在不同MV效果之间无缝切换;
- 支持配置用户自定义滤镜及短视频中提供的所有内置滤镜,并且可以灵活配置滤镜参数;
- 支持叠加音频;
- 支持叠加视频;
- 支持自定义MV时长。
2. 功能关键点方案介绍
2.1 MV资源文件的构成
如下图所示,一个基本MV资源需要至少一个config配置文件。
我们使用json文件来作为配置文件格式,方便配置和解析,并且可以做到平台无关性。
下表为一个基本的MV资源包内容
文件名称 | 用途 | 备注 |
---|---|---|
config.json | 资源文件配置信息 | 必需包含配置文件 |
music.mp3 | MV主音频文件 | 可以不包含 |
movie.mp4 | MV主视频文件 | 可以不包含 |
2.2 用户如何配置MV
一个合格的配置文件,既要包含基本的信息配置,又需要配置的灵活性,在此之上最关键的点是如何把配置的学习成本降到最低。
短视频SDK设计的一个原则就是开发者可以快速理解配置,不需要在理解如何配置上耗费太多时间。
config的root结构中除了基本信息的配置外,我们设计了两个灵活的关键信息:
- animations frame信息,包含某个时间点时MV具体作用效果,比如MV开始后何时滤镜开始,何时滤镜结束,用该信息来驱动MV的效果作用。开发者只需要学习配置animations 信息即可灵活变更同一主题的MV效果。
- filters,滤镜信息,包含可以作用到MV上的所有滤镜信息。
下表为congfig中几个基本字段
key | 类型 | 含义 | 用途 |
---|---|---|---|
movie | String | 主视频路径 | MV素材的主视频文件路径 |
music | String | 主音频路径 | MV素材的主音频文件路径 |
duration | long | MV时长 | 单位:ms |
用户在做MV配置时,可以提供movie或者music,但并不是必需的。
在设计上需要考虑用户配置的不同,我们采取依赖优先级:movie>music>duration的方案来做适配,即当存在movie时,MV以movie的时长为主时长,依次类推。
2.3 MV音视频数据的同步
MV携带的视频和音频如何同步到正在录制的文件中呢?
以下图为例:
为了使MV的配置更灵活,我们不依赖MV资源包中的主视频文件(movie.mp4)或者主音频文件(music.mp3)的pts变更来触发frame的作用效果,而是模拟了一条MV的timeline,该timeline以MV的开始时间为基准时间,duration为循环时间,心跳间隔为30ms(33帧/s),在每个心跳中,触发当前最近的frame中滤镜效果。
- texture0和pcm0分别代表采集的音视频信息
- texture1和pcm1分别代表MV的主视频和主音频信息,也就是资源包中的movie.mp4和music.mp4
** textureFilter1和textureFilter2分别代表对应frame*作用滤镜信息 - MIX的含义是对音视频做混合
- frame的触发条件:
//心跳触发事件
public void run() {
......
//每个心跳中以当前系统时间作为MV的PTS
long mv_pts = System.nanoTime() / 1000 / 1000;
//frame的触发相对时间
//frame.t即config中animations frame中的t,即frame的触发时间,该时间以MV的时长为参考时间
//比如:duration为5000ms的MV,当设置t为200ms时,即在MV开始后的200ms触发该frame效果
long current_frame_pts = frame.t + start_pts
if (current_frame_pts <= mv_pts) {
.....enable/disable effect
}
}
建议提前使用animations frame中所有frame创建一个针对timeline的触发器,参考结构如下
TreeMap>
// Key为frame的t,不重复,value为这个t上面需要发生的所有的frame
// 建议使用有序的TreeMap结构
3. MV功能模块设计方案
我们在设计某一个功能模块时,有几点设计因素需要优先考虑进去:
- 模块功能单一性:要把模块作为一个独立的单元设计;
- 模块的复用性:从需求的扩展性考虑,该模块可以用于短视频录制,也可能用于短视频编辑,因此要考虑到模块的复用性。
基于以上因素,我们设计了一套独立MVC结构的的MV单元,使用者可以通过传入MV资源文件路径或配置json字符串方便的构造MV资源数据信息,并提供给SDK内部,SDK内部各个功能模块可以复用该单元。
4. MV资源存储设计方案
建议将MV资源的zip包存储在server端,使用时动态下载MV资源到本地目录,有以下几点建议:
- 对于资源zip做更新检查,可以比较zip包的md5信息,以避免不必要的下载和copy;
- zip的包名和MV本地名称一致,方便识别mv;
5. MV视频与主视频的透明重叠方案
H.264编码的视频是不支持alpha通道的,想要多个有叠加效果,就需要对叠加视频的alpha作处理。
5.1 方案一
提供movie_alpha.mp4,用movie_alpha.mp4视频中的灰度信息代表叠加视频music.mp4的alpha值,该方案要求alpha视频帧数至少要大于等于原视频帧数。
- 优点:准确的转换alpha信息;
- 缺点:解析两个视频和计算所带来的性能损耗。
如上图所示,解析movie.mp4的同时需要解析movie_alpha.mp4,帧对帧的将movie_alpha.mp4 gray信息赋值给movie.mp4的alpha值,然后生成texture1。
最终主视频信息(texture0)和采集视频信息(texture1)做混合。
// 从 RGB 到 YUV 空间的 Y 转换公式为:
Y = R*0.299 + G*0.587 + B*0.114
// 建议:为优化运算速度可转为整数移位算法
Y= (R*19595 + G*38469 + B*7472) >> 16
5.2 方案二
以黑色作为透明信息的参考值,将视频中纯黑色部分透明处理,非纯黑部分再和原视频做混合。
- 优点:不用解析额外的视频;
- 缺点:提供的MV视频不能存在有效的黑色或者接近于黑色的信息,否则会被过滤掉。
如上图所示,把movie.mp4的视频信息和采集的视频信息做一个混合计算最终生成texture即可。
//混合计算公式:
R = 1-(1-screen.R)*(1-video.R)
G = 1-(1-screen.G)*(1-video.G)
B = 1-(1-screen.B)*(1-video.B)
A = 1-(1-screen.A)*(1-video.A)
5.3 重叠方案的总结
目前方案二可以满足大部分的的MV场景,并且在性能和复杂度上要优于方案一,因此最终我们采用的是方案二。
6. 总结
在完成MV的过程中,遇到一些问题:
- 使用
MediaPlayer+SurfaceTexure
的方式获取movie.mp4的视频texture,MV切换时建议重复利用MediaPlayer+SurfaceTexure
,不要反复创建SurfaceTexure
,使用不当容易造成SurfaceTexture
状态异常,抛出IllegalStateException
; -
SurfaceTexure
的onFrameAvailable
回调中建议配对调用updateTexImage
,否则容易造成后续onFrameAvailable
的事件不被触发; - 在有些机型上 调用
SurfaceTexure
的updateTexImage()
时,有时会抛出IllegalStateException
,不影响数据正确性的前提下可加try catch
忽略。
金山云多媒体SDK团队在很用心地开发短视频SDK,欢迎试用和提issue:
https://github.com/ksvc/KSYMediaEditorKit_Android
转载请注明:
作者金山视频云,首发 Jianshu.com
金山云多媒体SDK仓库地址:
https://github.com/ksvc
金山云SDK相关的QQ交流群:
- 视频云技术交流群:574179720
- 视频云Android技术交流:6200036233