java合成简单音频处理

项目中 处理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();
            }
        });
    }





}
上一篇:通过一个简单的例子,了解 Cypress 的运行原理


下一篇:[Bash] Chain Commands with Pipes and Redirect Output in Bash