Android本地視頻壓縮方案的示例代碼
前言
本文討論的不是類似秒拍的短視頻錄制,而是用戶選擇本地一個(gè)現(xiàn)有視頻,壓縮后上傳。秒拍的實(shí)現(xiàn)其實(shí)是自定義視頻錄制功能,從而控制錄制時(shí)長(zhǎng),分辨率,碼率等,生成體積很小的視頻再上傳。而我們則沒(méi)辦法控制原視頻的參數(shù),可能是一個(gè)很大的視頻需要壓縮處理。
思路
利用ffmpeg對(duì)視頻轉(zhuǎn)碼,通過(guò)設(shè)定參數(shù)生成分辨率和碼率更小的視頻,實(shí)現(xiàn)壓縮。當(dāng)然,ffmpeg的功能遠(yuǎn)不止如此,這是一個(gè)很大的專題。
用到的開(kāi)源庫(kù):https://github.com/WritingMinds/ffmpeg-android-java
使用方法
基本原理:將android環(huán)境下可執(zhí)行文件ffmpeg存放在本地,代碼執(zhí)行ffmpeg的壓縮命令。
//將開(kāi)源庫(kù)中asset目錄的ffmpeg可執(zhí)行文件,拷貝到 app的data/data/files目錄 FFmpeg.getInstance(this).loadBinary(null);
這個(gè)方法是異步執(zhí)行,所以最好在Application中執(zhí)行。方法有執(zhí)行成功與否的回調(diào),這里我傳入null不關(guān)心結(jié)果。執(zhí)行完看下手機(jī)中的目錄:
既然是可執(zhí)行文件,那么在android shell環(huán)境下肯定可以執(zhí)行了。adb shell進(jìn)入手機(jī)看下(前提是手機(jī)已經(jīng)獲取root權(quán)限):
執(zhí)行ffmpeg的一個(gè)命令:比如查看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,默認(rèn)值為23,數(shù)字越小輸出視頻的質(zhì)量越高。這里的30是我們經(jīng)過(guò)測(cè)試得到的經(jīng)驗(yàn)值
- -preset:轉(zhuǎn)碼速度,ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow和placebo。ultrafast編碼速度最快,但壓縮率低,生成的文件更大,placebo則正好相反。x264所取的默認(rèn)值為medium。需要說(shuō)明的是,preset主要是影響編碼的速度,并不會(huì)很大的影響編碼出來(lái)的結(jié)果的質(zhì)量。
- -acodec:音頻編碼,一般采用libmp3lame
- arg.thumbVideoPath:最后傳入的是視頻壓縮后保存的路徑
- -y:輸出時(shí)覆蓋輸出目錄已存在的同名文件(如果不加此參數(shù),就不會(huì)覆蓋)
問(wèn)題解決
此開(kāi)源庫(kù)用于視頻壓縮在實(shí)際開(kāi)發(fā)中存在不少問(wèn)題,下面一一解決
1.壓縮進(jìn)度反饋
執(zhí)行轉(zhuǎn)碼命令后,onProgress只是不停輸出字符串,而且文本很長(zhǎng) 需要正則表達(dá)式從中截取轉(zhuǎn)碼進(jì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.低碼率視頻壓縮會(huì)變大
實(shí)際中發(fā)現(xiàn)有些原質(zhì)量較差的視頻壓縮后,體積反而變大。
處理方法:壓縮前先執(zhí)行對(duì)視頻提取信息的命令,小于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.多線程壓縮多個(gè)視頻
開(kāi)源庫(kù)中執(zhí)行ffmpeg的命令是在AsycTask執(zhí)行的:
ffmpegExecuteAsyncTask = new FFmpegExecuteAsyncTask(command , timeout, ffmpegExecuteResponseHandler); ffmpegExecuteAsyncTask.execute();
execute 方法在api 11之后是串行方法,就是說(shuō)開(kāi)源庫(kù)已經(jīng)限制為單線程。
改為:ffmpegExecuteAsyncTask.executeOnExecutor(Executors.newCachedThreadPool()); 可以使用多線程
測(cè)試中發(fā)現(xiàn)多個(gè)視頻同時(shí)壓縮,手機(jī)會(huì)嚴(yán)重發(fā)熱,強(qiáng)烈建議采用原設(shè)計(jì) 。
4.壓縮速度和質(zhì)量
手機(jī)性能有限,壓縮視頻速度不太理想,即使在PC端用 格式工廠壓縮轉(zhuǎn)碼視頻也不是很快。
壓縮質(zhì)量還可以,基本能保持和原視頻一樣的清晰度。下面是測(cè)試數(shù)據(jù):
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)將應(yīng)用崩潰信息發(fā)送給開(kāi)發(fā)者并重啟應(yīng)用的方法
這篇文章主要介紹了Android實(shí)現(xiàn)將應(yīng)用崩潰信息發(fā)送給開(kāi)發(fā)者并重啟應(yīng)用的方法,涉及Android錯(cuò)誤處理與應(yīng)用操作的相關(guān)技巧,需要的朋友可以參考下2016-03-03Android之高德地圖定位SDK集成及地圖功能實(shí)現(xiàn)
本文主要介紹了Android中高德地圖定位SDK集成及地圖功能的實(shí)現(xiàn)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04Android動(dòng)態(tài)加載布局實(shí)現(xiàn)技巧介紹
通過(guò)使用LayoutInflater 每次點(diǎn)擊按鈕時(shí)候去讀取布局文件,然后找到布局文件里面的各個(gè)VIEW 操作完VIEW 后加載進(jìn)我們setContentView 方面里面的要放的布局文件里面,每次動(dòng)態(tài)加載文件必需調(diào)用 removeAllViews方法,清除之前的加載進(jìn)來(lái)的View2022-12-12Android APP檢測(cè)實(shí)體按鍵事件詳解
這篇文章主要為大家詳細(xì)介紹了Android APP檢測(cè)實(shí)體按鍵事件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Android高級(jí)界面組件之拖動(dòng)條和評(píng)星條的功能實(shí)現(xiàn)
這篇文章主要介紹了Android高級(jí)界面組件之拖動(dòng)條和評(píng)星條的實(shí)現(xiàn)實(shí)例,需要的的朋友參考下2017-03-03Android自定義View繪制貝塞爾曲線實(shí)現(xiàn)流程
貝塞爾曲線的本質(zhì)是通過(guò)數(shù)學(xué)計(jì)算的公式來(lái)繪制平滑的曲線,分為一階,二階,三階及多階。但是這里不講數(shù)學(xué)公式和驗(yàn)證,那些偉大的數(shù)學(xué)家已經(jīng)證明過(guò)了,所以就只講講Android開(kāi)發(fā)中的運(yùn)用吧2022-11-11Android 應(yīng)用的全屏和非全屏實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 應(yīng)用的全屏和非全屏實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-05-05Android 解決游戲發(fā)行切包資源索引沖突的問(wèn)題
這篇文章主要介紹了Android 解決游戲發(fā)行切包資源索引沖突的問(wèn)題,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03