滤镜及转场

短视频SDK提供了自定义特效能力,您可以基于通用特效配置文件,通过自定义OpenGL ES Shader(OpenGL ES 3.0语法),实现想要的滤镜与转场效果。有关OpenGL ES的知识点和解释并不属于本篇文档的范畴,我们默认您已经对OpenGL ES及其Shader Language有所了解。

简介

一个滤镜或转场的特效资源包文件夹,包含了一个名为config.json的通用特效配置文件以及一些图片素材。在短视频SDK中编辑视频和录制视频时,支持使用转场和滤镜特效,即调用相关编辑和录制接口时,传入所配置的特效资源包文件夹目录,来应用一个特效效果。

配置通用特效配置文件

通用特效配置文件采用JSON格式,描述了完整的渲染过程。整体结构分为两个层级,第一层级描述了特效的基本信息,第二层级用节点树描述了特效的实现细节。

特效基本信息-第一层级

特效的基本信息包含以下字段:

字段

说明

name

特效名称。

module

模块标识,该字段必须是ALIVC_GECF

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中,渲染流程如图所示:滤镜及特效.png

据上图所示,渲染过程被抽象为一系列节点组成的树状结构。

  • 输入节点INPUT_NODE代表原始输入源。在录制场景下,输入节点是摄像头采集的图像数据流。在编辑场景下,输入节点是当前播放视频流。在设计上,输入节点可以是多个。例如转场过程中,需要对前后两个视频做效果变换。此时,前一个视频是INPUT_NODE0,后一个是INPUT_NODE1。

  • 中间的节点树部分即对应配置文件中的nodeTree字段。一个节点树可以包含一个或多个渲染节点。可以看到,整个渲染配置文件的关键就是有关节点的配置。

  • 输出节点OUTPUT_NODE代表渲染后的视频流。在预览模式下,输出节点输出到屏幕。在合成模式下,输出节点输出到编码器编码。

节点

节点字段描述了整个渲染流程中,某一次绘制过程中的相关配置,这里的配置包含了自定义特效所必须的着色器代码以及相关参数描述。 节点包含以下字段:

字段

说明

nodeId

节点id,用于标识当前节点。

name

节点名称。

vertex

顶点着色器代码。

该字段作用与vertexPath字段相同,声明其中任意一个即可。

该字段可以不写,如果不填写,SDK会提供默认实现如下:

attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
 gl_Position = position;
 textureCoordinate = inputTextureCoordinate.xy;
}

vertexPath

顶点着色器代码所在文件路径。

该字段作用与vertex字段相同,声明其中任意一个即可。

attributes

attributes列表,该字段用于声明顶点着色中attribute参数名name和类型type。

type取值为:POSITION,顶点坐标;TEXTURECOORD,纹理坐标。

该字段可以不填写,如果不填写,SDK会提供默认实现如下:

[
 {
 "name": "position",
 "type": "POSITION"
 },
 {
 "name": "inputTextureCoordinate",
 "type": "TEXTURECOORD"
 }
]

fragment

片段着色器代码。

该字段作用与fragmentPath字段相同,声明其中任意一个即可。

fragmentPath

片段着色器代码所在文件路径。

该字段作用与fragment字段相同,声明其中任意一个即可。

textures

纹理列表。用于描述片段着色器中sampler2D纹理参数的相关属性。属性包括:

  • name:纹理名。

  • srcType:纹理数据源类型,代表待绘制的纹理数据从哪里获取。支持类型如下:

    • IMAGE:当前纹理来自资源图片,该类型需要同时声明path字段,并且把图片文件放到资源包中

    • INPUT_NODE:当前纹理来自输入节点传入的图像数据,该类型需要同时声明nodeId字段

    • CUSTOM_NODE:当前纹理来自自定义节点处理后的图像数据,该类型需要同时声明nodeId字段。

  • nodeId:节点id。

    • srcType为CUSTOM_NODE或INPUT_NODE时需要填写。

    • 当srcType为INPUT_NODE时,nodeId字段不能随意填写。滤镜场景下为0。转场场景下前一个视频流nodeId为0,后一个视频流nodeId为1。

  • path:资源文件路径,srcType为IMAGE时需要填写。

params

参数列表。用于描述片段着色器中uniform参数的相关属性。属性包括:

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字段就是当前参数的值。更新特效参数需要以下两步:

  1. 通过AliyunValue对象提供的update设值方法更新参数值。

  2. 调用特效更新方法更新参数。具体特效更新方法请参见如下操作步骤中的第三步更新特效参数。

Android操作步骤

  • 滤镜

    1. 调用EffectFilter(String path)方法创建特效对象,path参数为特效文件夹路径。

    2. 调用int addAnimationFilter(EffectFilter filter);方法应用滤镜特效。

    3. 调用int updateAnimationFilter(EffectFilter filter);方法更新滤镜特效参数。

  • 转场

    1. 调用TransitionBase(String path)创建特效对象,path参数为特效文件夹路径。

    2. 调用int setTransition(int index, TransitionBase transition);方法应用转场特效。

    3. 调用int updateTransition(int clipIndex, TransitionBase transitionBase);方法更新转场特效参数。

iOS操作步骤

  • 滤镜

    1. 调用AliyunEffectFilter- (instancetype)initWithFile:(NSString *)path;方法创建特效对象,path参数为特效文件夹路径。

    2. 调用- (int)applyAnimationFilter:(AliyunEffectFilter *)filter;方法应用滤镜特效。

    3. 调用- (int)updateAnimationFilter:(AliyunEffectFilter *)filter;方法更新滤镜特效参数。

  • 转场

    1. 调用AliyunTransitionEffect-(instancetype)initWithPath:(NSString *)path;方法创建特效对象,path参数为特效文件夹路径。

    2. 调用- (int)applyTransition:(AliyunTransitionEffect *)transition atIndex:(int)clipIdx;方法应用转场特效。

    3. 调用-(int)updateTransition:(AliyunTransitionEffect *)transition atIndex:(int)clipIdx;方法更新转场特效参数。