Android NDK开发之Linux系统下交叉编译导出FFmpeg库并集成到Android Studio

一、FFmpeg简介

FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用 LGPL 或 GPL 许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频 / 视频编 解码库libavcodec ,为了保证高可移植性和编解码质量, libavcodec 里很多 code 都是从头开发的。FFmpeg在 Linux 平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括 Windows Mac OS X 等。这个项目最早由 Fabrice Bellard 发起, 2004 年至 2015 年间由 Michael Niedermayer 主要负责 维护。许多FFmpeg 的开发人员都来自 MPlayer 项目,而且当前 FFmpeg 也是放在 MPlayer 项目组的服务 器上。项目的名称来自MPEG 视频编码标准 ,前面的 "FF" 代表 "Fast Forward" 。 多媒体视频处理工具FFmpeg 有非常强大的功能包括 视频采集 功能、 视频格式转换 、视频抓图、给视频加水印等。
其中,FFmpeg主要包括以下内容:
1、libavformat :用于各种音视频 封装格式 的生成和解析,包括获取解码所需信息以生成解码上下       文结构和 读取音视频帧等功能;
2、libavcodec :用于各种类型声音 / 图像编解码;
3、libavutil :包含一些公共的工具函数;
4、libswscale :用于视频场景比例缩放、色彩映射转换;
5、libpostproc :用于后期效果处理;
6、ffmpeg :该项目提供的一个工具,可用于格式转换、解码或 电视卡 即时编码等;
7、ffsever :一个 HTTP 多媒体即时广播串流服务器;
8、ffplay :是一个简单的播放器,使用 ffmpeg 库解析和解码,通过 SDL 显示;

二、Linux系统下载NDK和FFmpeg压缩包

提示:如果你的是windows环境,可以照样我上篇文章安装linux系统: windows下安装VM虚拟机和Ubuntu系统(附注册密钥)_Jesiah的博客-CSDN博客_window下  安装虚拟机
1、在Linux环境下,打开终端命令窗口,输入如下命令下载NDK:
     wget https: // dl . google . com / android / repository / android-ndk-r17c-linux-x86_64 . zip ?
     hl = zh_cn
2、再运行以下命令修改NDK文件名:
      mv android-ndk-r17c-linux-x86_64 . zip\ ? hl\ = zh_cn android-ndk-r17c-linux-
      x86_64 . zip
3、输入以下命令解压:
     unzip android-ndk-r17c-linux-x86_64 . zip
4、下载FFmpeg:
     wget http : //www.ffmpeg.org/releases/ffmpeg-4.0.2.tar.bz2
5、解压:
    tar - xjf ffmpeg - 4.0 . 2. tar . bz2
注意:如果无法运行命令,有可能是你的Linux系统没有安装相应的软件,根据报错提示安装相应的软件就可以了。

三、Linux系统下的交叉编译

1、什么是交叉编译?

 在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码,我们就称这种编译器支持交叉编译。这个编译过程就叫交叉编译。简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓平台,实际上包含两个概念:体系结构(Architecture)、操作系统(OperatingSystem)。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。举例来说,我们常说的x86 Linux平台实际上是Intel x86体系结构和Linux for x86操作系统的统称;而x86 WinNT平台实际上是Intel x86体系结构和Windows NT for x86操作系统的简称。

2、如何进行交叉编译?

(1)在刚才解压的ffmpeg里面创建一个Ubuntu_build.sh文件,并写入以下内容:

#!/bin/bash 
# 首先定义一个NDK目录的变量 NDK_ROOT 
NDK_ROOT=/root/Tools/android-ndk-r17c 

# 此变量执行ndk中的交叉编译gcc所在目录 
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 

#从as的 externalNativeBuild/xxx/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 -O0 - fPIC" 

INCLUDES=" -isystem $NDK_ROOT/sources/android/support/include"

# 1.定义编译后,所存放的目录 
PREFIX=./android/arm 
# 2.--enable-small 优化大小 非常重要,必须优化才行的哦 
# 3.--disable-programs 不编译ffmpeg程序(命令行工具),我们是需要获取静态、动态库 
# 4.--disable-avdevice 关闭avdevice模块,此模块在android中无用 
# 5.--disable-encoders 关闭所有编码器(播放不需要编码) 
# 6.--disable-muxers 关闭所有复用器(封装器),不需要生成mp4这样的文件,所有关闭 
# 7.--disable-filters 关闭所有滤镜 
# 8.--enable-cross-compile 开启交叉编译 
# 9.--cross-prefix 看右边的值就知道是干嘛的,gcc的前缀.. 
# 10.disable-shared / enable-static (代表关闭动态库,开启 静态库) 

# 11.--sysroot 
# 12.--extra-cflags 会传给gcc的参数 
# 13.--arch --target-os 

./configure \ 
--prefix=$PREFIX \ 
--enable-small \
 --disable-programs \ 
--disable-avdevice \ 
--disable-encoders \ 
--disable-muxers \ 
--disable-filters \ 
--enable-cross-compile \ 
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \ 
--disable-shared \ 
--enable-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

注意:NDK_ROOT必须改为自己下载的NDK存放路径,并且必须在ffmpeg里面创建一个android/arm文件侠,用来存放ffmpeg交叉编译后的文件!

(2)在以root权限在终端命令下打下ffmpeg,并输入 ./configure,再按回车,这时,如果你的系统没有安装gcc,则会报以下错误:

gcc is unable to create an executable file.

这时,我们需要安装一下gcc,可以输入以下命令安装:

yum install -y gcc

安装好后,我们再执行一下./configure命令,

我们发现还会报错,原因是我们没有关掉asm汇编相关的信息,可按提示执行./configure --disable-x86asm解决:

 当输出一大堆ffmpeg相关信息的时候,就说明关闭成功了,这时我们就可以运行刚才写的Ubuntu_build.sh脚本了,即输入:sh Ubuntu_build.sh,按回车,此时,有可能会出错:

 这是由于我们的linux系统在执行某些命令时缺少libtinfo.so.5导致的,所以,我们需要输入以下命令安装:

apt-get install libtinfo5

同时,sh脚本中也使用了make,所以也要安装一下make:

apt-get install make

安装完成后,再执行脚本:sh Ubuntu_build.sh,按回车键后系统就会开始编译ffmpeg,当编译完成后,打包ffmpeg目录下的android/arm文件夹,如果里面生成下面这三个文件夹,说明交叉编译成功:


 四、在Android Studio中集成FFmpeg

 1、创建一个Native C++工程。

 2、把在Linux系统下交叉编译生成的ffmpeg库中的include复制下工程目录cpp下。

3、在cpp目录下创建一个armeabi-v7a文件侠(这个是手机CPU架构指令集,通常情况下只创建这个就可以,但个别手机可能要根据手机CPU去创建,这里不做细讲),然后把交叉编译生成的ffmpeg库中lib下面的.a文件都拷贝进去。

4、在build.grade里面的defaultConfig添加如下配置:

        externalNativeBuild {
            cmake {
                // cppFlags "" // 这样写,默认是四大CPU架构平台

                // 指定CPU架构是armeabi-v7a 【注意:这里只指定本地库到armeabi-v7a】
                abiFilters "armeabi-v7a"
            }
        }

        // TODO 指定CPU的架构  apk/lib/平台
        // 下面代码不写,默认是四大CPU架构平台
        ndk {
            // 指定CPU架构是armeabi-v7a  【注意:这里只指定编译所有库到armeabi-v7a进apk】
            abiFilters("armeabi-v7a")
        }

 5、在main/cpp/CMakeLists.txt文件中引用头文件以及库文件。

#引入头文件
include_directories(${CMAKE_SOURCE_DIR}/include)
#引入库文件
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/${CMAKE_ANDROID_ARCH_ABI}")

target_link_libraries( 
        native-lib
        -Wl,--start-group # 忽略顺序引发的问题
        avcodec avfilter avformat avutil swresample swscale
        -Wl,--end-group
        ${log-lib} )

6、在native-lib.cpp里面调用头文件。

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

extern "C"{
    #include <libavutil/avutil.h>
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_liyx_ffmdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "当前的FFmpeg的版本是:";
    hello.append(av_version_info());
    return env->NewStringUTF(hello.c_str());
}

 7、MainActivity.java中调用native层代码。

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
    
    public native String stringFromJNI();
}

8、activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/sample_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

9、运行。

 最后,说下我的个人心得体会:

交叉编译只是NDK开发的入门基本,难点就在于我们对linux系统的不熟悉,我用的是windows电脑,需要在windows平台下安装linux系统,由于对linux系统的陌生,在安装过程中也踩了很多坑,在linux系统里编译ffmpeg坑更多,但是大多都是由于linux系统没有安装相关软件导致的,因此,我们在linux平台下执行命令的时候一定要有耐心,遇到问题不要慌,要学会根据错误信息找到原因。集成ffmpeg只是音视频开发过程中最简单最基本的一步,如果连这一步都做不好,那么在以后的开发过程中肯定会困难重重,所以,想要从事音视频开发的朋友们,一定要认认真真地做好每一步,把每个知识点弄清楚,遇到困难不要放弃,要学会冷静思考,只要坚持下去,一定会有收获的!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值