背景
业务需求中有一个需要通过 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
库。
文章参考