Windows下編譯Android所需的FFmpeg庫(小白)

最近開始學習FFmpeg,從小白到了解再到成功編譯,踩了很多坑,不得不感嘆網絡上的信息真是天花亂墜,碰壁兩天,終於走出了一條自己的路,以此記錄下。

安裝VMware虛擬機

我安裝的是14版本,需要授權許可,可網上搜索授權碼在這裏插入圖片描述

安裝 Ubuntu系統

1、下載ubuntu鏡像,我安裝的是18.04.3。
2、百度安裝教程。。。我參考的是安裝Ubuntu18.04虛擬機
3、安裝好,注意是否能上網,能否和window交互粘貼複製(爲了以後方便),是否開啓共享文件夾

ndk配置

將提前下載好的ndk壓縮包,(注意是linux平臺的!不要把window下的ndk就直接拷進去了,愚蠢的我弄了一上午,最後發現了差點沒噴血!)拷貝進虛擬機,最好是主目錄下,右鍵-提取到此處。目前我使用android-ndk-r15c.和android-ndk-r13b.是可以編譯成功的,
也可以直接在虛擬機裏面的終端上 輸入 wget 跟上下載鏈接如

wget https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip?hl=zh_cn

然後改下名字,因爲解壓出來的會有兩層目錄,將最外層的android-ndk-r15c-linux-x86_64改名爲ndk,也可以不改,只是等會配置的時候會顯得路徑名字太長了。

進入root 模式
直接右鍵打開終端,輸入sudo su,輸入密碼,進入root模式(後面的命令行會以root字樣開頭),建議所有命令都在root模式下輸入,因爲有些指令只有在root下才起作用的
在這裏插入圖片描述
打開bashrc文件添加內容
輸入 gedit ~/.bashrc ,可能會稍等十來秒,會打開一個文本,在文本最後添加上
在這裏插入圖片描述

export NDK=/home/wyl/ndk/android-ndk-r15c
export PATH=${PATH}:$NDK

保存 !保存 ! 保存!
/home是固定的,/wyl表示的是系統名稱,用戶安裝ubuntu系統的時候自定義的、/ndk/android-ndk-r15c就是上面解壓後的ndk的相對路徑
注意第一張圖片頂部,有顯示 /home/wyl。

然後 輸入 source ~/.bashrc 通知系統 環境變量已經更改
輸入 echo $NDK 會打印出剛剛配置的路徑,
再輸入 ndk-build 提示如下,說明ndk配置是OK的了,輸入 ndk-build -v 會打印出ndk版本

!!!這裏要在root下輸入纔會提示成功
這裏要在root下輸入纔會提示成功

FFmpeg源碼

ffmpeg源碼下載
我編譯使用的是 3.2.12,使用最新版沒成功,不知道是哪裏出了問題
打開源碼目錄,找到configure文件,可以直接打開,然後將裏面的

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

爲什麼呢?我們小白不需要知道爲什麼
在這裏插入圖片描述
同目錄下,創建一個腳本文件,build.sh,名字自己起,該目錄隨便複製粘貼一個文件,改下名字即可,因爲右鍵發現沒有創文件的選項…裏面的內容爲:

#清除上次編譯的東西
make clean
#配置NDK路徑
export NDK=/home/wyl/ndk/android-ndk-r15c
#配置工具鏈  注意這裏的目錄,要確保在你的ndk目錄裏存在,沒有就重新下  或是換個ndk版本
export PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt
#配置平臺  注意這裏的目錄,要確保在你的ndk目錄裏存在,沒有就重新下  或是換個ndk版本
export PLATFORM=$NDK/platforms/android-21/arch-arm
#配置編譯好了之後的文件輸出目錄,$(pwd)當前目錄下
export PREFIX=$(pwd)/android/
build_one(){
  ./configure --target-os=linux --prefix=$PREFIX \
--enable-cross-compile \
--enable-runtime-cpudetect \
--disable-asm \
--arch=arm \
--cc=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi-gcc \
--cross-prefix=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi- \
--disable-stripping \
--nm=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi-nm \
--sysroot=$PLATFORM \
--enable-gpl --enable-shared --disable-static --enable-nonfree --enable-version3 --enable-small \
--enable-zlib --disable-ffprobe --disable-ffplay --disable-ffmpeg --disable-ffserver --disable-debug \
--extra-cflags="-fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm -march=armv7-a" 
}
build_one

#4線程編譯
make -j4
make install

裏面的內容,是我看了很多博主的腳本之後,唯一一個能編譯成功的。。。
注意裏面的註釋,尤其是上面幾行,確保相應的目錄在ndk裏面是存在的
這兩個 arm-linux-androideabi-4.9android-21根據ndk裏面作相應更改即可,有的會是4.8

保存文件,然後執行腳本
先賦予權限 chmod +x ./build.sh
執行 ./build.sh
就等待它執行完成吧。

編譯過程中遇到的問題記錄.

成功之後,會在當前目錄生成android文件夾,裏面就是需要的頭文件和.so文件了
在這裏插入圖片描述
在這裏插入圖片描述
打開lib目錄,裏面的so文件,不帶數字的都是沒用的,將android目錄直接複製到共享目錄裏,它會有提示,直接全部跳過,就是裏面生成的鏈接文件,不帶數字的那些,是不能複製到windows的,最後到window下面,找到共享目錄,裏面的include目錄,和so文件就可以直接在Android studio上使用了。
在這裏插入圖片描述

Android studio 引入FFmpeg

1、新建項目,選擇 Native C++,我的AS版本是 3.5的,其他版本也類似
在這裏插入圖片描述
2、將cpp目錄下的CMakeLists.txt文件移動到與src目錄平級
在這裏插入圖片描述
在這裏插入圖片描述
3、在cpp目錄下創建 armeabi-v7a目錄,將編譯好的so文件複製進去,並將include目錄也複製到cpp目錄下,注意 include與armeabi-v7a是平級
在這裏插入圖片描述
4、修改build.gradle文件

android {
    compileSdkVersion 28
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.wyl.ffmpegdemo"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
        //添加目標平臺
         ndk {
            abiFilters 'armeabi-v7a'
        }
    }
    //配置jniLibs
    sourceSets {
        main {
            jniLibs.srcDirs = ['src/main/cpp']
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
           // path "src/main/cpp/CMakeLists.txt" 這裏是系統生成的  
            path "CMakeLists.txt" //因爲該文件移動到了外面,與src平級
            version "3.10.2"
        }
    }
}

5、修改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)

#important 需要注意目錄
#設置頭文件目錄
include_directories(src/main/cpp/include)

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

add_library(
        avcodec
        SHARED
        IMPORTED
)

#指定庫的位置
set_target_properties(
        avcodec
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/cpp/armeabi-v7a/libavcodec-57.so
)

add_library(
        avutil
        SHARED
        IMPORTED
)

set_target_properties(
        avutil
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/cpp/armeabi-v7a/libavutil-55.so
)

add_library(
        avdevice
        SHARED
        IMPORTED
)

set_target_properties(
        avdevice
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/cpp/armeabi-v7a/libavdevice-57.so
)

add_library(
        avfilter
        SHARED
        IMPORTED
)

set_target_properties(
        avfilter
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/cpp/armeabi-v7a/libavfilter-6.so
)

add_library(
        avformat
        SHARED
        IMPORTED
)

set_target_properties(
        avformat
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/cpp/armeabi-v7a/libavformat-57.so
)

add_library(
        postproc
        SHARED
        IMPORTED
)
set_target_properties(
        postproc
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/cpp/armeabi-v7a/libpostproc-54.so
)


add_library(
        swresample
        SHARED
        IMPORTED
)

set_target_properties(
        swresample
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/cpp/armeabi-v7a/libswresample-2.so
)

add_library(
        swscale
        SHARED
        IMPORTED
)

set_target_properties(
        swscale
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/cpp/armeabi-v7a/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
        avutil
        avdevice
        avfilter
        avformat
        postproc
        swscale
        swresample

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib} )

6、修改native-lib.cpp

#include <jni.h>
#include <string>
//注意下面的代碼都要在 extern "C" {}裏面編寫
extern "C" {
//引入cpp 下面 的include/libavcodec/avcodec.h頭文件 用於測試顯示配置信息
#include "include/libavcodec/avcodec.h"
jstring
//注意命名  將com_wyl_ffmpegdemo換成自己項目的包名
Java_com_wyl_ffmpegdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    // std::string hello = "Hello from C++";
    //return env->NewStringUTF(hello.c_str());
    return env->NewStringUTF(avcodec_configuration());
}
}

注意命名 將com_wyl_ffmpegdemo換成自己項目的包名

7、測試FFmpeg是否接入成功
在MainActivity中

 public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
        //注意不要把so的前綴lib給複製上來了

        System.loadLibrary("avutil-55");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avformat-57");
        System.loadLibrary("avdevice-57");
        System.loadLibrary("swresample-2");
        System.loadLibrary("swscale-4");
        System.loadLibrary("postproc-54");
        System.loadLibrary("avfilter-6");
    }

    @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());
    }

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

編譯通過,並運行安裝成功後會提示:
在這裏插入圖片描述
至此,Android Studio 接入FFmpeg就告一段落了。

FFmpeg的大門已經打開啦…總結一下接下來的路需要什麼裝備吧:
1、瞭解Linux下的一些命令
2、瞭解.sh腳本語言
3、編譯出主流架構下的so庫:armeabi-v7a,x86和armeabi
4、瞭解CMakeLists.txt
5、瞭解學習C,C++

更新:

爲何要將configure文件裏的代碼

# 將 configure 文件中的:
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)'

原來是因爲:

Android 工程中只支持導入 .so 結尾的動態庫,形如:libavcodec-57.so 。但是FFmpeg 編譯生成的動態庫默認格式爲 xx.so.版本號 ,形如:libavcodec.so.57 , 所以需要修改 FFmpeg 根目錄下的 configure 文件,使其生成以 .so 結尾格式的動態庫:
————————————————
版權聲明:本文爲CSDN博主「王英豪」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yhaolpz/article/details/76408829

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章