600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Java实现音频格式转换 WAV—mp3 可使音频压缩

Java实现音频格式转换 WAV—mp3 可使音频压缩

时间:2018-07-20 23:42:37

相关推荐

Java实现音频格式转换 WAV—mp3 可使音频压缩

/1749979.html

最近做的一个小项目中,师兄安排的任务,要实现录音然后保存文件,实现网络传输,然后我用初学的java实现了一个录音机的功能(见前面的博客),但是windows录音默认保存的格式是WAVE,后缀是WAV,经过大量测试,录制一分钟要1M大小,这样不便于网络的传输,于是下面的任务就是实现音频压缩了,搜了几天,找到了一个不错的软件Monkey Audio(实现说明,我们的项目得全是代码实现的),这个软件的开源的,但是在官网下载的源代码经过我们一个下午的测试,竟然跟最新软件的压缩差的很远,于是我们便尝试走其他的路,比如:音频格式转换也可以达到音频压缩的目的,于是便搜类似的东西,于是便找到了Lame解码器。

百度百科普及:

LAME 是最好的MP3编码器,编码高品质MP3的最好也是唯一的选择。LAME本身是DOS下的文件,需要加外壳程序才比较容易使用,也可以在别的软件(比如EAC)中间调用。是一款出色的MP3压缩程序,它使用了独创的人体听音心理学模型和声学模型,改变了人们对MP3高音发哑、低音发破的音质的印象。

然后我就通过代码在程序调用这个解码器,实现了最后的音频格式转换,当然也达到的压缩的目地,并且经过大量的测试,效果非常不错,并没有损坏音频,同时压缩比很高。

事先说明:Lame.exe文件必须得有,并且在程序调用的时候,如果没在java的src同一个文件夹下的话,必须在程序中使用绝对路径,否则报错。

贴出完整的录音代码(这次与上次博文中代码添加了音频格式转换的代码)

/** 实现录音机的功能*/package com.liuyun.MyRecord1;import java.awt.*;import javax.swing.*;import java.awt.event.*;import java.io.*;import javax.sound.sampled.*;import java.lang.*;public class MyRecord extends JFrame implements ActionListener{//定义录音格式AudioFormat af = null;//定义目标数据行,可以从中读取音频数据,该 TargetDataLine 接口提供从目标数据行的缓冲区读取所捕获数据的方法。TargetDataLine td = null;//定义源数据行,源数据行是可以写入数据的数据行。它充当其混频器的源。应用程序将音频字节写入源数据行,这样可处理字节缓冲并将它们传递给混频器。SourceDataLine sd = null;//定义字节数组输入输出流ByteArrayInputStream bais = null;ByteArrayOutputStream baos = null;//定义音频输入流AudioInputStream ais = null;//定义停止录音的标志,来控制录音线程的运行Boolean stopflag = false;//记录开始录音的时间long startPlay;//定义所需要的组件JPanel jp1,jp2,jp3;JLabel jl1=null;JButton captureBtn,stopBtn,playBtn,saveBtn;public static void main(String[] args) {//创造一个实例MyRecord mr = new MyRecord();}//构造函数public MyRecord(){//组件初始化jp1 = new JPanel();jp2 = new JPanel();jp3 = new JPanel();//定义字体Font myFont = new Font("华文新魏",Font.BOLD,30);jl1 = new JLabel("录音机功能的实现");jl1.setFont(myFont);jp1.add(jl1);captureBtn = new JButton("开始录音");//对开始录音按钮进行注册监听captureBtn.addActionListener(this);captureBtn.setActionCommand("captureBtn");//对停止录音进行注册监听stopBtn = new JButton("停止录音");stopBtn.addActionListener(this);stopBtn.setActionCommand("stopBtn");//对播放录音进行注册监听playBtn = new JButton("播放录音");playBtn.addActionListener(this);playBtn.setActionCommand("playBtn");//对保存录音进行注册监听saveBtn = new JButton("保存录音");saveBtn.addActionListener(this);saveBtn.setActionCommand("saveBtn");this.add(jp1,BorderLayout.NORTH);this.add(jp2,BorderLayout.CENTER);this.add(jp3,BorderLayout.SOUTH);jp3.setLayout(null);jp3.setLayout(new GridLayout(1, 4,10,10));jp3.add(captureBtn);jp3.add(stopBtn);jp3.add(playBtn);jp3.add(saveBtn);//设置按钮的属性captureBtn.setEnabled(true);stopBtn.setEnabled(false);playBtn.setEnabled(false);saveBtn.setEnabled(false);//设置窗口的属性this.setSize(400,300);this.setTitle("录音机");this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setLocationRelativeTo(null);this.setVisible(true);}public void actionPerformed(ActionEvent e) {if(e.getActionCommand().equals("captureBtn")){//点击开始录音按钮后的动作//停止按钮可以启动captureBtn.setEnabled(false);stopBtn.setEnabled(true);playBtn.setEnabled(false);saveBtn.setEnabled(false);//调用录音的方法capture();//记录开始录音的时间startPlay = System.currentTimeMillis();}else if (e.getActionCommand().equals("stopBtn")) {//点击停止录音按钮的动作captureBtn.setEnabled(true);stopBtn.setEnabled(false);playBtn.setEnabled(true);saveBtn.setEnabled(true);//调用停止录音的方法stop();//记录停止录音的时间long stopPlay = System.currentTimeMillis();//输出录音的时间System.out.println("Play continues " + (stopPlay-startPlay));}else if(e.getActionCommand().equals("playBtn")){//调用播放录音的方法play();}else if(e.getActionCommand().equals("saveBtn")){//调用保存录音的方法save();}}//开始录音public void capture(){try {//af为AudioFormat也就是音频格式af = getAudioFormat();DataLine.Info info = new DataLine.Info(TargetDataLine.class,af);td = (TargetDataLine)(AudioSystem.getLine(info));//打开具有指定格式的行,这样可使行获得所有所需的系统资源并变得可操作。td.open(af);//允许某一数据行执行数据 I/Otd.start();//创建播放录音的线程Record record = new Record();Thread t1 = new Thread(record);t1.start();} catch (LineUnavailableException ex) {ex.printStackTrace();return;}}//停止录音public void stop(){stopflag = true;}//播放录音public void play(){//将baos中的数据转换为字节数据byte audioData[] = baos.toByteArray();//转换为输入流bais = new ByteArrayInputStream(audioData);af = getAudioFormat();ais = new AudioInputStream(bais, af, audioData.length/af.getFrameSize());try {DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, af);sd = (SourceDataLine) AudioSystem.getLine(dataLineInfo);sd.open(af);sd.start();//创建播放进程Play py = new Play();Thread t2 = new Thread(py);t2.start(); } catch (Exception e) {e.printStackTrace();}finally{try {//关闭流if(ais != null){ais.close();}if(bais != null){bais.close();}if(baos != null){baos.close();}} catch (Exception e) {e.printStackTrace();}}}//保存录音public void save(){//取得录音输入流af = getAudioFormat();byte audioData[] = baos.toByteArray();bais = new ByteArrayInputStream(audioData);ais = new AudioInputStream(bais,af, audioData.length / af.getFrameSize());//定义最终保存的文件名File file = null;//写入文件try {//以当前的时间命名录音的名字//将录音的文件存放到F盘下语音文件夹下File filePath = new File("F:/语音文件");if(!filePath.exists()){//如果文件不存在,则创建该目录filePath.mkdir();}long time = System.currentTimeMillis();file = new File(filePath+"/"+time+".wav");AudioSystem.write(ais, AudioFileFormat.Type.WAVE, file);//将录音产生的wav文件转换为容量较小的mp3格式//定义产生后文件名String tarFileName = time+".mp3";Runtime run = null;try {run = Runtime.getRuntime();long start=System.currentTimeMillis();//调用解码器来将wav文件转换为mp3文件<strong><span style="color:#ff0000;">Process p=run.exec(filePath+"/"+"lame -b 16 "+filePath+"/"+file.getName()+" "+filePath+"/"+tarFileName); //16为码率,可自行修改</span></strong>//释放进程p.getOutputStream().close();p.getInputStream().close();p.getErrorStream().close();p.waitFor();long end=System.currentTimeMillis();System.out.println("convert need costs:"+(end-start)+"ms");//删除无用的wav文件if(file.exists()){file.delete();}} catch (Exception e) {e.printStackTrace();}finally{//最后都要执行的语句//run调用lame解码器最后释放内存run.freeMemory();}} catch (Exception e) {e.printStackTrace();}finally{//关闭流try {if(bais != null){bais.close();} if(ais != null){ais.close();}} catch (Exception e) {e.printStackTrace();} }}//设置AudioFormat的参数public AudioFormat getAudioFormat() {//下面注释部分是另外一种音频格式,两者都可以AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED ;float rate = 8000f;int sampleSize = 16;String signedString = "signed";boolean bigEndian = true;int channels = 1;return new AudioFormat(encoding, rate, sampleSize, channels,(sampleSize / 8) * channels, rate, bigEndian);////采样率是每秒播放和录制的样本数//float sampleRate = 16000.0F;//// 采样率8000,11025,16000,22050,44100////sampleSizeInBits表示每个具有此格式的声音样本中的位数//int sampleSizeInBits = 16;//// 8,16//int channels = 1;//// 单声道为1,立体声为2//boolean signed = true;//// true,false//boolean bigEndian = true;//// true,false//return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,bigEndian);}//录音类,因为要用到MyRecord类中的变量,所以将其做成内部类class Record implements Runnable{//定义存放录音的字节数组,作为缓冲区byte bts[] = new byte[10000];//将字节数组包装到流里,最终存入到baos中//重写run函数public void run() {baos = new ByteArrayOutputStream();try {stopflag = false;while(stopflag != true){//当停止录音没按下时,该线程一直执行//从数据行的输入缓冲区读取音频数据。//要读取bts.length长度的字节,cnt 是实际读取的字节数int cnt = td.read(bts, 0, bts.length);if(cnt > 0){baos.write(bts, 0, cnt);}}} catch (Exception e) {e.printStackTrace();}finally{try {//关闭打开的字节数组流if(baos != null){baos.close();}} catch (IOException e) {e.printStackTrace();}finally{td.drain();td.close();}}}}//播放类,同样也做成内部类class Play implements Runnable{//播放baos中的数据即可public void run() {byte bts[] = new byte[10000];try {int cnt;//读取数据到缓存数据while ((cnt = ais.read(bts, 0, bts.length)) != -1) {if (cnt > 0) {//写入缓存数据//将音频数据写入到混频器sd.write(bts, 0, cnt);}}} catch (Exception e) {e.printStackTrace();}finally{sd.drain();sd.close();}}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。