视频模板功能即通过替换模板中的视频、图片、文字,导出生成新的视频,是一种快速或规模化的视频生产方式。可通过短视频的模板能力实现剪同款功能。

版本支持

版本 是否支持
专业版 支持
说明 短视频SDK V3.27及以上版本才支持视频模板功能。
标准版 不支持
基础版 不支持

相关类功能

类名 功能
AliyunTemplate 模板。
AliyunTemplateParam 模板参数。
AliyunTemplateNode 模板编辑应用节点基类。
AliyunTemplateClipNode 模板片段编辑应用节点。
AliyunTemplateCaptionNode 模板字幕编辑应用节点。
AliyunTemplateEditor 模板应用编辑器。
AliyunTemplateModifyContent 定义模板生成器中要修改的内容。
AliyunTemplateBuilder 模板生成器。
AliyunTemplateExporter 模板导出器。
AliyunTemplateLoader 模板加载器。
AliyunTemplateImporter 模板导入器。
ATResourceModel 模板资源模型。
AliyunTemplateResourceExport 模板资源导出管理器。
AliyunTemplateResourceImport 模板资源导入管理器。

视频模板应用流程

视频模板的使用流程如下图所示:ios视频模板流程

生成模板

可以对编辑器或草稿目录生成模板文件,并存储在指定的目录下;也可以对已经生成的模板文件进行打开编辑。无论哪种形式,最终可以获取AliyunTemplate对象,并提供更新封面、预览视频、预览标题、预览模板ID、锁定节点等接口。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能
// 生成模板文件,并进行更新
NSString *taskPath = [[AlivcTemplateResourceManager builtTemplatePath] stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
AliyunTemplateBuilder *builder = [AliyunTemplateBuilder build:taskPath editorTaskPath:_taskPath];
if (builder) {
    // update title
    [builder updateTitle:_titleView.text];

    // update cover url
    NSString *coverPath = [_taskPath stringByAppendingPathComponent:@"template_cover.png"];
    NSData *data = UIImagePNGRepresentation(_coverImage);
    [data writeToFile:coverPath atomically:YES];
    [builder updateCover:coverPath];

    // update preview with remote url
    [builder updatePreviewVideo:_outputPath];

    // save all
    [builder save];

    AlivcTemplateBuilderViewController *vc = [[AlivcTemplateBuilderViewController alloc] initWithEditorTaskPath:taskPath isOpen:YES];
    [self.navigationController pushViewController:vc animated:YES];

    return;
}

导出模板

生成的模板,其关联到的自定义资源(包括模板资源和工程资源,APP内置资源或平台资源除外)都是以绝对路径(Source.Path)存在配置文件中。如果模板需要在不同的设备或平台中使用,那么需要进行导出模板。通过导出模板,把本地关联的资源进行拷贝到相对目录或上传,并返回指定的地址(Source.URL),从而达到跨设备使用目的。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能
NSString *taskPath = @"存储目录";
NSString *templateTaskPath = @"模板目录";

AliyunTemplateResourceExport *resourceExport = [AliyunTemplateResourceExport new];

// 模板资源导出,目的是把本地自定义资源的路径转换为http(需要把本地资源进行上传)或自定义协议地址(例如本地相对”alivc_resource://relation?path=“),参考demo
resourceExport.selfResourceExport = [AlivcTemplateResourceManager templateResourceExport:taskPath];

// 工程资源导出,目的是把本地自定义资源的路径转换为http(需要把本地资源进行上传)或自定义协议地址(例如本地相对”alivc_resource://relation?path=“),参考demo
resourceExport.projectResourceExport = [AlivcTemplateResourceManager projectResourceExport:taskPath];

// 执行导出
[AliyunTemplateExporter export:taskPath templateTaskPath:templateTaskPath resourceExport:resourceExport completed:^(NSError *error) {

    if (error) {
        // 失败
    }
    else {
        // 成功
    }
}];

导入模板

APP中需要使用的模板,往往来自内置或网络下载,这些模板通常都能够跨设备使用,当需要在当前设备使用模板时,需要通过导入来处理其关联的资源。通过导入模板,把非本地关联的资源进行下载(必要时),最终把自定义协议地址的资源进行处理,并返回指定的绝对路径(Source.Path),这样在加载模板时便确保能访问到对应资源。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能
NSString *tempTaskPath = @"模板目录";
NSString *taskPath = @"存储目录";
// 模板资源导入,目的是把自定义协议地址(例如本地相对”alivc_resource://relation?path=“)转换为本地全路径,详细可参考demo代码示例
AliyunResourceImport *resourceImport = [AlivcTemplateResourceManager templateResourceImport:tempTaskPath reset:YES];
[AliyunTemplateImporter import:taskPath templateTaskPath:tempTaskPath resourceImport:resourceImport completed:^(NSError *error) {
    if (error) {
        // 出错,删除本地模板文件,下次可以再次尝试执行导入
        [[NSFileManager defaultManager] removeItemAtPath:taskPath error:nil];
    }
    else {
        // 成功
    }
}];

加载模板

对已导入的模板,需要通过加载后才能使用,对Project资源进行导入后才能应用模板。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能
// 加载Loader
NSString *taskPath = @"模板目录";
AliyunTemplateLoader *loader = [[AliyunTemplateLoader alloc] initWithTaskPath:taskPath];
if (loader) {
    self.loader = loader;
}
else {
    // 失败
}

// 导入Project资源后,应用模板
NSString *templateTaskPath = @"模板目录";
__weak typeof(self) weakSelf = self;
[self.loader loadProject:[AlivcTemplateResourceManager projectResourceImport:templateTaskPath reset:NO shouldDownload:YES] completed:^(NSError *error) {
    if (error) {
        // 加载资源失败
    }
    else {
        // 成功,应用模板
        AlivcTemplateEditorViewController *tevc = [[AlivcTemplateEditorViewController alloc] initWithTemplateTaskPath:templateTaskPath];
        [weakSelf.navigationController pushViewController:tevc animated:YES];
    }
}];

应用模板

可以对指定的模板,或者一个已经应用模板的草稿进行编辑,可预览或替换视频、图片、字幕等节点,并导出视频。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能
// 创建应用模板编辑器
if (self.templateTaskPath) {
    // 新建
    NSString *taskPath = [[AlivcTemplateResourceManager projectTemplatePath] stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
    self.aliyunEditor = [AliyunTemplateEditor createTemplateEditor:self.templateTaskPath onTaskPath:taskPath];
}
else if (self.taskPath) {
    // 打开
    self.aliyunEditor = [AliyunTemplateEditor openTemplateEditor:self.taskPath];
}

// 设置预览视图
self.aliyunEditor.preview = self.videoDisplayView;

// 加载编辑器,加载后才能进行后续操作
int ret = [self.aliyunEditor loadEditor];
if (ret != ALIVC_COMMON_RETURN_SUCCESS) {
    NSLog(@"加载失败,可能是授权问题:%d", ret);
}

// 开始编辑
[self.aliyunEditor startEdit];

// 播放
[self.aliyunEditor..getPlayer play];

// 获取更换片段节点列表,按照锁定、开始时间进行排序
NSArray<AliyunTemplateClipNode *> *sortNodes = [[self.aliyunEditor clipNodes] sortedArrayUsingComparator:^NSComparisonResult(AliyunTemplateClipNode *obj1, AliyunTemplateClipNode *obj2) {
    if (obj1.lock && !obj2.lock) {
        return NSOrderedAscending;
    }
    else if (!obj1.lock && obj2.lock) {
        return NSOrderedDescending;
    }
    else if (obj1.timelineIn < obj2.timelineIn) {
        return NSOrderedAscending;
    }
    return NSOrderedDescending;
}];


// 更换视频/图片片段
int ret = [self.aliyunEditor updateClipNode:node clipPath:sourcePath clipType:AliyunClipVideo];
if (ret == ALIVC_COMMON_RETURN_SUCCESS) {
    // 成功
}
else {
    NSLog(@"替换失败: %d", ret);
}

// 导出
AlivcExportViewController *controller = [[AlivcExportViewController alloc] init];
controller.taskPath = self.aliyunEditor.taskPath;
controller.outputPath = [[AlivcTemplateResourceManager applyTemplatePath] stringByAppendingPathComponent:fileName];
controller.outputSize = self.aliyunEditor.getEditorProject.config.outputResolution;
controller.backgroundImage = [UIImage imageWithContentsOfFile:self.aliyunEditor.getCurrentTemplate.cover.path];
controller.coverImage = controller.backgroundImage;
controller.draft = draft;
[self.navigationController pushViewController:controller animated:YES];