×

在Mac下编译 FFmpeg ,并在Android中使用

96
maimingliang
2017.07.08 18:58* 字数 725

FFmpeg是一套具有非常强大功能的多媒体处理工具,它几乎涵盖了目前所有主流的多媒体数据封装格式、多媒体传输协议以及音视频编解码器,并且支持多媒体后处理,视频色彩转换、滤镜和缩放等,也支持众多主流的协议:HTTP、RTP、RTSP、RTMP、HLS、UDP等

FFmpeg它主要含有以下几个核心库:

1、libavcodec-提供了更加全面的编解码实现的合集
2、libavformat-提供了更加全面的音视频容器格式的封装和解析以及所支持的协议
3、libavutil-提供了一些公共函数
4、libavfilter-提供音视频的过滤器,如视频加水印、音频变声等
5、libavdevice-提供支持众多设备数据的输入与输出,如读取摄像头数据、屏幕录制
6、libswresample,libavresample-提供音频的重采样工具
7、libswscale-提供对视频图像进行色彩转换、缩放以及像素格式转换,如图像的YUV转换
8、libpostproc-多媒体后处理器

以及包含以下几个工具:

1、ffmpeg-一个流媒体的编解码、格式转换以及多媒体流的内容处理工具
2、ffplay-一个使用FFmpeg编解码的播放器
3、ffprobe-一个多媒体分析工具4、ffserver-一个流多媒体服务器

下载FFmpeg

解压如下

001.png

默认编译出来的文件后缀并不是 *.so,这 Android 是识别不了的,需要对ffmpeg-3.3.2目录下的config文件做修改(大概在3304行):

SLIBNAME_WITH_VERSION='$(SLIBNAME).$(LIBVERSION)'
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'

修改为:

SLIBNAME_WITH_VERSION='$(SLIBNAME).$(LIBVERSION)'
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'  
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'  
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'  
SLIB_INSTALL_LINKS='$(SLIBNAME)'

编写shell文件

在ffmpeg-3.3.2文件夹下创建config.sh,配置一些通用的全局变量,如下:

#ndk 环境 
NDK=/Users/maimingliang/Documents/NDK/android-ndk-r12b
SYSROOT=$NDK/platforms/android-21/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
# cpu 架构平台,若要编译 x86 则指定 x86
CPU=armv7-a

然后创建ffmpeg编译脚本build_android.sh。如下:

#!/bin/sh

#引入配置文件
. config.sh

PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
function build_android
{
./configure \
    #编译输出前缀
    --prefix=$PREFIX \
    #启动生成动态库
    --enable-shared \
    --disable-static \
    --disable-doc \
    --disable-ffmpeg \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-ffserver \
    --disable-avdevice \
    --disable-doc \
    --disable-symver \
    --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
    --target-os=linux \
    --arch=arm \
    --enable-cross-compile \
    --sysroot=$SYSROOT \
    --extra-cflags="-Os -fpic $ADDI_CFLAGS" \
    --extra-ldflags="$ADDI_LDFLAGS" \
    $ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
build_android

打开终端把目录切换到ffmpeg-3.3.2下,给 build_android.sh 和 config.sh 赋予可执行权限。(chmod 777 build_android.sh config.sh).
并执行 ./build_android.sh。注意:执行前,要把shell文件的注释去掉

003.png

编译过程:

004.png

编译后生成的目录结构如下

100.png

在Android里使用FFmpeg

创建一个工程FFmpegDemo,
对于 NDK 开发,AndroidStudio 2.2 以后就有较好的支持。
直接修改Cmakelists.txt,build.gradle文件即可。

创建工程时,勾选下面的选项:

005.png
006.png

把.so文件和include下文件copy到libs下。

008.png

配置build.gralde文件

android {
 ......
    defaultConfig {
        ....
        ndk {
            abiFilters 'armeabi-v7a'
        }
    }
 
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

配置Cmakelists.txt

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

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 )

set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../libs)

add_library( avutil-55
             SHARED
             IMPORTED )
set_target_properties( avutil-55
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/armeabi-v7a/libavutil-55.so )

add_library( swresample-2
             SHARED
             IMPORTED )
set_target_properties( swresample-2
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/armeabi-v7a/libswresample-2.so )
add_library( avcodec-57
             SHARED
             IMPORTED )
set_target_properties( avcodec-57
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/armeabi-v7a/libavcodec-57.so )
add_library( avfilter-6
             SHARED
             IMPORTED)
set_target_properties( avfilter-6
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/armeabi-v7a/libavfilter-6.so )
add_library( swscale-4
             SHARED
             IMPORTED)
set_target_properties( swscale-4
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/armeabi-v7a/libswscale-4.so )

add_library( avformat-57
             SHARED
             IMPORTED)
set_target_properties( avformat-57
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/armeabi-v7a/libavformat-57.so )



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

add_library( native-lib
             SHARED
             src/main/cpp/native-lib.cpp
              )

include_directories(libs/include)

#target_include_directories(native-lib PRIVATE libs/include)

target_link_libraries( native-lib swresample-2 avcodec-57 avfilter-6 swscale-4 avformat-57
                       ${log-lib} )

在android studio 2.2 以后使用cmake

配置完成上面的操作,就成功把ffmpeg引入进来了。

测试引入是否成功?

在Main Activity中编写native方法。如下


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    // Example of a call to a native method
    final TextView tv = (TextView) findViewById(R.id.sample_text);
//    tv.setText(stringFromJNI());

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tv.setText(avcodecinfo());
            }
        });


    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public native String avcodecinfo();
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");

    }
}

在native-lib.cpp编写native方法实现,如下:


#include <jni.h>
#include <string>
extern "C" {

    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavfilter/avfilter.h>

    JNIEXPORT jstring JNICALL
    Java_com_maiml_ffmpegdemo2_MainActivity_avcodecinfo(JNIEnv *env, jobject instance) {

        char info[40000] = {0};
        av_register_all();
        AVCodec *c_temp = av_codec_next(NULL);
        while (c_temp != NULL) {
            if (c_temp->decode != NULL) {
                sprintf(info, "%sdecode:", info);
            } else {
                sprintf(info, "%sencode:", info);
            }
            switch (c_temp->type) {
                case AVMEDIA_TYPE_VIDEO:
                    sprintf(info, "%s(video):", info);
                    break;
                case AVMEDIA_TYPE_AUDIO:
                    sprintf(info, "%s(audio):", info);
                    break;
                default:
                    sprintf(info, "%s(other):", info);
                    break;
            }
            sprintf(info, "%s[%10s]\n", info, c_temp->name);
            c_temp = c_temp->next;
        }
        return env->NewStringUTF(info);
    }

    extern "C"
    jstring
    Java_com_maiml_ffmpegdemo2_MainActivity_stringFromJNI(
            JNIEnv *env,
            jobject /* this */) {
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }

}


运行结果:

009.png

END。

NDK
Web note ad 1