很多朋友都知道,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); }