window10环境 android studio集成ffmpeg5.1 NDK r24

配置信息

NDK r24 24.0.8215888
CMake 3.18.1
AGP 7.2.1
Gradle 7.3.3

项目地址:

https://github.com/Dragonxwl/FFmpegDemo/tree/master

项目TAG信息 V1.0

{
FFmpeg 5.1 编译arm64-v8a so文件集成Demo
}

1.开发环境 Windows 10 专业版

2.android studio 环境与版本信息

2.1 android studio 版本信息 (2022.6.1 当前官网直接下载的版本)
image.png
2.2 Gradle信息
image.png
2.3 NDK信息(2022.6.1 当前AS SDKmanger最高版本)

24.0.8215888

2.4 CMake信息(2022.6.1 当前AS SDKmanger最高版本)

3.18.1(3.23.2也成功了,自己下载放入{SDKmanger路径}/cmake --eg:C:\Users\xiangwl\AppData\Local\Android\Sdk\cmake)


image.png

image.png

3.提前准备编译号的ffmpeg so文件(Ubuntn 环境、ffmpeg5.1、NDK r24 -- 24.0.8215888) 没有可以去github项目中拿一下

有需要可以看我的文章尝试自己编译,有问题欢迎评论区
window 10 下安装 Ubuntu 22.04 使用 NDK r24 编译FFmpeg 5.1

4.第一步:创建新的Native C++项目工程

4.1 创建工程过程按下图操作即可
image.png

image.png

image.png
4.2 工程创建好以后,打开build.gralde文件,添加ndkVersion(我选择最新的NDK版本)点击Sync,gradle对应默认NDK版本可能与自己想要的不一致
image.png

5.第二步:添加提前准备好的so文件

5.1 ANDROID_ABI:arm64-v8a(因为我使用的是华为手机,暂时仅添加arm64-v8a,armeabi-v7a、x86、x86_64后续再添加) 详细解释与官网说明
image.png
5.2 配置build.gradle文件
externalNativeBuild {}中添加
ndk{
    abiFilters "arm64-v8a"
}
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-android-extensions'
}

android {
compileSdkVersion 32
ndkVersion '24.0.8215888'
defaultConfig {
applicationId "com.xwl.ffmepgdemo"
minSdkVersion 15
targetSdkVersion 32
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags '-frtti -fexceptions -Wno-deprecated-declarations'
}
ndk{
abiFilters "arm64-v8a"
}
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.18.1'
}
}
buildFeatures {
viewBinding true
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
5.3 第三步:配置CMakeLists.txt文件
cmake_minimum_required(VERSION 3.4.1)

find_library( log-lib
log )

# 定义变量
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../libs)
message(CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR})

# 添加库——自己编写的库
# 库名称:native-lib
# 库类型:SHARED,表示动态库,后缀为.so(如果是STATIC,则表示静态库,后缀为.a)
# 库源码文件:src/main/cpp/native-lib.cpp
add_library( native-lib
SHARED
native-lib.cpp)

# 添加库——外部引入的库
# 库名称:avcodec(不需要包含前缀lib)
# 库类型:SHARED,表示动态库,后缀为.so(如果是STATIC,则表示静态库,后缀为.a)
# IMPORTED表明是外部引入的库
add_library( avcodec
SHARED
IMPORTED)
# 设置目标属性
# 设置avcodec目标库的IMPORTED_LOCATION属性,用于说明引入库的位置
# 还可以设置其他属性,格式:PROPERTIES key value
set_target_properties( avcodec
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavcodec.so)

add_library( avdevice
SHARED
IMPORTED)
set_target_properties( avdevice
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavdevice.so)

add_library( avfilter
SHARED
IMPORTED)
set_target_properties( avfilter
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavfilter.so)

add_library( avformat
SHARED
IMPORTED)
set_target_properties( avformat
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavformat.so)

add_library( avutil
SHARED
IMPORTED)
set_target_properties( avutil
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavutil.so)

add_library( postproc
SHARED
IMPORTED)
set_target_properties( postproc
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libpostproc.so)

add_library( swresample
SHARED
IMPORTED)
set_target_properties( swresample
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libswresample.so)

add_library( swscale
SHARED
IMPORTED)
set_target_properties( swscale
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libswscale.so)

# 引入头文件
include_directories(../../../libs/include)

# 告诉编译器生成native-lib库需要链接的库
# native-lib库需要依赖avcodec、avfilter等库
target_link_libraries( native-lib
avcodec
avdevice
avfilter
avformat
avutil
postproc
swresample
swscale
${log-lib} )

配置好CMakeLists.txt后点击build->Re fresh Linked C++ Projects


image.png
5.4第四步:JNI部分与代码调用

打开native-lib.cpp
Java_com_xwl_ffmpegdemo_MainActivity_XXX 规则
package="com.xwl.ffmpegdemo"
package="包名1.包名2.包名3"
类名->MainActivity,建议建立一个工具类
前面是固定的 JAVA_包名1_包名2_包名3_类名_方法名

#include <jni.h>
#include <string>

extern "C"
{


#include <libavcodec/codec.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>

JNIEXPORT jstring JNICALL
Java_com_xwl_ffmpegdemo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}

JNIEXPORT jstring JNICALL
Java_com_xwl_ffmpegdemo_MainActivity_avcodecinfo(JNIEnv *env, jobject instance) {

char info[40000] = {0};

void *item = nullptr;
for (;;) {
const AVCodec *cur = av_codec_iterate(&item);
if (!cur)
break;
if (av_codec_is_decoder(cur) != 0) {
sprintf(info, "%sdecode:", info);
} else {
sprintf(info, "%sencode:", info);
}
switch (cur->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, cur->name);
}

return env->NewStringUTF(info);
}

JNIEXPORT jstring JNICALL
Java_com_xwl_ffmpegdemo_MainActivity_urlprotocolinfo(JNIEnv *env, jobject instance) {
char info[40000] = {0};
struct URLProtocol *pup = nullptr;
struct URLProtocol **p_temp = &pup;
avio_enum_protocols((void **) p_temp, 0);
while ((*p_temp) != nullptr) {
sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 0));
}
pup = nullptr;
avio_enum_protocols((void **) p_temp, 1);
while ((*p_temp) != nullptr) {
sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 1));
}

return env->NewStringUTF(info);
}

JNIEXPORT jstring JNICALL
Java_com_xwl_ffmpegdemo_MainActivity_avformatinfo(JNIEnv *env, jobject instance) {
char info[40000] = {0};
void *inputItem = nullptr;
for (;;) {
const AVInputFormat *inputCur = av_demuxer_iterate(&inputItem);
if (!inputCur)
break;
sprintf(info, "%sInput: %s\n", info, inputCur->name);
}

void *outputItem = nullptr;
for (;;) {
const AVOutputFormat *outputCur = av_muxer_iterate(&outputItem);
if (!outputCur)
break;
sprintf(info, "%sOutput: %s\n", info, outputCur->name);
}
return env->NewStringUTF(info);
}

JNIEXPORT jstring JNICALL
Java_com_xwl_ffmpegdemo_MainActivity_avfilterinfo(JNIEnv *env, jobject instance) {
char info[40000] = {0};
void *item = nullptr;
for (;;) {
const AVFilter *cur = av_filter_iterate(&item);
if (!cur)
break;
sprintf(info, "%s%s\n", info, cur->name);
}
return env->NewStringUTF(info);
}


}

MainActivity中调用

package com.xwl.ffmpegdemo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
companion object {
init {
System.loadLibrary("native-lib")
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_protocol.setOnClickListener {
tv_info!!.text = urlprotocolinfo()
}
btn_codec.setOnClickListener {
tv_info!!.text = avcodecinfo()
}
btn_filter.setOnClickListener {
tv_info!!.text = avfilterinfo()
}
btn_format.setOnClickListener {
tv_info!!.text = avformatinfo()
}

}

external fun stringFromJNI(): String?
private external fun urlprotocolinfo(): String?
private external fun avformatinfo(): String?
private external fun avcodecinfo(): String?
private external fun avfilterinfo(): String?

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容