美文网首页Android Tech音视频FFmpeg
在Mac下编译 FFmpeg ,并在Android中使用

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

作者: maimingliang | 来源:发表于2017-07-08 18:58 被阅读1454次

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。

相关文章

网友评论

  • 双鱼大猫:请问 我执行 ./build_android.sh,为什么没有任何反应呢?
  • 533e9ec2b960:你好。我在编译的时候,总是报
    In file included from libavdevice/avdevice.c:19:0:
    ./libavutil/avassert.h:30:20: fatal error: stdlib.h: No such file or directory
    #include <stdlib.h>

    In file included from ./libavutil/reverse.c:21:0,
    from libavdevice/reverse.c:1:
    /Users/yinxiucheng/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/include/stdint.h:9:26: fatal error: stdint.h: No such file or directory
    # include_next <stdint.h>

    In file included from ./libavutil/avutil.h:296:0,
    from ./libavutil/log.h:25,
    from libavdevice/avdevice.h:48,
    from libavdevice/alldevices.c:23:
    ./libavutil/common.h:33:19: fatal error: errno.h: No such file or directory
    #include <errno.h>

    这样的错误,这些文件在我的NDK里面是有的,知道为啥嚒?
    汪简书:我也遇过,可以参见我的blog,FFmpeg 遇到的一些坑 https://www.jianshu.com/p/da5d55b59f4b
    ChangQin:In file included from libavfilter/aeval.c:26:0:
    ./libavutil/avassert.h:30:20: fatal error: stdlib.h: No such file or directory
    #include <stdlib.h> 我的是这个错
    ChangQin:+1同问,太坑了
  • 双鱼大猫:不错哦
  • 眷卿三世:请问作者,使用Android_build.sh这个脚本的时候没有报错?
    眷卿三世:临时文件路径我也加了,就是报这个错误
    眷卿三世:@maimingliang 现在是另一个错误:/Users/dev/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc is unable to create an executable file.
    maimingliang:是不是没有把注释去掉?
  • Muse_Ykh:很详细,非常感谢,总算成功了!网上和很多教程都比较老,都没有用as来做,找了很久终于找到一个讲解详细步骤清晰的教程了

本文标题:在Mac下编译 FFmpeg ,并在Android中使用

本文链接:https://www.haomeiwen.com/subject/vnadhxtx.html