美文网首页Android开发教程
音视频学习之路--编译FFmpeg

音视频学习之路--编译FFmpeg

作者: 蜗牛是不是牛 | 来源:发表于2021-12-05 21:09 被阅读0次

    前言

    看了前面的一些C/C++基础以及一些编译基础,那现在是时候实战一下,这里就编译顺便看一下FFmpeg的大体结构。

    正文

    这里就边操作,边记录吧,来看看大名鼎鼎的FFmpeg库。

    相关推荐
    Android音视频开发:音视频基础知识到直播推流实战系列教程_哔哩哔哩_bilibili

    FFmpeg定义

    FFmpeg既是一款音视频编解码工具,同时也是一组音视频编解码开发套件,作为编解码开发套件,为开发者提供了丰富的音视频处理的调用接口。

    FFmpeg提供了多种媒体格式的封装和解封装,包含多种音视频编解码、多种协议的流媒体、多种色彩格式转换、多种采样率转换、多种码率转换等等。

    同时FFmpeg框架提供了多种丰富的插件模块,包含封装与解封装插件、编码与解码的插件等。

    关于这里的一些具体概念,比如什么是封装和解封装,我们到后面学习音视频相关知识点就明白了,这里先大概了解。

    FFmpeg模块介绍

    关于下载FFmpeg代码很容易,从官网或者GitHub都可以,但是我尝试了在Linux上下载很慢,所以我直接在Windows上在GitHub下载了,拷贝到了Linux虚拟机中,下面就是完整的目录:

    FFmpeg框架的目录还是蛮清晰的,其中包括了几个模块,这里先简单介绍一下:

    • libavcodec

    编解码库,封装了Codec层,但是有一些codec是具备自己的License,FFmpeg不会默认添加,比如libx264、FDK-AAC、Lame等库,但是FFmpeg像是一个平台,可以降其他第三方codec以插件的方式添加进来,为开发者提供统一接口。

    • libavformat

    文件格式和协议库,封装了Protocol层和Demuxer、Muxer层,使得协议和格式对于开发者来说是透明的。

    • libavfilter

    音视频滤镜库,该模块包含了音视频特效的处理,在使用FFmpeg的API进行编解码的过程中,可以使用该模块高效的为音视频数据做特殊处理。

    • libavdevice

    输入输出设备库,比如需要编译出播放声音或者视频的工具ffplay,就需要确保该模块是打开的,同时也需要libsdl的预先编译,该设备模块播放声音和视频又都是使用libsdl库。

    • libavutil

    核心工具库,最基础模块之一,其他模块都会依赖该模块做一些基本的音视频处理操作。

    • libswresample

    用于音视频采样,可以对音频进行声道数、数据格式、采样率等多种基本信息的转换。

    • libswscale

    该模块用于图像格式转换,可以降YUV的数据转换为RGB的数据

    • libpostproc

    该模块用于后期处理,当我们使用filter的时候,就需要打开这个模块,filter会用到这个模块的一些基础函数。

    另外,库里还包含对H.264/MPEG-4 AVC视频编码的X264库,是非常常用的有损视频编码器,支持CBR、VBR模块,可以在编码的过程中直接改变码率的设置,在直播场景中非常适用,可以做码率自适应的功能。

    一些最基本的介绍就是上面了,具体是啥意思,我们后面再细说。

    编译FFmpeg

    wget命令

    在Linux中可以使用wget命令来下载文件,这个wget就相当于是一个下载器,但是呢最近发现很多网站使用wget下载特别慢,尤其是国外的一些网站,Windows挂了代理也还是不行,上网找了一些,推荐使用mwget。

    mwget命令

    mwget下载器是一个多线程下载应用,比wget下载更快,下面有个脚本可以直接安装:

    #!/bin/bashwget http://jaist.dl.sourceforge.net/project/kmphpfm/mwget/0.1/mwget_0.1.0.orig.tar.bz2
    yum install bzip2 gcc-c++ openssl-devel intltool -y
    bzip2 -d mwget_0.1.0.orig.tar.bz2
    tar -xvf mwget_0.1.0.orig.tar 
    cd mwget_0.1.0.orig
    ./configure   #一般用来生成 Makefile,为下一步的编译做准备,你可以通过在 configure 后加上参数来对安装进行控制,比如代码:./configure –prefix=/usr 意思是将该软件安装在/usr下面
    make       #编译,大多数的源代码包都经过这一步进行编译
    make install  #开始安装echo "至此,安装完成"
    
    

    这个脚本在Ubuntu上肯定运行不起来,就比如yum这个命令在Ubuntu上就不行,这里就简单介绍一下apt和yum。

    apt和yun

    一般来说著名的Linux系统分为2大类,

    • RedHat系列:Redhat、Centos、Fedora等

    • Debian系列:Debian、Ubuntu等

    这2个系统的包管理器用的是不一样的,有区分yum、dkpg和apt,下图是区别:

    所以上面yum安装bzip2的命令就需要修改一下,改成

    apt install bzip2 gcc-c++ openssl-devel intltool -y

    但是呢,会发现这4个软件只有一个bzip2能安装成功,其他几个都找不到,这又是什么鬼呢,下面再来细说。

    Ubuntu安装mwget

    这里还是单独说一下在Ubuntu下安装这个mwget,因为网上很多都是centos系统,直接看一个链接:

    # Ubuntu安装mwget

    会发现想跑通mwget的shell脚本需要安装3个软件,然后把压缩包bz2文件先进行解压,然后运行./configure脚本,这个脚本跑完后需要执行make和make install,注意这又是坑,首先需要sudo权限,然后会发现很多cpp文件缺少头文件,这时需要挨个去修改添加头文件。

    下载FFmpeg

    假设上面mwget能成功安装,这时就需要下载和解压FFmpeg了,命令如下:

    mwget https://ffmpeg.org/releases/ffmpeg-4.2.2.tar.bz2
    tar -jxvf ffmpeg-4.2.2.tar.bz2
    
    

    下载完之后,就是上面我们简单介绍的几个目录了,这时可以直接运行configure脚本,这个脚本是用来配置FFmpeg的,里面配置项巨多,我们可以直接运行:

    这里发现居然执行不过,原因很简单,是因为没有yasm汇编编译器,FFmpeg为了提高效率使用了汇编指令,所以需要安装汇编编译器:

    sudo apt-get install yasm
    
    

    即可,然后configure脚本就可以执行成功。

    编译FFmpeg

    当然上面脚本编译时是编译很多东西,我们需要针对我们自己的需求,定制一个脚本,其实就是配置FFmpeg的configure中的各种选项,下面我们来看一下:

    #!/bin/bash
    
    echo ">>>>>>>>> 注意:该编译环境目前只在 NDK17c + ffmpeg4.2.2 测试过 <<<<<<<<"
    echo ">>>>>>>>> 注意:该编译环境目前只在 NDK17c + ffmpeg4.2.2 测试过 <<<<<<<<"
    echo ">>>>>>>>> 注意:该编译环境目前只在 NDK17c + ffmpeg4.2.2 测试过 <<<<<<<<"
    
    #NDK_ROOT 变量指向 ndk 目录
    NDK_ROOT=$NDK_HOME
    #指定android api版本
    ANDROID_API=21
    
    
    #开始编译 在下面调用传入参数即可
    function build_ffmpeg()
    {
    echo "开始编译 $PREFIX_CPU"
    echo "开始编译 $PREFIX"
    echo "开始编译 $TOOLCHAIN"
    
    ./configure \
    --prefix=$PREFIX \
    --enable-small \
    --disable-programs \
    --disable-avdevice \
    --disable-encoders \
    --disable-muxers \
    --disable-filters \
    --enable-cross-compile \
    --cross-prefix=$CROSS_PREFIX \
    --disable-shared \
    --enable-static \
    --sysroot=$NDK_ROOT/platforms/android-$ANDROID_API/arch-$ARCH \
    --extra-cflags="$CFLAGES" \
    --arch=$ARCH \
    --target-os=android
    
    #上面运行脚本生成makefile之后,使用make执行脚本
    make clean
    make
    make install
    
    echo "$PREFIX_CPU 编译完成"
    echo "$PREFIX_CPU 编译完成"
    echo "$PREFIX_CPU 编译完成"
    }
    
    #armeabi-v7a
    PREFIX=./result/armeabi-v7a
    TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
    ARCH=arm
    CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
    CFLAGES="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS  -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security  -O0 -fPIC"
    
    build_ffmpeg
    
    #arm64-v8a
    PREFIX=./result/arm64-v8a
    TOOLCHAIN=$NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64
    ARCH=arm64
    CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
    CFLAGES="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS  -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security  -O0 -fPIC"
    
    build_ffmpeg
    
    #直接跳转到编译完成的路径
    cd /result
    
    
    

    上面就是编译的脚本,这里有几点需要说明一下,对于这种编译的脚本,还是要力求都看懂,不然出问题了根本无法查找。

    • 就是变量问题,比如这里的PREFIX、TOOLCHAIN、ARCH这3个变量就是有的是新建的目录、有的就是字符串。
    • 这里函数参数也要注意,比如工具链、CPU架构版本等等。
    • 这里可以在shell脚本中使用函数,其中和运行shell脚本一样可以直接在脚本名后面传递参数一样,这里可以直接定义build_ffmpeg()函数,然后在后面进行调用。
    • 其中在build_ffmpeg函数中,就是调用FFmpeg的configure脚本,并且传入一些列参数来配置这个脚本,关于这个脚本,后面还可以细说一下里面的常用配置。
    • 在运行完configure后,会生成一个makefile文件,然后通过make指令可以执行脚本。

    configure常用参数

    既然我们知道了这里的编译脚本就是配置configure中的一些配置,那常用的配置我们必须得懂,下面就罗列一些:

    • --prefix=PREFIX:设置动、静态库的位置,这个必须设置。
    • --enable-small:可以优化库的大小。
    • --disable-programs:我们不需要使用程序也就是不需要在Windows执行某个.exe程序,我们只在代码中使用。
    • --disable-avdevice:可以操控我们的摄像头,Android中是不支持。
    • --disable-encoders:编码是否打开,这里为了编译更快,如果用不到可以去掉。
    • --disable-muxers:混合封装是否可以打开,如果不用可以去掉。
    • --disable-filters:滤镜特效等是否开启,如果不用可以去掉。
    • --enable-cross-compile:开启交叉编译。
    • --cross-prefix=$CROSS_PREFIX:交叉编译的脚本,也就是前面设置的NDK里的编译脚本。
    • --disable-shared:是否开启编译成动态库。
    • --enable-static:是否开启编译成静态库。
    • --sysroot=NDKROOT/platforms/android−NDK_ROOT/platforms/android-NDKROOT/platforms/android−ANDROID_API/arch-$ARCH:交叉编译的一些配置。
    • --extra-cflags="$CFLAGES":其他的一些配置。
    • --arch=$ARCH:期望的运行环境的CPU架构
    • --target-os=android:期望运行在Android平台。

    编译问题

    首先这个编译可不是一帆风顺的,由于代码太多,我的Ubuntu虚拟机大概要编译20分钟,其中有几个主要错误,下面来说一下。

    • C compiler test failed:c编译器错误,这个原因主要是FFmpeg 4.2.2版本开始默认使用clang进行编译,这需要找到configure中的代码进行修改默认配置:
    //1. 修改 configure 文件
    vim configure
    //2. 把 默认的 clang 修改为 gcc
    if test "$target_os" = android; then
       # cc_default="clang"
             cc_default="gcc"
    fi
    
    
    
    • yasm not found:这个之前也说过,无法找到汇编编译器,需要安装即可。

    • vim中如何查找关键字,这个是vim的一个操作,在命令模式下,输入 /xxx 即可查找xxx,并且可以高亮显示,想查看下一个按 n 键即next可以查看下一个xxx关键字,这个在查找长脚本文件中很关键。

    总结

    编译FFmpeg还是很复杂的,这也正常,毕竟FFmpeg有这么多功能,音视频学习之路还很长,边学边总结吧,加油。

    相关推荐
    Android音视频开发:音视频基础知识到直播推流实战系列教程_哔哩哔哩_bilibili

    本文转自 https://juejin.cn/post/7025441094921879560,如有侵权,请联系删除。

    相关文章

      网友评论

        本文标题:音视频学习之路--编译FFmpeg

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