[iOS]編譯並集成FFmpeg


一:下載編譯腳本

地址:https://github.com/kewlbear/FFmpeg-iOS-build-script

二:下載並安裝gas-preprocessor

地址:https://github.com/FFmpeg/gas-preprocessor

將文件 gas-preprocessor.pl 復制到 /usr/local/bin

三:編譯文件

1:打開編譯腳本 build-ffmpeg.sh

2:修改版本號(以4.4.1為例)

可以選擇自己需要的版本進行編譯。

版本信息及更新日志:https://ffmpeg.org/download.html

3:修改配置

可以精簡掉一些沒有用到的功能,減少文件體積。

配置選項參考:https://blog.csdn.net/momo0853/article/details/78043903

4:安裝Yams

運行編譯腳本時,會自動安裝Yams,如果安裝失敗,可以手動下載安裝

地址:http://yasm.tortall.net/Download.html

5:運行編譯腳本

./build-ffmpeg.sh arm64 x86_64

參數為需要支持的平台,默認為arm64 armv7 x86_64 i386

等待編譯完成。

四:異常處理

1:xcrun -sdk iphoneos clang is unable to create an executable file.C compiler test failed.

解決方案:

sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/

2:編譯錯誤 unknown type name 'AudioDeviceID'; did you mean 'AudioFileID'?

解決方案:

添加配置參數 --disable-audiotoolbox

參考來源:https://github.com/kewlbear/FFmpeg-iOS-build-script/issues/161

五:集成

1:在Link Binary With Libraries中添加以下文件

libbz2.tbd
libiconv.tbd
libz.tbd
AVFoundation.framework

2:將編譯好的FFmpeg-iOS文件夾拖入項目中

3:添加頭文件路徑

Build Setting -> Search Paths -> Header Search Paths 添加 $(SRCROOT)/$(PRODUCT_NAME)/FFmpeg-iOS/include

4:將 ffmpeg-4.4.1 -> fftools 文件夾中以下文件拖入項目中,在配置文件中禁用功能對應的文件除外

cmdutils.c
cmdutils.h
ffmpeg_filter.c
ffmpeg_hw.c
ffmpeg_opt.c
ffmpeg_videotoolbox.c
ffmpeg.c
ffmpeg.h
ffplay.c
ffprobe.c

5:將 scratch 文件夾下任意一個架構文件夾中的 config.h 文件拖入項目中對應位置

6:將 ffmpeg-4.4.1 -> libavutil -> thread.h 文件拖入項目中對應位置

7:運行程序,注釋掉缺失文件引用

#include "libavresample/avresample.h"
#include "compat/va_copy.h"
#include "libavutil/internal.h"
#include "libpostproc/postprocess.h"
#include "libavutil/libm.h"
#include "libavcodec/mathops.h"
#include "libavformat/os_support.h"

8:注釋掉報錯的代碼

nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0],
                                  ost->last_nb0_frames[1],
                                  ost->last_nb0_frames[2]);

ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n",
        ost->forced_keyframes_expr_const_values[FKF_N],
        ost->forced_keyframes_expr_const_values[FKF_N_FORCED],
        ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N],
        ost->forced_keyframes_expr_const_values[FKF_T],
        ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T],
        res);

PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);

PRINT_LIB_INFO(postproc,   POSTPROC,   flags, level);

9:修改main函數

將 ffmpeg.c 中 int main(int argc, char **argv) 修改為

int ffmpeg_main(int argc, char **argv)

在 ffmpeg.h 中聲明

int ffmpeg_main(int argc, char **argv);

六:優化代碼

1:重置計數器

在 ffmpeg.c 中找到 static void ffmpeg_cleanup(int ret) 方法,在 term_exit() 前添加

static void ffmpeg_cleanup(int ret)
{
    /* ... */
    
    progress_avio       = NULL;
    subtitle_out        = NULL;
    input_files         = NULL;
    input_streams       = NULL;
    output_files        = NULL;
    output_streams      = NULL;
    filtergraphs        = NULL;
    
    nb_input_files      = 0;
    nb_input_streams    = 0;
    nb_output_files     = 0;
    nb_output_streams   = 0;
    nb_filtergraphs     = 0;
    received_sigterm    = 0;
    received_nb_signals = 0;
    
    term_exit();
    ffmpeg_exited = 1;
}

2:防止執行結束退出程序

方法1:在 ffmpeg.c 中找到 int ffmpeg_main(int argc, char **argv) 方法,將其中所有的 exit_program() 替換為 ffmpeg_cleanup()

方法2:在 cmdutils.c 中找到 void exit_program(int ret) ,修改為

int exit_program(int ret)
{
    if (program_exit)
        program_exit(ret);
    
    return ret;
}

在 cmdutils.h 找到對應的聲明,修改為

int exit_program(int ret);

七:調用FFmpeg tool命令

以將m3u8轉為mp4為例

- (void)action
{
    NSString *output = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
                        stringByAppendingPathComponent:@"output.mp4"];
    
    NSString *cmd = [NSString stringWithFormat:@"ffmpeg -i %@ -c:v copy -c:a copy %@",
                     self.url,output];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(run:) object:cmd] start];
}

- (void)run:(NSString *)cmd
{
    NSArray *argvs = [cmd componentsSeparatedByString:@" "];
    int argc = (int)argvs.count;
    char **argv = calloc(argc, sizeof(char *));
    for (int i = 0; i < argc; i++)
    {
        argv[i] = (char *)[argvs[i] UTF8String];
    }
    
    ffmpeg_main(argc, argv);
}

 FFmpeg tool命令格式為

ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...

常用參數

-i 輸入源

-r 幀率

-c:a 音頻編碼格式

-c:v 視頻編碼格式

-b:a 音頻比特率

-b:v 視頻比特率

詳細命令可見官方文檔

地址:https://ffmpeg.org/ffmpeg.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM