FFmpeg development (01): FFmpeg compilation and integration

The original article was first published on wechat official account: byte flow

Why learn FFmpeg development

FFmpeg is a well-known open source audio and video processing software. It provides rich and friendly interfaces to support developers' secondary development.

FFmpeg reads "ef ef em peg", where "FF" refers to "Fast Forward" and "mpeg" refers to "Moving Picture Experts Group".

FFmpeg project has complex and huge functions, and basically supports all common audio and video processing operations, such as packaging format conversion, audio and video transcoding, audio and video playback and editing, video adding watermark filter, etc.

Although FFmpeg is powerful, because it adopts the infectious LGPL/GPL open source protocol, some large manufacturers basically independently develop similar audio and video processing libraries, and even imitate FFmpeg in interface and organization modules.

Therefore, learning FFmpeg can not only help you master the relevant knowledge of audio and video development, but also enable you to quickly adapt to different audio and video processing frameworks.

FFmpeg compilation

FFmpeg has six common functional modules:

  • libavformat: packaging and unpacking Library of multimedia files or protocols, such as Mp4, Flv and other file packaging formats, RTMP, RTSP and other network protocol packaging formats;
  • libavcodec: audio and video codec library;
  • libavfilter: audio, video and caption filter library;
  • libswscale: image format conversion library;
  • libswresample: Audio resampling library;
  • libavutil: tool library;

This article is mainly to help beginners quickly get started with the compilation and integration of FFmpeg. There is no more detail on the compilation and configuration of FFmpeg project, which can not be accommodated in this article.

Here we mainly choose to compile ffmpeg v4 Version 2.2, because there are many online solutions in this version, and most of them are feasible.

Compilation environment:

  • CentOS Linux release 7.6.1810 (Core)
  • android-ndk-r20b-linux-x86_64
  • ffmpeg-4.2.2

Preparation before compilation:

//1. Download ffmpeg-4.2.2
wget https://ffmpeg.org/releases/ffmpeg-4.2.2.tar.bz2
//2. Decompress FFmpeg 
tar -jxvf ffmpeg-4.2.2.tar.bz2
//3. Configuration items
./configure --disable-x86asm

Create the compilation script build in the FFmpeg 4.2.2 decompression directory_ android_ arm64-v8a_ clang. sh:

#!/bin/bash

export NDK=/root/workspace/android-ndk-r20b #Configure your NDK path here first
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64


function build_android
{

./configure \
--prefix=$PREFIX \
--enable-neon  \
--enable-hwaccels  \
--enable-gpl   \
--disable-postproc \
--disable-debug \
--enable-small \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-static \
--enable-shared \
--disable-doc \
--enable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-avdevice \
--disable-doc \
--disable-symver \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC \
--cxx=$CXX \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS"

make clean
make -j16
make install

echo "============================ build android arm64-v8a success =========================="

}

#arm64-v8a
ARCH=arm64
CPU=armv8-a
API=21
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"

build_android

Compile 64 bit dynamic library and static library of FFmpeg Android platform:

# Modify build_android_arm64-v8a_clang.sh executable permissions
chmod +x build_android_arm64-v8a_clang.sh
# Run compiled script
./build_android_arm64-v8a_clang.sh

After successful compilation, the static library and dynamic library corresponding to the six modules will be generated in the android directory.

In addition, if you want to compile into a 32-bit library, you need to modify the corresponding compilation script:

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

FFmpeg integration

Based on the FFmpeg static library compiled in the previous section, we conduct a simple integration test on Android Studio.

As shown in the figure above, we can place the static libraries and header files of each module of FFmpeg in the specified directory to achieve a jni to obtain the version information of each module.

#include <cstdio>
#include <cstring>
#include "util/LogUtil.h"
#include "jni.h"

//Since the FFmpeg library is implemented in C language, tell the compiler to compile according to the rules of C
extern "C" {
#include <libavcodec/version.h>
#include <libavcodec/avcodec.h>
#include <libavformat/version.h>
#include <libavutil/version.h>
#include <libavfilter/version.h>
#include <libswresample/version.h>
#include <libswscale/version.h>
};

#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_byteflow_learnffmpeg_media_FFMediaPlayer
 * Method:    native_GetFFmpegVersion
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_byteflow_learnffmpeg_media_FFMediaPlayer_native_1GetFFmpegVersion
        (JNIEnv *env, jclass cls)
{
    char strBuffer[1024 * 4] = {0};
    strcat(strBuffer, "libavcodec : ");
    strcat(strBuffer, AV_STRINGIFY(LIBAVCODEC_VERSION));
    strcat(strBuffer, "\nlibavformat : ");
    strcat(strBuffer, AV_STRINGIFY(LIBAVFORMAT_VERSION));
    strcat(strBuffer, "\nlibavutil : ");
    strcat(strBuffer, AV_STRINGIFY(LIBAVUTIL_VERSION));
    strcat(strBuffer, "\nlibavfilter : ");
    strcat(strBuffer, AV_STRINGIFY(LIBAVFILTER_VERSION));
    strcat(strBuffer, "\nlibswresample : ");
    strcat(strBuffer, AV_STRINGIFY(LIBSWRESAMPLE_VERSION));
    strcat(strBuffer, "\nlibswscale : ");
    strcat(strBuffer, AV_STRINGIFY(LIBSWSCALE_VERSION));
    strcat(strBuffer, "\navcodec_configure : \n");
    strcat(strBuffer, avcodec_configuration());
    strcat(strBuffer, "\navcodec_license : ");
    strcat(strBuffer, avcodec_license());
    LOGCATE("GetFFmpegVersion\n%s", strBuffer);
    return env->NewStringUTF(strBuffer);
}

#ifdef __cplusplus
}
#endif

Calling logic of Java layer:

package com.byteflow.learnffmpeg.media;

public class FFMediaPlayer {
    static {
        System.loadLibrary("learn-ffmpeg");
    }

    public static String GetFFmpegVersion() {
        return native_GetFFmpegVersion();
    }

    private static native String native_GetFFmpegVersion();
}

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((TextView)findViewById(R.id.text_view)).setText(FFMediaPlayer.GetFFmpegVersion());
    }
}

CMakeLists.txt build script:

# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

set(jnilibs ${CMAKE_SOURCE_DIR}/../jniLibs)
set(libname learn-ffmpeg)

include_directories(
        include
        ${CMAKE_SOURCE_DIR}/util
)

link_directories(
        ${jnilibs}/${ANDROID_ABI})

file(GLOB src-files
        ${CMAKE_SOURCE_DIR}/*.cpp)

add_library( # Sets the name of the library.
             ${libname}

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             ${src-files}
        )

set(third-party-libs
        avformat
        avcodec
        avfilter
        swresample
        swscale
        avutil
        )

set(native-libs
        android
        EGL
        GLESv3
        OpenSLES
        log
        m
        z
        )

target_link_libraries( # Specifies the target library.
                       ${libname}

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

After compilation, run App to obtain the version and compilation configuration information of each module of FFmpeg.

reference resources

https://blog.csdn.net/leixiaohua1020
https://juejin.im/post/5e1eace16fb9a02fec66474e

Contact and communication

Technical exchange to obtain the source code, you can scan the code and add my wechat: byte flow

Tags: Android ffmpeg NDK

Posted by chrisg101 on Wed, 18 May 2022 05:38:19 +0300