使用LAME,把PCM编码格式的录音文件转换为MP3格式的文件
程序员文章站
2022-06-21 15:06:37
...
最近,项目需要把PCM编码的录音文件转为MP3格式。
通过学习,发现可以使用de.sciss.jump3r项目:
<dependency>
<groupId>de.sciss</groupId>
<artifactId>jump3r</artifactId>
<version>1.0.5</version>
</dependency>
测试代码:
public class LameTest {
private static Logger LOG = LoggerFactory.getLogger(LameTest.class);
@Test
public void encode() {
LameEncoder encoder = null;
try {
byte[] pcm = Files.readAllBytes(Paths.get("recordFiles/", "20190415_09_0016.wav"));
int r = ThreadLocalRandom.current().nextInt(1000);
Path file = Files.createFile(Paths.get("recordFiles/", "file_" + r + ".mp3"));
AudioFormat format = fileFormat(pcm);
encoder = new LameEncoder(format);
byte[] buffer = new byte[encoder.getPCMBufferSize()];
int bytesToTransfer = Math.min(buffer.length, pcm.length);
int bytesWritten;
int currentPcmPosition = 0;
while (0 < (bytesWritten = encoder.encodeBuffer(pcm, currentPcmPosition, bytesToTransfer, buffer))) {
currentPcmPosition += bytesToTransfer;
bytesToTransfer = Math.min(buffer.length, pcm.length - currentPcmPosition);
Files.write(file, copyOfRange(buffer, 0, bytesWritten), StandardOpenOption.APPEND);
}
LOG.info("new file is {}.", file.getFileName());
} catch (IOException ex) {
LOG.warn("encode error: {}.", ex);
} finally {
encoder.close();
}
}
}
wav文件头处理类:
public class WavFileUtil {
private static Logger LOG = LoggerFactory.getLogger(WavFileUtil.class);
private static final int HEAD_LENGTH = 12;
private static final int FORMAT_LENGTH = 24;
private static boolean isWav(byte[] head) {
return ("RIFF".equals(new String(head, 0, 4, ISO_8859_1)) &&
"WAVE".equals(new String(head, 8, 4, ISO_8859_1)));
}
private static void fileTooSmall(byte[] file) {
if (file.length < HEAD_LENGTH + FORMAT_LENGTH) {
LOG.warn("file is too small, size if {}.", file.length);
throw new IvcFileException();
}
}
public static int fileSize(byte[] file) {
fileTooSmall(file);
byte[] head = copyOfRange(file, 0, HEAD_LENGTH);
if (isWav(head)) {
return ByteBuffer.wrap(copyOfRange(head, 4, 8))
.order(LITTLE_ENDIAN)
.getInt() + 8;
} else {
LOG.warn("file format error: expected {}, actual {}.",
"[82, 73, 70, 70, *, *, *, *, 87, 65, 86, 69]",
head);
throw new IvcFileException();
}
}
public static AudioFormat fileFormat(byte[] file) {
fileTooSmall(file);
byte[] head = copyOfRange(file, 0, HEAD_LENGTH);
if (isWav(head)) {
byte[] format = copyOfRange(file, 12, HEAD_LENGTH + FORMAT_LENGTH);
String chuckID = new String(format, 0, 4, ISO_8859_1);
int chunkSize = ByteBuffer.wrap(copyOfRange(format, 4, 8))
.order(LITTLE_ENDIAN).getInt();
int audioFmt = ByteBuffer.wrap(copyOfRange(format, 8, 10))
.order(LITTLE_ENDIAN).getShort();
int channels = ByteBuffer.wrap(copyOfRange(format, 10, 12))
.order(LITTLE_ENDIAN).getShort();
int sampleRate = ByteBuffer.wrap(copyOfRange(format, 12, 16))
.order(LITTLE_ENDIAN).getInt();
int byteRate = ByteBuffer.wrap(copyOfRange(format, 16, 20))
.order(LITTLE_ENDIAN).getInt();
int frameSize = ByteBuffer.wrap(copyOfRange(format, 20, 22))
.order(LITTLE_ENDIAN).getShort();
int sampleSizeInBits = ByteBuffer.wrap(copyOfRange(format, 22, 24))
.order(LITTLE_ENDIAN).getShort();
//return new AudioFormat(PCM_SIGNED, sampleRate,
// sampleSizeInBits, channels, frameSize, sampleRate, false);
return new AudioFormat(sampleRate, sampleSizeInBits, channels,
false, false);
} else {
LOG.warn("file is not a wav.");
throw new IvcFileException();
}
}
}
测试通过,效果还不错。
下一篇: JS获取video原始宽高