zoukankan      html  css  js  c++  java
  • Xcode-FFmpeg环境搭建


    ## 集成FFmpeg
    主要分为量大块,按需将相关的库导入到工程中,补充缺失的头文件
    ## 编译FFmpeg
    以iOS为例
    需要指定平台,Xcode信息,root sdk路径,编译工具链,支持的arch,输出路径,等参数.这里推荐一份完成的脚本,如果自己编译碰到问题可以参考这个脚本[FFmpeg-iOS-build-script](https://github.com/kewlbear/FFmpeg-iOS-build-script)



    执行`./build-ffmpeg.sh`,会自动抓去依赖`yasm:1.2.0`,`FFmpeg 4.3.1`,`gas-preprocessor.pl`然后编译生成`FFmpeg-iOS `文件夹,内容如下:
    ```shell
    ├── include
    │   ├── libavcodec //用于各种类型声音、图像编解码;
    │   ├── libavdevice //与系统输入输出设备交互,读取和写入多媒体数据
    │   ├── libavfilter //实现滤镜效果,可以用其做一些音视频处理,如音视频倍速、水平翻转、裁剪、加方框、叠加文字等功能。
    │   ├── libavformat //用于各种音视频封装格式的生成和解析
    │   ├── libavutil //包含一些公共的工具函数
    │   ├── libswresample //音频重采样、rematrixing和样本格式转换操作
    │   └── libswscale //视频场景比例缩放、色彩映射转换;
    └── lib
    ├── libavcodec.a
    ├── libavdevice.a
    ├── libavfilter.a
    ├── libavformat.a
    ├── libavutil.a
    ├── libswresample.a
    └── libswscale.a
    ```
    ## 将FFmpeg-iOS集成到iOS工程中
    以Swift项目为例子说明
    创建并设置`bridge-header.h`,设置工程`Objective-Bridge-Header`的路径
    ```shell
    #ifndef bridge_h
    #define bridge_h
    #include <libavcodec/avcodec.h>
    #include <libavdevice/avdevice.h>
    #include <libavfilter/avfilter.h>
    #include <libavformat/avformat.h>
    #include <libavutil/avutil.h>
    #include <libswresample/swresample.h>
    #include <libswscale/swscale.h>
    #endif /* bridge_h */
    ```
    设置`User Search Path`
    添加依赖库
    ```shell
    * libz.dylib
    * libbz2.dylib
    * libiconv.dylib
    ```
    添加测试代码,根据编译结果添加对应的系统库
    ```Swift
    class ViewController: UIViewController {
    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    avdevice_register_all()
    avcodec_configuration()
    }
    }
    ```
    错误信息会提示类或者属性无法找到,根据前缀添加系统库,下面是完整的依赖库
    ```shell
    AudioToolbox.framework
    VideoToolbox.framework
    CoreAudio.framework
    CoreVideo.framework
    AVFoundation.framework
    CoreMedia.framework
    libz.tbd
    ibiconv.tbd
    libbz2.tbd
    ```
    点击运行,若失败则需检查前面的步骤是否遗漏,亲测有效
    ## 集成FFmpeg命令行工具(可选)
    此步骤可以将我们在终端命令行的`ffmpeg`命令传入到`ffmepg.h`的`main`函数中,可以同通过封装一套统一的协议api,输入参数到`main`函数中,然后输出文件
    向工程中添加`ffmpeg`工具链main文件相关的类,并加`.c`文件添加到编译的build phase中
    ```shell
    ├── cmdutils.c
    ├── cmdutils.h
    ├── config.h
    ├── ffmpeg.c
    ├── ffmpeg.h
    ├── ffmpeg_filter.c
    ├── ffmpeg_opt.c
    └── ffmpeg_videotoolbox.c
    ```
    ## 集成FFmpeg命令行-CONFIGURE_FLAGS设置
    需要重新编译新的`FFmpeg`库,将`--disable-programs` flags关闭,运行通过命令行参数调用.
    为了解决ffmpeg命令行依赖`libpostproc.a`库, 需要添加 `--enable-gpl` flags,网上看了很多博客都没有提到这,最后在全局搜索关键字`LICENSE`文件中发现了这样一段话
    ```shell
    None of
    these parts are used by default, you have to explicitly pass `--enable-gpl` to
    configure to activate them. In this case, FFmpeg's license changes to GPL v2+.
    Specifically, the GPL parts of FFmpeg are:
    - libpostproc
    ...
    ```
    大致意识就是如果你需要build这个库文件,需要指定`--enable-gpl`,但是FFmpeg的license将会变更成`GPL v2+`




    最终确认在`ffmpeg-build.sh`中将`CONFIGURE_FLAGS`设定为如下选项
    ```shell
    CONFIGURE_FLAGS="
    --enable-cross-compile
    --disable-debug
    --enable-gpl
    --disable-doc --enable-pic"
    #--disable-programs
    ```
    得出的编译产物如下,相比原来多了一个库`libpostproc.a`
    ```shell
    ├── include
    │ ├── libavcodec
    │ ├── libavdevice
    │ ├── libavfilter
    │ ├── libavformat
    │ ├── libavresample
    │ ├── libavutil
    │ ├── libpostproc
    │ ├── libswresample
    │ └── libswscale
    └── lib
    ├── libavcodec.a
    ├── libavdevice.a
    ├── libavfilter.a
    ├── libavformat.a
    ├── libavresample.a
    ├── libavutil.a
    ├── libpostproc.a
    ├── libswresample.a
    └── libswscale.a
    ```
    ## 集成FFmpeg命令行-缺失头文件补充
    集成新的`FFmpeg`之后运行工程,根据错误提示,按路径添加缺失的头文件`.h`
    根据如下类似的提示信息在`ffmpeg`库中搜索头文件并添加到工程中
    ```shell
    Showing All Messages
    /Users/qxq4633/ffmpegdemo/ffmpeg_demo/ffmpeg/ffmpeg.h:22:10: 'config.h' file not found
    ```
    最终完整的头文件如下,亲测有效, ffmpeg版本`4.3.1`,`Xcode 12`, `iOS 14.0`
    ```shell
    qxq4633@LSCN897187 ffmpeg_demo % tree -L 4
    .
    ├── FFmpeg-iOS
    │   ├── include
    │   │   ├── libavcodec
    │   │   │   ├── ac3_parser.h
    │   │   │   ├── adts_parser.h
    │   │   │   ├── avcodec.h
    │   │   │   ├── avdct.h
    │   │   │   ├── avfft.h
    │   │   │   ├── bsf.h
    │   │   │   ├── codec.h
    │   │   │   ├── codec_desc.h
    │   │   │   ├── codec_id.h
    │   │   │   ├── codec_par.h
    │   │   │   ├── d3d11va.h
    │   │   │   ├── dirac.h
    │   │   │   ├── dv_profile.h
    │   │   │   ├── dxva2.h
    │   │   │   ├── jni.h
    │   │   │   ├── mathops.h
    │   │   │   ├── mediacodec.h
    │   │   │   ├── packet.h
    │   │   │   ├── qsv.h
    │   │   │   ├── vaapi.h
    │   │   │   ├── vdpau.h
    │   │   │   ├── version.h
    │   │   │   ├── videotoolbox.h
    │   │   │   ├── vorbis_parser.h
    │   │   │   ├── x86
    │   │   │   └── xvmc.h
    │   │   ├── libavdevice
    │   │   │   ├── avdevice.h
    │   │   │   └── version.h
    │   │   ├── libavfilter
    │   │   │   ├── avfilter.h
    │   │   │   ├── buffersink.h
    │   │   │   ├── buffersrc.h
    │   │   │   └── version.h
    │   │   ├── libavformat
    │   │   │   ├── avformat.h
    │   │   │   ├── avio.h
    │   │   │   ├── os_support.h
    │   │   │   └── version.h
    │   │   ├── libavresample
    │   │   │   ├── avresample.h
    │   │   │   └── version.h
    │   │   ├── libavutil
    │   │   │   ├── adler32.h
    │   │   │   ├── aes.h
    │   │   │   ├── aes_ctr.h
    │   │   │   ├── attributes.h
    │   │   │   ├── audio_fifo.h
    │   │   │   ├── avassert.h
    │   │   │   ├── avconfig.h
    │   │   │   ├── avstring.h
    │   │   │   ├── avutil.h
    │   │   │   ├── base64.h
    │   │   │   ├── blowfish.h
    │   │   │   ├── bprint.h
    │   │   │   ├── bswap.h
    │   │   │   ├── buffer.h
    │   │   │   ├── camellia.h
    │   │   │   ├── cast5.h
    │   │   │   ├── channel_layout.h
    │   │   │   ├── common.h
    │   │   │   ├── cpu.h
    │   │   │   ├── crc.h
    │   │   │   ├── des.h
    │   │   │   ├── dict.h
    │   │   │   ├── display.h
    │   │   │   ├── dovi_meta.h
    │   │   │   ├── downmix_info.h
    │   │   │   ├── encryption_info.h
    │   │   │   ├── error.h
    │   │   │   ├── eval.h
    │   │   │   ├── ffversion.h
    │   │   │   ├── fifo.h
    │   │   │   ├── file.h
    │   │   │   ├── frame.h
    │   │   │   ├── hash.h
    │   │   │   ├── hdr_dynamic_metadata.h
    │   │   │   ├── hmac.h
    │   │   │   ├── hwcontext.h
    │   │   │   ├── hwcontext_cuda.h
    │   │   │   ├── hwcontext_d3d11va.h
    │   │   │   ├── hwcontext_drm.h
    │   │   │   ├── hwcontext_dxva2.h
    │   │   │   ├── hwcontext_mediacodec.h
    │   │   │   ├── hwcontext_opencl.h
    │   │   │   ├── hwcontext_qsv.h
    │   │   │   ├── hwcontext_vaapi.h
    │   │   │   ├── hwcontext_vdpau.h
    │   │   │   ├── hwcontext_videotoolbox.h
    │   │   │   ├── hwcontext_vulkan.h
    │   │   │   ├── imgutils.h
    │   │   │   ├── internal.h
    │   │   │   ├── intfloat.h
    │   │   │   ├── intreadwrite.h
    │   │   │   ├── lfg.h
    │   │   │   ├── libm.h
    │   │   │   ├── log.h
    │   │   │   ├── lzo.h
    │   │   │   ├── macros.h
    │   │   │   ├── mastering_display_metadata.h
    │   │   │   ├── mathematics.h
    │   │   │   ├── md5.h
    │   │   │   ├── mem.h
    │   │   │   ├── motion_vector.h
    │   │   │   ├── murmur3.h
    │   │   │   ├── opt.h
    │   │   │   ├── parseutils.h
    │   │   │   ├── pixdesc.h
    │   │   │   ├── pixelutils.h
    │   │   │   ├── pixfmt.h
    │   │   │   ├── random_seed.h
    │   │   │   ├── rational.h
    │   │   │   ├── rc4.h
    │   │   │   ├── replaygain.h
    │   │   │   ├── reverse.h
    │   │   │   ├── ripemd.h
    │   │   │   ├── samplefmt.h
    │   │   │   ├── sha.h
    │   │   │   ├── sha512.h
    │   │   │   ├── spherical.h
    │   │   │   ├── stereo3d.h
    │   │   │   ├── tea.h
    │   │   │   ├── thread.h
    │   │   │   ├── threadmessage.h
    │   │   │   ├── time.h
    │   │   │   ├── timecode.h
    │   │   │   ├── timestamp.h
    │   │   │   ├── tree.h
    │   │   │   ├── twofish.h
    │   │   │   ├── tx.h
    │   │   │   ├── version.h
    │   │   │   ├── video_enc_params.h
    │   │   │   ├── x86
    │   │   │   └── xtea.h
    │   │   ├── libpostproc
    │   │   │   ├── postprocess.h
    │   │   │   └── version.h
    │   │   ├── libswresample
    │   │   │   ├── swresample.h
    │   │   │   └── version.h
    │   │   └── libswscale
    │   │   ├── swscale.h
    │   │   └── version.h
    │   └── lib
    │   ├── libavcodec.a
    │   ├── libavdevice.a
    │   ├── libavfilter.a
    │   ├── libavformat.a
    │   ├── libavresample.a
    │   ├── libavutil.a
    │   ├── libpostproc.a
    │   ├── libswresample.a
    │   └── libswscale.a
    ├── LICENSE
    ├── README.en.md
    ├── README.md
    ├── compat
    │   └── va_copy.h
    ├── config.h
    ├── ffmpeg
    │   ├── cmdutils.c
    │   ├── cmdutils.h
    │   ├── ffmpeg.c
    │   ├── ffmpeg.h
    │   ├── ffmpeg_filter.c
    │   ├── ffmpeg_hw.c
    │   ├── ffmpeg_opt.c
    │   └── ffmpeg_videotoolbox.c
    ```
    ## 集成FFmpeg命令行-验证ffmpeg输入指令



    ```swift
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
     
    // self.navigationController?.pushViewController(SwiftPointViewController(), animated: true)
    let inputFile = "/Users/qxq4633/ffmpegdemo/ffmpeg_demo/ffmpeg_demo/resoures/input.mov";
     
    let outputFilePath = "/Users/qxq4633/ffmpegdemo/ffmpeg_demo/ffmpeg_demo/resoures/output2.webm";
     
    let arguments = [ "ffmpeg","-i",inputFile]
    let arr = UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>.allocate(capacity: arguments.count)
     
    for index in 0..<arguments.count {
    arr[index] = UnsafeMutablePointer<Int8>.init(mutating: (arguments[index] as NSString).utf8String)
    }
    print("======== start call ffmpeg async ========")
    DispatchQueue.global().async {
    print("======== ffmpeg_main start ========")
    ffmpeg_main(Int32(arguments.count), arr)
    print("======== ffmpeg_main end and call back result ========")
    }
    print("======== handler other logic ========")
     
    }
    ```
    ## 集成FFmpeg命令行-exit_program相关bug修复
    在运行中碰到诸多错误,由于`exit_program`函数推出时会卡住当前线程,所以需要将此函数设置返回值
    ```shell
    int exit_program(int ret)
    {
    // if (program_exit)
    // program_exit(ret);
    //exit(ret);
    return ret; //TODO: fix thread not exit
    }
    ```
    退出时需要释放野指针
    ```shell
    ffmpeg_exited = 1;
    //TODO: fix unsafe pointee
    ffmpeg_exited = 1;
    nb_filtergraphs = 0;
    nb_output_files = 0;
    nb_output_streams = 0;
    nb_input_files = 0;
    nb_input_streams = 0;
    ```
    我这个例子是打印文件信息的,没有指定output,默认的print函数会检查输出文件,需要修改此处崩溃
    ```shell
    static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time) { ...
    //TODO: Fix out put files not assiged
    if (output_files == NULL){
    return;
    }
    ```
    由于我们强制修改退出条件,在overrite文件时需要提前做清除
    ```shell
    static void assert_file_overwrite(const char *filename)
    {
     
    avpriv_io_delete(filename); //TODO: fix frozen
    ```
    这里也设置到返回值没有设定,需要增加返回值
    ```shell
    static int opt_init_hw_device(void *optctx, const char *opt, const char *arg)
    {
    if (!strcmp(arg, "list")) {
    enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
    printf("Supported hardware device types: ");
    while ((type = av_hwdevice_iterate_types(type)) !=
    AV_HWDEVICE_TYPE_NONE)
    printf("%s ", av_hwdevice_get_type_name(type));
    printf(" ");
    return exit_program(0); //TODO: fix none return
    } else {
    return hw_device_init_from_string(arg, NULL);
    }
    }
    ```
    以上就是通过Xcode执行`ffmpeg -i input.mov` 查看文件信息的全过程
    ## 集成FFmpeg命令行-执行顺序
    控制台打印结果如下,在同一个线程中可以看到`ffmpeg_main`函数是同步执行的. 所以基于此方法我们可以封装一套ffmpeg的命令行接口
    流程如下:
    `prepare arguments` -> `call ffmpeg_main async` -> `return ffmpeg result`
    实际的打印结果也验证了这一点
    ```shell
    ======== start call ffmpeg async ========
    ======== handler other logic ========
    ======== ffmpeg_main start ========
    ffmpeg version 4.3.1 Copyright (c) 2000-2020 the FFmpeg developers
    built with Apple clang version 12.0.0 (clang-1200.0.31.1)
    configuration: --prefix=FFmpeg --disable-shared --enable-static --disable-x86asm
    WARNING: library configuration mismatch
    avutil configuration: --target-os=darwin --arch=x86_64 --cc='xcrun -sdk iphonesimulator clang' --as='gas-preprocessor.pl -- xcrun -sdk iphonesimulator clang' --enable-cross-compile --disable-debug --enable-gpl --disable-doc --enable-pic --extra-cflags='-arch x86_64 -mios-simulator-version-min=8.0' --extra-ldflags='-arch x86_64 -mios-simulator-version-min=8.0' --prefix=/Users/qxq4633/ffmpegdemo/FFmpeg-iOS-build-script/thin/x86_64
    avcodec configuration: --target-os=darwin --arch=x86_64 --cc='xcrun -sdk iphonesimulator clang' --as='gas-preprocessor.pl -- xcrun -sdk iphonesimulator clang' --enable-cross-compile --disable-debug --enable-gpl --disable-doc --enable-pic --extra-cflags='-arch x86_64 -mios-simulator-version-min=8.0' --extra-ldflags='-arch x86_64 -mios-simulator-version-min=8.0' --prefix=/Users/qxq4633/ffmpegdemo/FFmpeg-iOS-build-script/thin/x86_64
    avformat configuration: --target-os=darwin --arch=x86_64 --cc='xcrun -sdk iphonesimulator clang' --as='gas-preprocessor.pl -- xcrun -sdk iphonesimulator clang' --enable-cross-compile --disable-debug --enable-gpl --disable-doc --enable-pic --extra-cflags='-arch x86_64 -mios-simulator-version-min=8.0' --extra-ldflags='-arch x86_64 -mios-simulator-version-min=8.0' --prefix=/Users/qxq4633/ffmpegdemo/FFmpeg-iOS-build-script/thin/x86_64
    avdevice configuration: --target-os=darwin --arch=x86_64 --cc='xcrun -sdk iphonesimulator clang' --as='gas-preprocessor.pl -- xcrun -sdk iphonesimulator clang' --enable-cross-compile --disable-debug --enable-gpl --disable-doc --enable-pic --extra-cflags='-arch x86_64 -mios-simulator-version-min=8.0' --extra-ldflags='-arch x86_64 -mios-simulator-version-min=8.0' --prefix=/Users/qxq4633/ffmpegdemo/FFmpeg-iOS-build-script/thin/x86_64
    avfilter configuration: --target-os=darwin --arch=x86_64 --cc='xcrun -sdk iphonesimulator clang' --as='gas-preprocessor.pl -- xcrun -sdk iphonesimulator clang' --enable-cross-compile --disable-debug --enable-gpl --disable-doc --enable-pic --extra-cflags='-arch x86_64 -mios-simulator-version-min=8.0' --extra-ldflags='-arch x86_64 -mios-simulator-version-min=8.0' --prefix=/Users/qxq4633/ffmpegdemo/FFmpeg-iOS-build-script/thin/x86_64
    swscale configuration: --target-os=darwin --arch=x86_64 --cc='xcrun -sdk iphonesimulator clang' --as='gas-preprocessor.pl -- xcrun -sdk iphonesimulator clang' --enable-cross-compile --disable-debug --enable-gpl --disable-doc --enable-pic --extra-cflags='-arch x86_64 -mios-simulator-version-min=8.0' --extra-ldflags='-arch x86_64 -mios-simulator-version-min=8.0' --prefix=/Users/qxq4633/ffmpegdemo/FFmpeg-iOS-build-script/thin/x86_64
    swresample configuration: --target-os=darwin --arch=x86_64 --cc='xcrun -sdk iphonesimulator clang' --as='gas-preprocessor.pl -- xcrun -sdk iphonesimulator clang' --enable-cross-compile --disable-debug --enable-gpl --disable-doc --enable-pic --extra-cflags='-arch x86_64 -mios-simulator-version-min=8.0' --extra-ldflags='-arch x86_64 -mios-simulator-version-min=8.0' --prefix=/Users/qxq4633/ffmpegdemo/FFmpeg-iOS-build-script/thin/x86_64
    libavutil 56. 51.100 / 56. 51.100
    libavcodec 58. 91.100 / 58. 91.100
    libavformat 58. 45.100 / 58. 45.100
    libavdevice 58. 10.100 / 58. 10.100
    libavfilter 7. 85.100 / 7. 85.100
    libswscale 5. 7.100 / 5. 7.100
    libswresample 3. 7.100 / 3. 7.100
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/qxq4633/ffmpegdemo/ffmpeg_demo/ffmpeg_demo/resoures/input.mov':
    Metadata:
    major_brand : qt
    minor_version : 0
    compatible_brands: qt
    creation_time : 2021-02-05T02:51:34.000000Z
    com.apple.quicktime.make: Apple
    com.apple.quicktime.model: MacBookPro15,1
    com.apple.quicktime.software: Mac OS X 10.15.6 (19G2021)
    com.apple.quicktime.creationdate: 2021-02-05T10:50:55+0800
    Duration: 00:00:26.63, start: 0.000000, bitrate: 2028 kb/s
    Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 766x1334 [SAR 1:1 DAR 383:667], 2015 kb/s, 59.93 fps, 60 tbr, 6k tbn, 12k tbc (default)
    Metadata:
    creation_time : 2021-02-05T02:51:34.000000Z
    handler_name : Core Media Video
    encoder : H.264
    At least one output file must be specified
    Stream mapping:
    Press [q] to stop, [?] for help
    ======== ffmpeg_main end and call back result ========
    ```
    ## 代码地址
    - repo: https://gitee.com/jiodg45/ffmpeg_demo.git
    - feature/add-ffmpeg-command-tool: 包含ffmpeg命令行工具集成
    - master: normal版本,不包含ffmpeg命令行工具集成



    ## 参考文章
    [FFmpeg](https://github.com/FFmpeg/FFmpeg.git)
    [FFmpeg-flutter](https://github.com/tanersener/flutter-ffmpeg.git)
    [FFmpeg-iOS-Scripts](https://github.com/kewlbear/FFmpeg-iOS-build-script.git)
    [在iOS中使用FFmpeg命令](https://blog.csdn.net/wenzfcsdn/article/details/84847534)
  • 相关阅读:
    AI Dropout
    笔记2 区块链
    Visual Studio的下载安装
    第48课 thinkphp5添加商品库
    一个手机号可以注册绑定5个百度网盘,永久2T
    第39-43课 thinkphp5完成商品会员价格功能(后置勾子afterInsert)
    第37课 thinkphp5添加商品基本信息及通过前置钩子上传商品主图 模型事件(勾子函数)
    php中 为什么验证码 必须要开启 ob_clean 才可以显示
    网站同一用户只能在同一个地方登录
    微信小程序第3课 目录结构及小知识点
  • 原文地址:https://www.cnblogs.com/wwoo/p/14539863.html
Copyright © 2011-2022 走看看