|
|
|
@ -87,7 +87,7 @@ public class ImgSpeak {
|
|
|
|
|
log.info("人脸检测响应: {}", responseBody);
|
|
|
|
|
|
|
|
|
|
JSONObject responseJson = JSON.parseObject(responseBody);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否通过人脸检测
|
|
|
|
|
JSONObject output = responseJson.getJSONObject("output");
|
|
|
|
|
if (output != null && !output.getBooleanValue("pass")) {
|
|
|
|
@ -96,31 +96,31 @@ public class ImgSpeak {
|
|
|
|
|
log.error(errorMsg);
|
|
|
|
|
throw new Exception(errorMsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return responseJson;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 调用灵动人像LivePortrait视频合成API
|
|
|
|
|
*
|
|
|
|
|
* @param imageUrl 图片URL
|
|
|
|
|
* @param audioUrl 音频URL
|
|
|
|
|
* @param templateId 模板ID,可选值:normal, dance, rap等
|
|
|
|
|
* @param eyeMoveFreq 眼睛移动频率,范围0-1
|
|
|
|
|
* @param videoFps 视频帧率,默认30
|
|
|
|
|
* @param imageUrl 图片URL
|
|
|
|
|
* @param audioUrl 音频URL
|
|
|
|
|
* @param templateId 模板ID,可选值:normal, dance, rap等
|
|
|
|
|
* @param eyeMoveFreq 眼睛移动频率,范围0-1
|
|
|
|
|
* @param videoFps 视频帧率,默认30
|
|
|
|
|
* @param mouthMoveStrength 嘴部动作强度,范围0-1
|
|
|
|
|
* @param pasteBack 是否贴回原图,true或false
|
|
|
|
|
* @param headMoveStrength 头部动作强度,范围0-1
|
|
|
|
|
* @param pasteBack 是否贴回原图,true或false
|
|
|
|
|
* @param headMoveStrength 头部动作强度,范围0-1
|
|
|
|
|
* @return 任务ID
|
|
|
|
|
* @throws Exception 异常信息
|
|
|
|
|
*/
|
|
|
|
|
@SneakyThrows
|
|
|
|
|
public static String synthesisVideo(String imageUrl, String audioUrl, String templateId,
|
|
|
|
|
double eyeMoveFreq, int videoFps, double mouthMoveStrength,
|
|
|
|
|
boolean pasteBack, double headMoveStrength) {
|
|
|
|
|
public static String synthesisVideo(String imageUrl, String audioUrl, String templateId,
|
|
|
|
|
double eyeMoveFreq, int videoFps, double mouthMoveStrength,
|
|
|
|
|
boolean pasteBack, double headMoveStrength) {
|
|
|
|
|
// 先进行人脸检测
|
|
|
|
|
detectFace(imageUrl);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建OkHttpClient,设置超时时间
|
|
|
|
|
OkHttpClient client = new OkHttpClient().newBuilder()
|
|
|
|
|
.connectTimeout(30, TimeUnit.SECONDS)
|
|
|
|
@ -287,7 +287,7 @@ public class ImgSpeak {
|
|
|
|
|
String imageUrl = "https://dsideal.obs.myhuaweicloud.com/HuangHai/%E5%A4%87%E4%BB%BD/p874897.png";
|
|
|
|
|
// 音频URL(音频)
|
|
|
|
|
String audioUrl = "https://dsideal.obs.myhuaweicloud.com/HuangHai/%E5%A4%87%E4%BB%BD/p874897.wav";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 模板ID - 使用模板
|
|
|
|
|
String templateId = "sing"; // 可选值:normal, dance, rap, sing等
|
|
|
|
|
// 眼睛移动频率
|
|
|
|
@ -302,9 +302,9 @@ public class ImgSpeak {
|
|
|
|
|
double headMoveStrength = 0.7;
|
|
|
|
|
|
|
|
|
|
// 调用灵动人像LivePortrait视频合成API
|
|
|
|
|
String taskId = synthesisVideo(imageUrl, audioUrl, templateId, eyeMoveFreq,
|
|
|
|
|
videoFps, mouthMoveStrength, pasteBack, headMoveStrength);
|
|
|
|
|
|
|
|
|
|
String taskId = synthesisVideo(imageUrl, audioUrl, templateId, eyeMoveFreq,
|
|
|
|
|
videoFps, mouthMoveStrength, pasteBack, headMoveStrength);
|
|
|
|
|
|
|
|
|
|
// 轮询查询任务状态
|
|
|
|
|
int maxRetries = 100;
|
|
|
|
|
int retryCount = 0;
|
|
|
|
@ -320,12 +320,11 @@ public class ImgSpeak {
|
|
|
|
|
// 任务成功,获取视频URL
|
|
|
|
|
videoUrl = result.getJSONObject("output").getJSONObject("results").getString("video_url");
|
|
|
|
|
log.info("生成的视频URL: {}", videoUrl);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取视频时长和比例信息
|
|
|
|
|
double videoDuration = result.getJSONObject("usage").getDoubleValue("video_duration");
|
|
|
|
|
String videoRatio = result.getJSONObject("usage").getString("video_ratio");
|
|
|
|
|
log.info("视频时长: {}秒, 视频比例: {}", videoDuration, videoRatio);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
} else if ("FAILED".equals(status)) {
|
|
|
|
|
// 任务失败
|
|
|
|
@ -343,7 +342,7 @@ public class ImgSpeak {
|
|
|
|
|
if (retryCount >= maxRetries) {
|
|
|
|
|
log.error("查询任务状态超时,已达到最大重试次数: {}", maxRetries);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果获取到了视频URL,则下载保存
|
|
|
|
|
if (videoUrl != null && !videoUrl.isEmpty()) {
|
|
|
|
|
String fileName = "liveportrait_sing_" + System.currentTimeMillis() + "_" + taskId + ".mp4";
|
|
|
|
|