標籤:
本文出自:這裡摘自http://blog.sina.com.cn/s/blog_47522f7f0102vbwp.html,按步驟實踐可行。感謝!
1. FFMPEG階層的簡單理解
要使用FFMPEG,首先需要理解FFMPEG的代碼結構。根據志哥的提示,ffmpeg的代碼是包括兩部分的,一部分是library,一部分是tool。api都是在library裡面,如果直接調api來操作視頻的話,就需要寫c或者c++了。另一部分是tool,使用的是命令列,則不需要自己去編碼來實現視頻操作的流程。實際上tool只不過把命令列轉換為api的操作而已。
2. 預熱-在mac os下使用ffmpeg
在mac os下使用ffmpeg比較簡單,可以直接使用命令列來操作。首先安裝ffmpeg,這裡預設系統已經安裝好brew,只需要在終端上輸入:
brew install ffmpeg
等待安裝結束即可。
安裝結束後,嘗試以下命令:
ffmpeg -i input.mp4 output.avi
如果能順利轉換,表明安裝成功
3. 編譯能在iOS下使用的FFMPEG library庫
這一步是編譯1所說的library,編譯好之後可以調用FFMPEG的api。網上有一些方法,但都要自己手動編譯,稍顯複雜而且比較陳舊。按照app store的需求,編譯出來的包還必須支援arm64。我在萬能的github中找到一個能夠"一鍵編譯"的指令碼,地址如下:
https://github.com/kewlbear/FFmpeg-iOS-build-script
而且寫這個指令碼的歪果仁挺好人,更新很及時,已經更新到了最新的2.5.3版本。下載下來,只有一個build-ffmpeg.sh指令檔。在終端中轉至指令碼的目錄,執行命令:
./build-ffmpeg.sh
指令碼則會自動從github中把ffmpeg源碼下到本地並開始編譯。
編譯結束後,檔案目錄如下:
【iOS開發】iOS下使用FFMPEG的一些總結
其中,ffmpeg-2.5.3是源碼,FFmpeg-iOS是編譯出來的庫,裡面有我們需要的.a靜態庫,一共有7個。
執行命令:
lipo -info libavcodec.a
查看.a包支援的架構,這幾個包都支援了armv7 armv7s i386 x86_64 arm64這幾個架構,這個指令碼果真是業界良心啊~~~
4.在xcode中引入FFMPEG library庫
建立工程,把上面編譯好的FFmpeg-iOS拖到xcode工程中,添加一個標頭檔引用
#include "avformat.h"
添加一個api語句:
av_register_all();
添加一個空的類,把執行檔案.m尾碼改為.mm,開啟混編模式。
添加相應的framework,包括avfoundation和coremedia。
運行工程,如果沒有報錯,則表明編譯成功。
5.在xcode項目中使用命令列
執行到第4步,已經可以使用library庫了。但是如果要對視頻進行操作,還是需要手動寫很多代碼去調用api,工作量較大,自然不如直接寫命令列方便。為了命令列能夠在xcode工程中使用,還需要做以下工作:
(1)添加源碼中的tools,具體檔案包括:
【iOS開發】iOS下使用FFMPEG的一些總結
(2)添加Header Search Paths
在target--build setting中搜尋Header Search Paths,並在Header Search Paths下面添加源碼ffmpeg-2.5.3和scratch的路徑。
(3)修改ffmpeg.h和ffmpeg.c源碼
如果此時run這個工程,則會報錯,原因是工程裡面有2個main函數,此時處理方法為:
在ffmpeg.h中添加一個函式宣告:
int ffmpeg_main(int argc, char **argv);
在ffmpeg.c中找到main函數,把main函數改為ffmpeg_main。
(4)調用命令列範例
添加標頭檔:#import "ffmpeg.h"
調用命令列
int numberOfArgs = 16;
char** arguments = calloc(numberOfArgs, sizeof(char*));
arguments[0] = "ffmpeg";
arguments[1] = "-i";
arguments[2] = inputPath;
arguments[3] = "-ss";
arguments[4] = "0";
arguments[5] = "-t";
arguments[6] = durationChar;
arguments[7] = "-vcodec";
arguments[8] = "copy";
arguments[9] = "-acodec";
arguments[10] = "aac";
arguments[11] = "-strict";
arguments[12] = "-2";
arguments[13] = "-b:a";
arguments[14] = "32k";
arguments[15] = outputPath;
int result = ffmpeg_main(numberOfArgs, arguments);
其中inputpath和outputpath是檔案路徑。經測試,這兩個路徑不支援asset-library://協議和file:// 協議,所以如果是要用相簿的檔案,我目前的解決辦法是把它拷貝到沙箱裡面。
6. 改關閉進程為關閉線程
如果順利進行到了第5步,在app中是能夠用命令列處理視頻了,但會出現一個問題,app會退出。經肖大神提醒,發現了命令列執行完畢之後會退出進程。而iOS下只能啟動一個進程,因此必須改關閉進程為關閉線程,或者直接把關閉進程的方法給注掉。
在ffmpeg.c中可以看到,執行退出進程的方法是exit_program,定位到了cmdutils.c中執行了c語言的exit方法。這裡我將它改為了pthread_exit(需要添加#include 標頭檔)。在xcode項目中使用時,則可以用NSThread來新開一個線程,執行完畢之後,把線程關閉了即可。再使用NSThreadWillExitNotification通知,即可監聽線程退出的情況。
7. 修複ffmpeg.c裡面的一個bug
在實際項目中,可能需要多次調用命令列,但在多次調用命令列的過程中,發現ffmpeg.c的代碼中會訪問空屬性導致程式崩潰。逐步debug後發現,很多指標已經置空了,但它們的計數卻沒有置零,不知道是不是ffmpeg.c的一個bug。修複方法如下:在ffmpeg_cleanup方法下,將各個計數器置零,包括:
nb_filtergraphs
nb_output_files
nb_output_streams
nb_input_files
nb_input_streams
置零之後,重複使用ffmpeg_main方法一切正常。
iOS基於FFmpeg之配置FFmpeg架構(二)