由于项目需要将多个音频拼接成一整段音频,所以在网上寻找解决办法。刚开始打算使用FFmpeg进行拼接,但是我们用的七牛云的文件存储,又在七牛云的文档中发现了音视频拼接接口,估综合考虑下使用七牛云的音视频拼接接口。
由于七牛云的音视频拼接接口看起来比较麻烦(~~刚开始用,看七牛云的文档太生硬了。),故在正确调用之后记录一下使用方法。
官方文档:https://developer.qiniu.com/dora/manual/1246/audio-and-video-stitching-avconcat
由于是音视频拼接,我只用到了音频拼接,具体视频拼接时修改fops的参数即可(注释中有解释)
拼接最重要的是 输入怎么输入,输出到哪。本文中,输入在代码中为:List<String> resUrl ,输出为回调链接中items节点的key节点。
具体代码如下:
//回调接口,执行接口之后,若拼接成功,七牛云会将信息发送到此链接
String persistentNotifyUrl = “https://localhost:8080/notify”;
// 定义一个输入源,存放整个url,必须是同一个bucket中的资源,例:https://qiniu.com/head.mp3,使用list是因为其有序,可保证拼接的顺序。
List<String> resUrl = new ArrayList<String>();
//测试数据
resUrl.add("https://qiniu.com/head.mp3");
resUrl.add("https://qiniu.com/mid.mp3");
resUrl.add("https://qiniu.com/foot.mp3");
String accessKey = "you accessKey";
String secretKey = "you secretKey";
//调用接口前必须获取auth
Auth auth = Auth.create(accessKey, secretKey);
//七牛云音频拼接cmd,详情见最后的注解1
StringBuffer fops = new StringBuffer("avconcat/2/format/mp3/index/1");
//待处理的key,也是拼接文件的头文件
String key = "";
//判断如果list不为空
if(!resUrl.isEmpty()){
//注意resUrl中的地址可能是Url编码之后的,所以需要decode,若存在 %20 这种已编码的符号,会报找不到资源的错误
String decodeUrl = "";
try {
//七牛云会将key作为拼接的第一位,所以单独拿出来,且不需要完整链接,只保留bucket中的文件名即可。
key = URLDecoder.decode(resUrl.get(0),"UTF-8");
//获取第一个资源的名字
String[] strings = key.split("/");
key = strings[strings.length-1];
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
log.info(" urlDecoder fail "+e.getMessage());
}
//获取到key之后需要删除,不然会出现重读音频的问题
resUrl.remove(0);
for (String url :
resUrl) {
try {
//decodeUrl 防止出现找不到资源问题
decodeUrl = URLDecoder.decode(url,"UTF-8");
//url 需要经过UrlSafeBase64.encodeToString() 进行再次编码才能拼接到fops中
fops.append("/"+ UrlSafeBase64.encodeToString(decodeUrl));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
log.info(" urlDecoder fail "+e.getMessage());
}
}
}
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
//构建持久化数据处理对象
OperationManager operationManager = new OperationManager(auth, cfg);
try {
//操作执行之后返回操作id
String persistentId = operationManager.pfop(bucket, key, fops.toString(), persistentPipeline, persistentNotifyUrl, true);
//可以根据该 persistentId 查询任务处理进度
log.info("persistentId :" + persistentId);
OperationStatus operationStatus = operationManager.prefop(persistentId);
//解析 operationStatus 的结果
log.info( "OperationStatus,id:" + operationStatus.id + " desc:" + operationStatus.desc + " code:" + operationStatus.code);
//根据返回的code确认操作是否成功
if(operationStatus.code == 1 ){
return success;
}
} catch (QiniuException e) {
log.info( "QiniuException : " + e.response.toString());
jsonResult.setSuccess(false);
jsonResult.setFailReason("音频拼接出错!");
}
按照上述代码所写,最终结果应该为按照 head+mid+foot 的顺序进行拼接为整一个mp3文件。
查看任务结果
https://api.qiniu.com/status/get/prefop?id=z0.5b6522b238b9f324a55279dc
即在https://api.qiniu.com/status/get/prefop?id=后面追加任务的id即可看到任务结果
例如:
出错:
正确:
如果设置了回调地址,七牛云会在任务完成之后将上述数据发送到回调url中,然后在url进行解析即可。
items中的key即为文件名称,如上所述我的最终结果为:
http://bucket.qiniu.com/KHK2DO-8LYk76XnOBQ-HwDrFlK0=/Frx-V0f3v_06rG7l1rIhZO2LBoGb.mp3
以上,如有问题会继续进行修改。
注解1:官网中音频拼接的字符串应该为 avconcat/<Mode>/format/<Format>/index/<Index> /<encodedUrl0>/<encodedUrl1>/<encodedUrl2>...
其中待<> 的为自定义参数,不到<> 的为固定值。<Mode>接口文档中固定为2,<Format> 需要拼接的类型可谓mp3,mp4等,具体支持的类型可以查看官方文档(https://developer.qiniu.com/dora/kb/1320/avthumb-parameters-formats-format-and-explanation),<index>固定为1即可,<encodedUrl0-2...> 为需要拼接的音视频文件地址(注意为完成路径),用“/”隔开。
{{ cmt.username }}
{{ cmt.content }}
{{ cmt.commentDate | formatDate('YYYY.MM.DD hh:mm') }}