iOS開發 - 超詳細集成 FFmpeg 步驟

轉自:https://blog.csdn.net/qq_30513483/article/details/87860390html

概述

網上充斥着大量的 iOS FFmpeg 編譯的教程,有的時間比較早了,有的不少都沒有說詳細,或者有個別坑做者沒有講到,有的講到到了一半,沒有例子。linux

因此本人蔘考了網上的編譯FFmpeg教程到集成的不少文章,而後加上本人進行了實際操做,總結出了此篇文章,但願你們若是有用到FFmpeg,之後少走一些坑。c++

此篇文章內容會包含:git

重新建 iOS 工程 -------> 到調用FFmpeg 命令 -------> 直到運行項目成功的本人實操的全部步驟。程序員


目錄

  1. FFmpeg 簡介
  2. FFmpeg 的編譯
  3. iOS 集成 FFmpeg
  4. iOS 集成 FFmpeg Tool
  5. 優化解決集成後問題
  6. iOS 調用 FFmpeg Tool

1、FFmpeg 簡介github


1,FFmpeg 是什麼 ?算法

你能夠把 FFmpeg 理解成一套音視頻解決方案,使用 C語言 開發的開源程序,而且免費、開源、跨平臺,它提供了錄製、轉換以及流化音視頻,編碼,特效,視音頻操做等功能,包含了很是先進的音頻/視頻編解碼庫。api

(1)FFmpeg 能作什麼 ?瀏覽器

能夠實現播放歌曲、視頻,甚至經過命令實現對 視頻文件的轉碼、混合、剪輯,採集等各
種複雜處理。
ruby

(2)哪些地方用到了FFmpeg?

使 FFmpeg內核視頻播放 : Mplayer,射手播放器 ,暴風影音 ,KMPlayer...
使 FFmpeg做爲內核的Direct show Filter 解碼 : ffdshow,lav filters...
使 FFmpeg做爲內核的轉碼工具: ffmpeg,格式工廠...

2,FFmpeg 做者

法布里斯·貝拉(FabriceBellard)是一位著名的計算機程序員,1972年生於法國Grenoble,大學就讀於巴黎高等綜合理工學院,後在國立巴黎高等電信學院攻讀。因FFmpeg、QEMU等項目而聞名業內。他也是最快圓周率算法貝拉公式、TCCBOOT和TCC(微型C編譯器)等項目的做者。

《我的成就》:

1997年 - 他發現了最快速的計算圓周率的算法。
2000年 - 他化名Gérard Lantau,建立了 FFmpeg 項目。
2004年 - 他編寫了一個只有138KB的啓動加載程序TCCBOOT,能夠在15秒內從源代碼編譯並啓動Linux系統。
2009年 - 他聲稱打破了圓周率計算的世界紀錄,算出小數點後2.7萬億位,僅用一臺普通PC機。
2011年 - 他單用JavaScript寫了一個PC虛擬機Jslinux,實現能在瀏覽器裏跑Linux 。



3,FFmpeg 項目的組成

(1)基本:

  • ffmpeg :是一個命令行工具,用來對視頻文件轉換格式;
  • ffsever :是一個HTTP多媒體實時廣播流服務器;
  • ffplay :是一個簡單的播放器,使用ffmpeg 庫解析和解碼,經過SDL顯示;

(2)其它:

  • libavutil :包含一些公共的工具函數;
  • libavcodec :用於各類類型聲音/圖像編解碼;
  • libswscale :用於視頻場景比例縮放、色彩映射轉換;
  • libpostproc :用於後期效果處理;
  • libavformat :用於音視頻封裝格式的生成和解析, 包括獲取解碼所需信息以生成解碼上下文結構和讀取音視頻幀等功能。

4,FFmpeg 的使用方式 (FFmpeg 代碼是包括兩部分)

(1)一部分是library

  • 直接調用靜態庫,c語言的文件。
  • API 都是在library ,若是直接調 api 來操做視頻的話,就須要寫c或者c++了。

(2)一部分是 Tool

  • 使用的是命令行,則不須要本身去編碼來實現視頻操做的流程,實際上tool就是把命令行轉換爲api的操做,不須要使用者懂C++。

本篇文章實踐部分,主要是使用 Tool 命令方式。


2、 FFmpeg 的編譯

1. 介紹

  • FFmpeg是一個多平臺多媒體處理工具,因此也能夠在Mac下運行,先說一下Mac下如何安裝FFmpeg。

2. 相關地址

3. 編譯Mac下可用 FFmpeg

  • 編譯Mac下可用 FFmpeg,主要是能夠在mac中,使用 FFmpeg 進行操做視頻等。

Homebrew介紹

  • 簡稱brew,是Mac OSX上的軟件包管理工具,能在Mac中方便的安裝軟件或者卸載軟件。

Homebrew安裝

Homebrew命令

  • 搜索軟件:brew search 軟件名, 如brew search wget
  • 安裝軟件:brew install 軟件名, 如brew install wget
  • 卸載軟件:brew remove 軟件名,如brew remove wget

經過Homebrew 安裝 FFmpeg

  • 終端執行:執行 brew install ffmpeg --with-libvpx --with-libvorbis --with-ffplay

  • 在終端中執行一下命令,等待安裝完成便可:

 
  1. ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

  2.  
  • 安裝好Homebrew,而後終端執行 "brew install ffmpeg",等待完成便可。

  • 執行結束,在終端中輸入ffmpeg,驗證是否安裝成功。

  • 若是顯示大概如上圖,那麼說明安裝成功

4. 編譯 iOS 下 FFmpeg

  • 主要是用於iOS下進行使用FFmpeg

在進行編譯以前,咱們首先須要作一些準備工做安裝必備文件:

(1)安裝 gas-preprocessor

  • 後面運行 FFmpeg-iOS-build-script 這個自動編譯腳本須要 gas-preprocessor .

  • 安裝步驟(依次執行下面命令):

 
  1. sudo git clone https://github.com/bigsen/gas-preprocessor.git /usr/local/bin/gas

  2. sudo cp /usr/local/bin/gas/gas-preprocessor.pl /usr/local/bin/gas-preprocessor.pl

  3. sudo chmod 777 /usr/local/bin/gas-preprocessor.pl

  4. sudo rm -rf /usr/local/bin/gas/

(2)安裝 yams

  • yasm是彙編編譯器,由於ffmpeg中爲了提升效率用到了彙編指令,因此編譯時須要安裝

  • 安裝步驟(依次執行下面命令):

 
  1. curl http://www.tortall.net/projects/yasm/releases/yasm-1.2.0.tar.gz -o yasm-1.2.0.gz

  2. tar -zxvf yasm-1.2.0.gz

  3. cd yasm-1.2.0

  4. ./configure && make -j 4 && sudo make install

(3)配置 FFmpeg 編譯腳本

1. 說明:

  • 編譯FFmpeg可以使用一個腳本:FFmpeg-iOS-build-script.sh。
  • FFmpeg-iOS-build-script 是一個外國人寫的自動編譯的腳本,腳本則會自動從github中把ffmpeg源碼下到本地並開始編譯出iOS可用的庫,支持各類架構。
手動編譯FFmpeg網上有一些方法,可是稍顯複雜而陳舊, 因此使用這個腳本比較方便。

2. 腳本下載地址:

git clone https://github.com/kewlbear/FFmpeg-iOS-build-script.git

3. 配置FFmpeg版本:

  • 下載完成後咱們可指定編譯的FFmpeg版本,修改 FF_VERSION 後面的參數就好了,本篇文章使用2.8版本。

配置裁剪(可選項):

FFmpeg庫是一個很是龐大的庫,包括編碼,解碼以及流媒體的支持等,若是不作裁剪所有編譯進來的話,最後生成的靜態庫會很大。而且有不少不須要的東西,均可以禁止掉。

1. 配置裁剪方法:

修改配置 build-ffmpeg.sh 腳本里面 CONFIGURE_FLAGS 後面的內容便可
例如:

配置的一些參數是爲了更好的選擇本身須要的功能,進行精簡和優化ffmpeg。
咱們能夠手動看一下,在ffmpeg源碼目錄下,終端執行 ./configure --help列出所有參數 。下面簡單列出部分參數:

標準選項參數

 
  1. --help : // 打印幫助信息 ./configure --help > ffmpegcfg.txt

  2. --prefix=PREFIX :// 安裝程序到指定目錄[默認:空]

  3. --bindir=DIR : // 安裝程序到指定目錄[默認:/bin]

  4. --datadir=DIR :// 安裝數據文件到指定目錄[默認:/share/ffmpeg]

  5. --incdir=DIR :// 安裝頭文件到指定目錄[默認:/include]

  6. --mandir=DIR :// 安裝man page到指定路徑[默認:/share/man]

2. 配置選項參數

 
  1. --disable-static :// 不構建靜態庫[默認:關閉]

  2. --enable-shared :// 構建共享庫

  3. --enable-gpl : // 容許使用GPL代碼。

  4. --enable-nonfree :// 容許使用非免費代碼。

  5. --disable-doc : // 不構造文檔

  6. --disable-avfilter :// 禁止視頻過濾器支持

  7. --enable-small : // 啓用優化文件尺寸大小(犧牲速度)

  8. --cross-compile : // 使用交叉編譯

  9. --disable-hwaccels :// 禁用全部硬件加速(本機不存在硬件加速器,全部不須要)

  10. --disable-network :// 禁用網絡

 
  1. --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-ffserver

  2. // 禁止ffmpeg、ffplay、ffprobe、ffserver

  3.  
  4. --disable-avdevice --disable-avcodec --disable-avcore

  5. // 禁止libavdevice、libavcodec、libavcore

 
  1. --list-decoders : // 顯示全部可用的解碼器

  2. --list-encoders : // 顯示全部可用的編碼器

  3. --list-hwaccels : // 顯示全部可用的硬件加速器

  4. --list-protocols : // 顯示全部可用的協議

  5. --list-indevs : // 顯示全部可用的輸入設備

  6. --list-outdevs : // 顯示全部可用的輸出設備

  7. --list-filters :// 顯示全部可用的過濾器

  8. --list-parsers :// 顯示全部的解析器

  9. --list-bsfs : // 顯示全部可用的數據過濾器

 
  1. --disable-encoder=NAME : // 禁用XX編碼器 | disables encoder NAME

  2. --enable-encoder=NAME : // 用XX編碼器 | enables encoder NAME

  3. --disable-decoders : // 禁用全部解碼器 | disables all decoders

  4.  
  5. --disable-decoder=NAME : // 禁用XX解碼器 | disables decoder NAME

  6. --enable-decoder=NAME : // 啓用XX解碼器 | enables decoder NAME

  7. --disable-encoders : // 禁用全部編碼器 | disables all encoders

  8.  
  9. --disable-muxer=NAME : // 禁用XX混音器 | disables muxer NAME

  10. --enable-muxer=NAME : // 啓用XX混音器 | enables muxer NAME

  11. --disable-muxers : // 禁用全部混音器 | disables all muxers

  12.  
  13. --disable-demuxer=NAME : // 禁用XX解軌器 | disables demuxer NAME

  14. --enable-demuxer=NAME : // 啓用XX解軌器 | enables demuxer NAME

  15. --disable-demuxers : // 禁用全部解軌器 | disables all demuxers

  16.  
  17. --enable-parser=NAME : // 啓用XX剖析器 | enables parser NAME

  18. --disable-parser=NAME : // 禁用XX剖析器 | disables parser NAME

  19. --disable-parsers : // 禁用全部剖析器 | disa

運行腳本生成 FFmpeg:

配置好選項參數後就能夠運行腳本,等待生成FFmpeg庫。

運行完畢就會生成:

  • ffmpeg-2.八、FFmpeg-iOS 、scratch、thin 等這些文件夾。

  • lib:對應的 FFmpeg 靜態庫

     

  • include:對應的 FFmpeg 頭文件

     

3、iOS 下 集成 FFmpeg

生成完FFmpeg庫與代碼後,咱們就能夠集成到iOS項目中進行使用

1,新建一個空項目,在Link Binary With Libraries 裏添加

  • libz.tbd
  • libbz2.tbd
  • libiconv.tbd
  • CoreMedia.framework
  • VideoToolbox.framework
  • AVFoundation.framework

2,導入庫文件

(1)將目錄下的 include 和 lib文件夾 拖拽進項目中。
(2)設置 Header Search Paths 路徑,指向 項目中include目錄 。
例如:

$(SRCROOT)/FFmpeg_iOS/FFmpeg/include

(3)而後導入 #import "avformat.h" 在代碼中 寫 av_register_all() 而後進行編譯,若是沒有報錯,表明編譯成功。

4、iOS 運行 FFmpeg Tool

(1)到這一步其實已經可使用library庫了,若是要對音視頻進行操做,須要手動寫C++代碼去調用 API 使用FFmpeg。

(2)若是想要使用Tool工具來調用 FFmpg 的話,就是直接經過調用傳參的方式執行ffmpeg 命令的話,就須要:

  • 把剩下的 ffmpeg.h ffmpeg.c 等依賴的文件拖進項目中,並導入ffmpeg.h 文件。
  • 而後進行調用 ffmpeg_main 函數傳遞參數,執行 ffmpeg 命令便可。

FFmpeg Tool 相關文件:

  • ffmpeg.c
  • ffmpeg.h
  • ffmpeg_opt.c
  • ffmpeg_filter.c
  • cmdutils.c
  • cmdutils.h
  • cmdutils_common_opts.h

  • config.h 文件 (在scratch目錄下四個文件都有 ):

示例 - 拖入對應文件到工程

註釋掉無關代碼:

  • 若是把相關其餘文件導入後,編譯的時候會發現有一些頭文件好比 <avutil/internal.h>找不到。
    不用擔憂,在我瞭解到 應該是 在 iOS 的 arm下不支持,也就不須要了。
  • 那麼這時候只須要把報紅的地方註釋掉就好了,另外若是精簡掉某些庫,那麼依賴的類文件也會找不到,也是直接註釋掉相關報錯沒問題的。

頭文件

 
  1. #include "compat/va_copy.h"

  2. #include "libavresample/avresample.h"

  3. #include "libpostproc/postprocess.h"

  4. #include "libavutil/libm.h"

  5. #include "libavutil/time_internal.h"

  6. #include "libavutil/internal.h"

  7. #include "libavutil/libm.h"

  8. #include "libavformat/network.h"

  9. #include "libavcodec/mathops.h"

  10. #include "libavformat/os_support.h"

宏定義調用

FF_DISABLE_DEPRECATION_WARNINGS

函數調用

 
  1. nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0],

  2. ost->last_nb0_frames[1],

  3. ost->last_nb0_frames[2]);

  4.  
  5. ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n",

  6. ost->forced_keyframes_expr_const_values[FKF_N],

  7. ost->forced_keyframes_expr_const_values[FKF_N_FORCED],

  8. ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N],

  9. ost->forced_keyframes_expr_const_values[FKF_T],

  10. ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T],

  11. res);

  12.  
  13. PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);

  14. PRINT_LIB_INFO(postproc, POSTPROC, flags, level);

其它

 
  1. { "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" },

  2.  
  3. { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },

解決導入後編譯問題:

  • GIF文件大小有限制,分開上傳了

(1)解決編譯問題1:

  •  

(2)解決編譯問題2:

若是提示如下錯誤,還需註釋如下代碼

 
  1. { "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" },

  2.  
  3. { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },

(3)解決main函數重複問題

FFmpeg也有個main函數,若是不更名就會衝突報錯。

  • 打開 ffmpeg.c 文件,找到main函數,修改成 ffmpeg_main。
  • 並在 ffmpeg.h 中聲明。

5、優化解決集成後問題

這個時候,咱們應該已經可否編譯成功了,可是還有一些小問題,須要修改下。

1. 計數器置零問題 (ffmpeg.c的代碼中會訪問空屬性致使程序崩潰)

  • 解決方法:
  • 在 ffmpeg.c 中 找到 ffmpeg_cleanup 方法,在 term_exit() 前,將各個計數器置零:
 
  1. nb_filtergraphs=0;

  2. nb_output_files=0;

  3. nb_output_streams=0;

  4. nb_input_files=0;

  5. nb_input_streams=0;

  • 以下圖:

2. 命令執行結束崩潰問題

說明

  • FFmpeg 默認執行完會執行 exit_program 方法結束進程,而iOS下只能啓動一個進程,若是默認不作處理,執行完一條命令後app就自動退出了,因此須要作一個處理。

解決方案有兩種:

(1)第一種方案(有缺點):

  • 網上流傳的方法的方法都是找到 exit_program 函數,而後註釋掉結束進程的代碼,而後調用 pthread_exit 結束線程來代替結束進程,進行解決。

這種方法的缺點:

  • 執行完 ffmpeg 的 main 函數後會回調一個code,這個回調是用於判斷命令指定過程當中是否執行錯誤的回調。可是咱們若是在退出的時候調用了pthread_exit 這樣線程就結束了,而後也不會走執行是否成功的回調了。
  • 而且這樣的話,想要監聽到命令結束,必需要註冊一個通知,進行監聽線程結束。

(2)第二種方案(修復缺點):

  • 在命令執行完不進行結束線程和進程,只進行 cleanup。

具體作法:

  • 在 ffmpeg.c 的 ffmpeg_main 函數中,把全部調用 exit_program 函數 ,改成調用 ffmpeg_cleanup 函數就能夠了。

     

6、iOS 調用 FFmpeg Tool

目前爲止,咱們作完上面全部步驟後,咱們已經能夠調用 FFmpeg Tool 進行各類音視頻操做了,例如 視頻合成、視頻轉Gif、視頻幀操做、視頻特效、格式轉換,視頻調速,等各類操做了。

1. FFmpeg 命令簡單介紹

使用ffmpeg命令行的大體格式以下:

ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

2. FFmpeg 命令常見參數

-f 強制指定編碼格式
-i 輸出源
-t 指定輸入輸出時長
-r 指定幀率,即1S內的幀數
-threads 指定線程數
-c:v 指定視頻的編碼格式
-ss 指定持續時長
-b:v 指定比特率
-s 指定分辨率
-y 覆蓋輸出
-filter 指定過濾器
-vf 指定視頻過濾器
-an 指定去除對音頻的影響











3. FFmpeg 命令示例 (更多使用可查看其它文檔)

 
  1. 格式轉換

  2. ffmpeg -i mkv.mkv -acodec copy -vcodec copy newVideo.mp4

  3. ffmpeg -i wav.wav -ar 44100 -y outputmusic.aac

  4.  
  5. 視頻轉GIF

  6. ffmpeg -i mkv.mkv -ss 00:00:10 -t 10 -pix_fmt rgb24 -f gif -s vga gif.gif

  7.  
  8. 視頻聲音分離 與合成

  9. ffmpeg -i mp4.mp4 -f mp3 -vn mp3.mp3

  10. ffmpeg -i mp4.mp4 -an mp4No.mp4

  11. ffmpeg -i mp3.mp3 -i mp4No.mp4 -map 0:0 -map 1:0 -c:v copy -c:a libfaac sound.mp4

  12.  
  13. 旋轉視頻

  14. ffmpeg -i mp4.mp4 -vf transpose=2 transpose.mp4

  15.  
  16. 反轉視頻

  17. 水平翻轉 :ffmpeg -i mp4.mp4 -vf hflip reversed.mp4

  18. 垂直翻轉 :ffmpeg -i mp4.mp4 -vf vflip reversed.mp4

  19.  
  20. 合併視頻

  21. ffmpeg -f concat -i filelist.txt -y -acodec copy -strict -2 toName

  22.  
  23. 水印字幕合成

  24. ffmpeg -i fromName -i fromOther -filter_complex [0:v][1:v]overlay=0:H-h:enable='between(t,0,1)'[tmp];[tmp][1:v]overlay=0:H-h:enable='between(t,3,4)' -t 7 -y -strict -2 toName

4. iOS 中調用FFmpeg Tool 示例:

(1)第一種調用方式

簡單容易理解,可是麻煩。

 
  1. #import "ViewController.h"

  2. #import "ffmpeg.h"

  3. @interface ViewController ()

  4. @end

  5. @implementation ViewController

  6. - (void)viewDidLoad {

  7. [super viewDidLoad];

  8.  
  9. NSString *fromFile = [[NSBundle mainBundle]pathForResource:@"video.mov" ofType:nil];

  10. NSString *toFile = @"/Users/sen/Desktop/Output/video.gif";

  11.  
  12. int argc = 4;

  13. char **arguments = calloc(argc, sizeof(char*));

  14. if(arguments != NULL)

  15. {

  16. arguments[0] = "ffmpeg";

  17. arguments[1] = "-i";

  18. arguments[2] = (char *)[fromFile UTF8String];

  19. arguments[3] = (char *)[toFile UTF8String];

  20.  
  21. if (!ffmpeg_main(argc, arguments)) {

  22. NSLog(@"生成成功");

  23. }

  24. }

  25. }

  26. @end

(2)第二種調用方式

比第一種方案,遍歷 FFmpeg 字符串命令,而後調用ffmpeg_main 傳遞參數。

 
  1. /**

  2. 第二種調用方式

  3. */

  4. - (void)normalRun2{

  5.  
  6. NSString *fromFile = [[NSBundle mainBundle]pathForResource:@"video.mov" ofType:nil];

  7. NSString *toFile = @"/Users/sen/Desktop/Output/video.gif";

  8.  
  9. NSString *command_str = [NSString stringWithFormat:@"ffmpeg -i %@ %@",fromFile,toFile];

  10.  
  11. // 分割字符串

  12. NSMutableArray *argv_array = [command_str componentsSeparatedByString:(@" ")].mutableCopy;

  13.  
  14. // 獲取參數個數

  15. int argc = (int)argv_array.count;

  16.  
  17. // 遍歷拼接參數

  18. char **argv = calloc(argc, sizeof(char*));

  19.  
  20. for(int i=0; i<argc; i++)

  21. {

  22. NSString *codeStr = argv_array[i];

  23. argv_array[i] = codeStr;

  24. argv[i] = (char *)[codeStr UTF8String];

  25. }

  26.  
  27. ffmpeg_main(argc, argv);

  28. }

結尾

  • 文中Demo:https://github.com/bigsen/FFmpeg_iOS
  • 到目前咱們已經能夠在iOS平臺調用FFmpeg了,更多FFmpeg命令可查看其它相關文章。
  • 後續的話,我會放出一款工具,能夠更方便的調用FFmpeg進行處理命令。
相關文章
相關標籤/搜索