《Android 视频编辑开发汇总》第零章 短视频编辑合成架构的
短视频编辑合成基本上包括以下几种内容:
视频剪辑、添加滤镜、添加特效、添加字幕、添加背景音乐、添加MV效果等功能。
这里面涉及比较多的视频帧以及音频处理,如果采用FFmpeg命令行处理的话,由于手机处理性能羸弱问题,处理的时间会非常长,用户等待时间过长会导致用户流失比较严重。因此,我们需要设想一些架构来实现短视频编辑功能,加快短视频编辑合成的等待时间。
为了实现快速合成功能,我们计划采用录制的方案进行短时频合成处理。通过播放器解码同步,然后回调音频PCM数据、通过SurfaceTexture attach到OpenGLES的渲染线程进行滤镜、特效和字幕的渲染处理。在合成阶段,我们通过回调的音频PCM数据与解码得到的背景音乐PCM数据进行合成,然后从OpenGLES线程中提取视频帧的byte数据,然后把得到的PCM数据、视频帧byte数据传递给录制编码线程进行编码合成进而输出MP4视频文件。整体架构设想如下图所示:
短视频编辑合成架构图
1、预览编辑阶段:
自研播放器,此时音频经过变速变调处理后,直接播放即可。视频帧可用是,则通过SurfaceTexture的onFrameAvailable方法回调,然后通过attachToGLContext方法绑定到OpenGLES渲染线程,将视频帧绘制到FBO中做滤镜、特效、字幕处理、MV效果等,并且处理完成之后,经由与OpenGLES 的EGLContext 上下文绑定的SurfaceTexture 输出到屏幕显示。
2、合成阶段:
自研播放器通过解码以及变速变调处理后,不播放音频,而是通过回调将音频PCM数据传递出来,然后将视频源的音频PCM数据跟音乐解码线程解码的到的PCM数据合成新的PCM数据,视频帧部分则通过OpenGLES渲染后,不显示到屏幕上,而是直接提取视频帧的数据,跟前面合成的PCM数据传递给录制编码线程。录制编码前程在接收到音频PCM数据、视频帧数据以及对应的显示时间戳(PTS)同步编码成H264和AAC进而复用(Muxer)输出MP4视频文件。
这个架构的想法主要是为了方便同步以及方便拆分各个部分功能。播放器部分既可以是硬解码也可以是基于ffmpeg的软解码,渲染线程既可以是JNI层的,也可以是Java层的,然后录制线程部分既可以是硬编码的,也可以是软编码的。解码、渲染、合成均可以单独拆分成各自的单独的库进行开发,各个部分通过接口进行数据交换,互不干扰,并且可以随时根据实际的情况进行软硬解码切换、软硬编码切换等。
另外还有一点好处就是,这里也可以选择图片进行合成输出,这里面的播放器部分则不再是播放视频了,而是渲染图片了。
这个架构的好处是,在短视频合成阶段,我们需要等待的时间可以变得很短,哪怕采用软编码的方式进行合成,时间也不会比视频时长本身长很多很多。虽然软编码无法完全做到百分百实时软编码处理,但我们可以采用缓冲等操作,当录制编码线程缓冲满了,则通知播放器暂停解码,等待缓冲区的数据消耗后,播放器再次继续解码输出。即使是采用软编码,整个合成时长也不会比视频时长本身长多少,相比FFmpeg命令行的方式进行处理会快很多很多。另外一个好处就是,合成时,我们并不需要考虑音视频同步的,利用播放器解码输出的显示时间戳(PTS)即可完成同步,合成阶段的音视频同步问题转化成了播放器的同步问题。
PS:本文章发表时,本人的开源项目还没实现短视频编辑合成功能。该架构仅仅是本人接下来要实现的思路,由于播放器、渲染线程、音乐解码与PCM合成、录制合成、添加外部MV效果等全部功能都需要自己一个人实现,所以估计短时间内无法完成全部内容。有兴趣的可以自行尝试实现一个。