@@ -11,8 +11,8 @@ public enum EnumVideoType { | |||
// 1:竖版 | |||
// 2:横版 | |||
VERTICAL_PLATE(1, "竖版"), | |||
HORIZONTAL_PLATE(2, "横版"), | |||
VERTICAL_PLATE(1, "竖版", "vertical"), | |||
HORIZONTAL_PLATE(2, "横版", "horizontal"), | |||
; | |||
public static EnumVideoType getEnum(Integer code) { | |||
@@ -34,10 +34,21 @@ public enum EnumVideoType { | |||
private Integer code; | |||
private String message; | |||
private String type; | |||
EnumVideoType(Integer code, String message) { | |||
public String getType() { | |||
return type; | |||
} | |||
public void setType(String type) { | |||
this.type = type; | |||
} | |||
EnumVideoType(Integer code, String message, String type) { | |||
this.code = code; | |||
this.message = message; | |||
this.type = type; | |||
} | |||
public Integer getCode() { | |||
@@ -11,17 +11,16 @@ import com.iformall.domain.po.sm.MaterialMould; | |||
import com.iformall.domain.po.sm.PersonMould; | |||
import com.iformall.domain.po.sm.UserMouldVideo; | |||
import com.iformall.domain.po.sm.VoiceMould; | |||
import com.iformall.enums.EnumMouldPatchType; | |||
import com.iformall.enums.EnumVideoStatus; | |||
import com.iformall.enums.EnumVideoType; | |||
import com.iformall.enums.EnumVoiceType; | |||
import com.iformall.enums.*; | |||
import com.iformall.mapper.UserMouldVideoMapper; | |||
import com.iformall.service.sm.MaterialMouldService; | |||
import com.iformall.service.sm.PersonMouldService; | |||
import com.iformall.service.sm.UserMouldVideoService; | |||
import com.iformall.service.sm.VoiceMouldService; | |||
import com.iformall.sm.AiVideoHelper; | |||
import com.iformall.sm.AiVideoParam; | |||
import com.iformall.sm.AiVideoResult; | |||
import com.iformall.utils.Base64Util; | |||
import com.iformall.video.VideoFactory; | |||
import com.iformall.video.entity.VideUploadResult; | |||
import org.apache.commons.lang3.StringUtils; | |||
@@ -106,8 +105,19 @@ public class UserMouldVideoServiceImpl implements UserMouldVideoService { | |||
JSONObject personObject = JSONObject.parseObject(record.getPersonJson()); | |||
if(personObject != null && !personObject.isEmpty()){ | |||
isPerson = true; | |||
Long id = personObject.getLong("id"); | |||
Integer type = personObject.getInteger("type"); | |||
String material = personObject.getString("material"); | |||
int x = personObject.getIntValue("x"); | |||
int y = personObject.getIntValue("y"); | |||
int z = personObject.getIntValue("z"); | |||
float w = personObject.getFloatValue("w"); | |||
float h = personObject.getFloatValue("h"); | |||
} | |||
}catch(Exception e){} | |||
}catch(Exception e){ | |||
e.printStackTrace(); | |||
return new ResultData(ErrorCode.SYS_PARAMETER_ERROR.getCode(),"数字人层级数据错误"); | |||
} | |||
//给数字人默认属性 | |||
if(!isPerson){ | |||
JSONObject personObject = new JSONObject(); | |||
@@ -126,8 +136,8 @@ public class UserMouldVideoServiceImpl implements UserMouldVideoService { | |||
personObject.put("y",y); | |||
} | |||
personObject.put("z",0); | |||
personObject.put("w","1");//比例系数(2位小数) | |||
personObject.put("h","1");//比例系数(2位小数) | |||
personObject.put("w",1.0f);//比例系数(2位小数) | |||
personObject.put("h",1.0f);//比例系数(2位小数) | |||
record.setPersonJson(personObject.toJSONString()); | |||
} | |||
//默认背景 | |||
@@ -196,11 +206,11 @@ public class UserMouldVideoServiceImpl implements UserMouldVideoService { | |||
materialIds.add(id); | |||
} | |||
String material = jsonObject.getString("material"); | |||
Integer x = jsonObject.getInteger("x"); | |||
Integer y = jsonObject.getInteger("y"); | |||
Integer z = jsonObject.getInteger("z"); | |||
String w = jsonObject.getString("w"); | |||
String h = jsonObject.getString("h"); | |||
int x = jsonObject.getIntValue("x"); | |||
int y = jsonObject.getIntValue("y"); | |||
int z = jsonObject.getIntValue("z"); | |||
float w = jsonObject.getFloatValue("w"); | |||
float h = jsonObject.getFloatValue("h"); | |||
} | |||
} | |||
record.setMaterialIds(JSONArray.toJSONString(materialIds)); | |||
@@ -258,12 +268,21 @@ public class UserMouldVideoServiceImpl implements UserMouldVideoService { | |||
} | |||
String voiceMouldSmId = null; | |||
String voiceType = "default";//默认 | |||
if(mouldVideo.getVoiceMouldId() == null){ | |||
msg = "未选择声音模板"; | |||
}else{ | |||
try{ | |||
JSONObject personMouldObject = JSONObject.parseObject(mouldVideo.getVoiceMouldSm()); | |||
voiceMouldSmId = personMouldObject.getString("mouldSmId"); | |||
Integer speakType = personMouldObject.getInteger("speakType"); | |||
Integer personType = personMouldObject.getInteger("personType"); | |||
if(speakType != null && speakType > 0){ | |||
voiceType = EnumSpeakType.getEnum(speakType).getMessage(); | |||
}else if(personType != null && personType > 0){ | |||
voiceType = EnumPersonType.getEnum(personType).getMessage(); | |||
} | |||
}catch(Exception e){} | |||
if(StringUtils.isBlank(voiceMouldSmId)){ | |||
msg = "参数错误,未找到声音模板数据"; | |||
@@ -284,8 +303,58 @@ public class UserMouldVideoServiceImpl implements UserMouldVideoService { | |||
return new AsyncResult<>(0); | |||
} | |||
Long backgroundId = mouldVideo.getBackgroundId(); | |||
if(backgroundId == null){ | |||
videoUpd.setVideoStatus(EnumVideoStatus.fail.getCode()); | |||
videoUpd.setVideoMsg("未选择背景"); | |||
this.saveOrUpdate(videoUpd); | |||
return new AsyncResult<>(0); | |||
} | |||
try{ | |||
AiVideoResult video = AiVideoHelper.createVideo(personMouldSmId, voiceMouldSmId, paperwork); | |||
AiVideoParam videoParam = new AiVideoParam(); | |||
videoParam.setGen_txt(paperwork); | |||
videoParam.setVideo_template_id(personMouldSmId); | |||
videoParam.setVoice_id(voiceMouldSmId); | |||
videoParam.setVoice_style(voiceType); | |||
AiVideoParam.VideoFiles videoFiles = new AiVideoParam.VideoFiles(); | |||
AiVideoParam.BackGround backGround = new AiVideoParam.BackGround(); | |||
backGround.setType(EnumVideoType.getEnum(mouldVideo.getVideoType()).getType()); | |||
JSONObject backgroundObject = JSONObject.parseObject(mouldVideo.getBackgroundSm()); | |||
backGround.setImage(Base64Util.imageUrlToBase64(backgroundObject.getString("material"))); | |||
videoFiles.setBack_ground(backGround); | |||
AiVideoParam.Material digitalHuman = new AiVideoParam.Material(); | |||
JSONObject personObject = JSONObject.parseObject(mouldVideo.getPersonJson()); | |||
int[] digitalHumanCoord = new int[]{personObject.getIntValue("x"),personObject.getIntValue("y")}; | |||
digitalHuman.setCoord(digitalHumanCoord); | |||
digitalHuman.setLevel(personObject.getIntValue("z")); | |||
digitalHuman.setRatio(personObject.getFloatValue("w")); | |||
videoFiles.setDigital_human(digitalHuman); | |||
if(StringUtils.isNotBlank(mouldVideo.getMaterialAllJson())){ | |||
JSONArray materialAllArray = JSONArray.parseArray(mouldVideo.getMaterialAllJson()); | |||
if(materialAllArray != null && !materialAllArray.isEmpty()){ | |||
List<AiVideoParam.Material> materialList = new ArrayList<>(); | |||
for(int i = 0;i < materialAllArray.size();i++) { | |||
JSONObject materialObject = materialAllArray.getJSONObject(i); | |||
if(EnumMouldPatchType.material_mould.getCode().equals(materialObject.getInteger("type"))){ | |||
AiVideoParam.Material material = new AiVideoParam.Material(); | |||
int[] materialCoord = new int[]{materialObject.getIntValue("x"),materialObject.getIntValue("y")}; | |||
material.setCoord(materialCoord); | |||
material.setImage(Base64Util.imageUrlToBase64(materialObject.getString("material"))); | |||
material.setLevel(materialObject.getIntValue("z")); | |||
material.setRatio(materialObject.getFloatValue("w")); | |||
materialList.add(material); | |||
} | |||
} | |||
if(materialList.size() > 0){ | |||
videoFiles.setMaterial(materialList); | |||
} | |||
} | |||
} | |||
videoParam.setVideo_files(videoFiles); | |||
AiVideoResult video = AiVideoHelper.createVideo(videoParam); | |||
if(video.isSuccess()){ | |||
videoUpd.setVideoPath(video.getUrl()); | |||
videoUpd.setVideoTime(video.getDuration()+""); | |||
@@ -1,6 +1,7 @@ | |||
package com.iformall.sm; | |||
import com.alibaba.fastjson.JSON; | |||
import com.alibaba.fastjson.JSONArray; | |||
import com.alibaba.fastjson.JSONObject; | |||
import com.iformall.common.ErrorCode; | |||
import com.iformall.douyin.pay.orderQuery.OrderQueryResult; | |||
@@ -8,8 +9,11 @@ import com.iformall.douyin.pay.orderQuery.QueryMerchantResult; | |||
import com.iformall.douyin.pay.orderQuery.QueryRefundResult; | |||
import com.iformall.douyin.pay.orderQuery.QuerySettleResult; | |||
import com.iformall.douyin.pay.preOrder.*; | |||
import com.iformall.enums.EnumMouldPatchType; | |||
import com.iformall.enums.EnumPayStatus; | |||
import com.iformall.enums.EnumVideoType; | |||
import com.iformall.exception.MallinkException; | |||
import com.iformall.utils.Base64Util; | |||
import com.iformall.utils.HttpUtil; | |||
import com.iformall.utils.sign.SignUtils; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -25,21 +29,15 @@ public class AiVideoHelper { | |||
public static String uri = "http://222.128.9.132:22266"; | |||
public static String doPost(String url, Map<String, Object> params) { | |||
return HttpUtil.doPost(url,params); | |||
public static String doPost(String url, String params) { | |||
return HttpUtil.doAiVideoPost(url,params); | |||
} | |||
public static AiVideoResult createVideo(String video_template_id,String voice_id,String gen_txt) { | |||
Map<String,Object> params = new HashMap<>(); | |||
params.put("video_template_id",video_template_id); | |||
if(StringUtils.isBlank(voice_id)){ | |||
voice_id = "default"; | |||
} | |||
params.put("voice_id",voice_id); | |||
params.put("gen_txt",gen_txt); | |||
log.info("生成视频start request:" + JSONObject.toJSONString(params)); | |||
String response = doPost(uri+"/gen_dh_video", params); | |||
public static AiVideoResult createVideo(AiVideoParam videoParam) { | |||
log.info("生成视频start request:" + JSONObject.toJSONString(videoParam)); | |||
String response = doPost(uri+"/gen_dh_video", JSONObject.toJSONString(videoParam)); | |||
log.info("生成视频end response:"+response); | |||
AiVideoResult result = new AiVideoResult(); | |||
@@ -50,12 +48,16 @@ public class AiVideoHelper { | |||
return result; | |||
} | |||
JSONObject jsonObject = JSON.parseObject(response); | |||
JSONObject status = jsonObject.getJSONObject("status"); | |||
Integer code = status.getInteger("code"); | |||
if(code == null){ | |||
result.setSuccess(false); | |||
result.setMsg("请求生成视频异常,请稍后重试"); | |||
return result; | |||
} | |||
if(null != code && code.intValue() == 1000){ | |||
if(code.intValue() == 1000){ | |||
JSONObject data = jsonObject.getJSONObject("data"); | |||
JSONObject video = data.getJSONObject("video"); | |||
result.setSuccess(true); | |||
@@ -93,8 +95,25 @@ public class AiVideoHelper { | |||
} | |||
public static void main(String[] args) { | |||
createVideo("16739389169485046_nVi875Ej","default", | |||
"恭喜发财"); | |||
AiVideoParam videoParam = new AiVideoParam(); | |||
videoParam.setGen_txt("我写了一篇小说,你帮我看看。"); | |||
videoParam.setVideo_template_id("16776650495633934_PgNAW8Sm"); | |||
videoParam.setVoice_id("zh-CN-XiaohanNeural"); | |||
videoParam.setVoice_style("default"); | |||
AiVideoParam.VideoFiles videoFiles = new AiVideoParam.VideoFiles(); | |||
AiVideoParam.BackGround backGround = new AiVideoParam.BackGround(); | |||
backGround.setType("vertical"); | |||
backGround.setImage(Base64Util.imageUrlToBase64("https://suimang.oss-accelerate.aliyuncs.com/builtin/background/grace/1080.jpg")); | |||
videoFiles.setBack_ground(backGround); | |||
AiVideoParam.Material digitalHuman = new AiVideoParam.Material(); | |||
int[] digitalHumanCoord = new int[]{0,0}; | |||
digitalHuman.setCoord(digitalHumanCoord); | |||
digitalHuman.setLevel(0); | |||
digitalHuman.setRatio(1.0f); | |||
videoFiles.setDigital_human(digitalHuman); | |||
videoParam.setVideo_files(videoFiles); | |||
AiVideoResult video = AiVideoHelper.createVideo(videoParam); | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
package com.iformall.sm; | |||
import lombok.Data; | |||
import java.util.List; | |||
@Data | |||
public class AiVideoParam { | |||
/** | |||
* | 参数 | 必选 | 类型 | 说明 | | |||
* | ----------------- | ---- | ------- | ------------------------------------------------------------ | | |||
* | gen_txt | 是 | string | 需要生成的文字内容 | | |||
* | video_template_id | 是 | string | 使用的视频模板ID | | |||
* | voice_id | 是 | string | 音色ID,如:"zh-CN-YunxiNeural"。如果使用“default”,表示不指定具体的,由后端服务自动匹配 | | |||
* | voice_style | 是 | string | TTS语音风格,如:”angry“。如果使用“default”,表示默认风格 | | |||
* | video_files | 否 | array[] | 字典类型,包含背景、数字人、素材信息。缺省,使用默认模板。 | | |||
* | + back_ground | 否 | array[] | 字典类型,背景信息 | | |||
* | ++ image | 是 | string | 背景图片,base64编辑后的字符串类型数据 | | |||
* | ++ type | 是 | string | 背景图片类型,共两种。horizontal 表示横版,vertical 表示竖版 | | |||
* | + digital_human | 否 | array[] | 字典类型,数字人信息 | | |||
* | ++ coord | 是 | array[] | 集合类型,表示相对于左上角的位置,如[100, 200],表示相对于左边缘100像素,相对于上边缘200相素 | | |||
* | ++ level | 是 | uint32 | 数字人图片的层级,值越大表示越高层,0表示最底层 | | |||
* | ++ ratio | 是 | float32 | 相对于原数字人图片大小的缩放比例,如0.5表示宽高均变为原来的一半 | | |||
* | + material | 否 | array[] | 字典类型,素材信息。具体的值是集合类型,内部由每个素材信息(素材信息是字典类型)组成,如"material":[{素材1的信息},{素材2的信息},{素材3的信息}] | | |||
* | ++ | 否 | array[] | 集合类型,每个素材信息(素材信息是字典类型)组成 | | |||
* | +++ coord | 是 | array[] | 集合类型,表示相对于左上角的位置,如[100, 200],表示相对于左边缘100像素,相对于上边缘200相素 | | |||
* | +++ image | 是 | string | 素材图片,base64编辑后的字符串类型数据 | | |||
* | +++ level | 是 | uint32 | 素材图片的层级,值越大表示越高层,0表示最底层 | | |||
* | +++ ratio | 是 | float32 | 相对于原素材图片大小的缩放比例,如0.5表示宽高均变为原来的一半 | | |||
*/ | |||
private String gen_txt; | |||
private String video_template_id; | |||
private String voice_id; | |||
private String voice_style; | |||
private VideoFiles video_files; | |||
@Data | |||
public static class VideoFiles { | |||
private BackGround back_ground; | |||
private Material digital_human; | |||
private List<Material> material; | |||
} | |||
@Data | |||
public static class BackGround { | |||
private String image; | |||
private String type; | |||
} | |||
@Data | |||
public static class Material { | |||
private int[] coord; | |||
private String image; | |||
private int level; | |||
private float ratio; | |||
} | |||
} |
@@ -1,8 +1,12 @@ | |||
package com.iformall.utils; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.io.Writer; | |||
import sun.misc.BASE64Encoder; | |||
import java.io.*; | |||
import java.net.HttpURLConnection; | |||
import java.net.URL; | |||
import java.util.regex.Matcher; | |||
import java.util.regex.Pattern; | |||
public class Base64Util { | |||
private static final char S_BASE64CHAR[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |||
@@ -309,4 +313,79 @@ public class Base64Util { | |||
} | |||
} | |||
/** | |||
* 图片URL转Base64编码 | |||
* @param imgUrl 图片URL | |||
* @return Base64编码 | |||
*/ | |||
public static String imageUrlToBase64(String imgUrl) { | |||
URL url = null; | |||
InputStream is = null; | |||
ByteArrayOutputStream outStream = null; | |||
HttpURLConnection httpUrl = null; | |||
try { | |||
url = new URL(imgUrl); | |||
httpUrl = (HttpURLConnection) url.openConnection(); | |||
httpUrl.connect(); | |||
httpUrl.getInputStream(); | |||
is = httpUrl.getInputStream(); | |||
outStream = new ByteArrayOutputStream(); | |||
//创建一个Buffer字符串 | |||
byte[] buffer = new byte[1024]; | |||
//每次读取的字符串长度,如果为-1,代表全部读取完毕 | |||
int len = 0; | |||
//使用输入流从buffer里把数据读取出来 | |||
while( (len = is.read(buffer)) != -1 ){ | |||
//用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 | |||
outStream.write(buffer, 0, len); | |||
} | |||
// 对字节数组Base64编码 | |||
return encode(outStream.toByteArray()); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} finally { | |||
try { | |||
if(is != null) { | |||
is.close(); | |||
} | |||
if(outStream != null) { | |||
outStream.close(); | |||
} | |||
if(httpUrl != null) { | |||
httpUrl.disconnect(); | |||
} | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
return null; | |||
} | |||
// /** | |||
// * 图片转字符串 | |||
// * @param image 图片Buffer | |||
// * @return Base64编码 | |||
// */ | |||
// public static String encode(byte[] image){ | |||
// BASE64Encoder decoder = new BASE64Encoder(); | |||
// return replaceEnter(decoder.encode(image)); | |||
// } | |||
// | |||
// /** | |||
// * 字符替换 | |||
// * @param str 字符串 | |||
// * @return 替换后的字符串 | |||
// */ | |||
// public static String replaceEnter(String str){ | |||
// String reg ="[\n-\r]"; | |||
// Pattern p = Pattern.compile(reg); | |||
// Matcher m = p.matcher(str); | |||
// return m.replaceAll(""); | |||
// } | |||
} |
@@ -133,13 +133,8 @@ public class HttpUtil { | |||
// 实例化HTTP方法 | |||
HttpPost request = new HttpPost(); | |||
request.setURI(new URI(url)); | |||
request.setConfig(RequestConfig.custom() | |||
.setConnectionRequestTimeout(5000) | |||
.setConnectTimeout(300000) | |||
.setSocketTimeout(300000) | |||
.build()); | |||
//设置参数 | |||
List<NameValuePair> nvps = new ArrayList<NameValuePair>(); | |||
for (Iterator iter = params.keySet().iterator(); iter.hasNext();) { | |||
@@ -382,52 +377,6 @@ public class HttpUtil { | |||
return null; | |||
} | |||
// /** | |||
// * post请求(用于请求json格式的参数) | |||
// * @param url | |||
// * @param params | |||
// * @return | |||
// */ | |||
// public static String doPost(String url, String params) throws Exception { | |||
// | |||
// CloseableHttpClient httpclient = HttpClients.createDefault(); | |||
// HttpPost httpPost = new HttpPost(url);// 创建httpPost | |||
// httpPost.setHeader("Accept", "application/json"); | |||
// httpPost.setHeader("Content-Type", "application/json"); | |||
// String charSet = "UTF-8"; | |||
// StringEntity entity = new StringEntity(params, charSet); | |||
// httpPost.setEntity(entity); | |||
// CloseableHttpResponse response = null; | |||
// | |||
// try { | |||
// response = httpclient.execute(httpPost); | |||
// StatusLine status = response.getStatusLine(); | |||
// int state = status.getStatusCode(); | |||
// if (state == HttpStatus.SC_OK) { | |||
// HttpEntity responseEntity = response.getEntity(); | |||
// String jsonString = EntityUtils.toString(responseEntity); | |||
// return jsonString; | |||
// } | |||
// else{ | |||
// logger.info("请求返回:"+state+"("+url+")"); | |||
// } | |||
// } | |||
// finally { | |||
// if (response != null) { | |||
// try { | |||
// response.close(); | |||
// } catch (IOException e) { | |||
// logger.error(e.getMessage()); | |||
// } | |||
// } | |||
// try { | |||
// httpclient.close(); | |||
// } catch (IOException e) { | |||
// logger.error(e.getMessage()); | |||
// } | |||
// } | |||
// return null; | |||
// } | |||
/** | |||
* post请求(用于请求json格式的参数) | |||
@@ -646,5 +595,61 @@ public class HttpUtil { | |||
// | |||
// } | |||
/** | |||
* post请求(用于请求json格式的参数) | |||
* @param url | |||
* @param params | |||
* @return | |||
*/ | |||
public static String doAiVideoPost(String url, String params){ | |||
CloseableHttpClient httpclient = HttpClients.createDefault(); | |||
HttpPost httpPost = new HttpPost(url);// 创建httpPost | |||
httpPost.setConfig(RequestConfig.custom() | |||
.setConnectionRequestTimeout(5000) | |||
.setConnectTimeout(3000000) | |||
.setSocketTimeout(3000000) | |||
.build()); | |||
httpPost.setHeader("Accept", "application/json"); | |||
httpPost.setHeader("Content-Type", "application/json"); | |||
String charSet = "UTF-8"; | |||
StringEntity entity = new StringEntity(params, charSet); | |||
httpPost.setEntity(entity); | |||
CloseableHttpResponse response = null; | |||
try { | |||
response = httpclient.execute(httpPost); | |||
StatusLine status = response.getStatusLine(); | |||
int state = status.getStatusCode(); | |||
if (state == HttpStatus.SC_OK) { | |||
HttpEntity responseEntity = response.getEntity(); | |||
String jsonString = EntityUtils.toString(responseEntity); | |||
return jsonString; | |||
} | |||
else{ | |||
logger.info("请求返回:"+state+"("+url+")"); | |||
} | |||
} | |||
catch(Exception e){ | |||
logger.error(e.getMessage()); | |||
return null; | |||
} | |||
finally { | |||
if (response != null) { | |||
try { | |||
response.close(); | |||
} catch (IOException e) { | |||
logger.error(e.getMessage()); | |||
} | |||
} | |||
try { | |||
httpclient.close(); | |||
} catch (IOException e) { | |||
logger.error(e.getMessage()); | |||
} | |||
} | |||
return null; | |||
} | |||
} | |||