Android本地視頻壓縮方案的示例代碼
前言
本文討論的不是類似秒拍的短視頻錄制,而是用戶選擇本地一個現(xiàn)有視頻,壓縮后上傳。秒拍的實現(xiàn)其實是自定義視頻錄制功能,從而控制錄制時長,分辨率,碼率等,生成體積很小的視頻再上傳。而我們則沒辦法控制原視頻的參數(shù),可能是一個很大的視頻需要壓縮處理。
思路
利用ffmpeg對視頻轉(zhuǎn)碼,通過設(shè)定參數(shù)生成分辨率和碼率更小的視頻,實現(xiàn)壓縮。當(dāng)然,ffmpeg的功能遠不止如此,這是一個很大的專題。
用到的開源庫:https://github.com/WritingMinds/ffmpeg-android-java
使用方法
基本原理:將android環(huán)境下可執(zhí)行文件ffmpeg存放在本地,代碼執(zhí)行ffmpeg的壓縮命令。
//將開源庫中asset目錄的ffmpeg可執(zhí)行文件,拷貝到 app的data/data/files目錄 FFmpeg.getInstance(this).loadBinary(null);
這個方法是異步執(zhí)行,所以最好在Application中執(zhí)行。方法有執(zhí)行成功與否的回調(diào),這里我傳入null不關(guān)心結(jié)果。執(zhí)行完看下手機中的目錄:

既然是可執(zhí)行文件,那么在android shell環(huán)境下肯定可以執(zhí)行了。adb shell進入手機看下(前提是手機已經(jīng)獲取root權(quán)限):

執(zhí)行ffmpeg的一個命令:比如查看ffmpeg的當(dāng)前版本:./ffmpeg -version

接著就可以在代碼中,使用ffmpeg的各種命令了:把命令寫入String[],然后調(diào)用fFmpeg.execute 即可
獲取視頻文件的信息
String[] command = new String[]{"-i", arg.filePath};
try {
fFmpeg.execute(commands, new ExecuteBinaryResponseHandler(){
@Override
public void onStart() {}
@Override
public void onProgress(String message) {
Log.e("dml", "onProgress: message is " + message);
}
@Override
public void onFailure(String message) {
Log.e("dml", "onFailure: message is " + message);
}
@Override
public void onSuccess(String message) {
Log.e("dml", "onSuccess: message is " + message);
}
@Override
public void onFinish() {
Log.e("dml", "onFinish: ");
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
e.printStackTrace();
}
壓縮視頻:
String[] commands = new String[]{"-threads","1","-i", arg.filePath, "-c:v", "libx264","-crf","30","-preset", "superfast" ,"-y", "-acodec","libmp3lame",arg.thumbVideoPath};
fFmpeg.execute(commands, new ExecuteBinaryResponseHandler(){});
參數(shù)解釋:
- -threads: 執(zhí)行線程數(shù),傳入1 單線程壓縮
- -i:input路徑,傳入視頻文件的路徑
- -c:v:編碼格式,一般都是指定libx264
- -crf: 編碼質(zhì)量,取值范圍是0-51,默認值為23,數(shù)字越小輸出視頻的質(zhì)量越高。這里的30是我們經(jīng)過測試得到的經(jīng)驗值
- -preset:轉(zhuǎn)碼速度,ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow和placebo。ultrafast編碼速度最快,但壓縮率低,生成的文件更大,placebo則正好相反。x264所取的默認值為medium。需要說明的是,preset主要是影響編碼的速度,并不會很大的影響編碼出來的結(jié)果的質(zhì)量。
- -acodec:音頻編碼,一般采用libmp3lame
- arg.thumbVideoPath:最后傳入的是視頻壓縮后保存的路徑
- -y:輸出時覆蓋輸出目錄已存在的同名文件(如果不加此參數(shù),就不會覆蓋)
問題解決
此開源庫用于視頻壓縮在實際開發(fā)中存在不少問題,下面一一解決
1.壓縮進度反饋
執(zhí)行轉(zhuǎn)碼命令后,onProgress只是不停輸出字符串,而且文本很長 需要正則表達式從中截取轉(zhuǎn)碼進度反饋:
@Override
public void onProgress(String s) {
Pattern timePattern = Pattern.compile("(?<=time=)[\\d:.]*");
Scanner sc = new Scanner(s);
String match = sc.findWithinHorizon(timePattern, 0);
if (match != null) {
String[] matchSplit = match.split(":");
if (duration!= 0) {
float progress = (Integer.parseInt(matchSplit[0]) * 3600 +
Integer.parseInt(matchSplit[1]) * 60 +
Float.parseFloat(matchSplit[2])) / duration;
int showProgress = (int) (progress * 100);
if(showProgress>100){
showProgress = 100;
}
notify.compressProgress(getTag(),showProgress);
}
}
}
2.低碼率視頻壓縮會變大
實際中發(fā)現(xiàn)有些原質(zhì)量較差的視頻壓縮后,體積反而變大。
處理方法:壓縮前先執(zhí)行對視頻提取信息的命令,小于1024kb/s的視頻 不壓縮:
@Override
public void onProgress(String s) {
//Log.d("dml","pre onProgress = " + s);
if(s.contains("Stream #0:0")){
String tem = s.substring(0, s.indexOf("kb/s"));
String type ;
int pos = tem.lastIndexOf(",");
if (pos != -1) {
type = tem.substring(pos + 1,tem.length()).trim();
try {
Integer integer = Integer.parseInt(type);
if(integer > 1024){
pressV(fFmpeg);//執(zhí)行壓縮
}else {
//放棄壓縮,直接使用原文件
}
}catch (Exception e){
}
}
}
}
并且在壓縮成功后,檢查壓縮后的文件和原文件大小,如果變大了,直接使用原文件。
3.多線程壓縮多個視頻
開源庫中執(zhí)行ffmpeg的命令是在AsycTask執(zhí)行的:
ffmpegExecuteAsyncTask = new FFmpegExecuteAsyncTask(command , timeout, ffmpegExecuteResponseHandler); ffmpegExecuteAsyncTask.execute();
execute 方法在api 11之后是串行方法,就是說開源庫已經(jīng)限制為單線程。
改為:ffmpegExecuteAsyncTask.executeOnExecutor(Executors.newCachedThreadPool()); 可以使用多線程
測試中發(fā)現(xiàn)多個視頻同時壓縮,手機會嚴重發(fā)熱,強烈建議采用原設(shè)計 。
4.壓縮速度和質(zhì)量
手機性能有限,壓縮視頻速度不太理想,即使在PC端用 格式工廠壓縮轉(zhuǎn)碼視頻也不是很快。
壓縮質(zhì)量還可以,基本能保持和原視頻一樣的清晰度。下面是測試數(shù)據(jù):

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android原生態(tài)實現(xiàn)分享轉(zhuǎn)發(fā)功能實例
大家好,本篇文章主要講的是Android原生態(tài)實現(xiàn)分享轉(zhuǎn)發(fā)功能實例,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下2021-12-12
Flutter?彈性布局基石flex算法flexible示例詳解
這篇文章主要為大家介紹了Flutter?彈性布局基石flex算法flexible示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
Android無需權(quán)限調(diào)起系統(tǒng)相機
在進行一些小型APP的開發(fā),或者是對拍照界面沒有自定義要求時,我們可以用調(diào)起系統(tǒng)相機的方式快速完成拍照需求2023-03-03
RxJava之網(wǎng)絡(luò)請求最常見的三種場景
本文想闡述一下當(dāng)你開發(fā)Android應(yīng)用并采用RxJava作為你的架構(gòu),尤其是有關(guān)網(wǎng)絡(luò)請求時最常見的三種場景。這篇文章主要介紹了RxJava之網(wǎng)絡(luò)請求最常見的三種場景,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05
打飛機游戲終極BOSS Android實戰(zhàn)打飛機游戲完結(jié)篇
打飛機游戲終極BOSS,Android實戰(zhàn)打飛機游戲完結(jié)篇,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-07-07
解決Android Studio 代碼自動提示突然失效的問題
這篇文章主要介紹了解決Android Studio 代碼自動提示突然失效的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
android開發(fā)基礎(chǔ)教程—文件存儲功能實現(xiàn)
文件存儲功能在實現(xiàn)數(shù)據(jù)讀寫時會頻繁使用到,接下來介紹文件存儲功能的實現(xiàn),感興趣的朋友可以了解下2013-01-01

