概述
接触微信公众号开发的小伙伴一定对AMR这种音频格式不陌生,在微信公众号发送的语音,基本是这种格式,接收到后台后,还需要手动转换为MP3,这里探讨一下几种实现方式。
使用七牛提供的API
如果你使用七牛作为系统的云储存,那么音频转码将非常简单,先来看几个文档:
1)普通音视频转码(avthumb)
https://developer.qiniu.com/dora/api/1248/audio-and-video-transcoding-avthumb
- 持久化处理结果消息回调数据格式
https://developer.qiniu.com/dora/api/1294/persistent-processing-status-query-prefop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
public class QiniuTest {
private final static String accessKey = "xxxx";
private final static String secretKey = "xxx-xxxxxx";
private final static String bucketName = "myfilestore1";
public static void main(String[] args) throws QiniuException {
Auth auth = Auth.create(accessKey, secretKey);
String uploadToken = auth.uploadToken(bucketName);
Configuration configuration = new Configuration();
UploadManager uploadManager = new UploadManager(configuration);
// 上传amr文件
final String fileKey = "123";
Response response = uploadManager.put(new File("/Users/wuwenze/Downloads/1.amr"), fileKey, uploadToken);
System.out.println(response);
// 将mp3文件转码为amr
OperationManager operationManager = new OperationManager(auth, configuration);
StringMap params = new StringMap()//
.putNotEmpty("notifyURL", "https://baidu.com")// 回调通知
.putWhen("force", 1, true)//
.putNotEmpty("pipeline", "test_a");// 使用私有多媒体队列(https://portal.qiniu.com/dora/mps/test_a/index)
String fops = "avthumb/mp3/ab/64k|saveas/" + UrlSafeBase64.encodeToString(bucketName + ":" + fileKey);
// 持久化结果ID
String persistentId = operationManager.pfop(bucketName, fileKey, fops, params);
System.out.println(persistentId);
// 上传mp3文件
final String fileKey1 = "456";
Response response1 = uploadManager.put(new File("/Users/wuwenze/Downloads/2.mp3"), fileKey1, uploadToken);
System.out.println(response1);
// 将mp3文件转码为amr
StringMap params1 = new StringMap()//
.putNotEmpty("notifyURL", "https://baidu.com")// 回调通知
.putWhen("force", 1, true)//
.putNotEmpty("pipeline", "test_a");// 使用私有多媒体队列(https://portal.qiniu.com/dora/mps/test_a/index)
String fops1 = "avthumb/amr/ab/64k|saveas/" + UrlSafeBase64.encodeToString(bucketName + ":" + fileKey1);
// 持久化结果ID
String persistentId1 = operationManager.pfop(bucketName, fileKey1, fops1, params1);
System.out.println(persistentId1);
}
}
|
上面的代码演示了使用七牛上传文件->异步转码的过程,转码指令发出后,如果配置了notifyURL,那么七牛转码成功后,会主动推送结果过来,也可以用持久化结果ID,主动去查询转码的结果。
使用FFMPEG
如果没有使用云储存,也可以在自己的服务器上安装ffmpeg,来实现转码。
官网地址:http://ffmpeg.org/ 自行按照操作系统安装之。
MP3转换AMR
1
|
ffmpeg -i 1.mp3 -ac 1 -ar 8000 1.amr
|
AMR转换MP3
基于以上固定格式的命令,咱们可以封装一个简单的工具类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
public class FFMpegUtils {
private static final Logger log = Slf4j.getLogger();
public static InputStream amrToMp3(InputStream source) {
return doConvert(source, ".amr", ".mp3");
}
public static InputStream mp3ToAmr(InputStream source) {
return doConvert(source, ".mp3", ".amr");
}
private static InputStream doConvert(InputStream source, String sourceSuffix, String targetSuffix) {
final String tempDir = System.getProperty("java.io.tmpdir") + "/ffmpeg_temp/";
final String tempFileName = UuidUtil.randomUuid();
final File sourceFile = new File(tempDir, tempFileName + sourceSuffix);
final File targetFile = new File(tempDir, tempFileName + targetSuffix);
String command = null;
try {
if (!sourceFile.exists()) {
File parentFolder = sourceFile.getParentFile();
if (!parentFolder.exists()) {
parentFolder.mkdirs();
}
sourceFile.createNewFile();
}
// 将 source 转换成文件
IoUtil.write(source, sourceFile);
// MP3转换AMR: ffmpeg -i 1.mp3 -ac 1 -ar 8000 1.amr
if (StringUtil.equals(sourceSuffix, ".mp3") && StringUtil.equals(targetSuffix, ".amr")) {
command = String.format("ffmpeg -i %s -ac 1 -ar 8000 %s", //
FileUtil.getCanonicalPath(sourceFile), FileUtil.getCanonicalPath(targetFile));
}
// AMR转换MP3: ffmpeg -i 1.amr 1.mp3
else if (StringUtil.equals(sourceSuffix, ".amr") && StringUtil.equals(targetSuffix, ".mp3")) {
command = String.format("ffmpeg -i %s %s", //
FileUtil.getCanonicalPath(sourceFile), FileUtil.getCanonicalPath(targetFile));
} else {
throw new RuntimeException("#0325 FFMpegUtils.doConvert() error, 不支持的文件格式,sourceSuffix=" + sourceSuffix + ",targetSuffix=" + targetSuffix);
}
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(command);
runtime.addShutdownHook(new ProcessKiller(process));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
while ((line = BufferedReaderUtil.readLine(bufferedReader)) != null) {
log.info("#0325 FFMpegUtils.doConvert(): " + line);
}
} catch (Throwable e) {
throw new RuntimeException("#0325 FFMpegUtils.doConvert() error, command=" + command, e);
}
// 返回转换的 targetFile
ByteArrayOutputStream targetStream = new ByteArrayOutputStream();
IoUtil.write(IoUtil.fileInputStream(targetFile), targetStream);
return new ByteArrayInputStream(targetStream.toByteArray());
}
public static void main(String[] args) throws IOException {
// test mp3 -> amr
File mp3File = new File("/Users/wuwenze/Downloads/1.mp3");
InputStream amrStream = FFMpegUtils.mp3ToAmr(IoUtil.fileInputStream(mp3File));
File amrFile = new File("/Users/wuwenze/Downloads/1-mp3-amr-result.amr");
if (amrFile.createNewFile()) {
IoUtil.write(amrStream, amrFile);
}
// test amr -> mp3
InputStream mp3Stream = FFMpegUtils.amrToMp3(IoUtil.fileInputStream(amrFile));
File newMp3File = new File("/Users/wuwenze/Downloads/1-amr-mp3-result.mp3");
if (newMp3File.createNewFile()) {
IoUtil.write(mp3Stream, newMp3File);
}
}
}
|
在自己的服务器上使用ffmpeg转码很简单,但是性能损耗也很大,如果能使用云存储,可能是更好的选择。
评论