使用java連線ffmpeg轉碼視訊
阿新 • • 發佈:2019-02-10
最近用到了ffmpeg,寫一篇東西壓壓驚
借鑑了一些大爺的部落格
重構了整個程式碼,解耦,新增若干註釋
本類:
package videoformat; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.UUID; import videoformat.utils.getProperties; /** * 把各種視訊檔案轉換為flv 有參構造,傳入檔案源路徑,檔案輸出路徑,檔名 無參構造通過配置檔案讀取,但需要檔名,並且存在檔案路徑中。 * * @author woshihuzios123 * @version 0.3 */ public class ConV2 { private Properties prop = getProperties.getPropertie();// 獲取配置檔案裡儲存的值 private String filePath;// 這裡傳入檔案路徑 private String outFilePath;// 輸出檔案存放路徑 private String fileName;// 檔名 private String filePathandName;// 檔案路徑+檔名 /** * 無參構造讀取配置檔案中的配置,但fileName還需要設定,不然無法轉碼 */ public ConV2() { super(); filePath = prop.getProperty("inputFilePath"); outFilePath = prop.getProperty("outputFilePath"); } /** * * @param filePath * 檔案所在路徑 * @param outFilePath * 檔案轉碼後輸出的路徑 * @param fileName * 當前檔名 */ public ConV2(String filePath, String outFilePath, String fileName) { super(); this.filePath = filePath; this.outFilePath = outFilePath; this.fileName = fileName; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getFilePath() { return filePath; } public String getOutFilePath() { return outFilePath; } public String getFilePathandName() { return filePathandName; } /** * 如果encoderForFlv輸出為false,則表示檔名可能輸錯,轉碼引數錯誤,檔案型別不支援等 * * @return */ public boolean encoderForFLV() { // 呼叫這個唯一的方法後才會拼接字串,防止出現問題 filePathandName = filePath + fileName; // 判斷檔案是否是檔案 if (!checkfile(filePathandName)) { return false; } if (proccess()) { return true; } return false; } private boolean checkfile(String path) { // 沒有許可權讀取或者不是一個正常的檔案會返回false File file = new File(path); if (!file.isFile()) { return false; } return true; } private boolean proccess() { int type = checkContentType(); boolean status = false; if (type == 0) { status = processFLV(); } return status; } private int checkContentType() { // 擷取字尾 String type = filePathandName.substring( filePathandName.lastIndexOf(".") + 1, filePathandName.length()) .toLowerCase(); // 後臺判斷能否轉換,前臺需要確定上傳檔案型別。 if (type.equals(prop.getProperty("avi")) || type.equals(prop.getProperty("mpg")) || type.equals(prop.getProperty("wmv")) || type.equals(prop.getProperty("3gp")) || type.equals(prop.getProperty("mov")) || type.equals(prop.getProperty("mp4")) || type.equals(prop.getProperty("asf")) || type.equals(prop.getProperty("asx")) || type.equals(prop.getProperty("flv")) || type.equals(prop.getProperty("vob"))) { return 0; } System.out.println(999); return 9; } private boolean processFLV() { if (!checkfile(filePathandName)) { return false; } fileName = fileNameHexToFLV(fileName);// 在這裡包裝 fileName,增加UUID,使用.分割 List<String> commend = new ArrayList<String>(); commend.add(prop.getProperty("encoderPath2")); commend.add(prop.getProperty("y"));// 覆蓋輸出檔案,即如果已存在就覆蓋而不提示 commend.add(prop.getProperty("i"));// 指定輸入目錄 commend.add(filePathandName);// 從這個目錄讀取檔案 commend.add(prop.getProperty("ab"));// 音訊資料流 ,64kb commend.add(prop.getProperty("ar"));// 音訊取樣率 24000hz commend.add(prop.getProperty("b"));// 動態位元速率,可以改成例如"-b 1500" 來指定位元速率 commend.add(prop.getProperty("r"));// 幀數 24 commend.add(prop.getProperty("s"));// 輸出解析度 480*272 commend.add(prop.getProperty("threads"));// 多執行緒, 可選項,指定2~4 commend.add(outFilePath + fileName);// 輸出路徑+修改後的檔名 // 使用圖片生成的返回值來判斷是否繼續 processJPG(); String s = commandTo(commend); boolean b = getRuntime(s);// 封裝,在命令列下執行 return b; } private String fileNameHexToFLV(String filename) { // 擷取字尾,然後新增flv filename = "flv"; // 檔案頭新增uuid String u = UUID.randomUUID().toString().replace("-", "") + prop.getProperty("fenge") + filename; // 返回u return u; } private boolean processJPG() { List<String> list = new ArrayList<String>(); list.add(prop.getProperty("encoderPath2"));// 轉碼器路徑 list.add(prop.getProperty("i"));// 指定輸入目錄 list.add(filePathandName);// 輸入目錄的路徑和檔案 list.add(prop.getProperty("y"));// 覆蓋輸出檔案,即如果已存在就覆蓋而不提示 list.add(prop.getProperty("f"));// 強制採用格式 list.add(prop.getProperty("image2"));// image2 list.add(prop.getProperty("s"));// 輸出解析度 480*272 list.add(prop.getProperty("t"));// 設定記錄時間 list.add(outFilePath + fileName + prop.getProperty("jpg"));// 新增檔案路徑加檔名再追加.jpg String s = commandTo(list); boolean b = getRuntime(s); return b; } private String commandTo(List<String> list) { StringBuilder sb = new StringBuilder(); ArrayList<String> arrayList = (ArrayList<String>) list; Iterator<String> its = arrayList.iterator(); while (its.hasNext()) { sb.append(its.next()); sb.append(" "); } System.out.println(sb.toString().replace(",", "")); return sb.toString().replace(",", ""); } // 執行程式 private boolean getRuntime(String arguments) { try { Process p = Runtime.getRuntime().exec(arguments); // 輸出流,防止出現流堵塞導致死鎖 outStream(p.getErrorStream()); outStream(p.getInputStream()); return true; } catch (IOException e) { e.printStackTrace(); } return false; } // 可能出現執行緒異常,列印到控制檯,ffmpeg日誌,可以使用log4j列印成日誌 private void outStream(InputStream p) { // 用一個讀輸出流類去讀 BufferedReader br = new BufferedReader(new InputStreamReader(p)); String line = null; // 逐行讀取輸出到控制檯 try { while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
配置檔案:
inputFilePath=c\:\\\\ffmpeg\\\\input\\\\ outputFilePath=c\:\\\\ffmpeg\\\\output\\\\ encoderPath2=c\:\\ffmpeg\\ffmpeg.exe mpg=mpg wmv=wmv 3gp=3gp avi=avi asf=asf asx=asx mp4=mp4 flv=flv mov=mov y=-y qscale=-qscale 4 r=-r 24 s=-s 1600x900 b=-b 1500 ar=-ar 22050 i=-i ab=-ab 56 image2=image2 ss=-ss 8 t=-t 0.001 jpg=.jpg f=-f fenge=. threads=-threads 2
工具類:
單元測試:package videoformat.utils; import java.io.IOException; import java.io.InputStream; import java.util.Properties; //獲取配置檔案 public class getProperties { static InputStream is = Object.class .getResourceAsStream("/decoder.properties"); // 相對路徑 public static Properties getPropertie() { Properties prop = new Properties(); try { prop.load(is); return prop; } catch (IOException e) { throw new RuntimeException(e); } } }
package videoformat.test;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import org.junit.Test;
import videoformat.ConV2;
public class junitTest {
<span style="white-space:pre"> </span>// 能使用多執行緒建立。
<span style="white-space:pre"> </span>@Test
<span style="white-space:pre"> </span>public void fun1() {
<span style="white-space:pre"> </span>String s = "C:\\ffmpeg\\input\\";
<span style="white-space:pre"> </span>String s2 = "C:\\ffmpeg\\output\\";
<span style="white-space:pre"> </span>String s3 = "a.avi";
<span style="white-space:pre"> </span>ConV2 conV2 = new ConV2(s, s2, s3);
<span style="white-space:pre"> </span>boolean b = conV2.encoderForFLV();
<span style="white-space:pre"> </span>System.out.println(b);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>@Test
<span style="white-space:pre"> </span>public void fun2() {
<span style="white-space:pre"> </span>// 生成所有ffmpeg的引數
<span style="white-space:pre"> </span>try {
<span style="white-space:pre"> </span>Process p = Runtime.getRuntime().exec(
<span style="white-space:pre"> </span>"c:\\ffmpeg\\ffmpeg.exe -h full");
<span style="white-space:pre"> </span>// outStream(p.getErrorStream());
<span style="white-space:pre"> </span>outStream(p.getInputStream());
<span style="white-space:pre"> </span>} catch (IOException e) {
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>// 把流中內容寫入到檔案
<span style="white-space:pre"> </span>private void outStream(InputStream p) {
<span style="white-space:pre"> </span>// 用一個讀輸出流類去讀
<span style="white-space:pre"> </span>BufferedReader br = new BufferedReader(new InputStreamReader(p));
<span style="white-space:pre"> </span>String line = null;
<span style="white-space:pre"> </span>// 逐行讀取輸出到控制檯
<span style="white-space:pre"> </span>try {
<span style="white-space:pre"> </span>String file = "f:/1.txt";
<span style="white-space:pre"> </span>OutputStreamWriter pw = new OutputStreamWriter(
<span style="white-space:pre"> </span>new FileOutputStream(file));
<span style="white-space:pre"> </span>while ((line = br.readLine()) != null) {
<span style="white-space:pre"> </span>System.out.println(line);
<span style="white-space:pre"> </span>// 寫入到檔案
<span style="white-space:pre"> </span>pw.write(line);
<span style="white-space:pre"> </span>pw.write("\r\n");
<span style="white-space:pre"> </span>pw.flush();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>pw.close();
<span style="white-space:pre"> </span>br.close();
<span style="white-space:pre"> </span>} catch (IOException e) {
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
}