暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

KTVVideoProcess 设计总结

ChangbaDev 2018-06-14
157

项目背景

在唱吧 App 视频录制流程中,随着对视频品质的要求不断提升,逐渐暴露出了视频处理能力不足的问题。更大的分辨率、更丰富的滤镜玩儿法都在挑战着硬件性能的极限。一款更高效的视频处理框架无疑会为日后的扩展提供更大的空间。

设计思路

问题分析

在设计新框架前,先要分析现有实现,发现问题和不足,从而在新框架中规避。经过分析,发现了一些现有实现中可供优化的点:

  • 非必要中间结果过多。

  • 可聚合的 GL 操作过多。

  • 与 GPU 传递数据不够灵活。

  • 对流程的控制权不足,需要一些多余操作来保证上下文的正确。

  • 同步串行的流程没有压榨出全部的硬件性能。

流程设计

如流程图所示,KTVVideoProcess 共有 3 个关键节点:

  1. Source - 用于获取原始数据,有文件读取、摄像头采集、播放器输出等方式。

  2. Pipeline - 用于渲染特效,内部由多个滤镜串联组成,将效果叠加至原始数据。

  3. Output - 用于分发渲染结果,可输出至屏幕、写入文件、直播发送等。

一次完整运行过程大致为:

  1. Source 吐出原始 Frame,异步交给 Pipeline。

  2. Pipeiline 将原始 Frame 送至内部的滤镜串处理,当全部滤镜依次作用在 Frame 后得到最终的处理结果,异步交给 Output。

  3. Output 将结果 Frame 按自身的特性进行分发。

制定原则

结合自身的运行方式和之前的问题,为尽可能保证性能,制定了如下原则:

  • 避免无用中间结果 。

  • 增强 Frame 的流通性,避免因流通而引发多余操作。

  • 在不影响结构的前提下,尽可能聚合 GL 操作。

  • 按需转换 glTexture/CVPixelBuffer,避免触发不必要的转换。

  • 严格控制 glFlush/glFinish 之类操作的调用时机,仅在必要时使用。

  • 结果分发采用异步处理,避免阻塞 Pipeline 的渲染。

  • 尝试并行。当 Pipeline 的消费能力弱于 Source 的生产能力且硬件性能仍有压榨空间时,可使用多条 Pipeline 来并行处理(流程图中 Concurrent Pipeline 部分)。

技术实现

通过上文已可以了解到 KTVVideoProcess 的运行过程,下面简单介绍一下用于内部支撑的几个类。

KTVVPFrame

@interface KTVVPFrame : NSObject

@property (nonatomic, assign) CMTime timeStamp;

@property (nonatomic, strong) KTVVPFrameLayout * layout;

@property (nonatomic, assign) GLuint texture;

- (void)uploadIfNeeded:(KTVVPFrameUploader *)uploader;

- (CVPixelBufferRef)corePixelBuffer;

- (void)lock;

- (void)unlock;

@end

KTVVPFrame 是流通于整个流程的视频帧对象,其有 layout 属性来描述图像内容的布局,如旋转、翻转、尺寸等信息,有 texture 属性来获取纹理 ID,有 corePixelBuffer 方法来获取图像数据,有 lock/lock 方法处理引用问题等接口。KTVVPFrame 为抽象类,可根据具体场景选择如下子类:

  • KTVVPGLTextureFrame

  • KTVVPGLDrawableFrame

  • KTVVPCVPixelBufferFrame

  • KTVVPCMSmapleBufferFrame

KTVVPFramePool

@interfaceKTVVPFramePool:NSObject

-(__kindof KTVVPFrame*)frameWithKey:(NSString*)key factory:(__kindof KTVVPFrame*(^)(void))factory;

@end

KTVVPFramePool 负责维护 KTVVPFrame 实例,管理它们的生命周期和复用情况。通过 Pool 获取到的 Frame 会被 lock。当使用完成调用 Frame 的 unlock 方法时,便会将其归还到 Pool 以便下次使用。

KTVVPFilter

@interfaceKTVVPFilter:NSObject<KTVVPFrameInput>

@property(atomic,weak)id <KTVVPFrameInput>output;

@end

KTVVPFilter 用于为 Input Frame 添加具体的一个特效。将通过 KTVVPFrameInput 接口获取到 Input Frame 进行处理,并向后传递给 self.output。KTVVPFrame 为抽象类,目前提供了一些功能类型的 Basic Filter 和一些效果类型的 Extension Filter:

Basic Filter
  • KTVVPTransformFilter

  • KTVVPPassthroughFilter

  • ......

Extension Filter
  • KTVVPBlackAndWhiteFilter

  • KTVVPBrightnessFilter

  • KTVVPExposureFilter

  • KTVVPRGBFilter

  • ......

KTVVPMessageLoop

@interface KTVVPMessageLoop : NSObject

@property (nonatomic, strong, readonly) NSThread * thread;

@property (nonatomic, strong, readonly) KTVVPObjectQueue * messageQueue;

- (void)putMessage:(KTVVPMessage *)message;

- (void)putMessage:(KTVVPMessage *)message delay:(NSTimeInterval)delay;

- (void)waitUntilFinished;

- (void)waitUntilStoped;

- (void)start;

- (void)stop;

@end

KTVVPMessageLoop 是为避免 OpenGL Context 频繁在不同线程中切换。其内部包含一个独立的子线程,用于保证添加到消息循环中的消息都将在此线程处理。并提供一些接口来处理多线程协作的状态同步。项目中所有需异步处理的任务均交由此类完成,是项目线程模型的根基,被广泛应用在 KTVVPSerialPipeline、KTVVPFrameView、KTVVPFrameWriter 等类。

OpenGL 相关

  • KTVVPGLImageTexture - 可将 UIImage 转为 glTexture。

  • KTVVPGLModel - 用于处理顶点、索引数据。

  • KTVVPGLPlaneModel - 用于二维平面的数据模型,支持旋转、翻转等变换。

  • KTVVPGLProgram - 快速创建、加载、绑定、链接 Shader。

  • KTVVPGLStandardProgram - 基于该项目标准 Shader 模板的 Program。

最后

项目开源在 GitHub,欢迎 Issue & PR。地址:https://github.com/ChangbaDevs/KTVVideoProcess

本文以回顾总结为主,并未对细节做过多解释说明。如有疑问建议可通过 GitHub 与我联系。


文章转载自ChangbaDev,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论