最近在公司在做视频混剪相关的业务,我也学习了一些相关的知识,这篇文章和大家分享一下获取音频时长的相关工具类
基于jaudiotagger的音频时长解析
为了代码的规范性,我们首先定义一个音频类型的枚举类,用来表明我们的工具支持哪些音频类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| import com.mysql.cj.util.StringUtils;
public enum AudioContentType {
ILLEGAL("","", 0), MP3("audio/mp3","MP3",1), WAV("audio/wav", "WAV",2); MP3_OTHER("audio/mpeg","MP3",3), WAV_OTHER("audio/wave", "WAV",4);
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()); } }
|
然后就是音频工具类的编写了
引入依赖
1 2 3 4 5 6 7
|
<dependency> <groupId>org</groupId> <artifactId>jaudiotagger</artifactId> <version>2.0.3</version> </dependency>
|
音频工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| 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;
@Slf4j public class AudioUtils {
private static final Long TIME_CONVERSION = 1000L;
public static Integer getDuration(File file, AudioContentType contentType) { switch (contentType) { case MP3: case MP3_OTHER: return getMp3Duration(file).intValue(); case WAV: case WAV_OTHER: return getWavDuration(file).intValue(); default: log.error("不支持的音频格式,无法获取音频时长"); return null; } }
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); } }
}
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,但是这样导致文件一直被占用,无法进行别的操作。
基于ffmpeg的音频时长解析
ffmpeg
是一款十分强大的音视频解析工具,巴拉巴拉……
🚧我们进入正题:
引入依赖
1 2 3 4 5
| <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>ffmpeg-platform</artifactId> <version>4.0.2-1.4.3</version> </dependency>
|
编写工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Slf4j public class AudioUtils {
private static final Long TIME_CONVERSION = 1000L;
public static Long audioDuration(File file) throws Exception { Long times = 0L; FFmpegFrameGrabber ff = null; try { ff = new FFmpegFrameGrabber(file); ff.start(); times = ff.getLengthInTime() / TIME_CONVERSION; } catch (Exception e) { log.error("音频时长解析错误", e); e.printStackTrace(); } finally { if (ff != null) { ff.stop(); } } return times; } }
|
因为ffmpeg工具十分强大(博主没见过什么世面),上面这个工具类不仅能解析音频时长,还可以解析视频的时长。由于博主电脑里只有.mp3
、.wav
格式的音频和.mp4
格式的视频所以只测试这几种格式的文件,时长解析是没有任何问题的。可以大胆上车!!
因为使用的是springboot,文件接收是用的MultipartFile,而我们的工具类传入的参数是File类型,所以我们还需要一个MultipartFile转File的工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| 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;
@Slf4j public class MultipartFileToFileUtils {
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(); } }
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(); } } } }
|
总结
上述这两款音频时长解析工具,博主更青睐后者(ffmpeg),真真正正的短小而精悍。代码少,效果好,谁会不爱呢⭐