有一段時間沒有更新博客了。
最近有人在我的博客中跟我說mp4Parse不能裁剪mov視頻,問我有沒有其他的解決方案,所以這次我更新了一下自己的項目:Android-Video-Trimmer,使用ffmpeg來實現視頻的裁剪。
FFmpeg是為大家所熟悉的處理視頻的一個跨平臺的開源庫,支持android、ios。我們可以自己手動編譯不同平臺的lib庫,從何集成到我們的項目中去。但是FFmpeg是一個C/C++的庫,對于熟悉Java開發的Android同學來說,更希望是Java層面的調用。
在我的項目中,集成了一個FFmpegAndroid開發庫,這個庫優點是我們可以直接用Java的API來執行ffmpge的命令,缺點是該庫比較大(大概19M),沒辦法對庫做瘦身縮減工作。下面是我集成這個庫的幾個步驟。
1. 引入庫的方式有兩種:aar或者源碼依賴
aar依賴:
dependencies {
compile 'com.writingminds:FFmpegAndroid:0.3.2'
}
源碼依賴:
用git將ffmpeg-android-javaclone到本地,然后把項目中FFmpegAndroid庫的源碼加入到自己的項目中。
2.庫的初始化
public class ZApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
initFFmpegBinary(this);
}
private void initFFmpegBinary(Context context) {
try {
FFmpeg.getInstance(context).loadBinary(new LoadBinaryResponseHandler() {
@Override
public void onFailure() {
}
});
} catch (FFmpegNotSupportedException e) {
e.printStackTrace();
}
}
}
初始化的目的是根據Android手機的cpu架構,load對應架構的ffmpeg庫。
3.執行ffmpeg的commend命令
上面的準備工作做完之后,剩下就是我們關心的問題了,如何執行ffmpeg命令行呢?在前面我已經說了,這個庫是對ffmpeg的在Linux系統中命令行的一個封裝,所以我們需要在該庫中找到一個這樣的API。
那我在FFmpegInterface.java類中找到了如下的PAI:
/**
* Executes a command
* @param environvenmentVars Environment variables
* @param cmd command to execute
* @param ffmpegExecuteResponseHandler {@link FFmpegExecuteResponseHandler}
* @throws FFmpegCommandAlreadyRunningException
*/
public void execute(Map<String, String> environvenmentVars, String[] cmd, FFmpegExecuteResponseHandler ffmpegExecuteResponseHandler) throws FFmpegCommandAlreadyRunningException;
/**
* Executes a command
* @param cmd command to execute
* @param ffmpegExecuteResponseHandler {@link FFmpegExecuteResponseHandler}
* @throws FFmpegCommandAlreadyRunningException
*/
public void execute(String[] cmd, FFmpegExecuteResponseHandler ffmpegExecuteResponseHandler) throws FFmpegCommandAlreadyRunningException;
小伙伴們可以看到參數String[] cmd,就是我所說的控制臺的命令行參數,只要將我們的命令行傳入,設置好回調,剩下的事情就是靜靜等著ffmpeg觸發我們的回調了,是不是感覺很爽!
下面是我的調用實現:
public static void trimVideo(Context context, String inputFile, String outputFile, long startMs, long endMs, final OnTrimVideoListener callback) {
final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
final String outputName = "trimmedVideo_" + timeStamp + ".mp4";
String start = convertSecondsToTime(startMs/1000);
String duration = convertSecondsToTime((endMs - startMs)/1000);
/**ffmpeg -ss START -t DURATION -i INPUT -vcodec copy -acodec copy OUTPUT
-ss 開始時間,如: 00:00:20,表示從20秒開始;
-t 時長,如: 00:00:10,表示截取10秒長的視頻;
-i 輸入,后面是空格,緊跟著就是輸入視頻文件;
-vcodec copy 和 -acodec copy 表示所要使用的視頻和音頻的編碼格式,這里指定為copy表示原樣拷貝;
INPUT,輸入視頻文件;
OUTPUT,輸出視頻文件*/
String cmd = "-ss " + start + " -t " + duration + " -i " + inputFile + " -vcodec copy -acodec copy " + outputFile + "/" + outputName;
String[] command = cmd.split(" ");
try {
FFmpeg.getInstance(context).execute(command, new ExecuteBinaryResponseHandler() {
@Override
public void onFailure(String s) {
}
@Override
public void onSuccess(String s) {
callback.onFinishTrim(null);
}
@Override
public void onStart() {
callback.onStartTrim();
}
@Override
public void onFinish() {
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
// do nothing for now
}
}
上面主要是拼出ffmpeg視頻裁剪的命令行參數。
FFmpeg命令大全
視頻裁剪的命令如下:
ffmpeg -ss START -t DURATION -i INPUT -vcodec copy -acodec copy OUTPUT
需要主意的是:
DURATION 是表示視頻的持續時間而不是結束時間
INPUT 表示輸入的包含文件名的文件路徑 e.g: sdcard/xxx/xx/input.mp4
OUTPUT 表示輸出的包含文件名的文件路徑 e.g: sdcard/xxx/xx/output.mov
其他命令也基本也差不多,需要實現什么功能之后可以去查詢具體的命令行,對著實現就行。
Thanks for reading. To help others please click ? to recommend this article if you found it helpful.
You can also follow me at GitHub.