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