使用jave(ffmpeg)将.amr音频转码成mp3

微信上的语音文件拿下来都是amr格式的,好像不分安卓和苹果。

ffmpeg这个工具可以实现音频、视频的格式转换。

java这里,有个现成的包jave,groupId是ws.schild

在maven库里可以看到ws.schild其下有好几个包

jave-core
jave-nativebin-win32
jave-nativebin-win64
jave-nativebin-linux32
jave-nativebin-linux64
jave-nativebin-osx64

jave-all-deps 是最完整的,它的pom.xml引用了所有版本的文件

看名字就能看出,jave-core是核心包,其它几个是windows、linux、maxosx系统下的本地文件

我用的是2.7.3版本,linux下的

<dependency>
    <groupId>ws.schild</groupId>
    <artifactId>jave-core</artifactId>
    <version>2.7.3</version>
</dependency>

<dependency>
    <groupId>ws.schild</groupId>
    <artifactId>jave-nativebin-linux64</artifactId>
    <version>2.7.3</version>
</dependency>

其实nativebin里面就是一个类似ffmpeg.exe的文件

程序在运行时拼接参数,再调用对应的ffmpeg去执行

 比如 Encoder的encode方法,其中有一段非常朴素的if/else判断,addArgument方法就是向一个list里追加参数

            String codec = videoAttributes.getCodec();
            if (codec != null)
            {
                ffmpeg.addArgument("-vcodec");
                ffmpeg.addArgument(codec);
            }
            String tag = videoAttributes.getTag();
            if (tag != null)
            {
                ffmpeg.addArgument("-vtag");
                ffmpeg.addArgument(tag);
            }
            Integer bitRate = videoAttributes.getBitRate();
            if (bitRate != null)
            {
                ffmpeg.addArgument("-vb");
                ffmpeg.addArgument(String.valueOf(bitRate.intValue()));
            }
            Integer frameRate = videoAttributes.getFrameRate();
            if (frameRate != null)
            {
                ffmpeg.addArgument("-r");
                ffmpeg.addArgument(String.valueOf(frameRate.intValue()));
            }
            VideoSize size = videoAttributes.getSize();
            if (size != null)
            {
                ffmpeg.addArgument("-s");
                ffmpeg.addArgument(String.valueOf(size.getWidth()) + "x"
                        + String.valueOf(size.getHeight()));
            }

            if (videoAttributes.isFaststart())
            {
                ffmpeg.addArgument("-movflags");
                ffmpeg.addArgument("faststart");
            }

            if (videoAttributes.getX264Profile() != null)
            {
                ffmpeg.addArgument("-profile:v");
                ffmpeg.addArgument(videoAttributes.getX264Profile().getModeName());
            }

            if (videoAttributes.getVideoFilters().size() > 0)
            {
                for (VideoFilter videoFilter : videoAttributes.getVideoFilters())
                {
                    ffmpeg.addArgument("-vf");
                    ffmpeg.addArgument(videoFilter.getExpression());
                }
            }

            Integer quality = videoAttributes.getQuality();
            if (quality != null)
            {
                ffmpeg.addArgument("-qscale:v");
                ffmpeg.addArgument(String.valueOf(quality.intValue()));
            }

打断点可以看到,最后ffmpeg.execute()执行的时候程序用list拼成一个数组,用Runtime去执行

        int argsSize = args.size();
        String[] cmd = new String[argsSize + 2];
        cmd[0] = ffmpegExecutablePath;
        for (int i = 0; i < argsSize; i++)
        {
            cmd[i + 1] = args.get(i);
        }
        cmd[argsSize + 1] = "-hide_banner";  // Don't show banner
        if (LOG.isDebugEnabled())
        {
            StringBuilder sb = new StringBuilder();
            for (String c : cmd)
            {
                sb.append(c);
                sb.append(' ');
            }
            LOG.debug("About to execute {}", sb.toString());
        }
        Runtime runtime = Runtime.getRuntime();
        ffmpeg = runtime.exec(cmd);
        if (destroyOnRuntimeShutdown)
        {
            ffmpegKiller = new ProcessKiller(ffmpeg);
            runtime.addShutdownHook(ffmpegKiller);
        }
        if (openIOStreams)
        {
            inputStream = ffmpeg.getInputStream();
            outputStream = ffmpeg.getOutputStream();
            errorStream = ffmpeg.getErrorStream();
        }

大体执行原理是这样。

因为是用java拼参数去调用一个执行文件的方式,所以我没办法用输入输出流做入参。转换代码是用指定源文件和目标文件的字符串路径的方式告诉程序要操作的文件是哪一个。所以,在生产里我用的是先创建临时文件,格式转换后再在finanlly里用Files.deleteIfExists删除的方式。

代码如下

    public void putFile(ChatVoice chat) throws Exception {
        
        Path source = null;
        File target = null;
        try {
            source = Files.createTempFile(chat.getMsgid(), ".amr");
            target = File.createTempFile(chat.getMsgid(), ".mp3");
            Files.write(source, bs);
            
            amrToMp3(source.toFile(), target);

            /* target的其它处理逻辑 */
            //......

        }finally {
            Files.deleteIfExists(source);
            Files.deleteIfExists(target.toPath());
        }
    }

    public void amrToMp3(File source, File target) throws EncoderException   {
        
        //Audio Attributes
        AudioAttributes audio = new AudioAttributes();
        audio.setCodec("libmp3lame");   //lame是一个mp3编码库

//        audio.setBitRate(128000);   
//        audio.setChannels(2);
//        audio.setSamplingRate(44100);

        EncodingAttributes attrs = new EncodingAttributes();
        attrs.setFormat("mp3");
        attrs.setAudioAttributes(audio);

        //Encode
        Encoder encoder = new Encoder();
        encoder.encode(new MultimediaObject(source), target, attrs);
    }

另外也可以视频格式转换,例子网上到处都有。

代码里audio对象可以设置一些参数,这个我不太懂,大约不特别指定就好,按官方代码指定了采样率和通道数后生成的mp3尺寸大了很多,播放效果还是随着源文件的质量来。

在windows下的cmd窗口运行 ffmpeg-amd64.exe --helpfmpeg-amd64.exe --help full

可以看到太多的参数选项,真的很多。

在官方网址里 https://github.com/a-schild/jave2 可以看到一些说明和调用示例

尤其是 More advanced examples 里  https://github.com/a-schild/jave2/blob/master/Examples.md


本文代码基本上是从官网上抄来的,剩下的也是看了网上很多大同小异的文章。

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值