FFmpeg笔记(二)

集成FFmpeg

主要分为量大块,按需将相关的库导入到工程中,补充缺失的头文件

编译FFmpeg

以iOS为例
需要指定平台,Xcode信息,root sdk路径,编译工具链,支持的arch,输出路径,等参数.这里推荐一份完成的脚本,如果自己编译碰到问题可以参考这个脚本FFmpeg-iOS-build-script

执行./build-ffmpeg.sh,会自动抓去依赖yasm:1.2.0,FFmpeg 4.3.1,gas-preprocessor.pl然后编译生成FFmpeg-iOS文件夹,内容如下:

├── 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的路径

#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

添加依赖库

* libz.dylib
* libbz2.dylib
* libiconv.dylib

添加测试代码,根据编译结果添加对应的系统库

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        avdevice_register_all()
        avcodec_configuration()
    }
}

错误信息会提示类或者属性无法找到,根据前缀添加系统库,下面是完整的依赖库

AudioToolbox.framework
VideoToolbox.framework
CoreAudio.framework
CoreVideo.framework
AVFoundation.framework
CoreMedia.framework
libz.tbd 
ibiconv.tbd
libbz2.tbd

点击运行,若失败则需检查前面的步骤是否遗漏,亲测有效

集成FFmpeg命令行工具(可选)

此步骤可以将我们在终端命令行的ffmpeg命令传入到ffmepg.hmain函数中,可以同通过封装一套统一的协议api,输入参数到main函数中,然后输出文件

向工程中添加ffmpeg工具链main文件相关的类,并加.c文件添加到编译的build phase中

├── 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文件中发现了这样一段话

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设定为如下选项

CONFIGURE_FLAGS="\
--enable-cross-compile \
--disable-debug \
--enable-gpl \
--disable-doc --enable-pic"
#--disable-programs \

得出的编译产物如下,相比原来多了一个库libpostproc.a

├── 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库中搜索头文件并添加到工程中

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

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输入指令

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函数推出时会卡住当前线程,所以需要将此函数设置返回值

int exit_program(int ret)
{
//    if (program_exit)
//        program_exit(ret);

    //exit(ret);
    return  ret; //TODO: fix thread  not exit
}

退出时需要释放野指针

   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函数会检查输出文件,需要修改此处崩溃

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文件时需要提前做清除

static void assert_file_overwrite(const char *filename)
{
    
    avpriv_io_delete(filename); //TODO: fix frozen

这里也设置到返回值没有设定,需要增加返回值

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:\n");
        while ((type = av_hwdevice_iterate_types(type)) !=
               AV_HWDEVICE_TYPE_NONE)
            printf("%s\n", av_hwdevice_get_type_name(type));
        printf("\n");
        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

实际的打印结果也验证了这一点

======== 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
FFmpeg-flutter
FFmpeg-iOS-Scripts
在iOS中使用FFmpeg命令

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值