由于项目需求,需要将多个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;
}
网友评论