zoukankan      html  css  js  c++  java
  • 利用jave2进行音频处理

    很多朋友都知道,ffmpeg是一个功能强大的多媒体处理工具,可惜它并不是java语言开发,如果需要在java项目中使用时,得自己写很多代码,幸好github上有一个开源项目jave2 把ffmpeg做了封装,很大程度上简化了开发,使用方法如下:

    先添加依赖项

    <dependency>
        <groupId>ws.schild</groupId>
        <artifactId>jave-all-deps</artifactId>
        <version>3.1.1</version>
    </dependency>

    以下是一些常用示例:

    1、获取音频文件的编码信息

       MultimediaInfo getMediaInfo() {
            String sourceFilePath = "/Users/jimmy/Downloads/bgm.wav";
            File file = new File(sourceFilePath);
            if (file != null && file.exists()) {
                try {
                    MultimediaObject multimediaObject = new MultimediaObject(file);
                    MultimediaInfo m = multimediaObject.getInfo();
                    return m;
                } catch (Exception e) {
                    e.printStackTrace();
    
                }
            }
            return null;
        }
    

    System.out.println(getMediaInfo()); 输出如下:

    ws.schild.jave.info.MultimediaInfo (format=wav (metadata={encoder=Lavf58.27.103}, duration=101850, video=null, audio=ws.schild.jave.info.AudioInfo (decoder=pcm_s16le ([1][0][0][0] / 0x0001), samplingRate=44100, channels=2, bitRate=1411000))

    从上面可以看出,该文件是wav格式,时长为101.850秒,编码格式为pcm_s16le,采集率为44100,双声道,bit率为1411000

    2、wav转mp3

    boolean convert2Mp3() {
            String sourceFilePath = "/Users/jimmy/Downloads/bgm.wav";
            String targetFilePath = "/Users/jimmy/Downloads/bgm.mp3";
            try {
                File source = new File(sourceFilePath);
                File target = new File(targetFilePath);
    
                //Audio Attributes
                AudioAttributes audio = new AudioAttributes();
                audio.setCodec("libmp3lame");
                audio.setBitRate(64000);
                audio.setChannels(2);
                audio.setSamplingRate(44100);
    
                //Encoding attributes
                EncodingAttributes attrs = new EncodingAttributes();
                attrs.setInputFormat("wav");
                attrs.setOutputFormat("mp3");
                attrs.setAudioAttributes(audio);
    
                //Encode
                Encoder encoder = new Encoder();
                encoder.encode(new MultimediaObject(source), target, attrs);
    
            } catch (Exception ex) {
                ex.printStackTrace();
                return false;
            }
            return true;
        }
    

      

    3、转换编码格式

        static boolean changeCode() {
            String sourceFilePath = "/Users/jimmy/Downloads/bgm.wav";
            String targetFilePath = "/Users/jimmy/Downloads/bgm_2.wav";
    
            //Audio Attributes
            AudioAttributes audio = new AudioAttributes();
            audio.setCodec("pcm_u8");
            audio.setBitRate(64000);
            audio.setChannels(2);
            audio.setSamplingRate(8000);
    
            //Encoding attributes
            EncodingAttributes attrs = new EncodingAttributes();
            attrs.setInputFormat("wav");
            attrs.setOutputFormat("wav");
            attrs.setAudioAttributes(audio);
    
            //Encode
            Encoder encoder = new Encoder();
            try {
                encoder.encode(new MultimediaObject(new File(sourceFilePath)), new File(targetFilePath), attrs);
    
                //辅助输出,观察编码格式的变化
                MultimediaObject srcObj = new MultimediaObject(new File(sourceFilePath));
                MultimediaObject targetObj = new MultimediaObject(new File(targetFilePath));
                System.out.println(srcObj.getInfo());
                System.out.println(targetObj.getInfo());
            } catch (Exception ex) {
                ex.printStackTrace();
                return false;
            }
            return true;
        }
    

    第7行,设置了新的编码pcm_u8

    4、分离左右声道

    boolean splitChannel() {
            String source = "/Users/jimmy/Downloads/bgm.wav";
            String left = "/Users/jimmy/Downloads/bgm_left.wav";
            String right = "/Users/jimmy/Downloads/bgm_right.wav";
            File leftFile = new File(left);
            File rightFile = new File(right);
            if (leftFile.exists()) {
                leftFile.delete();
            }
    
            if (rightFile.exists()) {
                rightFile.delete();
            }
            DefaultFFMPEGLocator locator = new DefaultFFMPEGLocator();
            ProcessWrapper ffmpeg = locator.createExecutor();
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(source);
            ffmpeg.addArgument("-map_channel");
            ffmpeg.addArgument("0.0.0");
            ffmpeg.addArgument(left);
            ffmpeg.addArgument("-map_channel");
            ffmpeg.addArgument("0.0.1");
            ffmpeg.addArgument(right);
            BufferedReader br = null;
            try {
                ffmpeg.execute();
                br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    //输出处理过程中的日志(辅助观察处理过程)
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            } finally {
                try {
                    if (br != null) {
                        br.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            try {
                //辅助输出,观察编码格式的变化
                MultimediaObject srcObj = new MultimediaObject(leftFile);
                MultimediaObject targetObj = new MultimediaObject(rightFile);
                System.out.println(srcObj.getInfo());
                System.out.println(targetObj.getInfo());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
    
            return true;
        }
    

     声道分离后,会生成2个文件,分别对应于左右声道。

      

    5、拼接音频(比如:把某段音频重复N次,合成1个新音频)

    boolean mergeAudio() {
    //        ffmpeg -i bullet.wav -i bullet.wav -i bullet.wav -filter_complex '[0:0] [1:0] concat=n=3:v=0:a=1 [a]' -map [a] bullet_3.wav
    
            //先生成要拼接的音频清单
            int times = 5;
    
            String src = "/Users/jimmy/Downloads/bullet.wav";
            String target = "/Users/jimmy/Downloads/bullet_" + times + ".wav";
    
            File targetFile = new File(target);
            if (targetFile.exists()) {
                targetFile.delete();
            }
    
            DefaultFFMPEGLocator locator = new DefaultFFMPEGLocator();
            ProcessWrapper ffmpeg = locator.createExecutor();
            for (int i = 1; i <= times; i++) {
                ffmpeg.addArgument("-i");
                ffmpeg.addArgument(src);
            }
            ffmpeg.addArgument("-filter_complex");
            ffmpeg.addArgument("[0:0] [1:0] concat=n=" + times + ":v=0:a=1 [a]");
            ffmpeg.addArgument("-map");
            ffmpeg.addArgument("[a]");
    
            ffmpeg.addArgument(target);
            BufferedReader br = null;
            try {
                ffmpeg.execute();
                br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    //输出处理过程中的日志(辅助观察处理过程)
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            } finally {
                try {
                    if (br != null) {
                        br.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
    

      

    6、截取音频中的某一段

    void cut() throws EncoderException {
            String src = "/Users/jimmy/Downloads/bgm.wav";
            String target = "/Users/jimmy/Downloads/bgm_1_3.wav";
    
            File targetFile = new File(target);
            if (targetFile.exists()) {
                targetFile.delete();
            }
    
            File srcFile = new File(src);
            MultimediaObject srcMultiObj = new MultimediaObject(srcFile);
            MultimediaInfo srcMediaInfo = srcMultiObj.getInfo();
    
            Encoder encoder = new Encoder();
    
    
            EncodingAttributes encodingAttributes = new EncodingAttributes();
            //设置起始偏移量(秒)
            encodingAttributes.setOffset(1.0F);
            //设置切片的音频长度(秒)
            encodingAttributes.setDuration(2.0F);
    
            //设置音频属性
            AudioAttributes audio = new AudioAttributes();
            audio.setBitRate(srcMediaInfo.getAudio().getBitRate());
            audio.setSamplingRate(srcMediaInfo.getAudio().getSamplingRate());
            audio.setChannels(srcMediaInfo.getAudio().getChannels());
    
            //如果截取的时候,希望同步调整编码,可以设置不同的编码
    //        audio.setCodec("pcm_u8");
            audio.setCodec(srcMediaInfo.getAudio().getDecoder().split(" ")[0]);
            encodingAttributes.setInputFormat("wav");
            encodingAttributes.setAudioAttributes(audio);
    
            //写文件
            encoder.encode(srcMultiObj, new File(target), encodingAttributes);
    
        }
    

      

    最后说一个可能会存在的问题:默认情况下,jave2在执行时,会把ffmpeg可执行文件释放到"java.io.tmpdir"临时目录下,但在tomcat等容器下执行时,如果启用tomcat的用户,与java应用的执行用户不同,可能会存在无写入权限的问题。遇到这种情况,可以先用代码把java.io.tmpdir这个系统变量,指到其它有权限的目录,执行完后,再还原回来

     String oldTmpDir = System.getProperty("java.io.tmpdir");
            try {
                System.setProperty("java.io.tmpdir", "有权限写入的新临时目录");
                // todo (jave2的其它处理)
            }  finally {
                System.setProperty("java.io.tmpdir", oldTmpDir);
            }
    

      

    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    JDK问题--linux下java unrecognized class file version错误的解决
    XP oracle32位客户端安装找不到orandce11.dll.dbl
    Oracle的安装问题
    xhost和DISPLAY
    linux下访问windows的共享
    windows域与工作组概念
    当页面加载完成时,JQ触发添加页面的元素的事件触发不了。。
    工厂模式Assembly.Load(path).CreateInstance 反射出错解决办法
    MVC之联动学习
    SQL2008将服务器的数据库表数据插入到本地数据库
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/14727815.html
Copyright © 2011-2022 走看看