Mac平台交叉編譯Android/iOS FFmpeg庫


一、前提

    FFmpeg版本必須與系統版本(iOS)和ndk版本(Android)相匹配,否則就會有各種奇葩的編譯問題。有些是ffmpeg代碼與iOS系統庫沖突,有些是ffmpeg代碼與ndkd版本沖突,解決這些問題很浪費時間,且毫無意義。

二、iOS

    1. 版本

    FFmpeg:4.4

    macOS:11.2.2

    2. 步驟

  • github上下載ffmpeg;
  • github上下載gas-preprocessor.pl,並拷貝至/usr/local/bin下,添加777權限;
  • mac安裝Command Line Tools
  • 下載編譯腳本:https://github.com/kewlbear/FFmpeg-iOS-build-script
  • 修改build-ffmpeg.sh腳本種的FF_VERSION為你的版本號,修改SOURCE為你的ffmpeg路徑
  • ./build-ffmpeg.sh 

三、Android

    1. 版本

    FFmpeg:4.2.1(建議無歷史包袱的項目采用較新版本的FFmpeg)

    ndk:r21e

    2. 編譯腳本

#!/bin/bash
# 以下路徑需要修改成自己的NDK目錄
TOOLCHAIN=/Users/jiayayao/Library/Android/sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64
# 最低支持的android sdk版本
API=21

function build_android
{
echo "Compiling FFmpeg for $CPU"
./configure \
 --prefix=$PREFIX \
 --disable-hwaccels \
 --disable-gpl \
 --disable-postproc \
 --enable-shared \
 --enable-jni \
 --disable-mediacodec \
 --enable-small \
 --enable-gpl \
 --disable-decoder=h264_mediacodec \
 --disable-static \
 --disable-doc \
 --disable-programs \
 --disable-ffmpeg \
 --disable-ffplay \
 --disable-ffprobe \
 --disable-avdevice \
 --disable-symver \
 --enable-neon \
 --disable-asm \
 --cross-prefix=$CROSS_PREFIX \
 --target-os=android \
 --arch=$ARCH \
 --cpu=$CPU \
 --cc=$CC \
 --cxx=$CXX \
 --enable-cross-compile \
 --sysroot=$SYSROOT \
 --extra-cflags="-mno-stackrealign -Os $OPTIMIZE_CFLAGS -fPIC" \
 --extra-ldflags="$ADDI_LDFLAGS" \
 $ADDITIONAL_CONFIGURE_FLAG
make clean
make -j16
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}

# armv8-a
ARCH=arm64
CPU=armv8-a
# r21版本的ndk中所有的編譯器都在/toolchains/llvm/prebuilt/darwin-x86_64/目錄下(clang)
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
# NDK頭文件環境
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
# so輸出路徑
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"
build_android

# 交叉編譯工具目錄,對應關系如下
# armv8a -> arm64 -> aarch64-linux-android-
# armv7a -> arm -> arm-linux-androideabi-
# x86 -> x86 -> i686-linux-android-
# x86_64 -> x86_64 -> x86_64-linux-android-

# CPU架構
# armv7-a
ARCH=arm
CPU=armv7-a
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
build_android

# x86
ARCH=x86
CPU=x86
CC=$TOOLCHAIN/bin/i686-linux-android$API-clang
CXX=$TOOLCHAIN/bin/i686-linux-android$API-clang++
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/i686-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
build_android

# x86_64
ARCH=x86_64
CPU=x86-64
CC=$TOOLCHAIN/bin/x86_64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/x86_64-linux-android$API-clang++
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/x86_64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel"
# 方法調用
build_android

 3. Android Studio使用編譯好的so:

a, Android Studio新建native項目,build.gradle添加如下代碼: 

    defaultConfig {
        applicationId "com.example.ffmpegtest"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags '-std=c++11'
            }
        }
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }
    }
    splits {
        abi {
            enable true
            reset()
            include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
            universalApk true
        }
    }

 b, CMakeList.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.10.2)

# Declares and names the project.

project("ffmpegtest")

# 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).
             native-lib.cpp )

set(JNI_LIBS_DIR ${CMAKE_SOURCE_DIR}/../ffmpeg)

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

add_library(avresample
        SHARED
        IMPORTED )
set_target_properties(avresample
        PROPERTIES IMPORTED_LOCATION
        ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libavresample.so )

add_library(swresample
        SHARED
        IMPORTED )
set_target_properties(swresample
        PROPERTIES IMPORTED_LOCATION
        ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libswresample.so )

add_library(swscale
        SHARED
        IMPORTED )
set_target_properties(swscale
        PROPERTIES IMPORTED_LOCATION
        ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libswscale.so )

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

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

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

add_library(avdevice
        SHARED
        IMPORTED )
set_target_properties(avdevice
        PROPERTIES IMPORTED_LOCATION
        ${JNI_LIBS_DIR}/${ANDROID_ABI}/lib/libavdevice.so )

include_directories(${JNI_LIBS_DIR}/${ANDROID_ABI}/include)

target_link_libraries(native-lib
        avutil swresample swscale avcodec avformat avfilter
        ${log-lib} ${android-lib} )

  c, native-lib.cpp添加如下代碼:

#include <jni.h>
#include <string>
#include <android/log.h>


extern "C" {
#include <libavformat/avformat.h>
}

void ffmpeg_log_output(void* ptr, int level, const char* fmt, va_list vl) {
    __android_log_print(ANDROID_LOG_INFO, "jiayayao", "[ffmpeg log]%s", fmt);
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_ffmpegtest_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    av_log_set_callback(ffmpeg_log_output);
    AVFormatContext *pContext = avformat_alloc_context();
    avformat_open_input(&pContext, "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8", nullptr, nullptr);
    avformat_find_stream_info(pContext, nullptr);
    std::string hello = "jiayayao";
    return env->NewStringUTF(hello.c_str());
}

 d, AndroidManifest.Xml添加如下權限以聯網:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

e, 日志顯示ffmpeg打開url成功:

I/jiayayao: [ffmpeg log]stream %d: start_time: %0.3f duration: %0.3f [ffmpeg log]format: start_time: %0.3f duration: %0.3f bitrate=%lld kb/s 
I/jiayayao: [ffmpeg log]After avformat_find_stream_info() pos: %lld bytes read:%lld seeks:%d frames:%d

f, github鏈接:https://github.com/jiayayao/ffmpegtest


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM