zoukankan      html  css  js  c++  java
  • 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

    • 本文作者: Jia Yayao
    • 赞赏:如果每人给我一块钱..$$
    • 支付宝

      微信

  • 相关阅读:
    Android之针对WebView的全屏播放
    Android之Android WebView常见问题及解决方案汇总
    android之针对fragment多次调用onCreateView的问题
    Android之在string.xml配置文字颜色粗体等效果
    ios成长之每日一遍(day 8)
    Android之TextView灵活使用
    ubuntu忘记root密码 的解决方法
    Mono Touch Table应用
    判断checkbox选中的个数
    C指针原理(14)
  • 原文地址:https://www.cnblogs.com/jiayayao/p/14829469.html
Copyright © 2011-2022 走看看