通过阅读本文,您可以了解通过服务端SDK调用OpenAPI进行批量混剪的示例。
前提条件
如果您要实现字幕对齐和卡点视频功能,除了开通IMS和OSS服务以外,还需要开通MPS服务。具体操作,请参见开通服务。
使用说明
以下示例代码中引入的服务端SDK版本号仅供参考。获取最新的版本,请参见服务端SDK。
基础混剪
主要功能
- 设置一段文字,转为人声音频,再转成字幕合成到视频中,同时设置字体、字号等属性。
- 进行任意数量的视频拼接。
- 设置一段音频作为背景音乐。
- 设置一个图片作为Logo水印。
成片预览
实现代码
Java
/**
Maven引入:
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>ice20201109</artifactId>
<version>1.1.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68.noneautotype</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>credentials-java</artifactId>
<version>0.2.12</version>
</dependency>
*/
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.abs.common.util.MD5Util;
import com.aliyun.ice20201109.models.*;
import com.aliyun.teaopenapi.models.Config;
import org.apache.logging.log4j.util.Strings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Create by oushu
* Date 2021/12/7 上午9:28
*/
public class BatchProduceVideo_release {
private String bucket;
private com.aliyun.ice20201109.Client iceClient;
public void initClient() throws Exception {
bucket = "your-bucket";
iceClient = createIceClient();
}
public static void main(String[] args) throws Exception {
BatchProduceVideo_release batchProduceVideo = new BatchProduceVideo_release();
batchProduceVideo.initClient();
batchProduceVideo.batchProduceVideo();
}
public void batchProduceVideo() throws Exception {
// 文字素材
String text = "测试文案";
// 视频素材
List<String> videoUrlList = new ArrayList();
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video1.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video2.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video3.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video4.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video5.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video6.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video7.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video8.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video9.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video10.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video11.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video12.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video13.mp4");
videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video14.mp4");
// 背景音乐
String bgMusic = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-music.mp3";
// 字幕样式设置
Integer fontSize = 60;
String fontName = "WenQuanYi Zen Hei Mono";
String fontColor = "#FFFFFF";
// 视频尺寸
Integer width = 1280;
Integer height = 720;
// logo
String logoUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-logo.png";
Integer logoX = 20;
Integer logoY = 20;
// 输出成片个数
Integer outputCount = 2;
// 每个成片包含视频片段数
Integer videoCount = 8;
for (int i = 0; i < outputCount; i++) {
Collections.shuffle(videoUrlList);
List<String> subUrls = videoUrlList.subList(0, videoCount);
produceSingleVideo(text, subUrls, bgMusic, fontSize, fontName, fontColor, logoUrl, logoX, logoY, width, height);
}
}
// 提交单个任务
public void produceSingleVideo(String text, List<String> videoUrls, String bgMusic, int fontSize, String fontName, String fontColor,
String logoUrl, Integer logoX, Integer logoY, int width, int height) throws Exception {
// 组装字幕轨
if (fontSize <= 0) {
fontSize = 32;
}
if (Strings.isBlank(fontName)) {
fontName = "WenQuanYi Zen Hei Mono";
}
if (Strings.isBlank(fontColor)) {
fontColor = "#000000";
}
// 组装视频轨
JSONArray videoTrackClips = new JSONArray();
for (String url : videoUrls) {
JSONObject clip = new JSONObject();
clip.put("MediaURL", url);
videoTrackClips.add(clip);
}
// 组装音频轨
String audioClip = "{\"AudioTrackClips\":[{\"Type\":\"AI_TTS\",\"Content\":\"" + text + "\",\"Voice\":\"sicheng\",\"Effects\":[{\"Type\":\"AI_ASR\",\"Font\":\"" + fontName + "\",\"Alignment\":\"BottomCenter\",\"Y\":0.1,\"FontSize\":" + fontSize + ",\"FontColor\":\"" + fontColor + "\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}},{\"Type\":\"Volume\",\"Gain\":10}]}]}";
String audioTracks;
if (Strings.isBlank(bgMusic)) {
audioTracks = "["+audioClip+"]";
} else {
// 两个音频轨,一个人声,一个音乐
audioTracks = "["+audioClip+",{\"AudioTrackClips\":[{\"MediaURL\":\"" + bgMusic + "\"}]}]";
}
// 贴图clips
String logoClip = "";
if (Strings.isNotBlank(logoUrl)) {
logoClip = "{\"ImageURL\":\"" + logoUrl + "\",\"X\":" + logoX + ",\"Y\":" + logoY + "}";
}
// 拼时间线
String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," +
"\"AudioTracks\":" + audioTracks + "," +
"\"ImageTracks\":[{\"ImageTrackClips\":[" + logoClip + "]}]}";
System.out.println("timeline : " + timeline);
// 提交合成任务
SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
submitMediaProducingJobRequest.setTimeline(timeline);
String mediaURL = "https://" + bucket + ".oss-shanghai" + ".aliyuncs.com/" + MD5Util.getMd5String(String.valueOf(Math.random())) + ".mp4";
submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":" + width + ",\"Height\":" + height + "}");
SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest);
System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL);
// 等待合成任务完成
while (true) {
GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest();
getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId);
GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest);
System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body));
String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus();
if ("Success".equals(status) || "Failed".equals(status)) {
break;
}
Thread.sleep(5000);
}
System.out.println("Produce succeed : " + mediaURL);
}
public com.aliyun.ice20201109.Client createIceClient() throws Exception {
// 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
// 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
Config config = new Config();
config.setCredential(credentialClient);
// 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
// config.accessKeyId = <yourAccessKeyId>;
// config.accessKeySecret = <yourAccessKeySecret>;
config.endpoint = "ice.cn-shanghai.aliyuncs.com";
Client client = new Client(config);
return client;
}
}
PHP
<?php
/**
composer 引入:
{
"require": {
"alibabacloud/ice-20201109": "1.1.6",
"aliyuncs/oss-sdk-php": "^2.4"
"alibabacloud/credentials"
}
}
*/
require_once '../vendor/autoload.php';
use AlibabaCloud\Credentials\Credential;
use AlibabaCloud\SDK\ICE\V20201109\ICE;
use AlibabaCloud\SDK\ICE\V20201109\Models;
use AlibabaCloud\SDK\ICE\V20201109\Models\SubmitMediaProducingJobRequest;
use AlibabaCloud\SDK\ICE\V20201109\Models\GetMediaProducingJobRequest;
use Darabonba\OpenApi\Models\Config;
class BatchProduceVideo {
var $iceClient;
var $bucket;
var $region;
function createClient() {
$this->bucket = "your-bucket";
$this->region = "cn-shanghai";
// ice
$iceConfig = new Config();
//本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。
$iceConfig->credential = $credential;
//如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
//$iceConfig->accessKeyId = "accessKeyId";
//$iceConfig->accessKeySecret = "accessKeySecret";
$iceConfig->regionId = "cn-shanghai";
$iceConfig->endpoint = "ice.cn-shanghai.aliyuncs.com";
$this->iceClient = new ICE($iceConfig);
}
function run() {
echo "start!!!\n";
// 初始化client
$this->createClient();
// 文字素材
$text = "测试文案";
// 视频素材
$videoUrls = array();
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video1.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video2.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video3.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video4.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video5.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video6.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video7.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video8.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video9.mp4";
$videoUrls[] = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video10.mp4";
// 背景音乐
$bgMusic = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/test_media/your-music.mp3";
// 字幕样式设置
$fontSize = 60;
$fontName = "WenQuanYi Zen Hei Mono";
$fontColor = "#FFFFFF";
// logo
$logoUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-logo.png";
$logoX = 20;
$logoY = 20;
// 视频尺寸
$width = 1920;
$height = 1080;
// 输出成片个数
$outputCount = 2;
// 每个成片包含视频片段数
$videoCount = 8;
for ($i = 0; $i < $outputCount; $i++) {
shuffle($videoUrls);
$subUrls = array_slice($videoUrls, 0, $videoCount);
$this->produceSingleVideo($text, $subUrls, $bgMusic, $fontSize, $fontName, $fontColor, $logoUrl, $logoX, $logoY, $width, $height);
}
}
// 提交单个任务
function produceSingleVideo($text, $videoUrls, $bgMusic, $fontSize, $fontName, $fontColor, $logoUrl, $logoX, $logoY, $width, $height) {
$bucket = $this->bucket;
$region = $this->region;
// 组装字幕轨
if ($fontSize <= 0) {
$fontSize = 32;
}
if ($fontName == "") {
$fontName = "WenQuanYi Zen Hei Mono";
}
if ($fontColor == "") {
$fontColor = "#000000";
}
// 组装视频轨
$videoTrackClips = array();
foreach ($videoUrls as $url) {
$videoTrackClips[] = array('MediaURL' => $url);
}
var_dump(json_encode($videoTrackClips));
// 组装音频轨
$audioClip = "{\"AudioTrackClips\":[{\"Type\":\"AI_TTS\",\"Content\":\"" . $text . "\",\"Voice\":\"sicheng\",\"Effects\":[{\"Type\":\"AI_ASR\",\"Font\":\"" . $fontName . "\",\"Alignment\":\"BottomCenter\",\"Y\":0.1,\"FontSize\":" . $fontSize . ",\"FontColor\":\"" . $fontColor . "\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}},{\"Type\":\"Volume\",\"Gain\":10}]}]}";
$audioTracks;
if ($bgMusic == "") {
$audioTracks = "[" . $audioClip . "]";
} else {
// 两个音频轨,一个人声,一个音乐
$audioTracks = "[" . $audioClip . ",{\"AudioTrackClips\":[{\"MediaURL\":\"" . $bgMusic . "\"}]}]";
}
var_dump($audioTracks);
// 贴图clips
$logoClip = "";
if ($logoUrl != "") {
$logoClip = "{\"ImageURL\":\"" . $logoUrl . "\",\"X\":" . $logoX . ",\"Y\":" . $logoY . "}";
}
var_dump($logoClip);
// 拼时间线
$timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" . json_encode($videoTrackClips) . "}]," .
"\"AudioTracks\":" . $audioTracks . "," .
"\"ImageTracks\":[{\"ImageTrackClips\":[" . $logoClip . "]}]}";
echo $timeline."\n";
// 提交合成任务
$submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
$submitMediaProducingJobRequest->timeline = $timeline;
$mediaURL = "https://" . $bucket . ".oss-" . $region . ".aliyuncs.com/" . md5(rand()) . ".mp4";
$submitMediaProducingJobRequest->outputMediaConfig = "{\"MediaURL\":\"" . $mediaURL . "\",\"Width\":" . $width . ",\"Height\":" . $height . "}";
$submitMediaProducingJobResponse = $this->iceClient->submitMediaProducingJob($submitMediaProducingJobRequest);
$jobId = $submitMediaProducingJobResponse->body->jobId;
$resuestId = $submitMediaProducingJobResponse->body->requestId;
echo "jobId : ". $jobId . ", resuestId : " . $resuestId . ", mediaURL : " . $mediaURL . "\n";
// 等待合成任务完成
while (true) {
$getMediaProducingJobRequest = new GetMediaProducingJobRequest();
$getMediaProducingJobRequest->jobId = $jobId;
$getMediaProducingJobResponse = $this->iceClient->getMediaProducingJob($getMediaProducingJobRequest);
$status = $getMediaProducingJobResponse->body->mediaProducingJob->status;
echo "job Status : " . $status . "\n";
if ("Success" == $status) {
break;
}
sleep(5);
}
echo "job finished !";
}
}
try {
$batchProduceVideo = new BatchProduceVideo();
$batchProduceVideo->run();
} catch (Error $e) {
var_dump($e);
}
相关接口
字幕对齐
主要功能
- 输入一段文字,转为人声音频,或直接输入一段人声音频,再转成字幕合成到视频中,同时设置字体、字号等属性。
- 进行任意数量的视频拼接,随机排序,将视频按照每段人声的长度进行截取并拼接。
- 为视频素材添加背景模糊效果、随机氛围类特效,并静音。
- 设置一段音频作为背景音乐。
- 设置一个图片作为Logo水印。
成片预览
实现代码
- 输入为文字Java
/** Maven引入: <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.3</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>ice20201109</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>mts20140618</artifactId> <version>3.3.33</version> </dependency> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.10.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>0.2.12</version> </dependency> */ import com.alibaba.common.lang.io.ByteArrayInputStream; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.aliyun.abs.common.util.MD5Util; import com.aliyun.ice20201109.models.GetMediaProducingJobRequest; import com.aliyun.ice20201109.models.GetMediaProducingJobResponse; import com.aliyun.ice20201109.models.SubmitMediaProducingJobRequest; import com.aliyun.ice20201109.models.SubmitMediaProducingJobResponse; import com.aliyun.mts20140618.models.QueryIProductionJobRequest; import com.aliyun.mts20140618.models.QueryIProductionJobResponse; import com.aliyun.mts20140618.models.SubmitIProductionJobRequest; import com.aliyun.mts20140618.models.SubmitIProductionJobResponse; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.model.OSSObject; import com.aliyun.oss.model.PutObjectRequest; import com.aliyun.teaopenapi.models.Config; import com.google.common.io.CharStreams; import org.apache.commons.io.Charsets; import org.apache.logging.log4j.util.Strings; import java.io.InputStream; import java.io.InputStreamReader; import java.util.*; /** * Create by oushu * Date 2021/12/7 上午9:28 */ public class BatchProduceTTSSubtitleRelease { private String bucket; private String output; private String regionId; private OSS ossClient; private com.aliyun.mts20140618.Client mpsClient; private com.aliyun.ice20201109.Client iceClient; public void initClient() throws Exception { bucket = "your-bucket"; output = "output-path"; regionId = "cn-shanghai"; ossClient = createOssClient(); mpsClient = createMpsClient(); iceClient = createIceClient(); } public static void main(String[] args) throws Exception { BatchProduceTTSSubtitleRelease batchProduceVideo = new BatchProduceTTSSubtitleRelease(); batchProduceVideo.initClient(); batchProduceVideo.batchProduceVideo(); } public void batchProduceVideo() throws Exception { // 文字素材 String text = "人们懂得用五味杂陈形容人生,因为懂得味道是每个人心中固守的情怀。在这个时代,每一个人都经历了太多的苦痛和喜悦,人们总会将苦涩藏在心里,而把幸福变成食物,呈现在四季的餐桌之上"; // 视频素材 List<String> videoUrlList = new ArrayList(); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_1.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_2.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_3.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_4.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_5.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_6.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_7.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_8.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_9.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_10.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_11.mp4"); videoUrlList.add("https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your_video_12.mp4"); // 背景音乐 String bgMusic = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/iproduction/demo/music/generated_6_good.wav"; // 字幕样式设置 Integer fontSize = 45; String fontName = "WenQuanYi Zen Hei Mono"; String fontColor = "#FFFFFF"; // 视频尺寸 Integer width = 720; Integer height = 1280; // logo String logoUrl = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/your-logo.png"; Integer logoX = 20; Integer logoY = 20; String title = "这里是标题"; String subTitle = "这里是副标题"; // 成片数量 int targetCount = 2; // 每次提交一个任务,业务方根据需要更换不同参数提交多次 produceSingleVideo(text, videoUrlList, title, subTitle, bgMusic, fontSize, fontName, fontColor, logoUrl, logoX, logoY, width, height, targetCount); } // 提交单个任务 public void produceSingleVideo(String text, List<String> videoUrls, String title, String subtitle, String bgMusic, int fontSize, String fontName, String fontColor, String logoUrl, Integer logoX, Integer logoY, int width, int height, int targetCount) throws Exception { // 提交MPS任务,文字生成语音和字幕 String voice = "zhichu"; String jobParams = "{\"voice\":\"" + voice + "\",\"format\":\"mp3\",\"sample_rate\":16000}"; String textObject = "iproduction/20211214/" + MD5Util.getMd5String(text) + ".txt"; text = text.replaceAll(",", "。"); // AsyncTextToSpeech任务用句号进行断句 putObjectContent(textObject, text); String input = "oss://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + textObject; System.out.println("input : " + input); SubmitIProductionJobRequest submitIProductionJobRequest = new SubmitIProductionJobRequest(); submitIProductionJobRequest.setFunctionName("AsyncTextToSpeech"); submitIProductionJobRequest.setInput(input); submitIProductionJobRequest.setOutput("oss://" + bucket + ".oss-" + regionId + ".aliyuncs.com/iproduction/20220617/{source}-{sequenceId}.{resultType}"); submitIProductionJobRequest.setJobParams(jobParams); SubmitIProductionJobResponse submitIProductionJobResponse = mpsClient.submitIProductionJob(submitIProductionJobRequest); System.out.println("submit mps response : " + JSONObject.toJSONString(submitIProductionJobResponse.body)); // 等待任务完成 String jobId = submitIProductionJobResponse.body.jobId; String result; while (true) { QueryIProductionJobRequest queryIProductionJobRequest = new QueryIProductionJobRequest(); queryIProductionJobRequest.setJobId(jobId); QueryIProductionJobResponse queryIProductionJobResponse = mpsClient.queryIProductionJob(queryIProductionJobRequest); System.out.println("job info : " + JSONObject.toJSONString(queryIProductionJobResponse.body)); if ("Success".equals(queryIProductionJobResponse.body.state)) { result = queryIProductionJobResponse.body.result; break; } Thread.sleep(5000); } // 获取生成的音频和字幕 JSONObject resultObj = JSONObject.parseObject(result); String dataString = resultObj.getString("Data"); System.out.println("data : " + dataString); String audioObject = null; String subtitleObject = null; JSONObject dataObject = JSONObject.parseObject(dataString); JSONArray array = dataObject.getJSONArray("result"); for (Object obj : array) { JSONObject jsonObject = (JSONObject)obj; String object = jsonObject.getString("file"); if (object.endsWith("mp3")) { audioObject = object; } else if (object.endsWith("txt")) { subtitleObject = object; } } System.out.println("audioObject : " + audioObject); System.out.println("subtitleObject : " + subtitleObject); // 获取字幕内容 String subtitleContent = getObjectContent(subtitleObject); System.out.println("subtitleContent : " + subtitleContent); // 组装字幕轨 if (fontSize <= 0) { fontSize = 32; } if (Strings.isBlank(fontName)) { fontName = "WenQuanYi Zen Hei Mono"; } if (Strings.isBlank(fontColor)) { fontColor = "#000000"; } for (int j = 0; j < targetCount; j++) { // 每次循环将视频素材随机,并提交合成任务 Collections.shuffle(videoUrls); JSONArray subtitleTrackClips = new JSONArray(); JSONArray mpsSubtitles = JSONArray.parseArray(subtitleContent); JSONArray videoTrackClips = new JSONArray(); // 字幕距离底部距离 float subtitleBottom = 0.25f; // 随机特效,更多特效见:https://help.aliyun.com/document_detail/207059.html List<String> vfxs = Arrays.asList("heartfireworks", "colorfulradial", "meteorshower", "starry", "colorfulstarry", "moons_and_stars", "flyfire", "starexplosion", "spotfall", "sparklestarfield"); // 随机转场,更多转场见:https://help.aliyun.com/document_detail/204853.html List<String> transitions = Arrays.asList("windowslice", "displacement", "bowTieVertical", "linearblur", "waterdrop", "polka", "wiperight", "gridflip", "hexagonalize", "windowblinds", "风车"); float transDuration = 0.3f; Collections.shuffle(vfxs); for (int i = 0; i < mpsSubtitles.size(); i++) { JSONObject mpsSubtitle = mpsSubtitles.getJSONObject(i); String content = mpsSubtitle.getString("text"); content = content.replaceAll("。", ""); Float timelineIn = mpsSubtitle.getFloat("begin_time") / 1000; Float timelineOut = mpsSubtitle.getFloat("end_time") / 1000; String subtitleClip = "{\"Content\":\"" + content + "\",\"TimelineIn\":" + timelineIn + ",\"TimelineOut\":" + timelineOut + ",\"Type\":\"Text\",\"X\":0.0,\"Y\":" + subtitleBottom + ",\"Font\":\"" + fontName + "\",\"Alignment\":\"BottomCenter\",\"FontSize\":" + fontSize + ",\"FontColor\":\"" + fontColor + "\",\"OutlineColour\":\"#000000\",\"FontColor\":\"#ffffff\",}"; subtitleTrackClips.add(JSONObject.parseObject(subtitleClip)); // 根据字幕轨,截取视频轨片段 float out = timelineOut - timelineIn; // 随机特效 String vfx = vfxs.get(i % vfxs.size()); String transition = transitions.get(i % transitions.size()); String url = videoUrls.get(i % videoUrls.size()); JSONObject clip = new JSONObject(); clip.put("MediaURL", url); if (url.endsWith(".jpg")) { clip.put("Duration", out + transDuration); clip.put("Type", "Image"); } else { clip.put("Out", out + transDuration); } JSONArray effects = new JSONArray(); // 添加背景模糊 effects.add(JSONObject.parseObject("{\"Type\":\"Background\",\"SubType\":\"Blur\",\"Radius\":0.1}")); // 添加氛围类特效 effects.add(JSONObject.parseObject("{\"Type\":\"VFX\",\"SubType\":\"" + vfx + "\"}")); // 视频静音 effects.add(JSONObject.parseObject("{\"Type\":\"Volume\",\"Gain\":0}")); // 添加转场 effects.add(JSONObject.parseObject("{\"Type\":\"Transition\",\"SubType\":\"" + transition + "\",\"Duration\":"+transDuration+"}")); clip.put("Effects", effects); videoTrackClips.add(clip); } if (title != null && title.length() > 0) { float titleY = 280; int titleFontSize = 70; String titleFont = "AlibabaPuHuiTi"; String titleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + titleY + ",\"Font\":\"" + titleFont + "\",\"Content\":\"" + title + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + titleFontSize + ",\"FontColor\":\"#FFD700\",\"Outline\":4,\"OutlineColour\":\"#000000\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}}"; subtitleTrackClips.add(JSONObject.parse(titleClip)); } if (subtitle != null && subtitle.length() > 0) { float subtitleY = 200; int subtitleFontSize = 60; String subtitleFont = "AlibabaPuHuiTi"; String subtitleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + subtitleY + ",\"Font\":\"" + subtitleFont + "\",\"Content\":\"" + subtitle + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + subtitleFontSize + ",\"FontColorOpacity\":1,\"FontColor\":\"#ffffff\",\"Outline\":2,\"OutlineColour\":\"#000000\",\"FontFace\":{\"Bold\":false,\"Italic\":false,\"Underline\":false}}"; subtitleTrackClips.add(JSONObject.parse(subtitleClip)); } // 组装音频轨 String audioUrl = "http://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + audioObject; String audioTrackClips = ""; if (Strings.isBlank(bgMusic)) { audioTrackClips = "[{\"MediaURL\":\"" + audioUrl + "\"}]"; } else { // 两个音频轨,一个人声,一个音乐 audioTrackClips = "[{\"MediaURL\":\"" + audioUrl + "\"}]},{\"AudioTrackClips\":[{\"MediaURL\":\"" + bgMusic + "\"}]"; } // 图片轨,用于展示logo String logoClip = ""; int logoWidth = 200; int logoHeight = 60; if (Strings.isNotBlank(logoUrl)) { logoClip = "{\"ImageURL\":\"" + logoUrl + "\",\"X\":" + logoX + ",\"Y\":" + logoY + ",\"Width\":\"" + logoWidth + "\",\"Height\":\"" + logoHeight + "\"}"; } // 拼时间线 String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," + "\"SubtitleTracks\":[{\"SubtitleTrackClips\":" + subtitleTrackClips.toJSONString() + "}]," + "\"AudioTracks\":[{\"AudioTrackClips\":" + audioTrackClips + "}]," + "\"ImageTracks\":[{\"ImageTrackClips\":[" + logoClip + "]}]}"; System.out.println("timeline : " + timeline); // 提交合成任务 SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest(); submitMediaProducingJobRequest.setTimeline(timeline); String outputPath = output + "/" + UUID.randomUUID().toString().replaceAll("-",""); String mediaURL = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + outputPath + ".mp4"; submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":" + width + ",\"Height\":" + height + "}"); SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest); System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL); // 等待合成任务完成 while (true) { GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest(); getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId); GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest); System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body)); String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus(); if ("Success".equals(status)) { break; } Thread.sleep(5000); } System.out.println("Produce succeed : " + mediaURL); } } public String getObjectContent(String object) throws Exception { OSSObject obj = ossClient.getObject(bucket, object); InputStream stream = obj.getObjectContent(); String result = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8)); return result; } public void putObjectContent(String object, String content) throws Exception { PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, object, new ByteArrayInputStream(content.getBytes())); ossClient.putObject(putObjectRequest); } public com.aliyun.mts20140618.Client createMpsClient() throws Exception { // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。 // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client(); Config config = new Config(); config.setCredential(credentialClient); // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。 // config.accessKeyId = <yourAccessKeyId>; // config.accessKeySecret = <yourAccessKeySecret>; config.endpoint = "mts." + regionId + ".aliyuncs.com"; com.aliyun.mts20140618.Client mtsClient = new com.aliyun.mts20140618.Client(config); return mtsClient; } public OSS createOssClient() throws Exception { String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"); String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"); String endpoint = "http://oss-" + regionId + ".aliyuncs.com"; OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); return ossClient; } public com.aliyun.ice20201109.Client createIceClient() throws Exception { // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。 // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client(); Config config = new Config(); config.setCredential(credentialClient); // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。 // config.accessKeyId = <yourAccessKeyId>; // config.accessKeySecret = <yourAccessKeySecret>; config.endpoint = "ice." + regionId + ".aliyuncs.com"; com.aliyun.ice20201109.Client iceClient = new com.aliyun.ice20201109.Client(config); return iceClient; } }
- 输入为人声音频Java
/** Maven引入: <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.3</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>ice20201109</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.8.graal</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>0.2.12</version> </dependency> */ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.aliyun.ice20201109.Client; import com.aliyun.teaopenapi.models.Config; import com.aliyun.ice20201109.models.*; import org.apache.logging.log4j.util.Strings; import java.util.*; /** * Create by oushu * Date 2021/12/7 上午9:28 */ public class BatchProduceASRSubtitleRelease { private String bucket; private String output; private String regionId; private Client iceClient; public void initClient() throws Exception { bucket = "your-bucket"; output = "output-path"; regionId = "cn-shanghai"; iceClient = createIceClient(); } public static void main(String[] args) throws Exception { BatchProduceASRSubtitleRelease batchProduceVideo = new BatchProduceASRSubtitleRelease(); batchProduceVideo.initClient(); batchProduceVideo.batchProduceVideo(); } public void batchProduceVideo() throws Exception { // 人声素材 String voiceUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-voice.mp3"; // 视频素材 List<String> videoUrlList = new ArrayList(); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video1.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video2.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video3.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video4.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video5.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video6.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video7.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video8.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video9.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video10.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video11.mp4"); videoUrlList.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-video12.mp4"); // 背景音乐 String bgMusic = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-music.wav"; // 字幕样式设置 Integer fontSize = 45; String fontName = "WenQuanYi Zen Hei Mono"; String fontColor = "#FFFFFF"; // 成片尺寸 Integer width = 720; Integer height = 1280; // logo String logoUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-logo.png"; Integer logoX = 20; Integer logoY = 20; String title = "这里是标题"; String subTitle = "这里是副标题"; int targetCount = 2; // 每次提交一个任务,业务方根据需要更换不同参数提交多次 for (int i = 0; i < targetCount; i++) { Collections.shuffle(videoUrlList); produceSingleVideo(voiceUrl, videoUrlList, title, subTitle, bgMusic, fontSize, fontName, fontColor, logoUrl, logoX, logoY, width, height); } } // 提交单个任务 public void produceSingleVideo(String voiceUrl, List<String> videoUrls, String title, String subtitle, String bgMusic, int fontSize, String fontName, String fontColor, String logoUrl, Integer logoX, Integer logoY, int width, int height) throws Exception { String inputFile = voiceUrl.replaceAll("https://", "oss://"); inputFile = inputFile.replaceAll("http://", "oss://"); SubmitASRJobRequest submitASRJobRequest = new SubmitASRJobRequest(); submitASRJobRequest.setInputFile(inputFile); SubmitASRJobResponse submitASRJobResponse = iceClient.submitASRJob(submitASRJobRequest); String smartJobId = submitASRJobResponse.getBody().getJobId(); String subtitleContent = ""; while (true) { GetSmartHandleJobRequest getSmartHandleJobRequest = new GetSmartHandleJobRequest(); getSmartHandleJobRequest.setJobId(smartJobId); GetSmartHandleJobResponse getSmartHandleJobResponse = iceClient.getSmartHandleJob(getSmartHandleJobRequest); System.out.println("asr response : " + JSONObject.toJSONString(getSmartHandleJobResponse.getBody())); String status = getSmartHandleJobResponse.getBody().getState(); if ("Failed".equalsIgnoreCase(status) || "Finished".equalsIgnoreCase(status)) { subtitleContent = getSmartHandleJobResponse.getBody().getOutput(); break; } Thread.sleep(5000); } System.out.println("subtitleContent : " + subtitleContent); // 组装字幕轨 if (fontSize <= 0) { fontSize = 32; } if (Strings.isBlank(fontName)) { fontName = "WenQuanYi Zen Hei Mono"; } if (Strings.isBlank(fontColor)) { fontColor = "#000000"; } JSONArray subtitleTrackClips = new JSONArray(); JSONArray mpsSubtitles = JSONArray.parseArray(subtitleContent); JSONArray videoTrackClips = new JSONArray(); // 字幕距离底部距离 float subtitleBottom = 0.25f; // 随机特效 List<String> vfxs = Arrays.asList("heartfireworks", "colorfulradial", "meteorshower", "starry", "colorfulstarry", "moons_and_stars", "flyfire", "starexplosion", "spotfall", "sparklestarfield"); Collections.shuffle(vfxs); for (int i = 0; i < mpsSubtitles.size(); i++) { JSONObject mpsSubtitle = mpsSubtitles.getJSONObject(i); String content = mpsSubtitle.getString("content"); content = content.replaceAll("。", ""); Float timelineIn = mpsSubtitle.getFloat("from") ; Float timelineOut = mpsSubtitle.getFloat("to") ; String subtitleClip = "{\"Content\":\"" + content + "\",\"TimelineIn\":" + timelineIn + ",\"TimelineOut\":" + timelineOut + ",\"Type\":\"Text\",\"X\":0.0,\"Y\":" + subtitleBottom + ",\"Font\":\"" + fontName + "\",\"Alignment\":\"BottomCenter\",\"FontSize\":" + fontSize + ",\"FontColor\":\"" + fontColor + "\",\"Outline\":2,\"OutlineColour\":\"#000000\",\"FontColor\":\"#ffffff\",}"; subtitleTrackClips.add(JSONObject.parseObject(subtitleClip)); // 根据字幕轨,截取视频轨片段 float out = timelineOut - timelineIn; // 随机特效 String vfx = vfxs.get(i % vfxs.size()); String url = videoUrls.get(i % videoUrls.size()); JSONObject clip = new JSONObject(); clip.put("MediaURL", url); if (url.endsWith(".jpg")) { clip.put("Duration", out); clip.put("Type", "Image"); } else { clip.put("Out", out); } JSONArray effects = new JSONArray(); // 添加背景模糊 effects.add(JSONObject.parseObject("{\"Type\":\"Background\",\"SubType\":\"Blur\",\"Radius\":0.1}")); // 添加氛围类特效 effects.add(JSONObject.parseObject("{\"Type\":\"VFX\",\"SubType\":\"" + vfx + "\"}")); // 视频静音 effects.add(JSONObject.parseObject("{\"Type\":\"Volume\",\"Gain\":0}")); clip.put("Effects", effects); videoTrackClips.add(clip); } if (title != null && title.length() > 0) { float titleY = 280; int titleFontSize = 70; String titleFont = "AlibabaPuHuiTi"; String titleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + titleY + ",\"Font\":\"" + titleFont + "\",\"Content\":\"" + title + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + titleFontSize + ",\"FontColor\":\"#FFD700\",\"Outline\":4,\"OutlineColour\":\"#000000\",\"TimelineIn\":0,\"TimelineOut\":5,\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}}"; subtitleTrackClips.add(JSONObject.parse(titleClip)); } if (subtitle != null && subtitle.length() > 0) { float subtitleY = 200; int subtitleFontSize = 60; String subtitleFont = "AlibabaPuHuiTi"; String subtitleClip = "{\"Type\":\"Text\",\"X\":0,\"Y\":" + subtitleY + ",\"Font\":\"" + subtitleFont + "\",\"Content\":\"" + subtitle + "\",\"Alignment\":\"TopCenter\",\"FontSize\":" + subtitleFontSize + ",\"FontColorOpacity\":1,\"FontColor\":\"#ffffff\",\"Outline\":2,\"OutlineColour\":\"#000000\",\"FontFace\":{\"Bold\":false,\"Italic\":false,\"Underline\":false}}"; subtitleTrackClips.add(JSONObject.parse(subtitleClip)); } // 组装音频轨 String audioTrackClips = ""; if (Strings.isBlank(bgMusic)) { audioTrackClips = "[{\"MediaURL\":\"" + voiceUrl + "\"}]"; } else { // 两个音频轨,一个人声,一个音乐 audioTrackClips = "[{\"MediaURL\":\"" + voiceUrl + "\"}]},{\"AudioTrackClips\":[{\"MediaURL\":\"" + bgMusic + "\"}]"; } // 图片轨,用于展示logo String logoClip = ""; int logoWidth = 200; int logoHeight = 60; if (Strings.isNotBlank(logoUrl)) { logoClip = "{\"ImageURL\":\"" + logoUrl + "\",\"X\":" + logoX + ",\"Y\":" + logoY + ",\"Width\":\"" + logoWidth + "\",\"Height\":\"" + logoHeight + "\"}"; } // 拼时间线 String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," + "\"SubtitleTracks\":[{\"SubtitleTrackClips\":" + subtitleTrackClips.toJSONString() + "}]," + "\"AudioTracks\":[{\"AudioTrackClips\":" + audioTrackClips + "}]," + "\"ImageTracks\":[{\"ImageTrackClips\":[" + logoClip + "]}]}"; System.out.println("timeline : " + timeline); // 提交合成任务 SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest(); submitMediaProducingJobRequest.setTimeline(timeline); String outputPath = output + "/" + UUID.randomUUID().toString().replaceAll("-",""); String mediaURL = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + outputPath + ".mp4"; submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":" + width + ",\"Height\":" + height + "}"); SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest); System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL); // 等待合成任务完成 while (true) { GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest(); getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId); GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest); System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body)); String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus(); if ("Success".equals(status)) { break; } Thread.sleep(5000); } System.out.println("Produce succeed : " + mediaURL); } public Client createIceClient() throws Exception { // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。 // 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client(); Config config = new Config(); config.setCredential(credentialClient); // 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。 // config.accessKeyId = <yourAccessKeyId>; // config.accessKeySecret = <yourAccessKeySecret>; config.endpoint = "ice." + regionId + ".aliyuncs.com"; Client client = new Client(config); return client; } }
相关接口
卡点视频
主要功能
- 输入一段音频,自动识别音频卡点。
- 输入任意数量视频或图片素材,随机排序,并根据音乐卡点生成Timeline。
- 添加转场和背景模糊效果。
成片预览
实现代码
Java
package com.alibaba.bltest;
/**
Maven引入:
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>ice20201109</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>mts20140618</artifactId>
<version>3.3.33</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>credentials-java</artifactId>
<version>0.2.12</version>
</dependency>
*/
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.ice20201109.models.GetMediaProducingJobRequest;
import com.aliyun.ice20201109.models.GetMediaProducingJobResponse;
import com.aliyun.ice20201109.models.SubmitMediaProducingJobRequest;
import com.aliyun.ice20201109.models.SubmitMediaProducingJobResponse;
import com.aliyun.mts20140618.models.QueryIProductionJobRequest;
import com.aliyun.mts20140618.models.QueryIProductionJobResponse;
import com.aliyun.mts20140618.models.SubmitIProductionJobRequest;
import com.aliyun.mts20140618.models.SubmitIProductionJobResponse;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.teaopenapi.models.Config;
import com.google.common.io.CharStreams;
import org.apache.commons.io.Charsets;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
/**
* Create by oushu
* Date 2022/07/11 上午11:57
*/
public class BatchProduceASRSubtitleRelease {
private String bucket;
private String regionId;
private String output;
private OSS ossClient;
private com.aliyun.mts20140618.Client mpsClient;
private com.aliyun.ice20201109.Client iceClient;
public void initClient() throws Exception {
bucket = "your-bucket";
output = "output-path";
regionId = "cn-shanghai";
ossClient = createOssClient();
mpsClient = createMpsClient();
iceClient = createIceClient();
}
public static void main(String[] args) throws Exception {
BatchProduceBeatMusicRelease batchProduceVideo = new BatchProduceBeatMusicRelease();
batchProduceVideo.initClient();
batchProduceVideo.batchProduceVideo();
}
public void batchProduceVideo() throws Exception {
String musicUrl = "https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-music.mp3";
List<String> mediaUrls = new ArrayList();
mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-image1.jpg");
mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-image2.jpg");
mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-image3.jpg");
mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-movie1.mp4");
mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-movie2.mp4");
mediaUrls.add("https://your-bucket.oss-cn-shanghai.aliyuncs.com/your-movie3.mp4");
int targetCount = 1;
for (int i = 0; i < targetCount; i++) {
Collections.shuffle(mediaUrls);
List<String> subImageUrls = mediaUrls.subList(0, 15);
produceSingleVideo(musicUrl, subImageUrls);
}
}
public void produceSingleVideo(String musicUrl, List<String> imageUrls) throws Exception {
System.out.println("Start produce!!!!");
// 提交节奏检测任务
String input = musicUrl;
SubmitIProductionJobRequest submitIProductionJobRequest = new SubmitIProductionJobRequest();
submitIProductionJobRequest.setFunctionName("AudioBeatDetection");
submitIProductionJobRequest.setInput(input);
submitIProductionJobRequest.setOutput("oss://" + bucket + ".oss-" + regionId + ".aliyuncs.com/iproduction/{source}-{timestamp}.txt");
SubmitIProductionJobResponse submitIProductionJobResponse = mpsClient.submitIProductionJob(submitIProductionJobRequest);
// 等待任务完成
String jobId = submitIProductionJobResponse.body.jobId;
String result;
while (true) {
QueryIProductionJobRequest queryIProductionJobRequest = new QueryIProductionJobRequest();
queryIProductionJobRequest.setJobId(jobId);
QueryIProductionJobResponse queryIProductionJobResponse = mpsClient.queryIProductionJob(queryIProductionJobRequest);
System.out.println("IProductionJob Info : " + JSONObject.toJSONString(queryIProductionJobResponse.body));
if ("Success".equals(queryIProductionJobResponse.body.state)) {
result = queryIProductionJobResponse.body.result;
break;
}
Thread.sleep(5000);
}
// 获取节奏检测任务结果
String file = JSONObject.parseObject(JSONObject.parseObject(result).getString("Data")).getJSONArray("result").getJSONObject(0).getString("file");
System.out.println("result file : " + file);
String resultContent = getObjectContent(file);
System.out.println("result content : " + resultContent);
JSONArray beatList = JSONObject.parseObject(resultContent).getJSONArray("BeatList");
// 封装时间线
JSONArray videoTrackClips = new JSONArray();
float transitionDur = 0.3f;
float lastBeat = 0;
for (int i = 0; i < imageUrls.size(); i++) {
float beat = Float.parseFloat(beatList.getString(i));
float beatDuration = beat - lastBeat;
float duration = beatDuration;
String url = imageUrls.get(i);
JSONObject clip = new JSONObject();
clip.put("MediaURL", url);
if (beatDuration > transitionDur) {
clip.put("Effects", JSONArray.parse("[{\"Type\": \"Transition\",\"SubType\": \"linearblur\",\"Duration\": " + transitionDur + "},{\"Type\":\"Background\",\"SubType\":\"Blur\"}]"));
duration += transitionDur;
} else {
clip.put("Effects", JSONArray.parse("[{\"Type\":\"Background\",\"SubType\":\"Blur\"}]"));
}
if (url.endsWith(".jpg")) {
clip.put("Duration", duration);
clip.put("Type", "Image");
} else {
clip.put("Out", duration);
}
videoTrackClips.add(clip);
lastBeat = beat;
}
String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":" + videoTrackClips.toJSONString() + "}]," +
"\"AudioTracks\":[{\"AudioTrackClips\":[{\"MediaURL\":\"" + musicUrl + "\"}]}]," +
"}";
System.out.println("timeline : " + timeline);
// 提交合成任务
SubmitMediaProducingJobRequest submitMediaProducingJobRequest = new SubmitMediaProducingJobRequest();
submitMediaProducingJobRequest.setTimeline(timeline);
String outputPath = output + "/" + UUID.randomUUID().toString().replaceAll("-","");
String mediaURL = "https://" + bucket + ".oss-" + regionId + ".aliyuncs.com/" + outputPath + ".mp4";
submitMediaProducingJobRequest.setOutputMediaConfig("{\"MediaURL\":\"" + mediaURL + "\",\"Width\":720,\"Height\":1280}");
SubmitMediaProducingJobResponse submitMediaProducingJobResponse = iceClient.submitMediaProducingJob(submitMediaProducingJobRequest);
System.out.println("job created, jobId : " + submitMediaProducingJobResponse.body.jobId + ", requestId : " + submitMediaProducingJobResponse.body.getRequestId() + ", mediaURL : " + mediaURL);
// 等待合成任务完成
while (true) {
GetMediaProducingJobRequest getMediaProducingJobRequest = new GetMediaProducingJobRequest();
getMediaProducingJobRequest.setJobId(submitMediaProducingJobResponse.body.jobId);
GetMediaProducingJobResponse getMediaProducingJobResponse = iceClient.getMediaProducingJob(getMediaProducingJobRequest);
System.out.println("GetMediaProducingJobResponse : " + JSONObject.toJSONString(getMediaProducingJobResponse.body));
String status = getMediaProducingJobResponse.getBody().getMediaProducingJob().getStatus();
if ("Success".equals(status)) {
break;
}
Thread.sleep(5000);
}
System.out.println("Produce succeed : " + mediaURL);
}
public String getObjectContent(String object) throws Exception {
OSSObject obj = ossClient.getObject(bucket, object);
InputStream stream = obj.getObjectContent();
String result = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
return result;
}
public com.aliyun.mts20140618.Client createMpsClient() throws Exception {
// 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
// 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
Config config = new Config();
config.setCredential(credentialClient);
// 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
// config.accessKeyId = <yourAccessKeyId>;
// config.accessKeySecret = <yourAccessKeySecret>;
config.endpoint = "mts." + regionId + ".aliyuncs.com";
com.aliyun.mts20140618.Client mtsClient = new com.aliyun.mts20140618.Client(config);
return mtsClient;
}
public OSS createOssClient() throws Exception {
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
String endpoint = "http://oss-" + regionId + ".aliyuncs.com";
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
return ossClient;
}
public com.aliyun.ice20201109.Client createIceClient() throws Exception {
// 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
// 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/document_detail/378657.html
com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client();
Config config = new Config();
config.setCredential(credentialClient);
// 如需硬编码AccessKey ID和AccessKey Secret,代码如下,但强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
// config.accessKeyId = <yourAccessKeyId>;
// config.accessKeySecret = <yourAccessKeySecret>;
config.endpoint = "ice." + regionId + ".aliyuncs.com";
com.aliyun.ice20201109.Client iceClient = new com.aliyun.ice20201109.Client(config);
return iceClient;
}
}