美文网首页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,为什么没有任何反应呢?
      • 江郎才无尽:你好。我在编译的时候,总是报
        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