视频混剪
This commit is contained in:
@@ -20,6 +20,11 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>ice20201109</artifactId>
|
||||||
|
<version>2.3.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mashape.unirest</groupId>
|
<groupId>com.mashape.unirest</groupId>
|
||||||
<artifactId>unirest-java</artifactId>
|
<artifactId>unirest-java</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package cn.iocoder.yudao.module.tik;
|
||||||
|
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
|
||||||
|
public class InitConfig implements CommandLineRunner {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... args) throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package cn.iocoder.yudao.module.tik.media;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.aliyun.ice20201109.Client;
|
||||||
|
import com.aliyun.ice20201109.models.*;
|
||||||
|
import com.aliyun.teaopenapi.models.Config;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
// 成功视频
|
||||||
|
// http://oushu-test-shanghai.oss-cn-shanghai.aliyuncs.com/ice_output/46b29eb5775f4f758846171ab79bfca7.mp4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要maven引入二方包依赖:
|
||||||
|
* <dependency>
|
||||||
|
* <groupId>com.aliyun</groupId>
|
||||||
|
* <artifactId>ice20201109</artifactId>
|
||||||
|
* <version>2.1.0</version>
|
||||||
|
* </dependency>
|
||||||
|
* <dependency>
|
||||||
|
* <groupId>com.alibaba</groupId>
|
||||||
|
* <artifactId>fastjson</artifactId>
|
||||||
|
* <version>1.2.9</version>
|
||||||
|
* </dependency>
|
||||||
|
*/
|
||||||
|
public class BatchProduceAlignment {
|
||||||
|
|
||||||
|
static final String regionId = "cn-hangzhou";
|
||||||
|
static final String bucket = "muye-ai-chat";
|
||||||
|
private Client iceClient;
|
||||||
|
|
||||||
|
private final String accessKeyId = "LTAI5tPV9Ag3csf41GZjaLTA";
|
||||||
|
private final String accessKeySecret = "kDqlGeJTKw6tJtFYiaY8vQTFuVIQDs";
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
BatchProduceAlignment batchProduce = new BatchProduceAlignment();
|
||||||
|
batchProduce.initClient();
|
||||||
|
// 文字素材
|
||||||
|
String text = "人们懂得用五味杂陈形容人生,因为懂得味道是每个人心中固守的情怀。在这个时代,每一个人都经历了太多的苦痛和喜悦,人们总会将苦涩藏在心里,而把幸福变成食物,呈现在四季的餐桌之上";
|
||||||
|
// 视频素材
|
||||||
|
String[] videoArray = new String[]{
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f1.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f2.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f3.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f4.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f5.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f6.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f7.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f8.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f9.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f10.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f11.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f12.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f13.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f14.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f15.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f16.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f17.mp4",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/food/f18.mp4"
|
||||||
|
};
|
||||||
|
// 背景音乐素材
|
||||||
|
String[] bgMusicArray = new String[]{
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/music/m1.wav",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/music/m2.wav",
|
||||||
|
"https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/test_media/music/m3.wav"
|
||||||
|
};
|
||||||
|
// 视频标题
|
||||||
|
String title = "舌尖上的美食";
|
||||||
|
// 生成的成片数
|
||||||
|
int produceCount = 3;
|
||||||
|
List<String> mediaList = batchProduce.batchProduceAlignment(title,text,videoArray,bgMusicArray,produceCount);
|
||||||
|
mediaList.forEach(System.out::println);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Produce failed. Exception: " + e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void initClient() throws Exception {
|
||||||
|
// 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
|
||||||
|
// 本示例以将AccessKey ID和 AccessKey Secret保存在环境变量为例说明。配置方法请参见:https://help.aliyun.com/zh/sdk/developer-reference/v2-manage-access-credentials?spm=a2c4g.11186623.0.0.423350fbOTFdOB#2a38e5c14b4em
|
||||||
|
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 = accessKeyId;
|
||||||
|
config.accessKeySecret = accessKeySecret;
|
||||||
|
config.endpoint = "ice." + regionId + ".aliyuncs.com";
|
||||||
|
config.regionId = regionId;
|
||||||
|
iceClient = new Client(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> batchProduceAlignment(String title,String text,String[] videoArray,String[] bgMusicArray,int produceCount) throws Exception {
|
||||||
|
|
||||||
|
// 批量提交任务
|
||||||
|
List<String> jobIds = new ArrayList<>();
|
||||||
|
for (int i = 0; i < produceCount; i++) {
|
||||||
|
String jobId = produceSingleVideo(title, text, videoArray, bgMusicArray);
|
||||||
|
jobIds.add(jobId);
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
Thread.sleep(3000);
|
||||||
|
boolean allFinished = true;
|
||||||
|
for (int i = 0; i < jobIds.size(); i++) {
|
||||||
|
String jobId = jobIds.get(i);
|
||||||
|
GetMediaProducingJobRequest req = new GetMediaProducingJobRequest();
|
||||||
|
req.setJobId(jobId);
|
||||||
|
GetMediaProducingJobResponse response = iceClient.getMediaProducingJob(req);
|
||||||
|
GetMediaProducingJobResponseBody.GetMediaProducingJobResponseBodyMediaProducingJob mediaProducingJob = response.getBody().getMediaProducingJob();
|
||||||
|
String status = mediaProducingJob.getStatus();
|
||||||
|
System.out.println("jobId: " + mediaProducingJob.getJobId() + ", status:" + status);
|
||||||
|
if ("Failed".equalsIgnoreCase(status)) {
|
||||||
|
throw new Exception("Produce failed. jobid: " + mediaProducingJob.getJobId());
|
||||||
|
}
|
||||||
|
if (!"Success".equalsIgnoreCase(status)) {
|
||||||
|
allFinished = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allFinished) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jobIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String produceSingleVideo(String title, String text, String[] videoArray, String[] bgMusicArray) throws Exception {
|
||||||
|
text = text.replace(",", "。");
|
||||||
|
text = text.replace("\n", "。");
|
||||||
|
String[] sentenceArray = text.split("。");
|
||||||
|
|
||||||
|
JSONArray videoClipArray = new JSONArray();
|
||||||
|
JSONArray audioClipArray = new JSONArray();
|
||||||
|
|
||||||
|
List<String> videoList = Arrays.asList(videoArray);
|
||||||
|
Collections.shuffle(videoList);
|
||||||
|
for (int i = 0; i < sentenceArray.length; i++) {
|
||||||
|
String sentence = sentenceArray[i];
|
||||||
|
String clipId = "clip" + i;
|
||||||
|
String videoUrl = videoList.get(i);
|
||||||
|
String videoClip = "{\"MediaURL\":\""+videoUrl+"\",\"ReferenceClipId\":\""+clipId+"\",\"Effects\":[{\"Type\":\"Background\",\"SubType\":\"Blur\",\"Radius\":0.1}]}";
|
||||||
|
videoClipArray.add(JSONObject.parseObject(videoClip));
|
||||||
|
String audioClip = "{\"Type\":\"AI_TTS\",\"Content\":\"" + sentence + "\",\"Voice\":\"zhichu\",\"ClipId\":\""+clipId+"\",\"Effects\":[{\"Type\":\"AI_ASR\",\"Font\":\"Alibaba PuHuiTi\",\"Alignment\":\"TopCenter\",\"Y\":0.75,\"FontSize\":55,\"FontColor\":\"#ffffff\",\"AdaptMode\":\"AutoWrap\",\"TextWidth\":0.8,\"Outline\":2,\"OutlineColour\":\"#000000\"}]}";
|
||||||
|
audioClipArray.add(JSONObject.parseObject(audioClip));
|
||||||
|
}
|
||||||
|
|
||||||
|
String subtitleTrack = "{\"SubtitleTrackClips\":[{\"Type\":\"Text\",\"Font\":\"HappyZcool-2016\",\"Content\":\""+title+"\",\"FontSize\":80,\"FontColor\":\"#ffffff\",\"Y\":0.15,\"Alignment\":\"TopCenter\",\"EffectColorStyle\":\"CS0004-000005\",\"FontFace\":{\"Bold\":true,\"Italic\":false,\"Underline\":false}}]}";
|
||||||
|
|
||||||
|
int bgMusicIndex = (int)(Math.random() * bgMusicArray.length);
|
||||||
|
String bgMusicUrl = bgMusicArray[bgMusicIndex];
|
||||||
|
String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":"+videoClipArray.toJSONString()+"}],\"AudioTracks\":[{\"AudioTrackClips\":"+audioClipArray.toJSONString()+"},{\"AudioTrackClips\":[{\"MediaURL\":\""+bgMusicUrl+"\"}]}],\"SubtitleTracks\":[" + subtitleTrack + "]}";
|
||||||
|
|
||||||
|
//
|
||||||
|
String targetFileName = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
String outputMediaUrl = "http://" + bucket + ".oss-" + regionId + ".aliyuncs.com/ice_output/" + targetFileName + ".mp4";
|
||||||
|
int width = 720;
|
||||||
|
int height = 1280;
|
||||||
|
String outputMediaConfig = "{\"MediaURL\":\"" + outputMediaUrl + "\",\"Width\":"+width+",\"Height\":"+height+"}";
|
||||||
|
|
||||||
|
SubmitMediaProducingJobRequest request = new SubmitMediaProducingJobRequest();
|
||||||
|
request.setTimeline(timeline);
|
||||||
|
request.setOutputMediaConfig(outputMediaConfig);
|
||||||
|
SubmitMediaProducingJobResponse response = iceClient.submitMediaProducingJob(request);
|
||||||
|
//ystem.out.println("start job. jobid: " + response.getBody().getJobId() + ", outputMediaUrl: " + outputMediaUrl);
|
||||||
|
return response.getBody().getJobId() + " : " + outputMediaUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package cn.iocoder.yudao.module.tik.media.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.module.tik.media.BatchProduceAlignment;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Tag(name = "BatchProduceAlignment - 视频混剪", description = "视频混剪相关接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/media")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class BatchProduceAlignmentController {
|
||||||
|
|
||||||
|
@PostMapping("/batchProduceAlignment")
|
||||||
|
@Operation(summary = "视频混剪", description = "视频混剪")
|
||||||
|
public Object batchProduceAlignment(
|
||||||
|
//视频标题
|
||||||
|
@RequestParam String title,
|
||||||
|
//文字素材
|
||||||
|
@RequestParam String text,
|
||||||
|
// 视频素材
|
||||||
|
@RequestParam String[] videoArray,
|
||||||
|
// 背景音乐素材
|
||||||
|
@RequestParam String[] bgMusicArray,
|
||||||
|
// 生成的成片数
|
||||||
|
int produceCount) {
|
||||||
|
try {
|
||||||
|
BatchProduceAlignment batchProduce = new BatchProduceAlignment();
|
||||||
|
batchProduce.initClient();
|
||||||
|
List<String> jobIds = batchProduce.batchProduceAlignment(title,text,videoArray,bgMusicArray,produceCount);
|
||||||
|
return CommonResult.success(jobIds);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return CommonResult.error(new ErrorCode(500, "Produce failed. Exception: " + e));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user