前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android - Mac & FFmpeg & AndroidStudio & CMake 环境搭建

Android - Mac & FFmpeg & AndroidStudio & CMake 环境搭建

作者头像
LiveVideoStack
发布2021-09-02 15:14:14
5790
发布2021-09-02 15:14:14
举报
文章被收录于专栏:音视频技术音视频技术

基础环境

  • MacOS 10.12.3
  • AndroidStudio 2.3
  • NDK 13.1.*
  • FFmpeg 3.2.*

下载 FFmpeg 源码

1

git clone https://git.ffmpeg.org/ffmpeg.git

切换到 3.2 分支

1

git checkout -b 3.2 remotes/origin/release/3.2

当然你也可以去去官网下载压缩包。

编译 FFmpeg for Android

修改 FFmpeg 的 configure

打开 configure 文件,找到:

1234

SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'

替换成:

代码语言:javascript
复制
1234SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'SLIB_INSTALL_LINKS='$(SLIBNAME)'

编写 Android 编译脚本

123456789101112131415161718192021222324252627282930313233343536373839

#!/bin/bashNDK=/Users/gavin/Develop/android-sdk/ndk-bundleSYSROOT=$NDK/platforms/android-15/arch-arm/TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64CPU=armPREFIX=$(pwd)/android/$CPU ADDI_CFLAGS="-marm"function build_one{./configure \--prefix=$PREFIX \--enable-shared \--disable-static \--disable-doc \--disable-ffmpeg \--disable-ffplay \--disable-ffprobe \--disable-ffserver \--disable-avdevice \--disable-doc \--disable-symver \--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \--target-os=linux \--arch=arm \--enable-cross-compile \--sysroot=$SYSROOT \--extra-cflags="-Os -fpic $ADDI_CFLAGS" \--extra-ldflags="$ADDI_LDFLAGS" \$ADDITIONAL_CONFIGURE_FLAGmake cleanmakemake install}build_one

前三行自行更换成自己的 NDK 路径即可,PREFIX 就是最终编译输出地址,根据情况也可以修改。

保存文件到 FFmpeg 根目录为 build_android.shchmod +x build_android.sh 赋予执行权限。

编译

执行脚本进行编译。

1

./build_android.sh

小憩一会儿,编译完成。 进入 PREFIX 目录:

123456789101112131415

── include│ ├── libavcodec│ ├── libavfilter│ ├── libavformat│ ├── libavutil│ ├── libswresample│ └── libswscale└── lib├── libavcodec-57.so├── libavfilter-6.so├── libavformat-57.so├── libavutil-55.so├── libswresample-2.so├── libswscale-4.so└── pkgconfig

我们需要的 so 和头文件都有啦。

导入 Android 工程

对于如何开始一个 C++ 项目,官方已经有中文文档了:

https://developer.android.google.cn/studio/projects/add-native-code.html

官网有的东西不赘述,再次声明学什么东西优先看 官方文档,官方文档,官方文档,并且Google dev现在已经有很多中文资源了。

新建一个 C/C++ 工程

勾选 Include C++ Support 即可得到一个基于CMake的模板工程。

拷贝 so 和 incude 文件到 libs

因为我们只编译了 arm 版本的 so,所以需要把 so 拷到 armeabi-v7a 目录下,完整路径如下:

1234567891011121314151617181920212223

├── build.gradle├── libs│ ├── armeabi-v7a│ │ ├── libavcodec-57.so│ │ ├── libavfilter-6.so│ │ ├── libavformat-57.so│ │ ├── libavutil-55.so│ │ ├── libswresample-2.so│ │ └── libswscale-4.so│ └── include│ ├── libavcodec│ ├── libavfilter│ ├── libavformat│ ├── libavutil│ ├── libswresample│ └── libswscale├── proguard-rules.pro└── src└── main├── AndroidManifest.xml├── cpp├── java└── res

指定 jniLibs 路径

12345678

android {...sourceSets {main {jniLibs.srcDirs = ['libs']}}}

指定 abiFilters

因为 so 只有 armeabi-v7a 的,所以我们还需要指定一下 abi 为 armeabi-v7a

123456789

android {...defaultConfig {...ndk {abiFilters 'armeabi-v7a'}}}

编写 CMakeLists

脚本怎么写,有什么讲究其实官方文档已经很清楚了:创建 CMake 构建脚本

https://developer.android.google.cn/studio/projects/add-native-code.html#create-cmake-script

Java 引入 so 库

12345678910

static {System.loadLibrary("native-lib");System.loadLibrary("avcodec-57");System.loadLibrary("avfilter-6");System.loadLibrary("avformat-57");System.loadLibrary("avutil-55");System.loadLibrary("swresample-2");System.loadLibrary("swscale-4");}

运行测试

如果成功运行不报错的话,就证明一切没有问题。

编写 FFmpeg 测试代码

UI

C++

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115

#include <jni.h>#include <string>extern "C" {#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libavfilter/avfilter.h>JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());}JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_avformatinfo(JNIEnv *env,jobject /* this */) {char info[40000] = {0};av_register_all();AVInputFormat *if_temp = av_iformat_next(NULL);AVOutputFormat *of_temp = av_oformat_next(NULL);while (if_temp != NULL) {sprintf(info, "%sInput: %s\n", info, if_temp->name);if_temp = if_temp->next;}while (of_temp != NULL) {sprintf(info, "%sOutput: %s\n", info, of_temp->name);of_temp = of_temp->next;}return env->NewStringUTF(info);}JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_urlprotocolinfo(JNIEnv *env,jobject /* this */) {char info[40000] = {0};av_register_all();struct URLProtocol *pup = NULL;struct URLProtocol **p_temp = &pup;avio_enum_protocols((void **) p_temp, 0);while ((*p_temp) != NULL) {sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 0));}pup = NULL;avio_enum_protocols((void **) p_temp, 1);while ((*p_temp) != NULL) {sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 1));}return env->NewStringUTF(info);}JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_avcodecinfo(JNIEnv *env,jobject /* this */) {char info[40000] = {0};av_register_all();AVCodec *c_temp = av_codec_next(NULL);while (c_temp != NULL) {if (c_temp->decode != NULL) {sprintf(info, "%sdecode:", info);} else {sprintf(info, "%sencode:", info);}switch (c_temp->type) {case AVMEDIA_TYPE_VIDEO:sprintf(info, "%s(video):", info);break;case AVMEDIA_TYPE_AUDIO:sprintf(info, "%s(audio):", info);break;default:sprintf(info, "%s(other):", info);break;}sprintf(info, "%s[%10s]\n", info, c_temp->name);c_temp = c_temp->next;}return env->NewStringUTF(info);}JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_avfilterinfo(JNIEnv *env, jobject /* this */) {char info[40000] = {0};avfilter_register_all();AVFilter *f_temp = (AVFilter *) avfilter_next(NULL);while (f_temp != NULL) {sprintf(info, "%s%s\n", info, f_temp->name);f_temp = f_temp->next;}return env->NewStringUTF(info);}}

运行

更多

最简单的基于FFmpeg的移动端例子:Android HelloWorld http://blog.csdn.net/leixiaohua1020/article/details/47008825 FFmpeg 教程 http://blog.csdn.net/column/details/ffmpeg-devel.html


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 LiveVideoStack 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档