目录
前言
- 安卓的Exoplayer已经迁移到了Media3里面了,而且在安卓端,使用Exoplayer要比libmpv等播放组件要稳定一些,因此我们又引入了Exoplayer作为安卓端的播放组件。但它支持的音视频格式远不及libmpv内置的ffmpge,Exoplayer官方也支持了当遇到Exoplayer不支持的格式时转给其他扩展的库解码,这其中就包括了ffmpeg。
- 所以我们将要编译一个安卓的ffmpge包,然后配置给Media3.Exoplayer使用。
- 踩了很多坑,留篇帖子记录下。
引用文档
- Media引入ffmpge官方文档
- ExoPlayer(AndroidX Media3) 扩展ffmpeg实现音频软解码
- FFmpeg library Support Format
- Flutter plugin集成 aar 出现错误
准备
- 系统 Ubuntu 20.04;建议使用Ubuntu(linux),官方并不提供windows编译支持
- JDK 17.0.6;你需要先安装好JDK
- NDK 、cmdtools、SDKManager(接下来会讲怎么装)
配置NDK 、cmdtools、SDKManager
- 首先是NDK
- 前往NDK官网下载Linux版zip包,然后解压
- 你可以将这个压缩包下载后传输到Ubuntu里
- 也可以复制它的下载链接,然后在Ubuntu内下载,比如:
- 前往NDK官网下载Linux版zip包,然后解压
cd {你想放NDK的目录}
wget {官网复制Linux版的下载链接}
unzip {刚刚下载的zip文件}
- 解压完后cd进去,接下来搞cmdtools
- 前往下载cmdtools仅限命令行工具;点击进入网页后往下滑动,找[仅限命令行工具],然后点击下载Linux版
- 注意,你需要将这个压缩包下载或者移动到刚刚解压的NDK目录内,然后解压即可得到cmdline-tools文件夹:
- 最后同意一下协议
cd {cmdline-tools目录}/bin
sudo ./sdkmanager --licenses --sdk_root={你的NDK的根目录}
- 然后一路输入y同意即可
编译ffmpge
- $ cd {NDK目录}
- 设置NDK_PATH变量:
NDK_PATH="$(pwd)"
- 拉取适配Media3的ffmpeg模块
cd {你想放Media3.decoder_ffmpeg的目录}
git clone https://github.com/androidx/media --depth 1
cd media
FFMPEG_MODULE_PATH="$(pwd)/libraries/decoder_ffmpeg/src/main"
- 设置编译平台:
Lunux执行:
HOST_PLATFORM="linux-x86_64"
MacOX执行:
HOST_PLATFORM="darwin-x86_64"
- 设置最小支持Android版本;通常为项目设置的minSDK版本,NDK版本r26最小支持SDK为21
ANDROID_ABI=21
- 下载ffmpeg源码;下载源码并设置FFMPEG_PATH变量
cd {你想放ffmpge源码的目录}
git clone git://source.ffmpeg.org/ffmpeg && \ cd ffmpeg && \ git checkout release/6.0 && \ FFMPEG_PATH="$(pwd)"
- 配置ffmpge解码器支持的格式;根据自己需要解码的格式设置,具体支持的解码格式参考官网
ENABLED_DECODERS=(vorbis opus flac alac pcm_mulaw pcm_alaw mp3 amrnb amrwb aac ac3 eac3 dca mlp truehd)
- 关联ffmpeg源码
cd "${FFMPEG_MODULE_PATH}/jni"
ln -s "$FFMPEG_PATH" ffmpeg
- 编译ffmpeg
./build_ffmpeg.sh \ "${FFMPEG_MODULE_PATH}" "${NDK_PATH}" "${HOST_PLATFORM}" "${ANDROID_ABI}" "${ENABLED_DECODERS[@]}"
- 编译成功后,会在ffmepg目录下生成一个android-libs目录,里面就是生成的ffmpge动态库,先不要动它,让我们把它编译成aar,方便安卓项目引入。
- 编译生成Android项目依赖的aar包
cd {开头放Media3.decoder_ffmpeg的目录}
./gradlew lib-decoder-ffmpeg:assembleRelease
- 等待编译完成后,会在{media源码目录}\libraries\decoder_ffmpeg\buildout\outputs\aar\目录生成aar包
项目引入ffmpge的aar包
- 先将Ubuntu内我们刚刚编译好的arr包复制到 {你的安卓项目}/app/libs/ 目录内
- 普通的安卓项目比较简单,直接修改 {你的安卓项目}/app/build.gradle 文件,找到 dependencies {} 块填入依赖即可:
dependencies {
implementation(fileTree('libs'))
}
- 但我们是Flutter项目,要复杂一些,我们是新建了一个flutter插件,然后插件引入了这个aar包,flutter主项目再引入这个插件的(参考文章)
- 对于flutter插件项目,如果仍按上面的普通安卓项目方式导入,会导致编译错误(Error while evaluating property 'hasLocalAarDeps' of task ':xxxx)或是运行时错误(java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/media3/decoder/ffmpeg/FfmpegAudioRenderer)(java.lang.ClassNotFoundException)
- 把aar复制到 {插件目录}android/libs/ 文件夹中
- 在插件的android目录的根部(和src同级)新建aar_tools.gradle文件。
- 在文件内写入以下内容,注意修改[copyAar2Host]的参数为你的插件包名:
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
// 把aar拷贝进入主项目的方法 com.example.android_control换成你自己的插件包名
// * 只修改下面这一行的参数就可以了
copyAar2Host('com.example.android_control')
// 拷贝aar的方法
static aarFileCopy(String srcPath,String desPath) {
System.out.println("copy aar from <<${srcPath}>> to <<${desPath}>>")
try {
FileInputStream fis = new FileInputStream(srcPath)
FileOutputStream fos = new FileOutputStream(desPath)
byte[] data = new byte[1024*8]
int len = 0
while ((len = fis.read(data))!=-1) {
fos.write(data,0,len)
}
fis.close()
fos.close()
}catch(Exception e) {
e.printStackTrace()
}
}
void copyAar2Host(String pluginGroup) {
Project currentProject = null
Project appProject = null
rootProject.allprojects.each {
p->
boolean isApp = p.plugins.hasPlugin("com.android.application")
println("<<${p.name}>> isHost ? ${isApp}")
if (p.group == pluginGroup) {
currentProject = p
println("Plugin project name is $currentProject")
}
if(isApp) {
appProject = p
println("Host project name is <<${p.name}>>")
}
}
Set<File> aarFiles = new HashSet<File>()
if (appProject != null && currentProject != null) {
File libs = new File("${currentProject.projectDir}","libs")
if(libs.isDirectory()) {
libs.listFiles().each {
f->
if(f.name.endsWith(".aar")) {
println("The aar file name to be copied is <<${f.name}>>")
aarFiles.add(f)
}
}
}
if (!aarFiles.isEmpty()) {
File applibs = new File("${appProject.projectDir}${File.separator}libs")
if(!applibs.isDirectory()) {
applibs.mkdirs()
}
aarFiles.each {
f->
File copyAar = new File("${appProject.projectDir}${File.separator}libs",f.name)
if(!copyAar.exists()) {
copyAar.createNewFile()
aarFileCopy(f.path,copyAar.path)
} else {
}
}
appProject.dependencies {
implementation fileTree(dir:"${appProject.projectDir}${File.separator}libs",include:["*.jar","*.aar"])
}
}
}
}
repositories{
flatDir {
dirs 'libs'
}
}
- 在 {插件目录}/android/build.gradle 文件的 apply plugin: 'com.android.library' 下一行位置插入apply from: './aar_tools.gradle',并确保这个文件中对aar的依赖是compileOnly
apply plugin: 'com.android.library'
// 在这里插入下面这一行
apply from: './aar_tools.gradle'
// 然后找到dependencies块,
dependencies {
// 这一行导入刚刚libs目录内的ffmpge的arr包
compileOnly(fileTree("libs"))
// 这里用于解决用android studio打开项目的android目录时里面的java/kotlin文件的import都是灰色的问题
compileOnly files("$flutterRoot/bin/cache/artifacts/engine/android-arm/flutter.jar")
compileOnly("androidx.annotation:annotation:1.3.0")
}
在代码里引入ffmpeg
- 最后是给Media3配置ffmpeg解码器
- 找到你初始化 Media3.Exoplayer 的 java 文件,然后增加一个类:
import androidx.media3.decoder.ffmpeg.FfmpegAudioRenderer;
class FfmpegRenderersFactory extends DefaultRenderersFactory {
public FfmpegRenderersFactory(Context context) {
super(context);
setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON);
}
@Override
protected void buildAudioRenderers(Context context, int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, AudioSink audioSink, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList<Renderer> out) {
out.add(new FfmpegAudioRenderer(eventHandler, eventListener, audioSink));
super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, audioSink, eventHandler, eventListener, out);
}
}
- 修改初始化 Media3.Exoplayer 的部分代码:
ExoPlayer.Builder builder = new ExoPlayer.Builder(context);
// 添加ffmpeg
builder.setRenderersFactory(new FfmpegRenderersFactory(context));
ExoPlayer player = builder.build();
buy prednisone online without a script: cost of prednisone – how much is prednisone 10 mg
how can i get generic clomid without dr prescription clomid on pharm where can i get cheap clomid
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали срочный ремонт телефонов meizu, можете посмотреть на сайте: ремонт телефонов meizu в москве
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов meizu в москве, можете посмотреть на сайте: ремонт телефонов meizu рядом
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
amoxicillin without prescription: AmoxStar – amoxicillin without a prescription
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов meizu в москве, можете посмотреть на сайте: ремонт телефонов meizu адреса
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
amoxicillin capsules 250mg buy cheap amoxicillin online amoxicillin no prescription
cost cheap clomid: clomidonpharm – can i purchase generic clomid pills
Здесь можно сейф для дома москва сейфы для дома цены
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов meizu сервис, можете посмотреть на сайте: ремонт телефонов meizu в москве
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
http://cipharmdelivery.com/# ciprofloxacin order online
http://clomidonpharm.com/# cost cheap clomid
Здесь можно купить домашний сейф сейф для дома
amoxicillin 500mg price canada AmoxStar amoxicillin 500mg buy online uk
buy generic clomid without rx: how to get generic clomid pills – get cheap clomid without dr prescription
where can i buy cipro online: antibiotics cipro – cipro 500mg best prices
prednisone 5mg cost PredniBest pharmacy cost of prednisone
buying cheap clomid without insurance: how to get clomid without a prescription – get generic clomid
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов samsung, можете посмотреть на сайте: ремонт телефонов samsung в москве
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
how to buy generic clomid for sale: where buy generic clomid pill – can you get cheap clomid without a prescription
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов samsung цены, можете посмотреть на сайте: срочный ремонт телефонов samsung
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
Здесь можно сейф для оружия купить москвакупить сейф под ружье
Здесь можно сейфы для ружейсейфы для ружей
https://amoxstar.com/# amoxicillin without prescription
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов samsung цены, можете посмотреть на сайте: ремонт телефонов samsung адреса
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
https://cipharmdelivery.com/# cipro online no prescription in the usa
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов samsung, можете посмотреть на сайте: ремонт телефонов samsung адреса
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов nothing адреса, можете посмотреть на сайте: срочный ремонт телефонов nothing
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
Здесь можно оружейный сейф купитьоружейные шкафы и сейфы
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали срочный ремонт телефонов nothing, можете посмотреть на сайте: ремонт телефонов nothing в москве
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
Предлагаем услуги профессиональных инженеров офицальной мастерской.
Еслли вы искали ремонт телефонов samsung, можете посмотреть на сайте: срочный ремонт телефонов samsung
Наши мастера оперативно устранят неисправности вашего устройства в сервисе или с выездом на дом!
Здесь можно оружейный шкаф купить в москвеоружейный сейф купить в москве
buy prednisone from canada Predni Best buy 40 mg prednisone
generic for amoxicillin amoxicillin 500mg cost amoxicillin 30 capsules price
how can i get cheap clomid without a prescription: clomidonpharm – can i get cheap clomid now
amoxicillin online canada: amoxicillin 500 mg tablet – can we buy amoxcillin 500mg on ebay without prescription
http://amoxstar.com/# amoxicillin 875 mg tablet
https://amoxstar.com/# buy amoxicillin 500mg uk
prednisone daily: Predni Best – 60 mg prednisone daily
over the counter prednisone cream: PredniBest – prednisone 10mg tabs
get cheap clomid pills clomidonpharm cost of clomid prices
cost cheap clomid no prescription clomidonpharm where to get generic clomid pill
can i get generic clomid without prescription: clomid on pharm – order generic clomid prices
cipro online no prescription in the usa: ci pharm delivery – cipro online no prescription in the usa
http://clomidonpharm.com/# how can i get generic clomid without insurance
https://cipharmdelivery.com/# antibiotics cipro
https://prednibest.com/# where can i buy prednisone online without a prescription
can i order cheap clomid for sale clomid without rx can i get clomid pill
15 mg prednisone daily: Predni Best – prednisone 1 mg tablet
medicine amoxicillin 500: amoxicillin generic brand – amoxicillin 500 mg tablet