Android 中多个Mp3音频文件合成

2020-05-28  本文已影响0人  chuanggggg

由于项目需求,需要将多个Mp3文件合并成一个Mp3文件,老项目中使用 FileChannel.transferFrom方法合并,直接导致生成的音频文件无法正确获取进度和时长,调研后选择使用MediaExtractor方法,参考https://juejin.im/post/5da80562f265da5bb5584a82

  /**
     *  合并音频文件
     *   @param videoPath  音频片段路径集合
     *   @param resultPath  生成文件路径
     *   @param isAdd  追加or覆盖
     *
     */
    public static void mergeMP3Files(List<String> videoPath,String resultPath,boolean isAdd){
        File file = new File(resultPath);
        if (file.exists()) {
            file.delete();
        }
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try {
            BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(resultPath, isAdd), 1024 * 200);
            for (int i = 0; i < videoPath.size(); i++) {
                writeVideoFile(videoPath.get(i),outputStream);
            }
            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     *   @param videoPath  音频片段路径
     *   @param outputStream 音频流
     */
    public static void writeVideoFile(String videoPath, BufferedOutputStream outputStream){
        try {
            MediaExtractor extractor = new MediaExtractor();
            extractor.setDataSource(videoPath);
            int videoTrackIndex = getAudioTrack(extractor);
            if (videoTrackIndex < 0) {
                return ;
            }
            //选择音频轨道
            extractor.selectTrack(videoTrackIndex);
            MediaFormat mediaFormat = extractor.getTrackFormat(videoTrackIndex);
            //获取音频时间
            float time = mediaFormat.getLong(MediaFormat.KEY_DURATION) / 1000;//返回的是微秒,转换成毫秒
            //合并音频
            ByteBuffer buffer = ByteBuffer.allocate(1024 * 200);
            while (true) {
                int sampleSize = extractor.readSampleData(buffer, 0);
                if (sampleSize <= 0) {
                    break;
                }
                byte[] buf = new byte[sampleSize];
                buffer.get(buf, 0, sampleSize);
                //写入文件
                outputStream.write(buf);
                //音轨数据往前读
                extractor.advance();
            }
            extractor.release();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取音频数据轨道
     */
    private static  int getAudioTrack(MediaExtractor extractor) {
        for (int i = 0; i < extractor.getTrackCount(); i++) {
            MediaFormat format = extractor.getTrackFormat(i);
            String mime = format.getString(MediaFormat.KEY_MIME);
            if (mime.startsWith("audio")) {//audio为音频,video为视频
                return i;
            }
        }
        return -1;
    }

------------------------------------------------------------------------------------------分割线-------------------------------------------------------------------------------------------------------------------------
本来以为合成的功能已经实现,项目本地播放并没有发现问题,但是把合成的文件放到其他播放器中播放时,问题出现了。文件播放到最后几秒时,音频总时长会莫名的自增,以及合成的文件总时长与多个音频片段相加的时长有几秒偏差。应该是音频文件在流写入时出了问题,有了解的大牛帮忙分析分析。最后放弃这个合并方案,选择了FFmpeg合并,解决了音频合成问题。合并命令如下:

    /**
     *   @param mp3ListFile  多个Mp3音频片段的路径拼接字符串  拼接规则 a.mp3|b.mp3|c.mp3
     *   @param resultFile  生成文件路径
     */
    public  String mergeMp3Cmd(String mp3ListFile,String resultFile){
        String cmd = "ffmpeg -i concat:%s -acodec copy %s";
        cmd = String.format(cmd, mp3ListFile,resultFile);
        return cmd;
    }
上一篇下一篇

猜你喜欢

热点阅读