正确构建适用于所有 Android 架构的 FFmpeg

Posted

技术标签:

【中文标题】正确构建适用于所有 Android 架构的 FFmpeg【英文标题】:Build FFmpeg for All Android architecture correctly 【发布时间】:2018-04-02 23:12:26 【问题描述】:

我为所有 android 架构构建了 ffmpeg 库。但是有些细节让我很困惑。首先让我一步一步解释我是如何构建的。

我下载了最新版本的libx264 从 https://www.videolan.org/developers/x264.html 创建并运行 build_all.sh 脚本(在 x264 文件夹中)为(几乎)所有 android 平台创建库。然后我在 x264 文件夹中得到了android 文件夹。例如 android/arm android/arm64 android/x86 android/x86_64 在 x264 文件夹中。 我从https://ffmpeg.org/download.html下载ffmpeg3.3.4 我创建了ffmpeg3.3.4 文件夹的4 个副本。用 android 架构名称命名它们。 喜欢ffmpeg3.3.4-arm64ffmpeg3.3.4-armffmpeg3.3.4-x86ffmpeg3.3.4-x86_64 为每个android平台创建了build_(architecture-name).sh。然后根据架构名称将'named'.sh files 中的每一个移动到命名的 ffmpeg 文件夹中。 例如build_android_x86.sh => ffmpeg3.3.4-x86

build_android_arm64.sh 示例

#!/bin/bash
#Change NDK to your Android NDK location
NDK=$HOME/Android/Sdk/ndk-bundle
PLATFORM=$NDK/platforms/android-21/arch-arm64/
PREBUILT=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64

GENERAL="\
--enable-small \
--enable-cross-compile \
--extra-libs="-lgcc" \
--arch=aarch64 \
--cc=$PREBUILT/bin/aarch64-linux-android-gcc \
--cross-prefix=$PREBUILT/bin/aarch64-linux-android- \
--nm=$PREBUILT/bin/aarch64-linux-android-nm \
--extra-cflags="-I../x264/android/arm64/include" \
--extra-ldflags="-L../x264/android/arm64/lib" "

MODULES="\
--enable-gpl \
--enable-libx264"



function build_arm64

  ./configure \
  --logfile=conflog.txt \
  --target-os=linux \
  --prefix=./android/arm64-v8a \
  $GENERAL \
  --sysroot=$PLATFORM \
  --extra-cflags="" \
  --extra-ldflags="-lx264 -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl -llog" \
  --enable-shared \
  --disable-static \
  --disable-doc \
  --enable-zlib \
  $MODULES

  make clean
  make
  make install


build_arm64


echo Android ARM64 builds finished
将所有ffmpeg3.3.4-arm64ffmpeg3.3.4-armffmpeg3.3.4-x86ffmpeg3.3.4-x86_64文件夹移至NDK_PATH(C:\Users\MyName\AppData\Local\Android\sdk\ndk-bundle) 将x264 文件夹与ffmpeg 文件夹置于同一层次 在 (C:\Users\MyName\AppData\Local\Android\sdk\ndk-bundle) 在各自的 ffmpeg 文件夹中逐个运行 build_android_x86.shbuild_android_x86_64.sh.. 脚本。然后我在 ffmpeg 文件夹中获得了 android 文件夹。 (创建android 文件夹有库文件夹) 例如ffmpeg3.3.4-x86/android/x86/(bin,inlude,lib,share)

为所有创建的android 文件夹创建Android.mk 文件,并将它们中的每一个移动到 android/armName 文件夹。例如Android.mk => ffmpeg3.3.4-x86/android/x86/

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavcodec
LOCAL_SRC_FILES:= lib/libavcodec-57.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavformat
LOCAL_SRC_FILES:= lib/libavformat-57.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libswscale
LOCAL_SRC_FILES:= lib/libswscale-4.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavutil
LOCAL_SRC_FILES:= lib/libavutil-55.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavfilter
LOCAL_SRC_FILES:= lib/libavfilter-6.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libswresample
LOCAL_SRC_FILES:= lib/libswresample-2.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := postproc
LOCAL_SRC_FILES := lib/libpostproc-54.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := lib/libavdevice-57.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

在我的项目的 jni 文件夹(myproject/app/jni/x86myproject/app/jni/x86_64)中创建“arm 命名”文件夹,例如 x86 x86_4 arm64 arm7

转到ndk路径打开命名的ffmpeg文件夹,然后将ffmpeg.cffmpeg_filter.cffmpeg_opt.ccmdutils.c文件从ffmpeg文件夹复制到“arm命名”文件夹。例如ffmpeg.c => myproject/app/jni/x86

在我的项目中创建了 Android.mk 文件。

LOCAL_PATH := $(call my-dir)
#$(warning $(LOCAL_PATH))

include $(CLEAR_VARS)
LOCAL_MODULE    := videoEdit
LOCAL_LDLIBS := -llog -ljnigraphics -lz -landroid
LOCAL_CFLAGS := -Wdeprecated-declarations
ANDROID_LIB := -landroid

$(info $(TARGET_ARCH_ABI))

ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
    LOCAL_C_INCLUDES:=/Users/MyName/AppData/Local/Android/sdk/ndk-bundle/sources/ffmpeg-3.3.4-armeabi
    LOCAL_SRC_FILES :=  videoEdit.c arm7/ffmpeg.c arm7/ffmpeg_filter.c arm7/ffmpeg_opt.c arm7/cmdutils.c
    LOCAL_CFLAGS += -lx264 -Wl,--no-merge-exidx-entries
else

    ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
            LOCAL_C_INCLUDES:=/Users/MyName/AppData/Local/Android/sdk/ndk-bundle/sources/ffmpeg-3.3.4-arm64-v8a
            LOCAL_SRC_FILES :=  videoEdit.c arm64/ffmpeg.c arm64/ffmpeg_filter.c arm64/ffmpeg_opt.c arm64/cmdutils.c
            LOCAL_CFLAGS += -funwind-tables -Wl,--no-merge-exidx-entries
    else

        ifeq ($(TARGET_ARCH_ABI),x86_64)
               LOCAL_C_INCLUDES:=/Users/MyName/AppData/Local/Android/sdk/ndk-bundle/sources/ffmpeg3.3.4-x86_64
               LOCAL_SRC_FILES :=  videoEdit.c x86_64/ffmpeg.c x86_64/ffmpeg_filter.c x86_64/ffmpeg_opt.c x86_64/cmdutils.c
        else
                LOCAL_C_INCLUDES:=/Users/MyName/AppData/Local/Android/sdk/ndk-bundle/sources/ffmpeg3.3.4-x86
                LOCAL_SRC_FILES :=  videoEdit.c x86/ffmpeg.c x86/ffmpeg_filter.c x86/ffmpeg_opt.c x86/cmdutils.c
        endif

    endif

endif

LOCAL_SHARED_LIBRARIES := libavformat libavcodec libswscale libavutil libswresample libavfilter libavdevice libpostproc

include $(BUILD_SHARED_LIBRARY)

ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)

    $(call import-module,ffmpeg-3.3.4-armeabi/android/armeabi-v7a)

else

    ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
            $(call import-module,ffmpeg-3.3.4-arm64-v8a/android/arm64-v8a)
    else

        ifeq ($(TARGET_ARCH_ABI),x86_64)
               $(call import-module,ffmpeg3.3.4-x86_64/android/x86_64)
        else
            $(call import-module,ffmpeg3.3.4-x86/android/i686-diasm)
        endif

    endif

endif

在我的项目中创建 Application.mk 文件。

APP_ABI := armeabi-v7a, arm64-v8a, x86_64, x86
APP_PLATFORM := android-14

创建了 videoEdit.c 而不是运行ndk-build build 命令。

构建没有错误。我可以运行 ffmpeg 命令,但我认为这需要太多时间。例如,当我尝试运行 hflip 时,它会在 15 秒内翻转视频。

代码示例:

JNIEXPORT jint JNICALL Java_com_name_app_library_VideoEditer_natives_VideoEditer_flipHorizontally
(JNIEnv *env, jclass someclass, jstring inputFile, jstring outFile) 

    int numberOfArgs = 14;

    char** arguments = calloc(numberOfArgs, sizeof(char*));
    const char *in, *out;

    in = (*env)->GetStringUTFChars(env, inputFile, 0);
    out = (*env)->GetStringUTFChars(env, outFile, 0);

    arguments[0] = "ffmpeg";
    arguments[1] = "-i";
    arguments[2] = in;
    arguments[3] = "-c:v";
    arguments[4] = "libx264";
    arguments[5] = "-preset";
    arguments[6] = "ultrafast";
    arguments[7] = "-threads";
    arguments[8] = "5";
    arguments[9] = "-c:a";
    arguments[10] = "copy";
    arguments[11] = "-vf";
    arguments[12] = "hflip";
    arguments[13] = out;

    int i;
    for (i = 0; i < numberOfArgs; i++) 
        log_message(arguments[i]);
    
    log_message("Printed all");

    main(numberOfArgs, arguments);
    free(arguments);
    (*env)->ReleaseStringUTFChars(env, inputFile, in);
    (*env)->ReleaseStringUTFChars(env, outFile, out);

    return 0;

在 android 上运行的 FFmpeg 命令,在模拟器上运行速度非常快,但在真实设备上运行速度很慢。

另外一件让我困惑的事情是./configure 命令的输出。 当我打开(例如)ffmpeg-3.3.4-arm64-v8a 文件夹并在终端中运行./configure 命令时。输出显示ARCH x86 (generic)。对于所有平台的输出都是相同的ARCH x86 (generic)

ffmpeg-3.3.4-arm64-v8a 文件夹中./configure 命令的输出

install prefix            /usr/local
source path               .
C compiler                gcc
C library                 glibc
ARCH                      x86 (generic)
big-endian                no
runtime cpu detection     yes
yasm                      yes
MMX enabled               yes
MMXEXT enabled            yes
3DNow! enabled            yes
3DNow! extended enabled   yes
SSE enabled               yes
SSSE3 enabled             yes
AESNI enabled             yes
AVX enabled               yes
XOP enabled               yes
FMA3 enabled              yes
FMA4 enabled              yes
i686 features enabled     yes
CMOV is fast              yes
EBX available             yes
EBP available             yes
debug symbols             yes
strip symbols             yes
optimize for size         no
optimizations             yes
static                    yes
shared                    no
postprocessing support    no
network support           yes
threading support         pthreads
safe bitstream reader     yes
texi2html enabled         no
perl enabled              yes
pod2man enabled           yes
makeinfo enabled          no
makeinfo supports HTML    no

External libraries:
iconv            xlib

EDIT 所有这些步骤都是在 ubuntu 上完成的,然后将所有文件夹移动到 windows。所以不要混淆路径。

对于所有这些步骤,我想问的是,我的步骤有什么问题吗?我应该遵循其他方式吗?为什么 ffmpeg 在真实设备上运行速度较慢。我很想知道一件事,retrica、snapchat、instagram 如何将视频录制为镜像翻转?他们是在录制后翻转(如果他们在一秒钟内如何做到这一点)还是在录制运行时翻转的视频?我想为 android 构建 ffmpeg 有点乱,而且做错事很容易。如果您查看我的步骤、问题并给我建议,我将不胜感激。

【问题讨论】:

我会查看构建文件的拱门。另外,你想念$(call import-module,android/cpufeatures) 吗? IIRC,这是打开 NEON 优化代码所必需的。见github.com/DrKLO/Telegram/blob/master/TMessagesProj/jni/… 构建哪个文件,抱歉无法理解。你是说 libx264 的构建文件还是 ffmpeg 文件的构建文件? 你是真的它不见了。我将添加$(call import-module,android/cpufeatures) 让我们看看它的效果。 @JamesPoag 添加cpufeatures 后,hflip 视频的性能没有变化(编译没有错误)。 @fthopkins 很抱歉提出愚蠢的问题。为什么要使用 libx264 并在此目录中运行所有脚本?编译FFMPEG需要libx264吗? 【参考方案1】:
ARCH                      x86 (generic)

那肯定错了,应该列出具体的架构。

我认为https://github.com/IljaKosynkin/FFmpeg-Development-Kit 会帮助你,我能够在第一次尝试时正确构建所有架构。您正在使用命令行 ffmpeg,因此您需要启用该程序。

【讨论】:

这个答案是解决我的问题的最佳方法。谢谢。 @fthopkins 请让我们知道您做错了什么以及如何解决问题。您是否关注github.com/IljaKosynkin/FFmpeg-Development-Kit 来解决此问题?您究竟更新了什么来解决问题?

以上是关于正确构建适用于所有 Android 架构的 FFmpeg的主要内容,如果未能解决你的问题,请参考以下文章

适用于 Apple 和 Android 的 Azure 通知中心

为 Phonegap 构建创建自定义 AdMob 插件(适用于 iOS 和 Android)

适用于 Android 的 Phonegap 推送通知

使用适用于 android 的字节播放声音

适用于android的良好ORM工具[关闭]

Phonegap/Cordova Geolocation 不适用于 Android 4.0+,但适用于所有其他平台