背景
业务需求中有一个需要通过 ffconcat 下载视频文件,完成后进行合并。由于视频文件PTS 都是从0开始的,不能直接下载后直接合并,使用如下命令
ffmpeg -protocol_whitelist "file,http,https,rtp,udp,tcp,tls" -f concat -safe 0 -i 1.ffconcat -vcodec copy -acodec copy tmp.ts
如果是这样能将 ffmpeg 集成到 IJKPlayer 中就方便多了,以后其他的格式也可以使用命令进行转换,非常方便
首先我们要研究一下 IJKPlayer 的编译的配置。
IJKPlayer 编译方式
依赖结构
IJKPlayer 的编译配置参考了Github 上的一个编译脚本,并对其进行了改造。先编译 ffmpeg 的主要代码库 libavcodec ``libavfilter libavformat libavutil libswscale libswresample ,这些代码库的包括了协议支持,封装格式支持,解码器和编码器,支持配置都由主目录下 config 下的 module.sh决定。 IJKPlayer 通过修改 ffplay 的代码和调用 ffmpeg 的库函数(应该还有 SDL 的相关代码,先挖坑)完成播放器的主要功能。所以 ffmpeg 这一层是可以自行编译更换的。
下载后看一下目录:
....├── android├── compile-android-j4a.sh├── config├── doc├── extra├── ijkmedia├── ijkprof├── init-android-exo.sh├── init-android-j4a.sh├── init-android-libsoxr.sh├── init-android-libyuv.sh├── init-android-openssl.sh├── init-android-prof.sh├── init-android-soundtouch.sh├── init-android.sh├── init-config.sh├── init-ios-openssl.sh├── init-ios.sh├── ios├── tools└── version.sh
关键的为 init-ios.sh 和 iOS 目录。
编译和配置的大致流程
- 执行
./init-ios.sh获取代码 - 修改 config 下的
module.sh配置,支持或者关闭一些解码器,编码器,库等 - cd 到
ios目录下执行./compile-ffmpeg.sh all进行代码编译 - 完成后到
ios/build目录下可以看到编译后的结果。./compile-ffmpeg.sh实际是调用的ios/tool/do-compile-ffmpeg.sh脚本,该脚本最后根据编译参数调用make。
例如
如果想打开硬解码编译,除了配置
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-audiotoolbox"export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-videotoolbox"
还需要改变一下支持系统版本,这个修改在ios/tool/do-compile-ffmpeg.sh 中,搜索一下 FF_XCRUN_OSVERSION将系统版本改为8.0。
每次编译后 ios/tool/do-compile-ffmpeg.sh 判断对应编译目录下(如 ios/ffmpeg-arm64)下有没有 config.h文件,如果有会直接用之前编译后的文件,所以如果修改了 config/module.sh需要使用 ./compile-ffmpeg.sh clean 后重新编译。
编译增加库
除此之外还有其他库如果需要参与编译,也可以在 module.sh文件下找到如libavdevice默认不参与编译是由编译选择决定的
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avdevice"
如果需要参与编译设置为 --enable-avdevice 配合脚本 complie-ffmpeg.sh 中 FF_LIBS 来决定编译。 修改 iOS\compile-ffmpeg.h 中 FF_LIBS 变量增加 libavdevice 在编译后的产物里就可以找到libavdevice.a文件。
配置 ffmpeg
请勿误解这里的 ffmpeg 不是指的 ffmpeg 的库,而是 ffmpeg 的执行文件。我们经常用 ffmpeg -i xxx做一些事情。新建一个空工程,将 ios/build/的头文件和静态编译库加入工程中,将 Build Setting中Header Search Paths 添加搜索目录 $(PROJECT_DIR)/iOSffmpeg/ffmpeg/include, 这里根据你的情况具体添加。
编译 ffmpeg
在 ios/ffmpeg-arm64 目录下将 fftools添加到项目中,删除 ffprobe.c 和 ffplay.c 文件,其他多余的文件也可以删除。将 ffmpeg.c 中的 main函数修改为ffmain, 并暴露到头文件。
尝试进行编译,当缺少头文件后到原来 ios/ffmpeg-arm64对应的目录下进行查找放入相应的库中。一部分代码可以注释掉,由于不引进 libpostproc库(应该是视频后期处理的一个库,挖坑)可以先删除。注释cmdutils.c目录下 **staticvoid**print_all_libs_info(**int** flags, **int** level) 的最后一句话
static void print_all_libs_info(int flags, int level){PRINT_LIB_INFO(avutil, AVUTIL, flags, level);PRINT_LIB_INFO(avcodec, AVCODEC, flags, level);PRINT_LIB_INFO(avformat, AVFORMAT, flags, level);PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level);PRINT_LIB_INFO(avfilter, AVFILTER, flags, level);PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);PRINT_LIB_INFO(swscale, SWSCALE, flags, level);PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level);//We not need this lib// PRINT_LIB_INFO(postproc, POSTPROC, flags, level);}
注释掉引入的额外文件
//#include "compat/va_copy.h"//#include "libpostproc/postprocess.h"
添加系统库 AudioToolBox.framwork VideoToolbox.framwork AVFoundation.framwork CoreMedia.framwork libbz2 libz libiconv。
尝试编译应该就能通过了。
修改退出代码
ffmpeg 由于大多数是进程模式执行,所以在 main 方法下有很多退出的代码,我们需要进行修改后才能在 iOS 下运行。修改的基本思路是保留出错的日志,将退出代码改为 return + 相应的错误即可。具体的内容可以查看 demo。
总结
- 使用
./init-ios.sh获取代码,修改支持的编解码库config/module.sh - 修改
complie-ffmpeg.sh库中FF_LIBS支持增加的库 - 如果遇到 iOS SDK 版本过低的问题修改
ios/tool/do-compile-ffmpeg.sh中FF_XCRUN_OSVERSION字段 - 增加 Xcode 的
Header Search Paths保证可以编译到代码 - 将
fftools下的代码移动到库中,根据编译情况修改部分代码
最后就可以得到支持当前 IJKPlayer 的ffmpeg库。
文章参考
