Use ApsaraVideo Media Processing (MPS) SDK for Java to merge and clip videos. Video merging combines clips of different formats, bitrates, and resolutions into a single output—commonly used to add opening or ending parts, or to stitch recorded live stream segments. Video clipping extracts a segment from a source video and saves it as a new file, making it useful for capturing highlights.
Scenarios
Intro/outro stitching: Add a fixed opening or ending to a video, or stitch together segments from a recorded live stream.
Clip extraction: Crop a segment from a source video and export it as a standalone file. Typically used to capture highlights.
Opening and ending effects: Embed an opening at the beginning of a video in Picture-in-Picture (PiP) mode, or append an ending part at the end.
Merge multiple video clips in sequence
The following example clips the input video starting at 00:00:03.000 with a duration of 00:00:13.000 seconds, then merges it with the segment from 00:00:01.000 to 00:00:05.030 of an opening video. The total output duration is 17.30 seconds.
/**
* Merge multiple video clips in sequence.
* @return
* @throws Exception
*/
public static void mergrUrlListJob() throws Exception {
// Construct output parameters.
JSONArray outputs = new JSONArray();
// Configure the job input. Make sure that the media file used as the job input resides in the same region as the client.
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
// Configure the job output.
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>");
// Construct data for video clipping.
JSONObject clip = new JSONObject();
// Cut the video from 1.000s to 5.030s.
clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"Duration\":\"5.30\"}");
// Cut the video from 1.000s to 5.030s that remains from the end of the video.
//clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"End\":\"5.30\"}");
// Specifies whether to edit the first clip of the video. Valid values: true and false. A value of true specifies that the video clips are merged for a transcoding job after editing. A value of false specifies that the video clips are merged for a transcoding job before editing.
clip.put("ConfigToClipFirstPart", true);
// Construct data for video merging.
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()
// The job input.
.setInput(input.toJSONString())
// The job output configuration.
.setOutputs(outputs.toJSONString())
// The OSS bucket in which the output file is stored.
.setOutputBucket("exampleBucket")
// The region in which the OSS bucket resides.
.setOutputLocation("oss-cn-shanghai")
// The ID of the pipeline.
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// Write your own code to display the response of the API operation if necessary.
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
Merge video clips using a configuration file
The following example clips the input video starting at 00:00:03.000 with a duration of 00:00:10.000 seconds, then merges it with the segment from 00:00:01.000 to 00:00:05.030 of the opening.
The configuration file mergeConfigfile contains the following:
{"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"}]}
/**
* Merge video clips by using the OSS path of a configuration file.
* @return
* @throws Exception
*/
public static void mergrConfigFileJob() throws Exception {
// Construct output parameters.
JSONArray outputs = new JSONArray();
// Configure the job input. Make sure that the media file used as the job input resides in the same region as the client.
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
// Configure the job output.
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>");
// Construct data for video clipping.
JSONObject clip = new JSONObject();
// Cut the video from 1.000s to 5.030s.
clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"Duration\":\"5.30\"}");
// Cut the video from 1.000s to 5.030s that remains from the end of the video.
//clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"End\":\"5.30\"}");
// Specifies whether to edit the first clip of the video. Valid values: true and false. A value of true specifies that the video clips are merged for a transcoding job after editing. A value of false specifies that the video clips are merged for a transcoding job before editing.
clip.put("ConfigToClipFirstPart", true);
output.put("Clip", clip);
// The OSS path of the configuration file must be an HTTP URL.
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()
// The job input.
.setInput(input.toJSONString())
// The job output configuration.
.setOutputs(outputs.toJSONString())
// The OSS bucket in which the output file is stored.
.setOutputBucket("exampleBucket")
// The region in which the OSS bucket resides.
.setOutputLocation("oss-cn-shanghai")
// The ID of the pipeline.
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// Write your own code to display the response of the API operation if necessary.
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
Embed an opening or append an ending to a video
The following example embeds an opening (680 x 480) starting at the third second of the input video in Picture-in-Picture (PiP) mode, and appends an ending part (680 x 480) at the end. The blank area after the ending is filled with a white background.
OSS objects referenced in opening and ending URLs must be UTF-8-encoded, and the URLs must use HTTP. For more information, see URL encoding.
/**
* Embed opening parts at the beginning of the input video or add ending parts to the end of the input video.
* @return
* @throws Exception
*/
public static void openAndTailJob() throws Exception {
// Construct output parameters.
JSONArray outputs = new JSONArray();
// Configure the job input. Make sure that the media file used as the job input resides in the same region as the client.
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
// Configure the job output.
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();
// Objects specified by URLs of the opening and ending parts must be UTF-8-encoded.
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()
// The job input.
.setInput(input.toJSONString())
// The job output configuration.
.setOutputs(outputs.toJSONString())
// The OSS bucket in which the output file is stored.
.setOutputBucket("exampleBucket")
// The region in which the OSS bucket resides.
.setOutputLocation("oss-cn-shanghai")
// The ID of the pipeline.
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// Write your own code to display the response of the API operation if necessary.
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
Complete sample code
All three examples use submitJobsWithOptions to submit asynchronous transcoding jobs. The client is initialized with credentials from environment variables.
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>Use your AccessKey pair to initialize the 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()
// Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is configured.
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is configured.
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
config.endpoint = "mts.cn-shanghai.aliyuncs.com";
return new com.aliyun.mts20140618.Client(config);
}
/**
* Merge multiple video clips in sequence.
* @return
* @throws Exception
*/
public static void mergrUrlListJob() throws Exception {
// Construct output parameters.
JSONArray outputs = new JSONArray();
// Configure the job input. Make sure that the media file used as the job input resides in the same region as the client.
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
// Configure the job output.
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>");
// Construct data for video clipping.
JSONObject clip = new JSONObject();
// Cut the video from 1.000s to 5.030s.
clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"Duration\":\"5.30\"}");
// Cut the video from 1.000s to 5.030s that remains from the end of the video.
//clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"End\":\"5.30\"}");
// Specifies whether to edit the first clip of the video. Valid values: true and false. A value of true specifies that the video clips are merged for a transcoding job after editing. A value of false specifies that the video clips are merged for a transcoding job before editing.
clip.put("ConfigToClipFirstPart", true);
// Construct data for video merging.
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()
// The job input.
.setInput(input.toJSONString())
// The job output configuration.
.setOutputs(outputs.toJSONString())
// The OSS bucket in which the output file is stored.
.setOutputBucket("exampleBucket")
// The region in which the OSS bucket resides.
.setOutputLocation("oss-cn-shanghai")
// The ID of the pipeline.
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// Write your own code to display the response of the API operation if necessary.
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
/**
* Merge video clips by using the OSS path of a configuration file.
* @return
* @throws Exception
*/
public static void mergrConfigFileJob() throws Exception {
// Construct output parameters.
JSONArray outputs = new JSONArray();
// Configure the job input. Make sure that the media file used as the job input resides in the same region as the client.
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
// Configure the job output.
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>");
// Construct data for video clipping.
JSONObject clip = new JSONObject();
// Cut the video from 1.000s to 5.030s.
clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"Duration\":\"5.30\"}");
// Cut the video from 1.000s to 5.030s that remains from the end of the video.
//clip.put("TimeSpan", "{\"Seek\":\"00:00:01.000\",\"End\":\"5.30\"}");
// Specifies whether to edit the first clip of the video. Valid values: true and false. A value of true specifies that the video clips are merged for a transcoding job after editing. A value of false specifies that the video clips are merged for a transcoding job before editing.
clip.put("ConfigToClipFirstPart", true);
output.put("Clip", clip);
// The OSS path of the configuration file must be an HTTP URL.
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()
// The job input.
.setInput(input.toJSONString())
// The job output configuration.
.setOutputs(outputs.toJSONString())
// The OSS bucket in which the output file is stored.
.setOutputBucket("exampleBucket")
// The region in which the OSS bucket resides.
.setOutputLocation("oss-cn-shanghai")
// The ID of the pipeline.
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// Write your own code to display the response of the API operation if necessary.
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
/**
* Embed opening parts at the beginning of the input video or add ending parts to the end of the input video.
* @return
* @throws Exception
*/
public static void openAndTailJob() throws Exception {
// Construct output parameters.
JSONArray outputs = new JSONArray();
// Configure the job input. Make sure that the media file used as the job input resides in the same region as the client.
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
// Configure the job output.
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();
// Objects specified by URLs of the opening and ending parts must be UTF-8-encoded.
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()
// The job input.
.setInput(input.toJSONString())
// The job output configuration.
.setOutputs(outputs.toJSONString())
// The OSS bucket in which the output file is stored.
.setOutputBucket("exampleBucket")
// The region in which the OSS bucket resides.
.setOutputLocation("oss-cn-shanghai")
// The ID of the pipeline.
.setPipelineId("dd3dae411e704030b921e52698e5****");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// Write your own code to display the response of the API operation if necessary.
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// The error message.
System.out.println(error.getMessage());
// The URL for troubleshooting.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
}