简介
- linux下编译FFmpeg
- Android项目使用FFmpeg
- 编译运行
- 常见问题
linux下编译FFmpeg
开发环境配置
- FFmpeg编译环境 centos6.8 64位
[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命令。
export ANDROID_HOME=/usr/local/android
export PATH=${PATH}:$ANDROID_HOME/tools/bin:$ANDROID_HOME/platform-tools/
查看可下载的内容sdkmanager --list
:
然后下载ndk。执行命令
sdkmanager 'ndk-bundle'
然后等待下载完成。
- 配置ndk环境变量
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
#!/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
执行完可能会有一个警告如下:
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.
这里不会有影响,直接忽略。接下来就开始编译
make -j4
编译完成后,安装
make install
在当前目录下会生成一个android目录。里面有个arm目录
[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包含了生成的动态库文件
-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 包含了头文件
[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需要下载配置好.红色都是需要安装的。
新建工程,注意勾选include C++ support(这里我们不再使用老的模式进行nkd开发,我们使用android studio新支持的模式)
看下项目工程目录:
将FFmpeg生成的include和so库放入到图中对应的位置中。
下面看下gradle文件:
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
# 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。下面就是设置动态库的路径:
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的一些信息并返回。
#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
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都要加入。
Github示例项目源码注意版本
常见问题
jni编译链接失败
很多朋友在网上看到代码,在引入头文件时候直接引用比如:#include "libavcodec/avcodec.h"
如果是C语言则没什么问题。如果是C++,则需要使用extern "C"
。
extern "C" {
#include "libavcodec/avcodec.h"
}
atof问题
cannot locate symbol "atof" referenced by "libavformat-57.so"...
这里有个解决办法就是在编译FFmpeg的时候使用android-16。也就是build_ffmpeg.sh的时候修改为:
SYSROOT=$NDK/platforms/android-16/arch-arm/
链接:https://www.jianshu.com/p/4037297d883d
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。