ffmpegconfigure研究2:分析屏幕输出及文件输出的具体过程
- 电脑硬件
- 2025-09-03 22:06:02

author: hjjdebug date: 2025年 02月 17日 星期一 16:57:55 CST description: ffmpeg configure 研究2 分析屏幕输出及文件输出的具体过程
文章目录 0. 执行./configure 命令1. sed: can't read 信息是从哪里来的 ?1.1 find_filters_extern()1.2 find_things_extern() 2. 屏幕输出信息的来源2.1,查找 prefix 变量在哪里定义的?2.2 函数名称: set_default2.3, 查找其它变量的定义. 3 configure 中创建的文件具体创建过程是怎样的?3.1 第一步,要找到变量定义.3.2. 读懂函数代码.3.3 函数名称: print_config3.4 函数名称: cp_if_changed3.5 函数名称: print_enabled_components 4 configure 对 Makefile 的影响 0. 执行./configure 命令
在家目录下创建目录t1, 把ffmpeg目录下的 configure 文件copy进去. 在 t1 目录下执行: cd ~/t1 ./configure
sed: can’t read ./libavfilter/allfilters.c: No such file or directory sed: can’t read ./libavdevice/alldevices.c: No such file or directory sed: can’t read ./libavdevice/alldevices.c: No such file or directory sed: can’t read ./libavformat/allformats.c: No such file or directory sed: can’t read ./libavformat/allformats.c: No such file or directory sed: can’t read ./libavcodec/allcodecs.c: No such file or directory sed: can’t read ./libavcodec/allcodecs.c: No such file or directory sed: can’t read ./libavcodec/parsers.c: No such file or directory sed: can’t read ./libavcodec/bitstream_filters.c: No such file or directory sed: can’t read ./libavcodec/hwaccels.h: No such file or directory sed: can’t read ./libavformat/protocols.c: No such file or directory
install prefix /usr/local source path . C compiler gcc C library glibc ARCH x86 (generic) big-endian no runtime cpu detection yes standalone assembly yes x86 assembler nasm MMX enabled yes …
运行./configure 后 会惊奇的发现在t1目录下生成了很多文件及目录. $ tree . ├── config.asm ├── config.h ├── configure # sh文件本身 ├── doc │ └── config.texi ├── ffbuild │ ├── config.fate │ ├── config.log │ ├── config.mak │ └── config.sh ├── libavcodec │ ├── bsf_list.c │ ├── codec_list.c │ └── parser_list.c ├── libavdevice │ ├── indev_list.c │ └── outdev_list.c ├── libavfilter │ └── filter_list.c ├── libavformat │ ├── demuxer_list.c │ ├── muxer_list.c │ └── protocol_list.c ├── libavutil │ └── avconfig.h ├── Makefile └── tests └── api
下面我们要阐明3个问题, 出错信息是从哪里来的? 屏幕打印信息从哪里来的? 输出文件是怎样生成的?
1. sed: can’t read 信息是从哪里来的 ?对应 ./configure 3912 处代码
FILTER_LIST=$(find_filters_extern libavfilter/allfilters.c) OUTDEV_LIST=$(find_things_extern muxer AVOutputFormat libavdevice/alldevices.c outdev) INDEV_LIST=$(find_things_extern demuxer AVInputFormat libavdevice/alldevices.c indev) MUXER_LIST=$(find_things_extern muxer AVOutputFormat libavformat/allformats.c) DEMUXER_LIST=$(find_things_extern demuxer AVInputFormat libavformat/allformats.c) ENCODER_LIST=$(find_things_extern encoder AVCodec libavcodec/allcodecs.c) DECODER_LIST=$(find_things_extern decoder AVCodec libavcodec/allcodecs.c)这里我们看到是调用了2个函数:
1.1 find_filters_extern() { file=$source_path/$1 sed -n 's/^extern AVFilter ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\);/\1_filter/p' $file } 1.2 find_things_extern() { thing=$1 pattern=$2 file=$source_path/$3 out=${4:-$thing} sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$out/p" "$file" }很简单,在控制台上执行一下sed命令就知道这些list 是什么内容了. 就是在指定的文件中查找pattern, 满足条件的行被替换内容后输出.保存到不同的变量中 由于t1目录只有一个configure 文件, 没有添加诸如 libavfilter/allfilters.c 文件,所以sed 报错了.
2. 屏幕输出信息的来源对应 ./configure 7285 处代码. 嗯,bashdb 调试执行太慢了,不能用bashdb 调试了, 在3912设断点等一会能到达,在7285处设断点就慢的没法忍受了.只能放弃,你可以用bash -x -v ./configure 来记录执行的过程
echo “install prefix $prefix” echo “source path $source_path” echo “C compiler $cc” echo “C library $libc_type” …
2.1,查找 prefix 变量在哪里定义的?有的变量定义是不太好找的. prefix 变量定义就是这样的. 在bash 中,变量的赋值是通过 a=b 方式进行的,如果是直接定义,可以通过字符串来查找. 但如果变量在函数中定义, 传进去的只是参数, 对参数的引用通过$i 或 $var 进行,则赋值就不能通过字符串直接查找了. prefix在configure 代码中没有发现直接定义, 即没有prefix=xxx 形式的行. 在3755行 有 prefix_default=“/usr/local”, 与prefix 很接近. 在PATH_LIST 中有 prefix 字符串 由set_default P A T H L I S T , s e t d e f a u l t 函数引用了 PATH_LIST, set_default函数引用了 PATHLIST,setdefault函数引用了PATH_LIST变量,它设置了prefix变量, 具体过程参见函数
2.2 函数名称: set_default输入参数: 列表 输出: 把列表作为变量名称,为其赋值. 描述: 把xxx_default变量的值送给xxx变量
set_default(){ for opt; do # 对传来的参数列表, 把其default值作为其值, 参数列表都是输出值 eval : ${$opt:=$${opt}_default} done } 当枚举到 $opt=prefix 则进行变量扩展后为
eval : ‘KaTeX parse error: Expected '}', got 'EOF' at end of input: {prefix:=prefix_default}’ 再执行一次 eval 命令完成赋值 赋值语句 x x x : = y y y , 当 {xxx:=yyy}, 当 xxx:=yyy,当xxx没有值或为空时,赋值给yyy, 2次扩展.sh 脚本的难点是函数, 函数也等价于一个命令 configure 有7000多行代码, 包含180个函数, 知道了这180个函数的意思, 也就不怕configure 文件了. 关于具体的函数,以后会慢慢介绍几个关键函数.
2.3, 查找其它变量的定义.先用grep 查找直接定义, 若找不到则可能是在函数中赋值的,如果代码不长运行较快可以用bashdb辅助查找,也可用bash -x -v输出log记录信息帮助查找
3 configure 中创建的文件具体创建过程是怎样的?
关注config.h 是怎样生成的, 顺便关注一下其它的文件 config.h 代码在7581-7628 向缓冲文件$TMPH 中打印头部信息
cat > $TMPH <<EOF /* Automatically generated by configure - do not modify! */ #ifndef FFMPEG_CONFIG_H #define FFMPEG_CONFIG_H #define FFMPEG_CONFIGURATION "$(c_escape $FFMPEG_CONFIGURATION)" #省略部分代码.... #define HAVE_MMX2 HAVE_MMXEXT #define SWS_MAX_FILTER_SIZE $sws_max_filter_size EOF #省略部分代码.... print_config ARCH_ "$config_files" $ARCH_LIST print_config HAVE_ "$config_files" $HAVE_LIST print_config CONFIG_ "$config_files" $CONFIG_LIST \ $CONFIG_EXTRA \ $ALL_COMPONENTS \ echo "#endif /* FFMPEG_CONFIG_H */" >> $TMPH echo "endif # FFMPEG_CONFIG_MAK" >> ffbuild/config.mak cp_if_changed $TMPH config.h 3.1 第一步,要找到变量定义.config_files=“$TMPH ffbuild/config.mak doc/config.texi” 3个文件 ARCH_LIST=“aarch64 alpha arm avr32 avr32_ap avr32_uc bfin ia64 m68k mips mips64 parisc ppc ppc64 s390 sh4 sparc sparc64 tilegx tilepro tomi x86 x86_32 x86_64”
ARCH_LIST 是24种cpu
3.2. 读懂函数代码.3.3 函数名称: print_config 输入参数: $1, 前缀 $2, 输出的文件名称列表 $v, 是$@的枚举值, 则\${$v:-no}是其值,默认为no 输出参数: 无 描述. 对$@ 执行显示其配置值信息并通过awk 向文件列表中输出信息 print_config(){ pfx=$1 files=$2 #文件列表 shift 2 map 'eval echo "$v \${$v:-no}"' "$@" | awk "BEGIN { split(\"$files\", files) } #把文件列表分割为文件 { c = \"$pfx\" toupper(\$1); #c变量是前缀和第一列值(即枚举字符串) v = \$2; #v变量是 第2列值,它是yes 或者 no sub(/yes/, 1, v); # 将yes 或no 变成1和0 sub(/no/, 0, v); for (f in files) { # 向文件列表中输出内容 file = files[f]; if (file ~ /\\.h\$/) { # .h 文件, 打印 #define xxx 1 形式 printf(\"#define %s %d\\n\", c, v) >>file; } else if (file ~ /\\.asm\$/) { # .asm 文件, 打印 %%define xxx 1形式 printf(\"%%define %s %d\\n\", c, v) >>file; } else if (file ~ /\\.mak\$/) { # .mak 文件, 打印xxx 或者!xxx n = -v ? \"\" : \"!\"; # 赋值n 为空或 ‘!' printf(\"%s%s=yes\\n\", n, c) >>file; } else if (file ~ /\\.texi\$/) { # .texi 文件, 打印pre@set xxx yes的形式 pre = -v ? \"\" : \"@c \"; # 赋值pre为空或@c yesno = \$2; c2 = tolower(c); gsub(/_/, \"-\", c2); printf(\"%s@set %s %s\\n\", pre, c2, yesno) >>file; } } }" } 3.4 函数名称: cp_if_changed 输入参数:$1,$2 两个文件名称 输出参数:无 函数功能: 比较2个文件$1,$2是否相同,相同给出提示 "$2 is nuchanged",返回, 不同则进行copy,不提示 cp_if_changed(){ cmp -s "$1" "$2" && { test "$quiet" != "yes" && echo "$2 is unchanged"; } && return mkdir -p "$(dirname $2)" cp -f "$1" "$2" }
其中9个list 都是由如下命令生成 print_enabled_components libavfilter/filter_list.c AVFilter filter_list $FILTER_LIST print_enabled_components libavcodec/codec_list.c AVCodec codec_list $CODEC_LIST print_enabled_components libavcodec/parser_list.c AVCodecParser parser_list $PARSER_LIST print_enabled_components libavcodec/bsf_list.c AVBitStreamFilter bitstream_filters $BSF_LIST print_enabled_components libavformat/demuxer_list.c AVInputFormat demuxer_list $DEMUXER_LIST print_enabled_components libavformat/muxer_list.c AVOutputFormat muxer_list $MUXER_LIST print_enabled_components libavdevice/indev_list.c AVInputFormat indev_list $INDEV_LIST print_enabled_components libavdevice/outdev_list.c AVOutputFormat outdev_list $OUTDEV_LIST print_enabled_components libavformat/protocol_list.c URLProtocol url_protocols $PROTOCOL_LIST
望文生义也可以猜到,例如它从$FILTER_LIST 参数中生成libavfilter/filter_list.c 文件, 使用AVFilter,filter_list 两个关键字
3.5 函数名称: print_enabled_components 输入参数: 第一参数输出文件名, 第二参数结构名称, 第三参数一个格式参考关键字,其它为模块名称作为输出文件内容 输出参数: 无 描述: 从一堆信息中,合成一个输出文件, 用printf 打印的 print_enabled_components(){ file=$1 #输出文件 struct_name=$2 #结构名称 name=$3 #名称 shift 3 echo "static const $struct_name * const $name[] = {" > $TMPH # 定义结构名称,向临时文件copy for c in $*; do if enabled $c; then # 如果变量是enabled , 对输出打印 case $name in # 判断输出要求什么格式, 可以进行修饰, 重新赋值给c filter_list) eval c=\$full_filter_name_${c%_filter} ;; indev_list) c=${c%_indev}_demuxer ;; outdev_list) c=${c%_outdev}_muxer ;; esac printf " &ff_%s,\n" $c >> $TMPH # 打印变量 fi done if [ "$name" = "filter_list" ]; then for c in asrc_abuffer vsrc_buffer asink_abuffer vsink_buffer; do printf " &ff_%s,\n" $c >> $TMPH done fi echo " NULL };" >> $TMPH cp_if_changed $TMPH $file #跟输出文件不同则copy } 4 configure 对 Makefile 的影响Makefile 其时是没有改变的, 但Makefile 有 include ffbuild/config.mak 参考 print_config() 函数, 它同时向3个文件
config_files="$TMPH ffbuild/config.mak doc/config.texi" 打印信息. 其中$TMPH 就是config.h的缓冲文件,ffmpegconfigure研究2:分析屏幕输出及文件输出的具体过程由讯客互联电脑硬件栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“ffmpegconfigure研究2:分析屏幕输出及文件输出的具体过程”