音频时长解析工具

1,277 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文同时参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金

最近在公司在做视频混剪相关的业务,我也学习了一些相关的知识,这篇文章和大家分享一下获取音频时长的相关工具类

为了代码的规范性,我们首先定义一个音频类型的枚举类,用来表明我们的工具支持哪些音频类型。

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();
            }
        }
    }
}