项目中 处理IM 录音模块,因为IOS 录音本身限制较多,只能单边录音,所以考虑了java 合成,由双端分别上传,因为坑了很久,所以希望对大家也有帮助
执行命令:
1628 ls
1629 mkdir ffmpeg
1630 cd ffmpeg/
1631 ls
1632 wget https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz
1633 ls
1634 xz -d ffmpeg-git-amd64-static.tar.xz
1635 ls
1636 tar -xvf ffmpeg-git-amd64-static.tar
1637 ls
1638 cd ffmpeg-git-20200909-amd64-static/
1639 ls
1640 ./ffmpeg
1641 ls
1642 pwd
1643 cd /usr/bin
1644 ln -s /data/im-boss/ffmpeg/ffmpeg-git-20200909-amd64-static/ffmpeg ffmpeg
1645 ln -s /data/im-boss/ffmpeg/ffmpeg-git-20200909-amd64-static/ffprobe ffprobe
1646 ffmpeg
执行代码工具类
public class AudioUtil {
private static Logger LOG = LoggerFactory.getLogger(AudioUtil.class);
private static int doWaitFor(Process process) {
int exitValue = -1; // returned to caller when p is finished
InputStream error = process.getErrorStream();
InputStream is = process.getInputStream();
byte[] b = new byte[1024];
int readbytes = -1;
try {
while ((readbytes = error.read(b)) != -1) {
LOG.info("标准错误输出信息:" + new String(b, 0, readbytes));
}
while ((readbytes = is.read(b)) != -1) {
LOG.info("标准输出信息:" + new String(b, 0, readbytes));
}
} catch (IOException e) {
LOG.error("等待进程结束出现错误!");
e.printStackTrace();
} finally {
try {
error.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return exitValue;
}
/**
* 音频混合
*
* /Users/mufeng/Downloads/1.mp3
*/
public static void mixAudio(String remoteTarget1, String remoteTarget2, String outFilePath) {
List<String> _commands = new ArrayList<>();
_commands.add("ffmpeg");
_commands.add("-i");
_commands.add(remoteTarget1);
_commands.add("-i");
_commands.add(remoteTarget2);
_commands.add("-acodec");
_commands.add("libmp3lame");
_commands.add("-ab");
_commands.add("96000");
_commands.add("-ac");
_commands.add("1");
_commands.add("-ar");
_commands.add("22050");
_commands.add("-filter_complex");
_commands.add("amix=inputs=2:duration=longest:dropout_transition=2");
_commands.add("-strict");
_commands.add("-2");
_commands.add(outFilePath);
String[] commands = new String[_commands.size()];
for (int i = 0; i < _commands.size(); i++) {
commands[i] = _commands.get(i);
}
try {
ProcessBuilder builder = new ProcessBuilder(commands);
builder.command(commands);
Process p = builder.start();
doWaitFor(p);
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void main(String args[]){
// String mp3file1="/Users/mufeng/Downloads/1.mp3";
// String mp3file2="/Users/mufeng/Downloads/2.mp3";
String mp3file3="/Users/mufeng/Downloads/3.mp3";
String mp3file1="http://8.222.201.38:8888/amr2mp3?path=http://8.222.201.38:80/fs/2/2020/09/29/19/-cAs-szz-2-1601379918-5xyqQnNy_img1601379916335.amr";
String mp3file2="http://8.222.201.38:8888/amr2mp3?path=http://8.222.201.38:80/fs/2/2020/09/29/19/5m7959__-2-1601379917-ENTLvCfv_img1601379915613.amr";
mixAudio(mp3file1,mp3file2,mp3file3);
}
public static void amr2mp3(String sourceUrl, File target) throws MalformedURLException, EncoderException {
//Audio Attributes
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setBitRate(128000);
audio.setChannels(2);
audio.setSamplingRate(44100);
//Encoding attributes
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp3");
attrs.setAudioAttributes(audio);
//Encode
Encoder encoder = new Encoder();
encoder.encode(new MultimediaObject(new URL(sourceUrl)), target, attrs);
LOG.info("amr2mp3 encoder success:sourceUrl:{}", sourceUrl);
}
}
合成转换的访问,访问格式两种:‘
单一的:
http://localhost:9001/api/audio/amr2mp3?path=http://143.129.79.195/group1/M00/00/0C/rBAyIWBUjEeAJ4i1AAVkOq3KTig669.wav
合成的:
http://localhost:9001/api/audio/amr2mp3?complexMp3=1&path=http://143.129.79.195/group1/M00/00/0C/rBAyIWBUjEeAJ4i1AAVkOq3KTig669.wav,path=http://143.129.79.195/group1/M00/00/0C/rBAyIWBUjEeAJ4i1AAVkOq3KTig669.wav
@Slf4j
@RequestMapping("/audio")
@RestController
public class AudioController {
@Value("${zz.audio.cache.dir}")
String cacheDirPath;
private File cacheDir;
@PostConstruct
public void init() {
cacheDir = new File(cacheDirPath);
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
}
@GetMapping("/amr2mp3")
public CompletableFuture<ResponseEntity<InputStreamResource>> amr2mp3(@RequestParam("path") String amrUrl,@RequestParam(value = "complexMp3",required = false) Integer complex) throws FileNotFoundException {
log.info("amr2mp3 amrUrl:{}"+amrUrl);
MediaType mediaType = new MediaType("audio", "mp3");
String fname;
final List<String> urlList=new ArrayList<>();
if(complex!=null&&complex.equals(1)&&amrUrl.contains(",")){
urlList.addAll(Arrays.asList(amrUrl.split(",")));
fname = urlList.get(0).substring(urlList.get(0).lastIndexOf('/') + 1);
fname = fname+"-"+urlList.get(1).substring(urlList.get(1).lastIndexOf('/') + 1) + ".mp3";
}else {
fname = amrUrl.substring(amrUrl.lastIndexOf('/') + 1) + ".mp3";
}
final String finalFname=fname;
File mp3File = new File(cacheDir, finalFname);
if (mp3File.exists()) {
InputStreamResource resource = new InputStreamResource(new FileInputStream(mp3File));
return CompletableFuture.completedFuture(ResponseEntity.ok()
// .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + mp3File.getName())
.contentType(mediaType)
.contentLength(mp3File.length())
.body(resource));
}
return CompletableFuture.supplyAsync(new Supplier<ResponseEntity<InputStreamResource>>() {
/**
* Gets a result.
*
* @return a result
*/
@Override
public ResponseEntity<InputStreamResource> get() {
try {
InputStreamResource resource;
if(complex!=null&&complex.equals(1)&&amrUrl.contains(",")){
AudioUtil.mixAudio(urlList.get(0),urlList.get(1),cacheDirPath + finalFname);
File file = new File(cacheDirPath + finalFname);
resource= new InputStreamResource(new FileInputStream(file));
}else {
AudioUtil.amr2mp3(amrUrl, mp3File);
resource= new InputStreamResource(new FileInputStream(mp3File));
}
return ResponseEntity.ok()
// .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + mp3File.getName())
.contentType(mediaType)
.contentLength(mp3File.length())
.body(resource);
} catch (MalformedURLException e) {
log.info("amr2mp3 MalformedURLException amrUrl:{}", amrUrl, e);
} catch (EncoderException e) {
log.info("amr2mp3 EncoderException amrUrl:{}", amrUrl, e);
} catch (FileNotFoundException e) {
log.info("amr2mp3 FileNotFoundException amrUrl:{}", amrUrl, e);
}
return ResponseEntity.status(404).build();
}
});
}
}