Android ffmpeg 编译

一、ffmpeg的编译

1、准备工作

安装虚拟机Centos 

下载ndk:https://dl.google.com/android/repository/android-ndk-r13b-linux-x86_64.zip

下载ffmpeg-3.2.1.tar.gzhttps://ffmpeg.org/releases/ffmpeg-3.2.1.tar.gz

坑:3.4.x报错:./libavutil/timer.h:38:31: fatal error: linux/perf_event.h: No such file or directory
根据 http://www.ffmpeg-archive.org/ffmpeg-3-4-1-with-android-td4682624.html 这个反馈,改了之后,果然没有报错,但是限制了最低版本为Android-21,这不是我想要的,好像还有一种办法,说是注释掉include ‘<‘linux/perf_event.h’>’

下载JDK

https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

下载dk-8u201-linux-x64.tar.gzhttps://download.oracle.com/otn-pub/java/jdk/8u201-b09/42970487e3af4f5aa5bca3f542482c60/jdk-8u201-linux-x64.tar.gz?AuthParam=1554439431_16b24965e20f66725c8647fbf4af8d41

2、安装配置

解压配置Java环境

JAVA_PATH=/home/jdk1.8.0_201
if [ -d "$JAVA_PATH/jre" -a -d "$JAVA_PATH/bin" ]; then
    export JAVA_HOME=$JAVA_PATH
    export ANDROID_JAVA_HOME=$JAVA_HOME
    export JRE_HOME=$JAVA_PATH/jre
    export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

    if [ -z "$CLASSPATH"  ]; then
        export CLASSPATH=.:$JAVA_HOME/bin/lib:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
    else
         export CLASSPATH=.:$JAVA_HOME/bin/lib:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:$CLASS_PATH  
    fi
fi

解压配置NDK环境

#!/bin/sh
export ANDROID_NDK=/home/android-ndk-r13b
export NDK_HOME=$ANDROID_NDK
export ANDROID_NDK_HOME=$ANDROID_NDK
export PATH=$ANDROID_NDK:$PATH

 

3、遇到的问题

nasm/yasm not found or too old. Use --disable-x86asm for a crippled build
解决:安装yasm编译器。安装方法如下:

在http://www.tortall.net/projects/yasm/releases
下面找到适合自己平台的yasm版本。然后进行安装。举例如下:

1)下载:wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
2)解压:tar zxvf yasm-1.3.0.tar.gz
3)切换路径: cd yasm-1.3.0
4)执行配置: ./configure
5)
编译:make

6)安装:
make install

 

4、修改ffmpeg的configure文件

原因是生成的.so文件是版本号后缀,例如:xxx.so.5.1.4,Android不能识别。

找到

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)'

替换为

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

5、编写编译脚本

最好再Linux环境编写

vim build_android.sh

#!/bin/bash
make clean
export NDK=/home/android-ndk-r13b
export SYSROOT=$NDK/platforms/android-9/arch-arm/
export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64

export CPU=arm
export PREFIX=$(pwd)/android/$CPU
export ADDI_CFLAGS="-marm"

export TEMPDIR=/home/ffmpeg-3.2.1/temp

./configure --target-os=linux \
        --prefix=$PREFIX --arch=arm \
        --disable-doc \
        --enable-shared \
        --disable-static \
        --disable-yasm \
        --disable-symver \
        --enable-gpl \
        --disable-ffmpeg \
        --disable-ffplay \
        --disable-ffprobe \
        --disable-ffserver \
        --disable-doc \
        --disable-symver \
        --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
        --enable-cross-compile \
        --sysroot=$SYSROOT \
        --extra-cflags="-Os -fpic $ADDI_CFLAGS" \
        --extra-ldflags="$ADDI_CFLAGS" \
        $ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install

设置权限:chmod +x build_android.sh

执行build_android.sh脚本开始编译

./build_android.sh

 

之后会在当前目录下出现android目录,里面就有需要的.so文件了。

 

5、Android 设备的CPU类型(通常称为”ABIs”)

  1. armeabiv-v7a: 第7代及以上的 ARM 处理器。2011年15月以后的生产的大部分Android设备都使用它.
  2. arm64-v8a: 第8代、64位ARM处理器,很少设备,三星 Galaxy S6是其中之一。
  3. armeabi: 第5代、第6代的ARM处理器,早期的手机用的比较多。
  4. x86: 平板、模拟器用得比较多。
  5. x86_64: 64位的平板。

 

 

二、Android  studio 在项目中配置ffmpeg

1、结构

include 放头文件,其它的一看就直到了

 

main目录下的CMakeLists.txt 配置:

cmake_minimum_required(VERSION 3.4.1)
#${CMAKE_SOURCE_DIR}  表示CMakeLists.txt文件所在的目录
#${CMAKE_ANDROID_ARCH_ABI} 表示不同架构的CPU 名字
#${PROJECT_SOURCE_DIR}/src/main/cpp

#定义.so输出路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/jniLibs/${ANDROID_ABI})

#定义常量cpp目录
set(CPP_FILE_DIR ${CMAKE_SOURCE_DIR}/cpp)
#定义常量
set(JNILIBS_PATH ${CMAKE_SOURCE_DIR}/jniLibs/${ANDROID_ABI})

#添加子目录,将自动找到指定目录中的CMakeLists.txt
ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/cpp)

 

cpp目录下的CMakeLists.txt 配置:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)


#${CMAKE_SOURCE_DIR}  表示CMakeLists.txt文件所在的目录
#${CMAKE_ANDROID_ARCH_ABI} 表示不同架构的CPU 名字

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        ${CPP_FILE_DIR}/native-lib.cpp
        )



add_library(
        avcodec
        SHARED
        IMPORTED
)
set_target_properties(
        avcodec
        PROPERTIES IMPORTED_LOCATION
        ${JNILIBS_PATH}/libavcodec.so
)

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

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

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

add_library(
        swresample
        SHARED
        IMPORTED
)
set_target_properties(
        swresample
        PROPERTIES IMPORTED_LOCATION
        ${JNILIBS_PATH}/libswscale.so
)

include_directories(
        native-lib
        PRIVATE
        ${CPP_FILE_DIR}/include)

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)


target_link_libraries( # Specifies the target library.
        native-lib
        avcodec
        avfilter
        avformat
        avutil
        swresample
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

上面两个配置文件名字虽然相同,但是作用不用,第一个CMakeLists.txt是主要的,在它的配置中能自动搜索cpp目录中的CMakeLists.txt文件,还可以自定义常量定义路径。

注意:第一个CMakeLists.txt需要在build.gradle中配置,其实就是给指定路径,如下:

 externalNativeBuild {
        cmake {
            path "src/main/CMakeLists.txt"
        }
    }

 

可能会遇到报错:

Paths that match a first-pick pattern will be selected into the APK. If more than one path matches the first-pick, only the first found will be selected.

解决:

 packagingOptions {
        pickFirst 'lib/arm64-v8a/libnative-lib.so'
        pickFirst 'lib/armeabi/libnative-lib.so'
        pickFirst 'lib/armeabi-v7a/libnative-lib.so'
        pickFirst 'lib/x86/libnative-lib.so'
        pickFirst 'lib/x86_64/libnative-lib.so'
    }

 

配置好的build_gradle文件的内容

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.lht.hijni"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
            ndk{
                abiFilters "armeabi-v7a","arm64-v8a","x86","x86_64"
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/CMakeLists.txt"
        }
    }

    packagingOptions {
        pickFirst 'lib/arm64-v8a/libnative-lib.so'
        pickFirst 'lib/armeabi/libnative-lib.so'
        pickFirst 'lib/armeabi-v7a/libnative-lib.so'
        pickFirst 'lib/x86/libnative-lib.so'
        pickFirst 'lib/x86_64/libnative-lib.so'
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

参考资料:

 

1、add_library 

该指令的主要作用就是将指定的源文件生成链接文件(.so文件),然后添加到工程中去。该指令常用的语法如下:
add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [source1] [source2] [...])
其中<name>表示库文件的名字,该库文件会根据命令里列出的源文件来创建。而STATIC、SHARED和MODULE的作用是指定生成的库文件的类型。STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被动态链接(动态链接库),在运行时会被加载。MODULE库是一种不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数。默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建,该命令也会在这里被调用。
而语法中的source1 source2分别表示各个源文件。

例子:

2. link_directories
该指令的作用主要是指定要链接的库文件的路径,该指令有时候不一定需要。因为find_package和find_library指令可以得到库文件的绝对路径。不过你自己写的动态库文件放在自己新建的目录下时,可以用该指令指定该目录的路径以便工程能够找到。

例子如下:


link_directories(
    lib
)
3. target_link_libraries
该指令的作用为将目标文件与库文件进行链接。该指令的语法如下:


target_link_libraries(<target> [item1] [item2] [...]
                      [[debug|optimized|general] <item>] ...)
上述指令中的<target>是指通过add_executable()和add_library()指令生成已经创建的目标文件。而[item]表示库文件没有后缀的名字。默认情况下,库依赖项是传递的。当这个目标链接到另一个目标时,链接到这个目标的库也会出现在另一个目标的连接线上。这个传递的接口存储在interface_link_libraries的目标属性中,可以通过设置该属性直接重写传递接口。
 

4、find_library用于查找包含的库文件

搜索指定的预建库并将路径存储为变量。因为cmake在搜索路径中包含系统库默认情况下,只需指定公共NDK库的名称您要添加。cmake验证库之前是否存在正在完成其生成。

find_library( # 设置路径变量的名称
        log-lib

        # 指定要CMAKE定位的NDK库的名称。
        log)

5、SET_TARGET_PROPERTIES 

 1、按照一般的习惯,静态库名字跟动态库名字应该是一致的,只是扩展名不同;

 即:静态库名为 libhello.a; 动态库名为libhello.so ;

希望 "hello_static" 在输出时,不是"hello_static",而是以"hello"的名字显示,故设置如下:

SET_TARGET_PROPERTIES (hello_static PROPERTIES OUTPUT_NAME "hello")

2、# cmake在构建一个新的target时,会尝试清理掉其他使用这个名字的库,

# 因此,在构建libhello.a时,就会清理掉libhello.so.

# 为了回避这个问题,比如再次使用SET_TARGET_PROPERTIES定义 CLEAN_DIRECT_OUTPUT属性。

SET_TARGET_PROPERTIES (hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

SET_TARGET_PROPERTIES (hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)

3、# 按照规则,动态库是应该包含一个版本号的,

# VERSION指代动态库版本,SOVERSION指代API版本。

SET_TARGET_PROPERTIES (hello PROPERTIES VERSION 1.2 SOVERSION 1)

 

6、添加头文件目录INCLUDE_DIRECTORIES

语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

它相当于g++选项中的-I参数的作用,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH变量的作用。

include_directories(../../../thirdparty/comm/include)

 

二、测试环境是否可用

public class MainActivity extends Activity {

    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        testLog();
    }

    public native String stringFromJNI();

    public native void testLog();


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

#include "android/log.h"

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"========info========",__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROE,"========error========",__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARING,"========waring========",__VA_ARGS__)


extern "C" JNIEXPORT jstring JNICALL
// Java_包名(点换成下划线)_类名_方法名( )
Java_com_lht_hijni_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT void JNICALL
Java_com_lht_hijni_MainActivity_testLog(JNIEnv *env, jobject instance) {

    LOGI("LOG %s","ceshi");

}

三、

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值