拼接是把多个不同格式 、不同编码、分辨率的视频拼接在一起,输出成一个格式、编码、分辨率相同的新视频。常用于添加固定的片头和片尾、直播录制视频拼接。剪辑是指裁剪视频的某一段,输出成一个新视频。常用于截取视频中精彩或关键的内容。本文介绍媒体处理Java SDK进行视频拼接和简单剪辑的示例代码。
使用场景
片头和片尾:用于添加固定的片头和片尾,以及直播录制视频的拼接,以提升品牌的辨识度。
剪辑拼接:对视频的特定段落进行裁剪,并输出为一个新的视频文件。此操作常用于提取视频中精彩或关键的内容。
开板尾板:视频开板和尾板是一种特殊的拼接效果,嵌入于正片视频中,以画中画的形式进行展示。
普通视频拼接任务-URL方式
例如,针对一个正片视频,从00:00:03.000秒开始截取,持续00:00:13.000秒,并将其与片头视频中从00:00:01.000秒截取至00:00:05.030秒的部分进行拼接,最终生成的视频总时长为17.30秒。
/**
* 普通视频拼接任务 URL方式
* @return
* @throws Exception
*/
public static void mergrUrlListJob() throws Exception {
//构建输出参数
JSONArray outputs = new JSONArray();
//构建input, 需要保证Location区域和服务client区域一致
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
//构建一个输出对象
JSONObject output = new JSONObject();
try {
input.put("Object", URLEncoder.encode("mps-test/demo/test.mp4", "utf-8"));
String outPutObject = URLEncoder.encode("mps-test/demo/merge-out.mp4", "utf-8");
output.put("OutputObject", outPutObject);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("input URL encode failed");
}
output.put("TemplateId", "<transcode templateId>");
//构建一个素材截取数据
JSONObject clip = new JSONObject();
//代表从01秒000毫秒开始,截取到第5秒30毫秒为止
clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"Duration\":\"5.30\"}");
//代表从01秒000毫秒开始,截取到距离片尾剩余5秒30毫秒为止
//clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"End\":\"5.30\"}");
//true:先剪辑第一个片段,再拼接(转码)
clip.put("ConfigToClipFirstPart", true);
//构建一个拼接数据
JSONArray mergeList = new JSONArray();
JSONObject merge = new JSONObject();
merge.put("MergeURL", "http://bucket-name.oss-cn-shanghai.aliyuncs.com/" + URLEncoder.encode("mps-test/demo/test2mp4", "utf-8"));
merge.put("Start", "00:00:03.000");
merge.put("Duration", "00:00:13.000");
mergeList.add(merge);
output.put("Clip", clip);
output.put("MergeList", mergeList);
outputs.add(output);
com.aliyun.mts20140618.Client client = MergeClipJobs.createClient();
com.aliyun.mts20140618.models.SubmitJobsRequest submitJobsRequest = new com.aliyun.mts20140618.models.SubmitJobsRequest()
//作业输入
.setInput(input.toJSONString())
//作业输出配置
.setOutputs(outputs.toJSONString())
//输出文件所在的OSS Bucket
.setOutputBucket("exampleBucket")
//输出文件所在的 OSS Bucket 的地域(OSS Region)
.setOutputLocation("oss-cn-shanghai")
//管道ID
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
普通视频拼接任务-ConfigFile方式
例如,针对一个正片视频,从00:00:03.000秒开始截取,持续时间为00:00:10.000秒,并将其与片头视频拼接,后者从00:00:01.000秒开始截取至距离片尾剩余5秒30毫秒为止。
所用mergeConfigfile内容示例如下:
{"MergeList":[{"MergeURL":"https://bucket-name.oss-cn-beijing.aliyuncs.com/mps-test/demo/test2.mp4","Start":"00:00:03.000","Duration":"00:00:10.000"}]}
/**
* 普通视频拼接任务 ConfigFile方式
* @return
* @throws Exception
*/
public static void mergrConfigFileJob() throws Exception {
//构建输出参数
JSONArray outputs = new JSONArray();
//构建input, 需要保证Location区域和服务client区域一致
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
//构建一个输出对象
JSONObject output = new JSONObject();
try {
input.put("Object", URLEncoder.encode("mps-test/demo/test.mp4", "utf-8"));
String outPutObject = URLEncoder.encode("mps-test/demo/merge-out.mp4", "utf-8");
output.put("OutputObject", outPutObject);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("input URL encode failed");
}
output.put("TemplateId", "<transcode templateId>");
//构建一个素材截取数据
JSONObject clip = new JSONObject();
//代表从01秒000毫秒开始,截取到第5秒30毫秒为止
clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"Duration\":\"5.30\"}");
//代表从01秒000毫秒开始,截取到距离片尾剩余5秒30毫秒为止
//clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"End\":\"5.30\"}");
//true:先剪辑第一个片段,再拼接(转码)
clip.put("ConfigToClipFirstPart", true);
output.put("Clip", clip);
//MergeConfigUrl的地址必须为HTTP地址
output.put("MergeConfigUrl", "http://bucket-name.oss-cn-shanghai.aliyuncs.com/mps-test/demo/mergeConfigfile");
outputs.add(output);
com.aliyun.mts20140618.Client client = MergeClipJobs.createClient();
com.aliyun.mts20140618.models.SubmitJobsRequest submitJobsRequest = new com.aliyun.mts20140618.models.SubmitJobsRequest()
//作业输入
.setInput(input.toJSONString())
//作业输出配置
.setOutputs(outputs.toJSONString())
//输出文件所在的OSS Bucket
.setOutputBucket("exampleBucket")
//输出文件所在的 OSS Bucket 的地域(OSS Region)
.setOutputLocation("oss-cn-shanghai")
//管道ID
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
开板尾板拼接任务
例如,在一个正片视频中,在第3秒增加一个开板视频,该开板视频区域的分辨率为680*480。同时,在视频结尾处增加一个尾板视频,尾板视频区域的分辨率同样为680*480,空白部分填充以白色背景色。
开板和尾板视频的URL中的Object部分必须经过URL Encoding说明(基于UTF-8编码)处理后使用,并且该URL必须为HTTP地址。
/**
* 开板尾板拼接任务
* @return
* @throws Exception
*/
public static void openAndTailJob() throws Exception {
//构建输出参数
JSONArray outputs = new JSONArray();
//构建input, 需要保证Location区域和服务client区域一致
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
//构建一个输出对象
JSONObject output = new JSONObject();
try {
input.put("Object", URLEncoder.encode("mps-test/demo/test.mp4", "utf-8"));
String outPutObject = URLEncoder.encode("mps-test/demo/merge-out.mp4", "utf-8");
output.put("OutputObject", outPutObject);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("input URL encode failed");
}
output.put("TemplateId", "<transcode templateId>");
JSONArray openingList = new JSONArray();
JSONObject opening = new JSONObject();
opening.put("OpenUrl", "http://bucket-name.oss-cn-shanghai.aliyuncs.com/" + URLEncoder.encode("mps-test/demo/open.mp4", "utf-8"));
opening.put("Start", "3");
opening.put("Width", "680");
opening.put("Height", "480");
openingList.add(opening);
JSONArray tailSlateList = new JSONArray();
JSONObject tailSlate = new JSONObject();
//Object必须经过URLEncoding(基于UTF-8编码)后使用。
tailSlate.put("TailUrl", "http://bucket-name.oss-cn-shanghai.aliyuncs.com/" + URLEncoder.encode("mps-test/demo/tail.mp4", "utf-8"));
tailSlate.put("BlendDuration", "2");
tailSlate.put("Width", "680");
tailSlate.put("Height", "480");
tailSlate.put("IsMergeAudio", true);
tailSlate.put("BgColor", "White");
tailSlateList.add(tailSlate);
output.put("OpeningList", openingList);
output.put("TailSlateList", tailSlateList);
outputs.add(output);
com.aliyun.mts20140618.Client client = MergeClipJobs.createClient();
com.aliyun.mts20140618.models.SubmitJobsRequest submitJobsRequest = new com.aliyun.mts20140618.models.SubmitJobsRequest()
//作业输入
.setInput(input.toJSONString())
//作业输出配置
.setOutputs(outputs.toJSONString())
//输出文件所在的OSS Bucket
.setOutputBucket("exampleBucket")
//输出文件所在的 OSS Bucket 的地域(OSS Region)
.setOutputLocation("oss-cn-shanghai")
//管道ID
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
完整代码
package com.alibaba.bltest.api_v2;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.tea.TeaException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class MergeClipJobs {
/**
* <b>description</b> :
* <p>使用AK&SK初始化账号Client</p>
* @return Client
*
* @throws Exception
*/
public static com.aliyun.mts20140618.Client createClient() throws Exception {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
config.endpoint = "mts.cn-shanghai.aliyuncs.com";
return new com.aliyun.mts20140618.Client(config);
}
/**
* 普通视频拼接任务 URL方式
* @return
* @throws Exception
*/
public static void mergrUrlListJob() throws Exception {
//构建输出参数
JSONArray outputs = new JSONArray();
//构建input, 需要保证Location区域和服务client区域一致
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
//构建一个输出对象
JSONObject output = new JSONObject();
try {
input.put("Object", URLEncoder.encode("mps-test/demo/test.mp4", "utf-8"));
String outPutObject = URLEncoder.encode("mps-test/demo/merge-out.mp4", "utf-8");
output.put("OutputObject", outPutObject);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("input URL encode failed");
}
output.put("TemplateId", "<transcode templateId>");
//构建一个素材截取数据
JSONObject clip = new JSONObject();
//代表从01秒000毫秒开始,截取到第5秒30毫秒为止
clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"Duration\":\"5.30\"}");
//代表从01秒000毫秒开始,截取到距离片尾剩余5秒30毫秒为止
//clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"End\":\"5.30\"}");
//true:先剪辑第一个片段,再拼接(转码)
clip.put("ConfigToClipFirstPart", true);
//构建一个拼接数据
JSONArray mergeList = new JSONArray();
JSONObject merge = new JSONObject();
merge.put("MergeURL", "http://bucket-name.oss-cn-shanghai.aliyuncs.com/" + URLEncoder.encode("mps-test/demo/test2mp4", "utf-8"));
merge.put("Start", "00:00:03.000");
merge.put("Duration", "00:00:13.000");
mergeList.add(merge);
output.put("Clip", clip);
output.put("MergeList", mergeList);
outputs.add(output);
com.aliyun.mts20140618.Client client = MergeClipJobs.createClient();
com.aliyun.mts20140618.models.SubmitJobsRequest submitJobsRequest = new com.aliyun.mts20140618.models.SubmitJobsRequest()
//作业输入
.setInput(input.toJSONString())
//作业输出配置
.setOutputs(outputs.toJSONString())
//输出文件所在的OSS Bucket
.setOutputBucket("exampleBucket")
//输出文件所在的 OSS Bucket 的地域(OSS Region)
.setOutputLocation("oss-cn-shanghai")
//管道ID
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
/**
* 普通视频拼接任务 ConfigFile方式
* @return
* @throws Exception
*/
public static void mergrConfigFileJob() throws Exception {
//构建输出参数
JSONArray outputs = new JSONArray();
//构建input, 需要保证Location区域和服务client区域一致
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
//构建一个输出对象
JSONObject output = new JSONObject();
try {
input.put("Object", URLEncoder.encode("mps-test/demo/test.mp4", "utf-8"));
String outPutObject = URLEncoder.encode("mps-test/demo/merge-out.mp4", "utf-8");
output.put("OutputObject", outPutObject);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("input URL encode failed");
}
output.put("TemplateId", "<transcode templateId>");
//构建一个素材截取数据
JSONObject clip = new JSONObject();
//代表从01秒000毫秒开始,截取到第5秒30毫秒为止
clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"Duration\":\"5.30\"}");
//代表从01秒000毫秒开始,截取到距离片尾剩余5秒30毫秒为止
//clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"End\":\"5.30\"}");
//true:先剪辑第一个片段,再拼接(转码)
clip.put("ConfigToClipFirstPart", true);
output.put("Clip", clip);
//MergeConfigUrl的地址必须为HTTP地址
output.put("MergeConfigUrl", "http://bucket-name.oss-cn-shanghai.aliyuncs.com/mps-test/demo/mergeConfigfile");
outputs.add(output);
com.aliyun.mts20140618.Client client = MergeClipJobs.createClient();
com.aliyun.mts20140618.models.SubmitJobsRequest submitJobsRequest = new com.aliyun.mts20140618.models.SubmitJobsRequest()
//作业输入
.setInput(input.toJSONString())
//作业输出配置
.setOutputs(outputs.toJSONString())
//输出文件所在的OSS Bucket
.setOutputBucket("exampleBucket")
//输出文件所在的 OSS Bucket 的地域(OSS Region)
.setOutputLocation("oss-cn-shanghai")
//管道ID
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
/**
* 开板尾板拼接任务
* @return
* @throws Exception
*/
public static void openAndTailJob() throws Exception {
//构建输出参数
JSONArray outputs = new JSONArray();
//构建input, 需要保证Location区域和服务client区域一致
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
//构建一个输出对象
JSONObject output = new JSONObject();
try {
input.put("Object", URLEncoder.encode("mps-test/demo/test.mp4", "utf-8"));
String outPutObject = URLEncoder.encode("mps-test/demo/merge-out.mp4", "utf-8");
output.put("OutputObject", outPutObject);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("input URL encode failed");
}
output.put("TemplateId", "<transcode templateId>");
JSONArray openingList = new JSONArray();
JSONObject opening = new JSONObject();
opening.put("OpenUrl", "http://bucket-name.oss-cn-shanghai.aliyuncs.com/" + URLEncoder.encode("mps-test/demo/open.mp4", "utf-8"));
opening.put("Start", "3");
opening.put("Width", "680");
opening.put("Height", "480");
openingList.add(opening);
JSONArray tailSlateList = new JSONArray();
JSONObject tailSlate = new JSONObject();
//Object必须经过URLEncoding(基于UTF-8编码)后使用。
tailSlate.put("TailUrl", "http://bucket-name.oss-cn-shanghai.aliyuncs.com/" + URLEncoder.encode("mps-test/demo/tail.mp4", "utf-8"));
tailSlate.put("BlendDuration", "2");
tailSlate.put("Width", "680");
tailSlate.put("Height", "480");
tailSlate.put("IsMergeAudio", true);
tailSlate.put("BgColor", "White");
tailSlateList.add(tailSlate);
output.put("OpeningList", openingList);
output.put("TailSlateList", tailSlateList);
outputs.add(output);
com.aliyun.mts20140618.Client client = MergeClipJobs.createClient();
com.aliyun.mts20140618.models.SubmitJobsRequest submitJobsRequest = new com.aliyun.mts20140618.models.SubmitJobsRequest()
//作业输入
.setInput(input.toJSONString())
//作业输出配置
.setOutputs(outputs.toJSONString())
//输出文件所在的OSS Bucket
.setOutputBucket("exampleBucket")
//输出文件所在的 OSS Bucket 的地域(OSS Region)
.setOutputLocation("oss-cn-shanghai")
//管道ID
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
}