环境
- mac版本:MacBook Pro(Apple M1 Pro) M1芯片
- Xcode版本:15.4
拉取代码
按照 blibili官方开源库ijkplayer README中iOS配置步骤进行配置。
# 先切到一个文件夹下
cd Desktop/
# 克隆ijkplayer的代码
git clone https://github.com/Bilibili/ijkplayer.git
# cd到拉下来的ijkplayer中
cd ijkplayer
# 切到最新版本k0.8.8(可在官方tags中查看最新版本)
git checkout -B latest k0.8.8
项目拉下来后文件结构如下:
配置解码器类型
- module-default.sh 更多的编解码器/格式
- module-lite-hevc.sh 较少的编解码器/格式(包括hevc)
- module-lite.sh 较少的编解码器/格式(默认情况)
cd config
# 删除默认的解码器
rm module.sh
# 创建一个软连接指向 module-lite-hevc.sh,这个可根据自己需求进行选择
ln -s module-lite-hevc.sh module.sh
# 回到上一层目录
cd ..
# 进入ios目录
cd ios
# 将compile-ffmpeg.sh脚本清空,等待后期重新执行新的脚本
sh compile-ffmpeg.sh clean
注:sh compile-ffmpeg.sh clean
同./compile-ffmpeg.sh clean
一样,都是在当前文件夹下执行脚本命令
配置ffmpeg内核版本
回到上一目录ijkplayer
找到init-ios.sh
文件进行编辑,可通过终端使用vi
命令进入编辑环境,再输入i
开始编辑,编辑结束后按键盘左上角上的esc
键退出编辑,然后在终端中输入:wq
进行保存并退出编辑环境, 或者找到该文件直接通过xcode
打开开始修改。
# 回到上一目录ijkplayer
cd ..
# 编辑init-ios.sh文件
vi init-ios.sh
打开文件后可以看到如下内容,需要注意IJK_FFMPEG_COMMIT
字段,该字段配置ffmpeg
版本,如果不修改,则默认使用ff3.4--ijk0.8.7--20180103--001
版本,我们需要将其修改为ff4.0--ijk0.8.25--20200221--001
。
原本bilibili
的ffmpeg库支持查看版本的,可惜现在看不到了。
#! /usr/bin/env bash
#
# Copyright (C) 2013-2015 Bilibili
# Copyright (C) 2013-2015 Zhang Rui <bbcallen@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# IJK_FFMPEG_UPSTREAM=git://git.videolan.org/ffmpeg.git
IJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git
IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git
IJK_FFMPEG_COMMIT=ff4.0--ijk0.8.25--20200221--001
IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg
IJK_GASP_UPSTREAM=https://github.com/Bilibili/gas-preprocessor.git
配置ffmpeg所依赖的环境
# 获取依赖的文件,这个会久一点,中途有失败再执行一下就可以了
./init-ios.sh
配置支持https协议(如果不需要支持https可以跳过)
编辑ijkplayer
文件夹下的init-ios-openssl.sh
文件
vi init-ios-openssl.sh
和升级ffmpeg
类似,找到IJK_OPENSSL_COMMIT
字段,将其默认值OpenSSL_1_0_2n
替换成OpenSSL_1_0_2u
。
配置https所需的openssl环境
# 比较耗时,耐心等待
./init-ios-openssl.sh
成功后终端输出如下:
编辑config文件夹下的module.sh文件
vi config/module.sh
在文件的末尾加上如下两行:
# 支持https
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-openssl"
# ffmpeg4.0 需要
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=eac3_core"
同时将以下两行注释掉:
#export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffserver"
#export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vda"
更改最低支持的版本到8.0
因为ffmpeg4.0
使用的部分API是iOS8.0
以上的,因此需要更改最低支持的版本超过8.0
,否则编译ffmpeg
时会出现如下错误:
libavcodec/videotoolbox.c:862:9: error: 'VTDecompressionSessionInvalidate' is only available on iOS 8.0 or newer
[-Werror,-Wunguarded-availability]
VTDecompressionSessionInvalidate(videotoolbox->session);
依次找到ios/tools
目录下的do-compile-ffmpeg.sh
和do-compile-openssl.sh
文件,打开文件并找到有关version-min小于8.0
的统一改为8.0
。
取消支持armv7编译环境
因为使用Xcode15.4
编译,已经弱化了对32位
的支持,因此需要移除掉armv7
环境。如果想支持armv7
,请使用低版本Xcode 例:Xcode9
编译打包。
找到ios目录下的compile-ffmpeg.sh
和compile-openssl.sh
文件,打开文件并将FF_ALL_ARCHS_IOS8_SDK="armv7 arm64 i386 x86_64"
修改为FF_ALL_ARCHS_IOS8_SDK="arm64 i386 x86_64"
,否则可能会在编译ffmpeg的时候出现以下报错:
./libavutil/arm/asm.S:50:9: error: unknown directive
.arch armv7-a
^
make: *** [libavcodec/arm/aacpsdsp_neon.o] Error 1
编译openssl
cd ios
# 先编译OpenSSL,如果不需要支持https可以跳过
./compile-openssl.sh all
编译openssl
成功后终端输出如下:
编译openssl
成功后项目在ios/build
文件夹下多出了openssl-arm64
、openssl-i386
、openssl-x86_64
、universal
四个文件夹,并在universal
文件夹下的lib
文件夹中多出了libcrypto.a
和libssl.a
两个文件
编译ffmpeg
在编译ffmpeg
之前需要在ios/tools
目录中的do-compile-ffmpeg.sh
文件中增加一行FFMPEG_CFLAGS="$FFMPEG_CFLAGS -Wno-error=incompatible-function-pointer-types"
,否则会在编译的时候提示指针问题。
# 编译ffmpeg遇到的error问题
libavcodec/aarch64/h264dsp_init_aarch64.c:84:38: error: incompatible function pointer types assigning to 'h264_weight_func' (aka 'void (*)(unsigned char *, long, int, int, int, int)') from 'void (uint8_t *, int, int, int, int, int)' (aka 'void (unsigned char *, int, int, int, int, int)') [-Wincompatible-function-pointer-types]
c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels_16_neon;
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
开始编译ffmpeg
# 编译ffmpeg
./compile-ffmpeg.sh all
编译ffmpeg
成功后终端输出如下:
编译ffmpeg
成功后项目在ios/build
文件夹下多出了ffmpeg-arm64
、ffmpeg-i386
、ffmpeg-x86_64
、universal
四个文件夹,并在universal
文件夹下的lib
文件夹中多出了libavcodec.a
、libavfilter.a
、libavformat.a
、libavutil.a
、libswresample.a
、libswscale.a
六个文件。
检查项目
至此为止已经编译通过了,然后打开IJKMediaPlayer.xcodeproj
文件查看ffmpeg
所需要的库是否已正确引用上
如果lib文件夹下各库文件为红色则表示未正确引用上
,有可能是配置ffmpeg
的步骤没弄好,需要清空openssl
及ffmpeg
脚本重新加载。
# 清空openssl.sh脚本
./compile-openssl.sh clean
# 清空ffmpeg.sh脚本
./compile-ffmpeg.sh clean
# 重新加载openssl脚本
./compile-openssl.sh all
# 重新加载ffmpeg脚本
./compile-ffmpeg.sh all
检查通过后运行项目处理错误
IJKMediaFramework
一运行发现demo中有一处方法没返回值编译不过去,添加上返回值。
如需支持https协议需在IJKMediaPlayer中增加上编译完openssl后生成的两个库文件
如果不增加这两个库文件,在运行IJKMediaDemo
的时候会报错。
运行IJKMediaDemo
运行之后报错如下:
发现之前配置
openssl
及ffmpeg
的时候设置最低8.0
,由于demo中Minimum Deployments
值是7.0
,版本太低需将其提高(不知道为什么8.0不行,改为9.0正常了)
打包framework
配置为Release
模式,使的编译状态即可打包出framework。
分别选择真机环境及模拟器环境编译一遍,然后在设置中的Locations分栏
中点击箭头跳到编译后的目录,找到真机包和模拟器包。
lipo命令查看包支持的环境及合并包
-
lipo命令查看包支持的环境
在终端中输入lipo -info framework地址
获取该包支持的环境
lipo -info /Users/***/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-flteyzdokpvvjrggfniynketqxrr/Build/Products/Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework
Architectures in the fat file: /Users/***/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-flteyzdokpvvjrggfniynketqxrr/Build/Products/Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework are: arm64 x86_64
可以看到该模拟器包支持arm64
和x86_64
指令集
-
lipo命令合并真机与模拟器包
在终端中输入lipo -create 真机包地址 模拟器包地址 -output 包名称
将真机包与模拟器包合并为一个新的包同时支持两种编译环境。
值得注意的是:
在Apple
发布M1芯片
之前,一直使用Intel
的芯片,没有出现什么问题。发布 M1芯片
后,由于两者架构的不同(M1
是arm64
架构,Intel
是x86_64
的架构),导致lipo -create
命令在执行的时候会出现如下错误:
lipo -create /Users/***/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-flteyzdokpvvjrggfniynketqxrr/Build/Products/Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework /Users/***/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-flteyzdokpvvjrggfniynketqxrr/Build/Products/Release-iphoneos/IJKMediaFramework.framework/IJKMediaFramework -output IJKMediaFramework
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: /Users/***/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-flteyzdokpvvjrggfniynketqxrr/Build/Products/Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework and /Users/***/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-flteyzdokpvvjrggfniynketqxrr/Build/Products/Release-iphoneos/IJKMediaFramework.framework/IJKMediaFramework have the same architectures (arm64) and can't be in the same fat output file
在我们创建framework
时,选择真机编译出来的包只包含arm64
指令,选择模拟器编译出来的包会同时包含arm64
和x86_64
指令。有网上教程说将模拟器部分的arm64
指令移除,但是要支持M1
机器正常跑模拟器环境,必须同时包含arm64
和x86_64
指令。
解决方案:
2019年的WWDC
,苹果提供了一种新的框架封装格式XCFramework
,简单理解就是之前用lipo
命令合并不同指令集的包,现在改为使用心得指令合并成XCFramework
格式的包。
xcodebuild指令
实验过很多次,仍旧无法解决在M1
机器上编译出的arm64+x86_64
指令同时存在的framework
改为xcframework
。