集成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.h
的main
函数中,可以同通过封装一套统一的协议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("%sn", 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命令
最后
以上就是尊敬柜子最近收集整理的关于FFmpeg笔记(二)的全部内容,更多相关FFmpeg笔记(二)内容请搜索靠谱客的其他文章。
发表评论 取消回复