从本文开始,我们会就VideoEditor软件设计中一系列重要的问题展开谈谈如何解决这些问题,上文我们提到了VideoEditor中几个富有挑战性的问题,我们不会手把手教你怎么做,我觉得那样不能做到“授之以渔”的目的,希望大家在分析和拆解问题的过程中能收获一些东西。
本文我们主要谈一谈如何设计VideoEditor中的线程模型。有的同学可能会好奇,线程模型还需要专门拿出来谈谈吗?直接设计一些线程池,然后各种耗时操作往里面抛就可以了。这样子太简单粗暴了,我们设计一个SDK,给一个开发者使用,你需要让开发者明白的事情:
开发者确实没有必要了解SDK内部的软件结构,他们只关心SDK是否好用,调用是否方便,作为一个SDK的设计者,你必须要非常清晰地理清这些关系。线程设计的原则是:
这儿还是要补充一下,线程设计要精简,一个线程的创建必须有独特的作用,如果是可有可无的的线程,那这个线程就就不必要存在。线程少不仅可以节省资源,而且管理起来比较方便,少了很多不同线程之间的状态同步问题。pthread_mutex_t这种线程之间的互斥锁越少越好,使用pthread_mutex_t太多,给开发者和后续的维护者增加了太多成本,而且比较容易出错。
功能隔绝原则就是前后两种功能如果差异比较大,那就最好用不同的线程维护它,举个例子:VideoEditor可以添加视频和音乐,解码音乐肯定要放在单独的线程中,不宜和视频的处理放在一个线程中。
能同步就别异步,作为开发者而言,我肯定喜欢调用同步方法,因为同步方法比较简单,但是根据实际情况,如果实在不方便设计成同步方法,还是不要勉强,这里只是给出一些建议。
VideoEditor中有两大主要业务模块:拍照/录像、视频编辑,如下图
第一张图是拍照/录像界面,第二张图是视频编辑界面。这两个功能模块是相对独立的,我们可以分开谈谈。
拍照录制模块
1.Camera获取视频帧
2.AudioRecord获取音频数据(录制视频过程中)
3.处理独立音乐文件
4.滤镜、美颜等特效
5.合成音频和视频帧为一个完成的视频
我们选择了其他比较重要的几个功能(其实就是可能涉及到线程的几个功能)。发现如果要完整视频录制功能,需要下面几个线程:
1.Camera线程
2.GL处理线程
3.Audio record采集线程
4.音乐文件播放线程
5.音乐文件解码线程
6.音频编码线程
7.视频编码线程
8.视频封装线程
视频编辑模块
1.解码视频文件
2.解码音乐文件
3.抽取缩略图
4.滤镜、美颜等特效
5.合成音频和视频帧为一个完成的视频
视频编辑模块中导出部分和相机录制是一致的,所以这部分的线程处理也是一样的。前面的部分有所不同。其包含的线程如下:
1.GL处理线程
2.视频解封装线程
3.视频中视频track的解码线程
4.视频中音频track的解码线程
5.音乐文件播放线程
6.音乐文件解码线程
7.抽取缩略图线程
8.音频编码线程
9.视频编码线程
10.视频封装线程
最后的编码封装过程和上面的录制模块是一样的,只不过是数据源不一样,视频录制的数据源来自Camera和AudioRecord,视频编辑的数据源来自导入的视频和音频。
搞清楚了VideoEditor中的线程,我们还有最后一个文件,VideoEditor的开发一般都在Native层,不能直接复用iOS或者Android上层的那套消息队列的机制,所以还需要在Native层设计出一套消息队列,实现类似iOS或者Android上层的MessageQueue的机制。下一篇文章阐述一下如何在Native层设计一套消息队列给VideoEditor,其实不一定是VideoEditor,很多音视频相关的软件都需要类似的消息队列。