NDK R20编译Ffmpeg集成Android命令

本次编译环境为windows,linux和mac大同小异(windows都异类了,其他环境编译没啥问题)
下载好MINGW,咋个配置的,百度吧,忘了。

下载好NDK文件,我是R20版本的;在从ffmpeg的官方下载源码,版本4.2.2

脚本编译

ffmpeg从四点几开始的不想了解了,就已经默认对android编译进行了设置。
NDK R20编译Ffmpeg集成Android命令_第1张图片
也默认开启了clang编译
NDK R20编译Ffmpeg集成Android命令_第2张图片

所以只需要写个编译脚本就van事了。

#!/bin/bash
export TMPDIR=`dirname $0`/tmpdir
NDK=D:/technology/android-ndk-r20
API=16
# arm aarch64 i686 x86_64
ARCH=arm
# armv7a aarch64 i686 x86_64
PLATFORM=armv7a
TARGET=$PLATFORM-linux-androideabi
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/windows-x86_64/bin
SYSROOT=$NDK/sysroot
PREFIX=`dirname $0`/Android/$PLATFORM
 
CFLAG="-D__ANDROID_API__=$API -U_FILE_OFFSET_BITS -DBIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD -Os -fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm"
 
mkdir -p $TMPDIR
 
build_one()
{
./configure \
--ln_s="cp -rf" \
--prefix=$PREFIX \
--cc=$TOOLCHAIN/$TARGET$API-clang \
--cxx=$TOOLCHAIN/$TARGET$API-clang++ \
--ld=$TOOLCHAIN/$TARGET$API-clang \
--target-os=android \
--arch=$ARCH \
--cpu=$PLATFORM \
--cross-prefix=$TOOLCHAIN/$ARCH-linux-androideabi- \
--enable-cross-compile \
--enable-shared \
--disable-static \
--enable-runtime-cpudetect \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-symver \
--enable-small \
--enable-gpl --enable-nonfree --enable-version3 --disable-iconv --enable-neon --enable-hwaccels \
--enable-jni \
--enable-mediacodec \
--enable-avdevice  \
--disable-decoders --enable-decoder=vp9 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=aac --enable-decoder=h264_mediacodec \
--disable-postproc \
--extra-cflags="$CFLAG" \
--extra-ldflags="-marm"
}
 
build_one
 
make clean
 
make -j4
 
make install

针对配置开开关关的到处打log看为什么错误。哎。最终这个配置能使用。
编译结束后会直接有文件Android的生成,需要的动态库和文件都在这里面

PS:以上配置要用64位的需要重新编写文件路径(换成自己的就好了)

Android集成

将刚刚编译好的包以及头文件进行移动
NDK R20编译Ffmpeg集成Android命令_第3张图片
整个最后的文件类似于这种,你也可以按照自己的喜好来,ffmpeg.c这个是为了执行ffmpeg的各种命令
从之前的源码包里,在fftools这个文件夹里能够找到各个文件,然后导入进来
build.gradle的配置

    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt" //改成自己的路径
        }
    }

编写CMakaList.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)

include_directories(
        ${CMAKE_SOURCE_DIR}/include/
        ${CMAKE_SOURCE_DIR}/
        D:/technology/ffmpeg-422
)
#定义全局 my_source_path 变量
file(GLOB my_source_path
        ${CMAKE_SOURCE_DIR}/*.cpp
        ${CMAKE_SOURCE_DIR}/*.c
        )
# Creates and names a library, sets it as either STATICw
# 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).
        ${my_source_path})

add_library(avcodec SHARED IMPORTED)
add_library(avdevice SHARED IMPORTED)
add_library(avfilter SHARED IMPORTED)
add_library(avformat SHARED IMPORTED)
add_library(avutil SHARED IMPORTED)
add_library(swresample SHARED IMPORTED)
add_library(swscale SHARED IMPORTED)
#add_library(postproc SHARED IMPORTED)

set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavcodec.so)
set_target_properties(avdevice PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavdevice.so)
set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavfilter.so)
set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavformat.so)
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavutil.so)
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswresample.so)
set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswscale.so)
#set_target_properties(postproc PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libpostproc.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
#        postproc
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

接着需要改动一些东西,方法名随意
ffmpeg.c里的int main()改为int ffmpeg_exec()
在该函数的末尾添加:

    nb_filtergraphs = 0;
    nb_output_files = 0;
    nb_output_streams = 0;
    nb_input_files = 0;
    nb_input_streams = 0;

注释掉exit_program()方法,可注释掉该函数内的所有这个方法,不过注意一下if的作用域

//    exit_program(received_nb_signals ? 255 : main_return_code); // 退出程序,不过以报错的形式

接着在ffmpeg.h头文件里,对方法进行添加
int ffmpeg_exec(int argc, char **argv);

然后按照JNI的方式调用方法进行命令行的执行
native-lib.cpp

#include 
#include 
#include "android_log.h"

extern "C" {
#include "ffmpeg.h"

JNIEXPORT jint JNICALL
Java_cn_krisez_vvv_FFmpegUtil_exec(JNIEnv *env, jclass, jobjectArray cmd) {
    int leng = env->GetArrayLength(cmd);
    char *argv[leng];
    for (int i = 0; i < leng; ++i) {
        argv[i] = (char*) env->GetStringUTFChars((jstring) env->GetObjectArrayElement(cmd, i), nullptr);
    }
    return ffmpeg_exec(leng,argv);
}
}

Java层:

public class FFmpegUtil {
    static {
        System.loadLibrary("avcodec");
        System.loadLibrary("avdevice");
        System.loadLibrary("avfilter");
        System.loadLibrary("avformat");
        System.loadLibrary("avutil");
        System.loadLibrary("swresample");
        System.loadLibrary("swscale");
//        System.loadLibrary("postproc");
        System.loadLibrary("native-lib");
    }
    public static native String stringFromJNI();
    public static native int exec(String[] cmd);
}

执行的时候直接调用FFmpegUtil.exec();

tv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                String out = Environment.getExternalStorageDirectory() + "/" + System.currentTimeMillis() + ".mp4";
                //以数组的方式传递参数
                tv.setText("a  "+FFmpegUtil.exec(new String[]{
                        "ffmpeg",
                        "-i",
                        Environment.getExternalStorageDirectory()+"/ysgs.mp4",
                        "-ss","14",
                        "-c","copy","-t","10",
                        out
                }));
            }
        }).run();
    }
});

如此将ffmpeg的命令调用方式编译进了Android
仓库自取:Github

你可能感兴趣的:(android开发,android)