5 Star 24 Fork 20

天涯行客 / Effect-Designer

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 14.07 KB
一键复制 编辑 原始数据 按行查看 历史
liaozhilong1 提交于 2020-02-29 20:47 . 修改readme

Effect-Designer


1.开源Effect-Designer的由来

  • Effect-Designer是一款外观模和操作都模仿抖音特效制作工具(Effect Creator)的一款运行在windows平台的C++开源软件;前期是为公司内部短视频App制作视频特效而制作的一种探索和尝试,由于初期人力投入有限,工具90%以上的界面和操作都是参照抖音的特效工具,甚至界面的图片也是笔者用PS截取抖音的工具而来的,所以这款软件可以说是抖音特效工具的一个小翻版,真正涉及到公司业务的相关的内容并不多而且已经基本全部剥离;

  • 后期由于本工具与公司另外其他团队做的另一个工具相冲突与公司规划等原因,本项目被公司中途终止而夭折,之后一直处于闲置废弃状态。项目是笔者花费了几个月的时间和精力而编写完成的,完成度90%以上,觉得废弃掉实属可惜;同时软件的界面引用了另一个个人认为是全网最好的windows DUI界面开源引擎(REDM(曾评为码云最有价值开源项目),该库笔者也曾有幸与作者进行过深度参与并持续维护),该库完全是在windows Api的基础上进行封装的界面引擎,该引擎具有使用简便、扩展方便、生成产物体积小等优点,笔者觉得工程代码总体上具有有一定的学习和参考价值;现本着开放的态度将代码开源出来供大家相互学习和交流,希望能对读者有一定的帮助和借鉴;由于个人能力、水平和时间精力有限,如果有什么不好的地方还望指正和互相探讨......

2. 项目相关

1.0 软件的由来和用途

  • 公司开发的短视频App特效素材的制作一直是延用三方公司(商汤)自带的一款特效素材制作工具而制作的,该工具界面粗糙、工具的很多操作习惯和体验做的并不友好等痛点,不太适合小白或非专业人士使用;因此公司寻思着另外开发一款类似抖音特效素材制作工具的一款适合普通小白用户的大众化操作工具来替代商汤的工具。 effectcreator

                                                图示:抖音特效素材制作工具
  • 另外本工具并不涉及到图像、人脸识别等图像方面的相关算法,图像算法方面均由商汤的内核引擎进行解析。软件的功能主要是用于解析并编辑商汤的特效素材包(素材包主要包括json文件以及一些图片素材文件等,这些素材规则也是由商汤的引擎来制定的);即软件的主要用途可以概况为读取原始(或者新建)素材包,并通过素材包里面的json描述文件来把相应的素材元素(可能是贴纸、美妆图片等界面元素也可能是Transition等非界面元素)读取并构建在工具界面上,然后可以通过工具进行相应的界面元素编辑或者属性编辑等操作来达到对素材编辑的目的,并最终输出新素材包,最后素材包可导入移动端并由商汤的引擎进行相应的解析和处理。

  • 软件的大致概览如下(注:图片太大,登录后可预览)(点击下载软件可执行文件): recordsoft

2.0 工程的创建

  • 工程全部由cmake来维护的,您可以根据您本地vs的版本来生成相应的sln解决方案:(注:图片太大,登录后可预览) projcreate

3.部分代码预读解析

1. 界面编辑功能的Undo和Redo功能
1.0 工具的编辑功能支持对编辑操作等动作的Undo和Redo操作,首先这些动作不是具体的某种动作,是抽象的多类动作,所以笔者把这些动作抽象为动作基类ActionSlot,这个基类有两个抽象函数PerformUndoActionSlot()和PerformRedoActionSlot()来执行具体的Undo和Redo动作。
2.0 其实实现Undo、Redo动作功能跟浏览器的后退和前进功能一样,主要是通过数据结构中的栈来实现的,即动作保持先进后出、后进先出,当有新的动作来到时即执行入栈操作;笔者这里是用一个双向链表来实现这个栈的,具体实现可以查看ActionSlotMgr类。
2. 窗口的托盘图标安装类实现
之前笔者在做REDM的时候封装过一个单例类,暴露出InstallIcon接口来达到接口调用的目的,后发现之前的单例类实现实在不美观,现在采用继承和模板类的思想来实现该类DMTrayIconImpl;任何窗口想实现托盘图标的安装继承该类即可,然后调用该父类的接口InstallIcon来实现托盘的安装操作。
3. 资源包中json资源元素解析实现
1.0 特效原始资源包中的json文件是整个资源元素结构的定义文件,里面定义了多种不同类型的元素类型,比如:backgroundEdge、beautifyParts、faceExchange、faceMorph(美妆父属性节点)、makeups(美妆节点)、parts(贴纸节点)、transitions等元素。程序需要根据这个json的定义来搭构界面元素和属性的设置。json文件格式大致定义如下:

jsons

2.0 这些元素如何有规划的在界面搭建起来呢,笔者这里采用了DUI引擎读取XML文件的思想来巧妙的把这些元素转化成具体的类对象;如果熟悉DUI引擎的人都知道DUI引擎都是通过xml文件来保存界面元素信息的,比如一个Button类有着button的类属性和类方法,static类有static的类属性和类方法,然后这些类都是从DUIWindow父类继承下来的,这些子类重载了父类的部分虚函数。而这些子类的名称都会注册在类工厂里,xml里面只需要引用这些注册的类名(比如一个button对应注册的类名是“button”,xml里面写button即可构建一个按钮);当DUI引擎解析这个xml时,会从xml的顶节点开始递归的解析xml的所有节点,当遇到子控件(比如button)对象时,就会从类工厂里面寻找是否该类已经被注册,如果已经注册就会new出一个对应的类对象,然后把他放到控件树中,DUI通过维护这颗树的层级/父子关系来达到维护子控件的层级/父子关系。同样,笔者在解析json文件的时候也是用了这种思想:递归读取和解析json文件-->遇到子元素(如makeup节点)-->从类工厂查找对应的注册类,如果存在就new一个对应的对象-->将生成的对象指针加入到界面树结构中-->最后根据zposition熟悉微调界面元素的位置....。这些元素有个公共的父类EDJSonParser(类似DUI引擎中的DUIWindow基类),具体可参考工程Core目录下的代码。
4. 类工厂注册模块
类工厂模式是一个常用的设计模式,尤其在DUI引擎中对xml中的节点解析发挥了很大的作用,这点在上面的DUI加载xml的原理有过解释;REDM的类工厂的类注册就用的十分巧妙的,注册管理类DMRegMgr负责类的注册的;对应注册接口是:DMCode Register(IDMReg &RegObj, bool bReplace=false);参数中的IDMReg的实体子类实现其实是模板类template< class T> DMRegHelperT类,这个类的实现是极其巧妙的,因为他将真正的开辟的目标类对象(比如EDJSonParser类)用目标T来表示;该类本身的size大小为0,只有真正开辟目标类对象的时候才真正开辟内存空间。而这些注册到类工厂的目标类有个注册前提就是必须从EDBase类继承下来并且实现其三个静态函数:

static LPCWSTR GetClassName();
static LPCWSTR GetBaseClassName();
static int GetClassType();

所以每个从EDBase类继承的子类中都有类似EDDECLARE_CLASS_NAME(EDJSonParser,L"EDJSonParser", DMREG_Attribute) 的声明,EDDECLARE_CLASS_NAME其实就是这几个函数实现的宏定义。
5. Event事件的绑定模块
REDM很多模块其实写的非常不错的,其中一个就是DUI引擎中的Event函数的同步调用。Event管理类DMEventMgr用到了观察者模式所有注册进来的函数按EventID分类全部放一起,调用的时候根据EventID来进行函数的分发调用;而这些函数的调用是封装在以DMSlotFunctorBase为基类的DMFreeFunctionSlot(普通非类成员函数)类和DMMemberFunctionSlot(类成员函数)类中。DMMemberFunctionSlot类巧妙的利用了c++类模板来对不确定类注册的封装。最后类成员函数通过:

template < class T >
DMMemberFunctionSlot Subscriber(DMCode (T::* pFn)(DMEventArgs*), T* pObject) {
  return DMMemberFunctionSlot(pFn, pObject);
}

来完成类成员函数注册,普通函数是通过:

inline DMFreeFunctionSlot Subscriber(DMCode (pFn)(DMEventArgs)) {
  return DMFreeFunctionSlot(pFn);
}

来完成普通函数注册。
6.工程代码部分解析
工程中最复杂的功能莫过于特效图片的编辑控件(DUIObjEditor)了,类中包含了DUIRoot(白色区域编辑区的顶层父窗口)成员以及DUIDragFrame(元素控件拖拽的顶层Trackrect)成员;所有图片元素控件都会创建在DUIRoot窗口下(子窗口),拖拽元素上层的DUIDragFrame窗口的时候会通过DUIPos修改对应编辑的图片控件的布局,图片控件的布局是描点布局;DUI库中需要重写描点布局Layout类,并将其重新注册来替换默认的DUI描点布局类。

ed

7. windows内存泄漏检测
windows的内存泄漏检测经常采用一个开源库:“vld”来完成的。原理就是通过注册程序的内存开辟和释放的钩子来达到监控程序内存的开辟和释放,当有内存开辟时记录起来,当相应的内存释放时从记录中剔除,所以这个记录起来的表就是所有开辟未被释放的内存记录;然后通过这个记录记录的Eip可以回溯对应的开辟堆栈。笔者将vld核心代码提取并封装成CMemLeak,主要是考虑到:1.原生的vld代码和监测逻辑比较多,真正运行监测的时候会比较卡顿 2.原生的vld输出的内存开辟堆栈是零散的,笔者将同类的堆栈进行了归总和排序,也做了内存不同时间段的diff等小的封装来满足自己的需求。

4. 工程编译与运行

1.0 工程是通过cmake来维护的,需要提前安装cmake;工程支持底层用skia进行底层渲染,如果需要用到该功能,需要在cmake过程中勾选相应的选项来支持。
2.0 工程debug的时候会通过相对目录来定位程序的DUI资源,DUI的xml等相关界面资源目录在EDesigner\Res\EDesignerRes目录下,Debug模式下采用相对目录读取资源文件的方式;但是在Release模式下需要把资源目录下的layout和themes文件夹压缩为EDesignerRes.zip并放在Res目录下;Release模式下会把DUI压缩资源链接到Exe文件的资源段里,这样虽然增大了Exe的体积,但可以避免将界面资源文件直接暴露给用户,也可以避免升级不完全或者用户修改而导致界面资源文件不完整而引起的Bug。

5. 开源协议

Effect-Designer需要遵守什么开源协议?

用于个人,团体,公司进行相应的交流和学习,如果你能从这个库中拿到你需要的代码,这也是OK的。

6. 关于

C++
1
https://gitee.com/lzlong88/Effect-Designer.git
git@gitee.com:lzlong88/Effect-Designer.git
lzlong88
Effect-Designer
Effect-Designer
master

搜索帮助