有一段時(shí)間沒有更新博客了。
最近有人在我的博客中跟我說mp4Parse不能裁剪mov視頻,問我有沒有其他的解決方案,所以這次我更新了一下自己的項(xiàng)目:Android-Video-Trimmer,使用ffmpeg來實(shí)現(xiàn)視頻的裁剪。
FFmpeg是為大家所熟悉的處理視頻的一個(gè)跨平臺的開源庫,支持android、ios。我們可以自己手動編譯不同平臺的lib庫,從何集成到我們的項(xiàng)目中去。但是FFmpeg是一個(gè)C/C++的庫,對于熟悉Java開發(fā)的Android同學(xué)來說,更希望是Java層面的調(diào)用。
在我的項(xiàng)目中,集成了一個(gè)FFmpegAndroid開發(fā)庫,這個(gè)庫優(yōu)點(diǎn)是我們可以直接用Java的API來執(zhí)行ffmpge的命令,缺點(diǎn)是該庫比較大(大概19M),沒辦法對庫做瘦身縮減工作。下面是我集成這個(gè)庫的幾個(gè)步驟。
1. 引入庫的方式有兩種:aar或者源碼依賴
aar依賴:
dependencies {
compile 'com.writingminds:FFmpegAndroid:0.3.2'
}
源碼依賴:
用git將ffmpeg-android-javaclone到本地,然后把項(xiàng)目中FFmpegAndroid庫的源碼加入到自己的項(xiàng)目中。

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();
}
}
}
初始化的目的是根據(jù)Android手機(jī)的cpu架構(gòu),load對應(yīng)架構(gòu)的ffmpeg庫。
3.執(zhí)行ffmpeg的commend命令
上面的準(zhǔn)備工作做完之后,剩下就是我們關(guān)心的問題了,如何執(zhí)行ffmpeg命令行呢?在前面我已經(jīng)說了,這個(gè)庫是對ffmpeg的在Linux系統(tǒng)中命令行的一個(gè)封裝,所以我們需要在該庫中找到一個(gè)這樣的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;
小伙伴們可以看到參數(shù)String[] cmd,就是我所說的控制臺的命令行參數(shù),只要將我們的命令行傳入,設(shè)置好回調(diào),剩下的事情就是靜靜等著ffmpeg觸發(fā)我們的回調(diào)了,是不是感覺很爽!
下面是我的調(diào)用實(shí)現(xiàn):
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 開始時(shí)間,如: 00:00:20,表示從20秒開始;
-t 時(shí)長,如: 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視頻裁剪的命令行參數(shù)。
FFmpeg命令大全
視頻裁剪的命令如下:
ffmpeg -ss START -t DURATION -i INPUT -vcodec copy -acodec copy OUTPUT
需要主意的是:
DURATION 是表示視頻的持續(xù)時(shí)間而不是結(jié)束時(shí)間
INPUT 表示輸入的包含文件名的文件路徑 e.g: sdcard/xxx/xx/input.mp4
OUTPUT 表示輸出的包含文件名的文件路徑 e.g: sdcard/xxx/xx/output.mov
其他命令也基本也差不多,需要實(shí)現(xiàn)什么功能之后可以去查詢具體的命令行,對著實(shí)現(xiàn)就行。
Thanks for reading. To help others please click ? to recommend this article if you found it helpful.
You can also follow me at GitHub.