Java分析音频文件声音大小

2020-08-23 00:00:00 大小 声音 音频文件

客户虐我千百遍,我待客户如初恋。
年前接到了一个奇怪的需求,需求是要采集用户上传的音频文件,并分析出此音频的声音分贝大小,这边记录一下

1.首先在pom.xml中导入jar

<dependency>
    <groupId>com.github.dadiyang</groupId>
    <artifactId>jave</artifactId>
    <version>1.0.4</version>
</dependency>

注意这里使用了ffmpeg,具体的安装步骤自行百度

2.调用AudioUtils.amrToWav转换音频格式

使用MediaId从微信获取上传的音频文件并使用ffmpeg转换格式为wav格式:

    try { 
        InputStream wxAudio = WxApi.getWxAudio(mediaId, wxToken);
        if (wxAudio != null) { 
            String fileName = System.currentTimeMillis() + "_" + new Random().nextInt(1000) + ".arm";
            File file = new File(path + fileName);
            FileUtils.copyInputStreamToFile(wxAudio, file);
            File file1 = new File(path + fileName.split("\\.")[0] + ".wav");
            AudioUtils.amrToWav(file, file1);
            //删除文件
            file.delete();
            String db = FfmpegUtil.convert(file1);
            return Result.ok(db);
        }
    } catch (IOException e) { 
        log.error("voice exception:", e);
    }

ps:其中有个问题,具体问题我忘记了,好像是ffmpeg执行文件的问题,翻阅了一下第一步中导入jar包的源码发现其中有ffmpeg的执行文件
《Java分析音频文件声音大小》
这里不做描述,间隔时间太久远了,只提供一下类似问题的解决思路

3.研究ffmpeg命令

先贴命令

/usr/tomcat/tomcat8.5/temp/jave-1/ffmpeg -i /opt/voice/1576573683569_278.wav -filter_complex volumedetect -c:v copy -f null /dev/null

大概解释一下

  • /usr/tomcat/tomcat8.5/temp/jave-1/ffmpeg 表示你的ffmpeg执行文件路径

  • /opt/voice/1576573683569_278.wav 表示你的要分析音频文件的路径

后面的都是固定的,我们来执行一下得到如下结果

ffmpeg version 4.0.1-static https://johnvansickle.com/ffmpeg/  Copyright (c) 2000-2018 the FFmpeg developers
  built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516
  configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc-6 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg
  libavutil      56. 14.100 / 56. 14.100
  libavcodec     58. 18.100 / 58. 18.100
  libavformat    58. 12.100 / 58. 12.100
  libavdevice    58.  3.100 / 58.  3.100
  libavfilter     7. 16.100 /  7. 16.100
  libswscale      5.  1.100 /  5.  1.100
  libswresample   3.  1.100 /  3.  1.100
  libpostproc    55.  1.100 / 55.  1.100
Input #0, wav, from '/opt/voice/1576573683569_278.wav':
  Metadata:
    encoder         : Lavf58.12.100
  Duration: 00:00:02.80, bitrate: 8 kb/s
    Stream #0:0: Audio: mp3 (U[0][0][0] / 0x0055), 8000 Hz, mono, fltp, 8 kb/s
[Parsed_volumedetect_0 @ 0x6adcc40] n_samples: 0
Stream mapping:
  Stream #0:0 (mp3float) -> volumedetect
  volumedetect -> Stream #0:0 (pcm_s16le)
Press [q] to stop, [?] for help
Output #0, null, to '/dev/null':
  Metadata:
    encoder         : Lavf58.12.100
    Stream #0:0: Audio: pcm_s16le, 8000 Hz, mono, s16, 128 kb/s
    Metadata:
      encoder         : Lavc58.18.100 pcm_s16le
size=N/A time=00:00:02.80 bitrate=N/A speed=2.09e+03x    
video:0kB audio:44kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
[Parsed_volumedetect_0 @ 0x6af7a40] n_samples: 22464
[Parsed_volumedetect_0 @ 0x6af7a40] mean_volume: -39.6 dB
[Parsed_volumedetect_0 @ 0x6af7a40] max_volume: -22.6 dB
[Parsed_volumedetect_0 @ 0x6af7a40] histogram_22db: 2
[Parsed_volumedetect_0 @ 0x6af7a40] histogram_23db: 2
[Parsed_volumedetect_0 @ 0x6af7a40] histogram_24db: 9
[Parsed_volumedetect_0 @ 0x6af7a40] histogram_25db: 27

这么多东西,其实其中只有2个值是我们需要关注的
max_volume为最大分贝
mean_volume为平均分贝
不要问我为什么是负数,我也不知道-_-||,如果有知道的小伙伴可以留言指导指导一下

4.Java代码执行ffmpeg命令

    private static final String FFMPEG_PATH = System.getProperty("catalina.home") + "/temp/jave-1/ffmpeg";

    /** * 获取wav音量分贝 * * @param file * @return * @throws IOException */
    public static String convert(File file) throws IOException { 
        List<String> command = new ArrayList<String>();
        command.add(FFMPEG_PATH);
        command.add("-i");
        command.add(file.getAbsolutePath());
        command.add("-filter_complex");
        command.add("volumedetect");
        command.add("-c:v");
        command.add("copy");
        command.add("-f");
        command.add("null");
        command.add("/dev/null");
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.start();
        InputStream errorStream = process.getErrorStream();
        InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(inputStreamReader);
        String db = "";
        while ((db = br.readLine()) != null) { 
            if (db.contains("max_volume")) { 
                db = db.split(": ")[1];
                db = db.split(" ")[0];
                break;
            }
        }
        br.close();
        inputStreamReader.close();
        errorStream.close();
        return db;
    }

其实很简单相当于通过java调用linux命令来获取ffmpeg返回的结果。

PS:ffmpeg很强大,如果遇到类似的问题都是可以采用这种方式来取到我们需要的信息

    原文作者:TsukasaHwan
    原文地址: https://blog.csdn.net/weixin_49172831/article/details/108751304
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章