短视频SDK提供了自定义特效能力,您可以基于通用特效配置文件,通过自定义OpenGL ES Shader(OpenGL ES 3.0语法),实现想要的滤镜与转场效果。有关OpenGL ES的知识点和解释并不属于本篇文档的范畴,我们默认您已经对OpenGL ES及其Shader Language有所了解。
简介
一个滤镜或转场的特效资源包文件夹,包含了一个名为config.json的通用特效配置文件以及一些图片素材。在短视频SDK中编辑视频和录制视频时,支持使用转场和滤镜特效,即调用相关编辑和录制接口时,传入所配置的特效资源包文件夹目录,来应用一个特效效果。
配置通用特效配置文件
通用特效配置文件采用JSON格式,描述了完整的渲染过程。整体结构分为两个层级,第一层级描述了特效的基本信息,第二层级用节点树描述了特效的实现细节。
特效基本信息-第一层级
特效的基本信息包含以下字段:
字段 | 说明 |
name | 特效名称。 |
module | 模块标识,该字段必须是 |
version | 版本号,当前版本为1。 |
type | 特效类型,1表示滤镜,2表示转场。 |
nodeTree | 节点树,用于描述特效的实现细节,详细内容请参见节点树-第二层级。 |
以特效Intense滤镜的配置文件为例,示例如下:
{
"name": "Intense",
"module": "ALIVC_GECF",
"version": 1,
"type": 1,
"nodeTree": [
{
"nodeId": 0,
"name": "Intense",
"fragment": "/** ...... */",
"textures": [
{
"name": "inputImageTexture",
"srcType": "INPUT_NODE",
"nodeId": 0
},
{
"name": "inputImageTexture2",
"srcType": "IMAGE",
"path": "color.png"
}
]
}
]
}
节点树-第二层级
节点树nodeTree
用于描述一个渲染流程,包含了一个或多个节点。
在短视频SDK中,渲染流程如图所示:
据上图所示,渲染过程被抽象为一系列节点组成的树状结构。
输入节点INPUT_NODE代表原始输入源。在录制场景下,输入节点是摄像头采集的图像数据流。在编辑场景下,输入节点是当前播放视频流。在设计上,输入节点可以是多个。例如转场过程中,需要对前后两个视频做效果变换。此时,前一个视频是INPUT_NODE0,后一个是INPUT_NODE1。
中间的节点树部分即对应配置文件中的
nodeTree
字段。一个节点树可以包含一个或多个渲染节点。可以看到,整个渲染配置文件的关键就是有关节点的配置。输出节点OUTPUT_NODE代表渲染后的视频流。在预览模式下,输出节点输出到屏幕。在合成模式下,输出节点输出到编码器编码。
节点
节点字段描述了整个渲染流程中,某一次绘制过程中的相关配置,这里的配置包含了自定义特效所必须的着色器代码以及相关参数描述。 节点包含以下字段:
字段 | 说明 |
nodeId | 节点id,用于标识当前节点。 |
name | 节点名称。 |
vertex | 顶点着色器代码。 该字段作用与vertexPath字段相同,声明其中任意一个即可。 该字段可以不写,如果不填写,SDK会提供默认实现如下:
|
vertexPath | 顶点着色器代码所在文件路径。 该字段作用与vertex字段相同,声明其中任意一个即可。 |
attributes | attributes列表,该字段用于声明顶点着色中attribute参数名name和类型type。 type取值为:POSITION,顶点坐标;TEXTURECOORD,纹理坐标。 该字段可以不填写,如果不填写,SDK会提供默认实现如下:
|
fragment | 片段着色器代码。 该字段作用与fragmentPath字段相同,声明其中任意一个即可。 |
fragmentPath | 片段着色器代码所在文件路径。 该字段作用与fragment字段相同,声明其中任意一个即可。 |
textures | 纹理列表。用于描述片段着色器中
|
params | 参数列表。用于描述片段着色器中
|
params参数类型(type) 支持的类型
类型 | 参数取值示例 |
INT | [1] |
FLOAT | [-2.0] |
VEC2I | [3, 2] |
VEC3I | [1, 2, 3] |
VEC4I | [4, 3, 2, 1] |
VEC2F | [-1.0, 1.0] |
VEC3F | [0.5, 0.5, 0.5] |
VEC4F | [1.0, -1.0, 1.0, -1.0] |
MAT3F | [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0] |
MAT4F | [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] |
以特效Translate转场的配置文件为例,示例如下:
{
"name": "Translate",
"module": "ALIVC_GECF",
"version": 1,
"type": 2,
"nodeTree": [
{
"nodeId": 0,
"name": "Translate",
"vertex": "/** ...... */",
"attributes": [
{
"name": "a_position",
"type": "POSITION"
},
{
"name": "a_texcoord",
"type": "TEXTURECOORD"
}
],
"fragment": "/** ...... */",
"textures": [
{
"name": "RACE_Tex0",
"srcType": "INPUT_NODE",
"nodeId": 0
},
{
"name": "RACE_Tex1",
"srcType": "INPUT_NODE",
"nodeId": 1
}
],
"params": [
{
"name": "direction",
"type": "INT",
"value": [
0
],
"maxValue": [
3
],
"minValue": [
0
]
}
]
}
]
}
内建变量
SDK中内置了一些变量,您可以在shader中直接声明,目前有以下内建变量:
uniform highp float BUILTIN_PROGRESS; // 转场进度:0~1
uniform highp float BUILTIN_WIDTH; // 图像宽
uniform highp float BUILTIN_HEIGHT; // 图像高
在短视频SDK中使用特效
使用特效通常需要先创建特效对象,再应用特效,最后按需更新特效参数。
初始化后的特效对象内可以获取到描述特效配置的AliyunEffectConfig
对象,该对象内部结构与特效配置文件的结构相对应。 如果某一个自定义特效配置文件里包含有params字段
,对应在代码中可以通过AliyunEffectConfig
-> nodeTree
-> params
获取到AliyunParam
对象。AliyunParam
对象中的value
字段就是当前参数的值。更新特效参数需要以下两步:
通过
AliyunValue
对象提供的update设值方法更新参数值。调用特效更新方法更新参数。具体特效更新方法请参见如下操作步骤中的第三步更新特效参数。
Android操作步骤
滤镜
调用
EffectFilter(String path)
方法创建特效对象,path
参数为特效文件夹路径。调用
int addAnimationFilter(EffectFilter filter);
方法应用滤镜特效。调用
int updateAnimationFilter(EffectFilter filter);
方法更新滤镜特效参数。
转场
调用
TransitionBase(String path)
创建特效对象,path
参数为特效文件夹路径。调用
int setTransition(int index, TransitionBase transition);
方法应用转场特效。调用
int updateTransition(int clipIndex, TransitionBase transitionBase);
方法更新转场特效参数。
iOS操作步骤
滤镜
调用
AliyunEffectFilter
的- (instancetype)initWithFile:(NSString *)path;
方法创建特效对象,path
参数为特效文件夹路径。调用
- (int)applyAnimationFilter:(AliyunEffectFilter *)filter;
方法应用滤镜特效。调用
- (int)updateAnimationFilter:(AliyunEffectFilter *)filter;
方法更新滤镜特效参数。
转场
调用
AliyunTransitionEffect
的-(instancetype)initWithPath:(NSString *)path;
方法创建特效对象,path
参数为特效文件夹路径。调用
- (int)applyTransition:(AliyunTransitionEffect *)transition atIndex:(int)clipIdx;
方法应用转场特效。调用
-(int)updateTransition:(AliyunTransitionEffect *)transition atIndex:(int)clipIdx;
方法更新转场特效参数。