You can replace the videos, images, and text in a video template to generate a new video. The video template feature of short videos allows you to crop a large number of videos that have the same style as an existing video at a time.

Supported editions

Edition Supported
Professional Yes
Note Only the short video SDK V3.27 or later supports the video template feature.
Standard No
Basic No

Related classes

Class Description
AliyunTemplate A class that defines the template.
AliyunTemplateParam A class that defines parameters in the template.
AliyunTemplateTextParam A class that defines text parameters in the template.
AliyunTemplateImageParam A class that defines image parameters in the template.
AliyunTemplateVideoParam A class that defines video parameters in the template.
AliyunTemplatePlayer A class that defines the template player.
AliyunTemplateBuilder A class that defines the template builder.
AliyunTemplateEditor A class that defines the template editor.
AliyunTemplateFactory A class that defines the template factory.

Generate a template

After a video is generated, you can select replaceable elements such as videos, images, and subtitles and call AliyunTemplateBuilder to generate a template. For information about the parameters that are used in the code, see Related classes.
// Generate a template builder based on the path of the project configuration file.
AliyunTemplateBuilder mAliyunTemplateBuilder = AliyunTemplateFactory.createAliyunTemplateBuilder(Uri.parse(path));
// Obtain editable parameters.
List<AliyunTemplateParam> list = mAliyunTemplateBuilder.getAllParams();
File appFilesDir = getExternalFilesDir(null);
// Specify the template directory.
File templateDir = new File(appFilesDir.getAbsolutePath() + File.separator + TemplateManager.TEMPLATE_LIST_DIR + File.separator + System.currentTimeMillis());
if (!templateDir.exists()) {
    templateDir.mkdirs();
}
// Copy the sample video to the template directory.
File videoFile = new File(mOutputPath);
File videoDestFile = new File(templateDir, videoFile.getName());
FileUtils.copyFile(videoFile, videoDestFile);
Source videoSource = new Source(videoDestFile.getPath());
videoSource.setURL(AlivcResUtil.getRelationResUri(videoFile.getName()));
// Copy the source thumbnail to the template directory.
File coverFile = new File(mAliyunTemplateBuilder.getEditorProject().getCover().getPath());
File coverDestFile = new File(templateDir, coverFile.getName());
FileUtils.copyFile(coverFile, coverDestFile);
Source coverSource = new Source(coverDestFile.getPath());
coverSource.setURL(mAliyunTemplateBuilder.getEditorProject().getCover().getURL());
if (StringUtils.isEmpty(coverSource.getURL())) {
    coverSource.setURL(AlivcResUtil.getRelationResUri(coverFile.getName()));
}
// Set the path of the project configuration file.
File projectFile = new File(templateDir, AliyunEditorProject.PROJECT_FILENAME);
Source projectSource = new Source(projectFile.getPath());
projectSource.setURL(AlivcResUtil.getRelationResUri(AliyunEditorProject.PROJECT_FILENAME));
// Build a template.
mAliyunTemplateBuilder.build(templateDir, title, videoSource, coverSource,projectSource, mTemplateInputAdapter.list, new AliyunTemplateSourceHandleCallback() {
    @Override
    public void onHandleResourceTasks(String templateDir, List<AliyunResTask> tasks) {
        // Process template resources.
        HashMap<String, List<AliyunResTask>> map = new HashMap<>();
        // Filter duplicate resources.
        for (AliyunResTask task : tasks) {
            if (task.getSource() == null || task.getSource().getPath() == null) {
                task.onIgnore();
                continue;
            }
            // If the URL does not start with alivc_resource, process the URL.
            String url = task.getSource().getURL();
            if (StringUtils.isEmpty(url) || !url.startsWith("alivc_resource")) {
                if (map.containsKey(task.getSource().getPath())) {
                    map.get(task.getSource().getPath()).add(task);
                } else {
                    List<AliyunResTask> list = new ArrayList<>();
                    list.add(task);
                    map.put(task.getSource().getPath(), list);
                }
            } else {
                // Ignore the error.
                task.onIgnore();
            }
        }
        for (Map.Entry<String, List<AliyunResTask>> entry : map.entrySet()) {
            try {
                String path = entry.getKey();
                if (path == null) {
                    continue;
                }
                File srcFile = new File(path);
                File destFile = new File(templateDir, srcFile.getName());
                if (!path.contains(templateDir)) {
                    FileUtils.copyFile(srcFile, destFile);
                }
                List<AliyunResTask> list = entry.getValue();
                for (AliyunResTask task:list){
                    Source source = task.getSource();
                    source.setPath(destFile.getPath());
                    source.setURL(AlivcResUtil.getRelationResUri(srcFile.getName()));
                    task.onHandleCallback(source);
                }
            } catch (Exception e) {
                // Ignore the error.
                List<AliyunResTask> list = entry.getValue();
                for (AliyunResTask item:list){
                    item.onIgnore();
                }
            }
        }
    }

    @Override
    public void onSuccess() {
        // The template is generated.
    }

    @Override
    public void onFailure(String msg) {
        // The template fails to be generated.
    }
});

Import resources to the template to generate a project configuration file

After the template draft is generated in the template path, call AliyunTemplateEditor to edit the template draft. For information about the parameters that are used in the code, see Related classes.
// Obtain the information of the template from the template path.
AliyunTemplate template  = AliyunTemplateFactory.getAliyunTemplate(Uri.parse(mTemplatePath));
// Obtain the parameters for template import.
List<AliyunTemplateParam> params = template.getImportParams();
List<AliyunClip> clips = new ArrayList<>();
// Select corresponding resources to replace template parameters.
List<MediaInfo> data = new ArrayList<>();
for (MediaInfo mediaInfo : data) {
    if (mediaInfo.mimeType.startsWith("video")) {
        clips.add(new AliyunVideoClip.Builder()
                .source(mediaInfo.filePath)
                .startTime(mediaInfo.startTime)
                .endTime(mediaInfo.startTime + mediaInfo.duration)
                .duration(mediaInfo.duration)
                .build());
    } else if (mediaInfo.mimeType.startsWith("image")) {
        clips.add(new AliyunImageClip.Builder()
                .source(mediaInfo.filePath)
                .duration(mediaInfo.duration)
                .build());
    }
}
// Use imported videos and images to generate the template configuration file.
AliyunEditorProject project = template.createEditorProject(TemplateMediaActivity.this, clips);
// Pass the path to the editor to generate the video that contains replaced resources.
String path = project.getProjectFile().getAbsolutePath();

Edit the template and produce the video

Generate the parameters that are required to produce the video based on the value of AliyunEditorProject returned by the template editor and pass the parameters to AliyunCompose to produce the video. For information about the parameters that are used in the code, see Related classes.
AlivcEditOutputParam outputParam = new AlivcEditOutputParam();
// Obtain the project configuration from the template editor.
AliyunEditorProject project = mAliyunTemplateEditor.getEditorProject();
// Set the parameters that are required to generate the video.
outputParam.setConfigPath(project.getProjectFile().getAbsolutePath());
outputParam.setOutputVideoHeight(project.getConfig().getOutputHeight());
outputParam.setOutputVideoWidth(project.getConfig().getOutputWidth());
outputParam.setVideoRatio(((float) mPasterContainerPoint.x) / mPasterContainerPoint.y);
AliyunVideoParam param = new AliyunVideoParam.Builder()
        .frameRate(project.getConfig().getFps())
        .gop(project.getConfig().getGop())
        .crf(project.getConfig().getCrf())
        .videoQuality(VideoQuality.values()[project.getConfig().getVideoQuality()])
        .scaleMode(VideoDisplayMode.valueOf(project.getConfig().getDisplayMode()))
        .scaleRate(project.getConfig().getScale())
        .outputWidth(project.getConfig().getOutputWidth())
        .outputHeight(project.getConfig().getOutputHeight())
        .videoCodec(VideoCodecs.getInstanceByValue(project.getConfig().getVideoCodec()))
        .build();
outputParam.setVideoParam(param);
if (project.getCover() != null && !StringUtils.isEmpty(project.getCover().getPath()) && FileUtils.isFileExists(project.getCover().getPath())) {
    String path = project.getCover().getPath();
    outputParam.setThumbnailPath(path);
} else {
    outputParam.setThumbnailPath(Constants.SDCardConstants.getDir(getApplicationContext()) + File.separator + "thumbnail.jpg");
}

// Jump to another interface after you edit the video.
Intent intent = new Intent();
intent.setClassName(TemplateEditorActivity.this, EditorActivity.NEXT_ACTIVITY_CLASS_NAME);
intent.putExtra(PublishActivity.KEY_PARAM_THUMBNAIL, outputParam.getThumbnailPath());
intent.putExtra(PublishActivity.KEY_PARAM_CONFIG, outputParam.getConfigPath());
intent.putExtra(PublishActivity.KEY_PARAM_VIDEO_WIDTH, outputParam.getOutputVideoWidth());
intent.putExtra(PublishActivity.KEY_PARAM_VIDEO_HEIGHT, outputParam.getOutputVideoHeight());
// Pass in the ratio of the video.
intent.putExtra(PublishActivity.KEY_PARAM_VIDEO_RATIO, outputParam.getVideoRatio());
intent.putExtra("videoParam", outputParam.getVideoParam());
// Jump to the page to generate the video.
startActivityForResult(intent, PublishActivity.REQUEST_CODE);