小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文同时参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金
最近在公司在做视频混剪相关的业务,我也学习了一些相关的知识,这篇文章和大家分享一下获取音频时长的相关工具类
为了代码的规范性,我们首先定义一个音频类型的枚举类,用来表明我们的工具支持哪些音频类型。
import com.mysql.cj.util.StringUtils;
/**
* @author caicai
* @date 2021/8/27 14:08
*/
public enum AudioContentType {
/**
* 非法类型
*/
ILLEGAL("","", 0),
MP3("audio/mpeg","MP3",1),
WAV("audio/wave", "WAV",2);
private String contentType;
private String type;
private int code;
AudioContentType(String contentType, String type, int code) {
this.contentType = contentType;
this.type = type;
this.code = code;
}
public String getContentType() {
return contentType;
}
public int getCode() {
return code;
}
public String getType() {
return type;
}
public static AudioContentType create(String contentType) {
if (StringUtils.isNullOrEmpty(contentType)) {
return ILLEGAL;
}
for (AudioContentType type : values()) {
if (type.contentType.equals(contentType)) {
return type;
}
}
return ILLEGAL;
}
public static AudioContentType create(int code) {
for (AudioContentType type : values()) {
if (type.code == code) {
return type;
}
}
return ILLEGAL;
}
public static AudioContentType create(Integer code) {
return create(code.intValue());
}
}
然后就是音频工具类的编写了
引入依赖
<!-- 获取音频时长 -->
<!-- https://mvnrepository.com/artifact/org/jaudiotagger -->
<dependency>
<groupId>org</groupId>
<artifactId>jaudiotagger</artifactId>
<version>2.0.3</version>
</dependency>
音频工具类
import com.talkingdata.addct.common.enums.AudioContentType;
import lombok.extern.slf4j.Slf4j;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.mp3.MP3AudioHeader;
import org.jaudiotagger.audio.mp3.MP3File;
import org.springframework.web.multipart.MultipartFile;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @author caicai
* @date 2021/8/27 17:36
*/
@Slf4j
public class AudioUtils {
private static final Long TIME_CONVERSION = 1000L;
/**
* 获取音频时长 支持格式:mp3 wav
*/
public static Integer getDuration(File file, AudioContentType contentType) {
switch (contentType) {
case MP3:
return getMp3Duration(file).intValue();
case WAV:
return getWavDuration(file).intValue();
default:
log.error("不支持的音频格式,无法获取音频时长");
return null;
}
}
/**
* 获取语音文件播放时长(毫秒) 支持wav 格式
*
* @param wavFile
* @return
*/
public static Float getWavDuration(File wavFile) {
BufferedInputStream bufferedInputStream = null;
AudioInputStream audioInputStream = null;
try {
bufferedInputStream = new BufferedInputStream(new FileInputStream(wavFile));
audioInputStream = AudioSystem.getAudioInputStream(bufferedInputStream);
AudioFormat format = audioInputStream.getFormat();
long audioFileLength = wavFile.length();
int frameSize = format.getFrameSize();
float frameRate = format.getFrameRate();
float durationInSeconds = (audioFileLength / (frameSize * frameRate));
return durationInSeconds * TIME_CONVERSION;
} catch (Exception e) {
log.error("音频时长解析错误", e);
return 0f;
} finally {
try {
bufferedInputStream.close();
audioInputStream.close();
} catch (IOException e) {
log.error("字节流关闭错误", e);
}
}
}
/**
* 获取mp3语音文件播放时长(毫秒)
*
* @param mp3File
* @return
*/
public static Float getMp3Duration(File mp3File) {
try {
MP3File f = (MP3File) AudioFileIO.read(mp3File);
MP3AudioHeader audioHeader = (MP3AudioHeader) f.getAudioHeader();
return Float.parseFloat(audioHeader.getPreciseTrackLength() + "") * TIME_CONVERSION;
} catch (Exception e) {
log.error("音频时长解析错误", e);
return 0f;
}
}
/**
* 获取音频名称
*/
public static String getAudioName(MultipartFile audio) {
return audio.getOriginalFilename().split("\\.")[0];
}
}
注意:
getWavDuration(File wavFile)方法中AudioSystem.getAudioInputStream(bufferedInputStream);需要用缓冲流。我之前直接用的file,但是这样导致文件一直被占用,无法进行别的操作。
因为使用的是springboot,文件接收是用的MultipartFile,而我们的工具类传入的参数是File类型,所以我们还需要一个MultipartFile转File的工具类
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author wangpeixu
* @date 2021/8/31 14:05
*/
@Slf4j
public class MultipartFileToFileUtils {
/**
* MultipartFile 转 File
*
* @param file
* @throws Exception
*/
public static File multipartFileToFile(MultipartFile file) throws Exception {
File toFile = null;
if (file.equals("") || file.getSize() <= 0) {
file = null;
} else {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(System.currentTimeMillis()+"_"+file.getOriginalFilename());
inputStreamToFile(ins, toFile);
}
return toFile;
}
//获取流文件
private static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除本地临时文件
* @param file
*/
public static void delteTempFile(File file) {
if (file != null) {
File del = new File(file.toURI());
boolean result = false;
int tryCount = 0;
while(!result && tryCount++ <10)
{
log.info("try to delete file "+ del.getName() +" cnt:"+tryCount);
result = del.delete();
}
}
}
}