• [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

  • 相关阅读:
    Spring3+hibernate4+struts2整合的 过程中发生如下错误
    使用HQL语句的按照参数名字查询数据库信息的时候 “=:”和参数之间不能存在空格,否则会报错
    org.hibernate.service.classloading.spi.ClassLoadingException: Specified JDBC Driver com.mysql.jdbc.Driver class not found
    Java多线程编程:
    数据库连接池的工作原理
    Oracle数据库表的备份和数据表的删除操作
    数据库连接池
    Mysql登录异常的一个问题:
    2019年终总结
    设计模式入门-简单工厂模式
  • 原文地址:https://www.cnblogs.com/EverNight/p/15843288.html
Copyright © 2020-2023  润新知