FFmpeg源代码简单分析 configure

本文简要分析FFmpeg的Configure脚本,该脚本用于检测编译环境并生成config.mak、config.h文件。主要内容包括设置默认值、解析选项、检查编译器、检查函数和头文件、检查第三方库、输出配置信息等步骤。同时提供了相关函数如check_func、check_header等的用途说明。
摘要由CSDN通过智能技术生成

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

=====================================================

FFmpeg的库函数源代码分析文章列表:

【架构图】

FFmpeg源代码结构图 - 解码

FFmpeg源代码结构图 - 编码

【通用】

FFmpeg 源代码简单分析:av_register_all()

FFmpeg 源代码简单分析:avcodec_register_all()

FFmpeg 源代码简单分析:内存的分配和释放(av_malloc()、av_free()等)

FFmpeg 源代码简单分析:常见结构体的初始化和销毁(AVFormatContext,AVFrame等)

FFmpeg 源代码简单分析:avio_open2()

FFmpeg 源代码简单分析:av_find_decoder()和av_find_encoder()

FFmpeg 源代码简单分析:avcodec_open2()

FFmpeg 源代码简单分析:avcodec_close()

【解码】

图解FFMPEG打开媒体的函数avformat_open_input

FFmpeg 源代码简单分析:avformat_open_input()

FFmpeg 源代码简单分析:avformat_find_stream_info()

FFmpeg 源代码简单分析:av_read_frame()

FFmpeg 源代码简单分析:avcodec_decode_video2()

FFmpeg 源代码简单分析:avformat_close_input()

【编码】

FFmpeg 源代码简单分析:avformat_alloc_output_context2()

FFmpeg 源代码简单分析:avformat_write_header()

FFmpeg 源代码简单分析:avcodec_encode_video()

FFmpeg 源代码简单分析:av_write_frame()

FFmpeg 源代码简单分析:av_write_trailer()

【其它】

FFmpeg源代码简单分析:日志输出系统(av_log()等)

FFmpeg源代码简单分析:结构体成员管理系统-AVClass

FFmpeg源代码简单分析:结构体成员管理系统-AVOption

FFmpeg源代码简单分析:libswscale的sws_getContext()

FFmpeg源代码简单分析:libswscale的sws_scale()

FFmpeg源代码简单分析:libavdevice的avdevice_register_all()

FFmpeg源代码简单分析:libavdevice的gdigrab

【脚本】

FFmpeg源代码简单分析:makefile

FFmpeg源代码简单分析:configure

【H.264】

FFmpeg的H.264解码器源代码简单分析:概述

=====================================================


本文记录FFmpeg的Configure脚本的源代码。Configure一方面用于检测FFmpeg的编译环境,另一方面根据用户配置的选项生成config.mak,config.h文件(可能还有config.asm),提供给Makefile使用。由于FFmpeg的configure脚本很复杂(一个4000-5000行的Shell脚本),难以逐行细致的分析,因此本文简单梳理一下它的结构。

PS1:Configure的日志位于config.log文件中。查看该文件有助于分析Configure的过程。

PS2:使用“sh -x script_name.sh”可以调试Shell脚本。


Configure文件的整体流程

Configure文件的整体流程如下所示。

Configure的整体流程可以分成以下几步:

Set Default Value:设置各个变量默认值;

Parse Options:解析输入的选项;

Check Compiler:检查编译器;

die_license_disabled():检查GPL等协议的设置情况;

Check:检查编译环境(数学函数,第三方类库等);

Echo info:控制台上打印配置信息;

Write basic info:向config.mak中写入一些基本信息; 

print_config():向config.h、config.mak、config.asm中写入所有配置信息;

print_enabled():向config.mak写入所有enabled的组件信息;

pkgconfig_generate():向libavXXX/libavXXX.pc中写入pkgconfig信息(XXX代表avcodec,avformat等);

下文简单梳理一下这些步骤。

Set Default Value

Set Default Value部分设置一些Configure的默认值。例如下面的代码。
# 默认参数 default parameters# 日志logfile="config.log"# 安装路径 installation pathsprefix_default="/usr/local"bindir_default='${prefix}/bin'datadir_default='${prefix}/share/ffmpeg'incdir_default='${prefix}/include'libdir_default='${prefix}/lib'mandir_default='${prefix}/share/man'shlibdir_default="$libdir_default"postproc_version_default="current"# 工具链 toolchainar_default="ar"cc_default="gcc"cxx_default="g++"cc_version=\"unknown\"host_cc_default="gcc"install="install"ln_s="ln -sf"nm_default="nm"objformat="elf"pkg_config_default=pkg-configranlib="ranlib"strip_default="strip"yasmexe_default="yasm"nm_opts='-g'nogas=":"# 机器 machinearch_default=$(uname -m)cpu="generic"# 操作系统 OStarget_os_default=$(tolower $(uname -s))host_os=$target_os_default# alternative libpostproc versionALT_PP_VER_MAJOR=51ALT_PP_VER_MINOR=2ALT_PP_VER_MICRO=101ALT_PP_VER=$ALT_PP_VER_MAJOR.$ALT_PP_VER_MINOR.$ALT_PP_VER_MICRO# 选项 configurable options# PROGRAM_LIST内容是 ffplay ffprobe ffserver ffmpegenable $PROGRAM_LISTenable avcodecenable avdeviceenable avfilterenable avformatenable avutilenable postprocenable strippingenable swresampleenable swscaleenable asmenable debugenable docenable fastdivenable networkenable optimizationsenable safe_bitstream_readerenable staticenable swscale_alpha# 编译选项 build settingsSHFLAGS='-shared -Wl,-soname,$$(@F)'FFSERVERLDFLAGS=-Wl,-E# 前缀后缀LIBPREF="lib"LIBSUF=".a"FULLNAME='$(NAME)$(BUILDSUF)'# 名称LIBNAME='$(LIBPREF)$(FULLNAME)$(LIBSUF)'# 动态库前缀后缀SLIBPREF="lib"SLIBSUF=".so"# 名称SLIBNAME='$(SLIBPREF)$(FULLNAME)$(SLIBSUF)'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)'AS_O='-o $@'CC_O='-o $@'CXX_O='-o $@'host_cflags='-D_ISOC99_SOURCE -O3 -g'host_libs='-lm'target_path='$(CURDIR)'

需要注意的是,“enable avcodec”,“enable avformat”,“enable avutil”等中的enable()本身是一个函数。enable()的定义如下。
#把所有输入参数的值设置为"yes"enable(){    set_all yes $*}

可以看出enable()调用了set_all()函数。并且将第1个参数设置为“yes”,并且将调用enable()时候的参数传递给set_all()。set_all()函数的定义如下所示。
#第一个参数为值,后面的参数为变量set_all(){    value=$1    shift    for var in $*; do        eval $var=$value    done}

可以看出set_all()将传入的参数全部进行赋值。特定于enable()函数来说,就是将所有的输入变量赋值为“yes”。由此可见,“enable avcodec”实际上相当于执行了:
avcodec=”yes”

Parse Options

Parse Options部分用于解析Configure的附加参数。该部分的代码如下所示。
#注意:opt不是参数列表(实际上也没有看见opt变量的定义)#原因是处在for循环中,当你没有为in指定列表时,for会默认取命令行参数列表。#因此“opt”这个名字实际上是可以随便取的for opt do# "#"用于去除特定字符前面的字符串# optval内容为opt去掉"="以及其前面字符串之后的内容    optval="${opt#*=}"    case "$opt" in    # 不同的选项    --extra-ldflags=*) add_ldflags $optval    ;;    --extra-libs=*) add_extralibs $optval    ;;    --disable-devices) disable $INDEV_LIST $OUTDEV_LIST    ;;    --enable-debug=*) debuglevel="$optval"    ;;    --disable-everything)    map 'eval unset \${$(toupper ${v%s})_LIST}' $COMPONENT_LIST    ;;    --enable-*=*|--disable-*=*)    eval $(echo "${opt%%=*}" | sed 's/--/action=/;s/-/ thing=/')    is_in "${thing}s" $COMPONENT_LIST || die_unknown "$opt"    eval list=\$$(toupper $thing)_LIST    name=$(echo "${optval}" | sed "s/,/_${thing}|/g")_${thing}    $action $(filter "$name" $list)    ;;    --enable-?*|--disable-?*)    eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g')    if is_in $option $COMPONENT_LIST; then        test $action = disable && action=unset        eval $action \$$(toupper ${option%s})_LIST    elif is_in $option $CMDLINE_SELECT; then        $action $option    else        die_unknown $opt    fi    ;;    --list-*)        NAME="${opt#--list-}"        is_in $NAME $COMPONENT_LIST || die_unknown $opt        NAME=${NAME%s}        eval show_list $NAME \$$(toupper $NAME)_LIST    ;;    --help|-h) show_help    ;;    *)    #% 就是从右边开始删除符合条件的字符串(符合条件的最短字符串)    #%%是删除符合条件的最长的字符串    #删除“=”右边的内容    optname="${opt%%=*}"    #删除左边的“--”    optname="${optname#--}"    optname=$(echo "$optname" | sed 's/-/_/g')    #看看是否在opt列表中,不在的话就会返回错误    if is_in $optname $CMDLINE_SET; then        eval $optname='$optval'    elif is_in $optname $CMDLINE_APPEND; then        append $optname "$optval"    else         die_unknown $opt    fi    ;;    esacdone

在这里需要注意,取出opt的值一般都是“--extra-ldflags=XXX”的形式,通过“${opt#*=}”截取获得“=”号后面的内容作为optval,对于“--extra-ldflags=XXX”来说,optval取值为“XXX”。
然后根据opt种类的不同,以及optval取值的不同,分别作不同的处理。

Check Compiler

Check Compiler用于检查编译器。这部分代码还没有细看,暂时不做分析。

die_license_disabled()

die_license_disabled()用于检查是否指定了特定了License。像libx264、libfaac这些第三方类库,都需要指定特定的License才可以使用(例如libfaac必须指定nonfree)。开启这些第三方类库后如果没有指定License,Configure会立刻退出。这部分代码如下所示。
#检查License#GPLdie_license_disabled gpl libcdiodie_license_disabled gpl libx264die_license_disabled gpl libxavsdie_license_disabled gpl libxviddie_license_disabled gpl x11grab#nonfreedie_license_disabled nonfree libaacplusdie_license_disabled nonfree libfaacdie_license_disabled nonfree openssl#Version3die_license_disabled version3 libopencore_amrnbdie_license_disabled version3 libopencore_amrwbdie_license_disabled version3 libvo_aacencdie_license_disabled version3 libvo_amrwbenc

其中涉及到一个函数die_license_disabled(),它的定义如下所示。
#不符合License则立刻结束die_license_disabled() {    enabled $1 || { enabled $2 && die "$2 is $1 and --enable-$1 is not specified."; }}

从定义可以看出,die_license_disabled()首先会看第1个参数(对应“gpl”,“nonfree”)对应的组件是否enable,如果已经enable,则正常运行完函数;如果没有enable,则会检查第2个参数(对应“libx264”,“libfaac”)是否enable,如果第2个参数enable了,就会报错退出。

Check

Check部分是Configure中最重要的部分。该部分用于检查编译环境(例如数学函数,第三方类库等)。这一部分涉及到很多的函数。包括check_cflags()、check_struct()、require()、check_lib()、check_header()、check_func()、check_mathfunc()等等。这些函数之间的调用关系如下图所示。


下面简单举例下面几个函数:

check_func():用于检查函数。

check_header():用于检查头文件。

check_func_headers():用于同时检查头文件和函数。

check_mathfunc():用于检查数学类函数。

require():检查第三方类库。

check_cflags ():用于检查编译器的cflags标志参数。

下面详细看看这几个函数。


check_func()

check_func()用于检查函数。它的输入参数一个函数名。Configure中与check_func()有关的代码如下所示。
check_func  isattycheck_func  localtime_rcheck_func  ${malloc_prefix}memalign            && enable memaligncheck_func  mkstempcheck_func  mmapcheck_func  ${malloc_prefix}posix_memalign      && enable posix_memaligncheck_func  setrlimitcheck_func  strerror_rcheck_func  strptimecheck_func  sched_getaffinitycheck_func  sysconfcheck_func  sysctl

check_func()的定义如下所示。
check_func(){    log check_func "$@"    func=$1    shift    disable $func    check_ld "cc" "$@" <<EOF && enable $funcextern int $func();int main(void){ $func(); }EOF}

从check_func()的定义可以看出,该函数首先将输入的第1个参数赋值给func,然后生成一个下述内容的C语言文件。
extern int $func();int main(void){ $func(); }

最后调用check_ld()完成编译测试。check_ld()的定义如下所示。
check_ld(){    log check_ld "$@"    type=$1    shift 1    flags=''    libs=''    for f; do        test 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值