前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux下ndk编译移植FFmpeg到Android平台简介

Linux下ndk编译移植FFmpeg到Android平台简介

作者头像
用户2929716
发布2018-08-23 13:33:56
1.9K0
发布2018-08-23 13:33:56
举报
文章被收录于专栏:流媒体流媒体

简介

  • linux下编译FFmpeg
  • Android项目使用FFmpeg
  • 编译运行
  • 常见问题

linux下编译FFmpeg

开发环境配置
  • FFmpeg编译环境 centos6.8 64位
代码语言:javascript
复制
[root@iZ94g6hanmqZ include]# lsb_release -a
LSB Version:    :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
Distributor ID: CentOS
Description:    CentOS release 6.8 (Final)
Release:    6.8
Codename:   Final
  • linux下安装sdkmanager以及ndk 参考Linux下Android构建环境,可以sdk加入的环境变量中,方便执行sdkmanager命令。
代码语言:javascript
复制
export ANDROID_HOME=/usr/local/android
export PATH=${PATH}:$ANDROID_HOME/tools/bin:$ANDROID_HOME/platform-tools/

查看可下载的内容sdkmanager --list

6.png

然后下载ndk。执行命令

代码语言:javascript
复制
sdkmanager 'ndk-bundle'

然后等待下载完成。

7.png

  • 配置ndk环境变量
代码语言:javascript
复制
export NDK_HOME=/usr/local/android/ndk-bundle
export PATH=${PATH}:$NDK_HOME
下载编译FFmpeg

这里我们选择3.2.4版本(注意:这里使用的3.2.4版本,如果用最新的版本,编译可能出现问题,为了想让大家上手,建议版本先保持一致)。直接github上选择下载解压即可。为了方便编译,我们在解压后的目录中写一个shell脚本来进行配置。build_ffmpeg.sh

代码语言:javascript
复制
#!/bin/bash
NDK=/usr/local/android/ndk-bundle
SYSROOT=$NDK/platforms/android-16/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64

function build_one
{
    ./configure \
        --prefix=$PREFIX \
        --enable-shared \
        --disable-static \
        --disable-doc \
        --disable-ffserver \
        --enable-cross-compile \
        --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
        --target-os=linux \
        --arch=arm \
        --sysroot=$SYSROOT \
        --extra-cflags="-Os -fpic $ADDI_CFLAGS" \
        --extra-ldflags="$ADDI_LDFLAGS" \
        $ADDITIONAL_CONFIGURE_FLAG
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one

注意:这里的platforms使用的android-16,如果使用更高,可能在app运行时会出现atof相关错误,同样至于为什么,现在先不做解释

NDK替换成自己的路径即可。接下来给脚本添加运行属性chmod +x build_ffmpeg.sh。现在就可以开始运行build_ffmpeg.sh来生成Makefile。./build_ffmpeg.sh

1.png

执行完可能会有一个警告如下:

代码语言:javascript
复制
WARNING: /usr/local/android/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-pkg-config not found, library detection may fail.

这里不会有影响,直接忽略。接下来就开始编译

代码语言:javascript
复制
make -j4

编译完成后,安装

代码语言:javascript
复制
make install

在当前目录下会生成一个android目录。里面有个arm目录

代码语言:javascript
复制
[root@iZ94g6hanmqZ android]# ll
total 4
drwxr-xr-x 6 root root 4096 Oct 31 07:12 arm
[root@iZ94g6hanmqZ android]# cd arm/
[root@iZ94g6hanmqZ arm]# ll
total 16
drwxr-xr-x 2 root root 4096 Oct 31 07:12 bin
drwxr-xr-x 9 root root 4096 Oct 31 07:12 include
drwxr-xr-x 3 root root 4096 Oct 31 07:12 lib
drwxr-xr-x 3 root root 4096 Oct 31 07:12 share

我们看到有bin、include、lib、share

lib包含了生成的动态库文件

代码语言:javascript
复制
-rwxr-xr-x 1 root root 11414264 Oct 31 07:12 libavcodec-57.so
lrwxrwxrwx 1 root root       16 Oct 31 07:12 libavcodec.so -> libavcodec-57.so
-rwxr-xr-x 1 root root    59384 Oct 31 07:12 libavdevice-57.so
lrwxrwxrwx 1 root root       17 Oct 31 07:12 libavdevice.so -> libavdevice-57.so
-rwxr-xr-x 1 root root  1638076 Oct 31 07:12 libavfilter-6.so
lrwxrwxrwx 1 root root       16 Oct 31 07:12 libavfilter.so -> libavfilter-6.so
-rwxr-xr-x 1 root root  1952368 Oct 31 07:12 libavformat-57.so
lrwxrwxrwx 1 root root       17 Oct 31 07:12 libavformat.so -> libavformat-57.so
-rwxr-xr-x 1 root root   443860 Oct 31 07:12 libavutil-55.so
lrwxrwxrwx 1 root root       15 Oct 31 07:12 libavutil.so -> libavutil-55.so
-rwxr-xr-x 1 root root    91532 Oct 31 07:12 libswresample-2.so
lrwxrwxrwx 1 root root       18 Oct 31 07:12 libswresample.so -> libswresample-2.so
-rwxr-xr-x 1 root root   406924 Oct 31 07:12 libswscale-4.so
lrwxrwxrwx 1 root root       15 Oct 31 07:12 libswscale.so -> libswscale-4.so
drwxr-xr-x 2 root root     4096 Oct 31 07:12 pkgconfig

include 包含了头文件

代码语言:javascript
复制
[root@iZ94g6hanmqZ arm]# cd include/
[root@iZ94g6hanmqZ include]# ll
total 28
drwxr-xr-x 2 root root 4096 Oct 31 07:12 libavcodec
drwxr-xr-x 2 root root 4096 Oct 31 07:12 libavdevice
drwxr-xr-x 2 root root 4096 Oct 31 07:12 libavfilter
drwxr-xr-x 2 root root 4096 Oct 31 07:12 libavformat
drwxr-xr-x 2 root root 4096 Oct 31 07:12 libavutil
drwxr-xr-x 2 root root 4096 Oct 31 07:12 libswresample
drwxr-xr-x 2 root root 4096 Oct 31 07:12 libswscale

到此为止,FFmpeg的动态库就编译完成了。

Android项目使用FFmpeg

首先android studio及其ndk需要下载配置好.红色都是需要安装的。

3.png

新建工程,注意勾选include C++ support(这里我们不再使用老的模式进行nkd开发,我们使用android studio新支持的模式)

2.png

看下项目工程目录:

4.png

将FFmpeg生成的include和so库放入到图中对应的位置中。

下面看下gradle文件:

代码语言:javascript
复制
apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.wangheart.ffmpegdemo"
        minSdkVersion 16
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters "armeabi"
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

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

主要增加abiFilters "armeabi",因为我们刚才编译的FFmpeg是arm平台。所以这里就选择arm平台。

重点看到CMakeLists.txt
代码语言:javascript
复制
# 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)


#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

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).
             src/main/cpp/native-lib.cpp )

#引用的头文件
include_directories(
                    src/main/cpp/include
                    )

#添加库 动态库为SHARED  静态库就是STATIC
add_library(avcodec SHARED IMPORTED)
set_target_properties(avcodec
  PROPERTIES IMPORTED_LOCATION
  ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-57.so)

add_library(avdevice SHARED IMPORTED)
set_target_properties(avdevice
  PROPERTIES IMPORTED_LOCATION
  ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavdevice-57.so)

add_library(avfilter SHARED IMPORTED)
set_target_properties(avfilter
  PROPERTIES IMPORTED_LOCATION
  ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavfilter-6.so)

add_library(avformat SHARED IMPORTED)
set_target_properties(avformat
  PROPERTIES IMPORTED_LOCATION
  ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavformat-57.so)

add_library(avutil SHARED IMPORTED)
set_target_properties(avutil
  PROPERTIES IMPORTED_LOCATION
  ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavutil-55.so)

add_library(swresample SHARED IMPORTED)
set_target_properties(swresample
  PROPERTIES IMPORTED_LOCATION
  ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libswresample-2.so)

add_library(swscale SHARED IMPORTED)
set_target_properties(swscale
  PROPERTIES IMPORTED_LOCATION
  ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libswscale-4.so)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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 )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
# 链接库
target_link_libraries( # Specifies the target library.
                       native-lib

                       avcodec
                       avdevice
                       avfilter
                       avformat
                       avutil
                       swresample
                       swscale
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

add_library表示添加库,可以添加动态库或静态库。如:

add_library(avcodec SHARED IMPORTED)如果是静态库就是STATIC。下面就是设置动态库的路径:

代码语言:javascript
复制
set_target_properties(avcodec
  PROPERTIES IMPORTED_LOCATION
 ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-57.so)

然后添加链接库,在target_link_libraries中加入我们需要连接的库。到这里基本CMakeLists.txt就配置完成了。

编辑native-lib.cpp文件

这里就是我们需要开发的c++文件,需要做什么功能都可以在这里编辑,本节只是做个演示,我就只是获取FFmpeg的一些信息并返回。

代码语言:javascript
复制
#include <jni.h>
#include <string>

//这里很重要,FFmpeg是C语言写的,如果不使用extern "C"则
//会出现链接出错
extern "C" {
#include "libavcodec/avcodec.h"
}

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_wangheart_ffmpegdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */thiz) {
    char info[10000] = {0};
//    avcodec_version();
    sprintf(info, "%s\n", avcodec_configuration());
    return env->NewStringUTF(info);
}
MainActivity
代码语言:javascript
复制
package com.wangheart.ffmpegdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("avutil-55");
        System.loadLibrary("swresample-2");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avformat-57");
        System.loadLibrary("swscale-4");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avdevice-57");
        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 = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());



    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

这里注意要把其他所有的so都要加入。

8.png

Github示例项目源码注意版本

10.png

常见问题

jni编译链接失败

5.png

很多朋友在网上看到代码,在引入头文件时候直接引用比如:#include "libavcodec/avcodec.h"

如果是C语言则没什么问题。如果是C++,则需要使用extern "C"

代码语言:javascript
复制
extern "C" {
#include "libavcodec/avcodec.h"
}
atof问题
代码语言:javascript
复制
cannot locate symbol "atof" referenced by "libavformat-57.so"...

这里有个解决办法就是在编译FFmpeg的时候使用android-16。也就是build_ffmpeg.sh的时候修改为:

代码语言:javascript
复制
SYSROOT=$NDK/platforms/android-16/arch-arm/
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.10.31 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
    • linux下编译FFmpeg
      • Android项目使用FFmpeg
        • 常见问题
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档