前言
基于 WIN10 提供的 WSL 功能可快速搭建 linux(unbuntu)开发环境,最重要的是两个系统之间文件互通!文件互通!文件互通!这里我们将利用该功能编译 FFMPEG 的链接库(本文章以静态库为例)。
开启WSL
开启该功能需要重启系统才能生效,请注意保存数据!
打开控制面板
切换查看方式为小图标,寻找并打开程序和功能
侧边栏进入 - 启动或关闭Windows功能
开启WSL
找到并开启子系统
下载linux系统
打开Windows应用商店,搜索ubuntu并选择其中任意的一个版本下载安装即可。我这里用的是最高版本 20.04 LTS 。经过验证,同时下载安装多个版本并不会造成任何不良影响,且各版本之间运行相互独立互不干扰。
启动ubuntu
这里我们找到并启动unbuntu。注意:首次启动会要求新建用户并创建密码。(这里我已经创建好了就略过了,大家自行尝试即可)
当看到如下界面时,即表示ubuntu系统已成功运行!可以开始编译FFMPEG!
注意:
unbuntu系统的文件路径见下图:
开始编译FFMEPG
这里我们是以ndk-r17c + FFMPEG-4.0.5为准进行编译工作。至于为什么选择用r17c是由于google已经在r18版本中移除了gcc编译器,所以r17c是gcc可用的最高ndk版本,见下图。
如果需要编译最新版本的ffmpeg请使用更高版本(r18及以上)的ndk并使用clang编译器。具体可参考一下链接:
注意:
1. 粘贴内容到unbuntu窗口中只需要鼠标右键即可。
2. 下文出现的junt为本人创建的用户名!请自行替换!
3. 以下所有操作请在管理员权限下进行:
a. sudo -s
b. 输入之前创建的密码
成功进入管理员模式见下图:
复制代码
下载并配置ndk
利用wget命令下载ndk:
wget https://dl.google.com/android/repository/android-ndk-r17c-windows-x86_64.zip
利用unzip命令解压压缩包:
unzip android-ndk-r17c-linux-x86_64.zip
复制代码
利用ls命令查看解压后的ndk文件夹:
(这里文件夹有点多,是因为我尝试了不同版本的ffmpeg,请先忽略。)
复制代码
配置ndk环境变量
编辑profile文件:
键入命令vim /etc/profile
按下insert按键进入编辑模式
在profile文件的最后添加ndk路径,见下图:
复制代码
编辑完成后按下Esc按键,并键入 :wq (注意这里的英文字符:),回车保存。
复制代码
利用source命令使得环境变量生效:
source /etc/profile
看到如下启动提示则代表环境变量已生效:
复制代码
验证ndk-build命令,如果出现找不到项目路径则代表ndk运行正常:
复制代码
下载ffmpeg
(如果真实用于项目,并不推荐使用最新版本得ffmpeg,尤其是4.2网上)
利用wget命令下载ffmpeg:
wget https://ffmpeg.org/releases/ffmpeg-4.0.5.tar.bz2
利用tar命令解压压缩包:
tar -jxvf ffmpeg-4.0.5.tar.bz2
复制代码
利用ls命令查看解压后的ffmpeg文件夹:
复制代码
编译FFMPEG
进入ffmpeg文件夹:
cd ffmpeg-4.0.5
复制代码
新建编译脚本build.sh:
vim build.sh
脚本内容如下(来自某易学员的分享,如果需要编译多版本请参考1.0-FFMPEG-Android利用ndk(r20)编译最新版本ffmpeg4.2.1):
#!/bin/bash
#注意此处的NDk路径需要自行替换
NDK_ROOT=/home/junt/android-ndk-r17c
#TOOLCHAIN 变量指向ndk中的交叉编译gcc所在的目录
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/
#FLAGS与INCLUDES变量 可以从AS ndk工程的.externativeBuild/cmake/debug/armeabi-v7a/build.ninja中拷贝,需要注意的是**地址**
FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -O0 -fPIC"
INCLUDES="-isystem $NDK_ROOT/sources/cxx-stl/llvm-libc++/include -isystem $NDK_ROOT/sources/android/support/include -isystem $NDK_ROOT/sources/cxx-stl/llvm-libc++abi/include"
#--prefix : 安装目录
#--enable-small : 优化大小
#--disable-programs : 不编译ffmpeg程序(命令行工具),我们是需要获得静态(动态)库。
#--disable-avdevice : 关闭avdevice模块,此模块在android中无用
#--disable-encoders : 关闭所有编码器 (只播放不需要编码)
#--disable-muxers : 关闭所有复用器(封装器),不需要生成mp4这样的文件,所以关闭
#--disable-filters :关闭视频滤镜
#--enable-cross-compile : 开启交叉编译(ffmpeg比较**跨平台**,并不是所有库都有这么happy的选项 )
#--cross-prefix: 看右边的值应该就知道是干嘛的,gcc的前缀 xxx/xxx/xxx-gcc 则给xxx/xxx/xxx-
#disable-shared enable-static 不写也可以,默认就是这样的。
#--sysroot:
#--extra-cflags: 会传给gcc的参数
#--arch --target-os :
PREFIX=./android/armeabi-v7a
bash ./configure \
--prefix=$PREFIX \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--enable-shared \
--disable-static \
--sysroot=$NDK_ROOT/platforms/android-21/arch-arm \
--extra-cflags="$FLAGS $INCLUDES" \
--extra-cflags="-isysroot $NDK_ROOT/sysroot" \
--arch=arm \
--target-os=android
make clean
make install
编辑完成后按下Esc按键,并键入 :wq (注意这里的英文字符:),回车保存。
运行编译:
sh build.sh
编译完成后,会在ffmpeg文件夹下生成android文件夹,这里我们在windows下即可查看静态库文件:
复制代码
具体如何寻找FLAGS与INCLUDES见下图,自行替换ndk路径:
复制代码
导入AndroidStudio运行
新建native-c++工程
由于我们上面编译时是使用的21版本,所以这里的sdk版本请选择21及已上!
导入ffmpeg
同时需要头文件以及.a静态库
编辑CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
add_library(
native-lib
#将所有的cpp文件打包成so动态库(apk解压后lib目录下可见native-lib.so)
SHARED
native-lib.cpp )
include_directories(include)
set(my_lib_path ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${my_lib_path}")
target_link_libraries(
native-lib
-Wl,--start-group
avformat avcodec avutil avfilter swresample swscale
-Wl,--end-group
z
OpenSLES
log
)
复制代码
配置build.gradle(Module:app)
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a"
}
}
ndk{
abiFilters "armeabi-v7a"
}
复制代码
验证ffmpeg
//修改native-lib.cpp返回ffmpeg版本信息
#include
#include
extern "C"{
#include
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_ffmpegdemo_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */){
return env->NewStringUTF(av_version_info());
}
运行app效果如下则代表ffmpeg运行成功:
复制代码
适配AndroidQ
/**
* 这里通过系统默认的文件选择器来选择一个视频文件
*/
public void selectMedia(View view){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("video/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, 99);
}
/**
* 拿到Uri后做如下转换
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data){
super.onActivityResult(requestCode, resultCode, data);
if (data != null) {
try {
Uri uri = data.getData();
ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
int pid = android.os.Process.myPid();
String path = "/proc/" + pid + "/fd/" + parcelFileDescriptor.dup().getFd();
//传递到native层的cpp中
//const char *dataSource = env->GetStringUTFChars(path, 0);
//avformat_open_input(&avFormatContext, dataSource, 0, &dictionary);
//用完后释放ReleaseStringUTFChars(data_source_, dataSource);
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码