在FFmpeg源码下增加自定义程序

为了了解FFmpeg解码的细节,使用avcodec_send_packet和avcodec_receive_frame组合,写了一个简单的例子,解码video生成yuv文件,比起用FFmpeg跟踪代码要简单很多。

但是问题是在FFmpeg下编译的ffmpeg/ffplay都可以直接跟踪调试,自己编译的因为连接的系统的动态库,所以不能跟踪到代码里面。

所以参考tools/enum_options程序,在FFmpeg源码目录新增一个目录,修改Makefile相关代码,就可以编译生成类似ffmpeg/ffplay的可执行文件,放在vscode里面非常方便的展台调试。

STEP 1:增加decode目录

decode/
├── decode3.c
└── Makefile

如果是直接编译,链接系统库,没法gdb调试FFmpeg源码,试了下make tools/enum_options可以生成enum_options程序,并且gdb可以调试FFmpeg源码,所以参考tools/Makefile,decode/Makefile如下:

STEP 2:Makefile

DECODE = decode3

OUTDIRS += decode

clean::
	$(RM) $(CLEANSUFFIXES:%=decode/%)

STEP 3:添加到FFmpeg/Makefile

将这个Makefile还要加入到FFmpeg/Makefile里面,下面是diff文件,为了知道每个变量的内容,增加了info打印:

--- a/Makefile
+++ b/Makefile
@@ -39,13 +39,29 @@ SKIPHEADERS = compat/w32pthreads.h
 # first so "all" becomes default target
 all: all-yes
 
+# decode3
+
 include $(SRC_PATH)/tools/Makefile
+include $(SRC_PATH)/decode/Makefile
 include $(SRC_PATH)/ffbuild/common.mak
 
 FF_EXTRALIBS := $(FFEXTRALIBS)
 FF_DEP_LIBS  := $(DEP_LIBS)
 FF_STATIC_DEP_LIBS := $(STATIC_DEP_LIBS)
 
+$(info debug - info FF_EXTRALIBS: $(FF_EXTRALIBS))
+$(info debug - info FF_DEP_LIBS: $(FF_DEP_LIBS))
+$(info debug - info DEP_LIBS: $(DEP_LIBS))
+$(info debug - info LD_O: $(LD_O))
+$(info debug - info LDFLAGS: $(LDFLAGS))
+$(info debug - info LDEXEFLAGS: $(LDEXEFLAGS))
+$(info debug - info EXTRALIBS: $(EXTRALIBS))
+$(info debug - info ELIBS: $(ELIBS))
+$(info debug - info LD: $(LD))
+$(info debug - info EXESUF: $(EXESUF))
+$(info debug - info DECODE: $(DECODE))
+$(info debug - info LIBFUZZER_PATH: $(LIBFUZZER_PATH))
+
 $(TOOLS): %$(EXESUF): %.o
        $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(EXTRALIBS-$(*F)) $(EXTRALIBS) $(ELIBS)
 
@@ -64,6 +80,8 @@ tools/target_dem_fuzzer$(EXESUF): tools/target_dem_fuzzer.o $(FF_DEP_LIBS)
 tools/target_io_dem_fuzzer$(EXESUF): tools/target_io_dem_fuzzer.o $(FF_DEP_LIBS)
        $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
 
+decode/decode3$(EXESUF): decode/decode3.o $(FF_DEP_LIBS)
+       $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH)
 
 tools/enum_options$(EXESUF): ELIBS = $(FF_EXTRALIBS)
 tools/enum_options$(EXESUF): $(FF_DEP_LIBS)

STEP 4:编译

这样编译就可以生成decode3,奇怪的是得先make decode,然后再make decode3

$ make decode
debug - info FF_EXTRALIBS: -lavdevice -lavfilter -lavformat -lavcodec -lpostproc -lswresample -lswscale -lavutil  -lm -latomic -lxcb -lxcb-shm -lxcb-shape -lxcb-xfixes -lasound -lSDL2 -lsndio -lXv -lX11 -lXext -pthread -lm -latomic -lva -lm -latomic -lz -pthread -lm -latomic -llzma -L/usr/local/lib/x86_64-linux-gnu -llc3 -L/usr/local/lib/x86_64-linux-gnu -lopus -L/usr/local/lib -lx264 -L/usr/local/lib/x86_64-linux-gnu -lopenh264 -lz -lva -lm -latomic -lm -latomic -lm -latomic -pthread -lva-drm -lva -lva-x11 -lva -lvdpau -lX11 -lm -lva -latomic -lX11 
debug - info FF_DEP_LIBS: libavdevice/libavdevice.a libavfilter/libavfilter.a libavformat/libavformat.a libavcodec/libavcodec.a libpostproc/libpostproc.a libswresample/libswresample.a libswscale/libswscale.a libavutil/libavutil.a
debug - info DEP_LIBS: libavdevice/libavdevice.a libavfilter/libavfilter.a libavformat/libavformat.a libavcodec/libavcodec.a libpostproc/libpostproc.a libswresample/libswresample.a libswscale/libswscale.a libavutil/libavutil.a
debug - info LD_O: -o 
debug - info LDFLAGS: -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil
debug - info LDEXEFLAGS: 
debug - info EXTRALIBS: 
debug - info ELIBS: 
debug - info LD: @printf "LD\t%s\n" ; gcc
debug - info EXESUF: 
debug - info DECODE: decode3
debug - info LIBFUZZER_PATH: 
Current directory: ffmpeg ffplay ffprobe


$ make decode/decode3
debug - info FF_EXTRALIBS: -lavdevice -lavfilter -lavformat -lavcodec -lpostproc -lswresample -lswscale -lavutil  -lm -latomic -lxcb -lxcb-shm -lxcb-shape -lxcb-xfixes -lasound -lSDL2 -lsndio -lXv -lX11 -lXext -pthread -lm -latomic -lva -lm -latomic -lz -pthread -lm -latomic -llzma -L/usr/local/lib/x86_64-linux-gnu -llc3 -L/usr/local/lib/x86_64-linux-gnu -lopus -L/usr/local/lib -lx264 -L/usr/local/lib/x86_64-linux-gnu -lopenh264 -lz -lva -lm -latomic -lm -latomic -lm -latomic -pthread -lva-drm -lva -lva-x11 -lva -lvdpau -lX11 -lm -lva -latomic -lX11 
debug - info FF_DEP_LIBS: libavdevice/libavdevice.a libavfilter/libavfilter.a libavformat/libavformat.a libavcodec/libavcodec.a libpostproc/libpostproc.a libswresample/libswresample.a libswscale/libswscale.a libavutil/libavutil.a
debug - info DEP_LIBS: libavdevice/libavdevice.a libavfilter/libavfilter.a libavformat/libavformat.a libavcodec/libavcodec.a libpostproc/libpostproc.a libswresample/libswresample.a libswscale/libswscale.a libavutil/libavutil.a
debug - info LD_O: -o 
debug - info LDFLAGS: -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil
debug - info LDEXEFLAGS: 
debug - info EXTRALIBS: 
debug - info ELIBS: 
debug - info LD: @printf "LD\t%s\n" ; gcc
debug - info EXESUF: 
debug - info DECODE: decode3
debug - info LIBFUZZER_PATH: 
Current directory: ffmpeg ffplay ffprobe
CC      decode/decode3.o
LD      decode/decode3

没有decode目录,make decode/decode3会报错,手动创建decode目录也是可以的。

不然会报错:

src/decode/decode3.c: At top level:
src/decode/decode3.c:165:1: fatal error: opening dependency file decode/decode3.d: No such file or directory
  165 | }
      | ^
compilation terminated.
make: *** [src/ffbuild/common.mak:81: decode/decode3.o] Error 1

decode/Makefile中已经定义了OUTDIRS += decode,检查FFmpeg/Makefile中的OUTDIRS有:

$(sort $(OUTDIRS)):
	$(Q)mkdir -p $@

所以从这里判断make clean,重新make后应该可以直接make decode/decode3,试了下果然可以了。

STEP 5:运行调试

查找decode3的符号可以发现,这个是包含了所有FFmpeg的代码,不需要加载FFmpeg的动态库,所以FFmpeg中的源码更新后直接make decode/decode3即可

$ nm decode3 |  grep -E "avcodec_send_packet|avcodec_receive_frame|av_read_frame"
000000000031dd95 T avcodec_receive_frame
000000000041a5b6 T avcodec_send_packet
000000000009ea7c T av_read_frame

ldd也可以确定这一点:

$ ldd decode3
        linux-vdso.so.1 (0x00007ffe27536000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f04eadf4000)
        libdrm.so.2 => /usr/lib/x86_64-linux-gnu/libdrm.so.2 (0x00007f04eabe3000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f04ea9c6000)
        libopus.so.0 => /usr/local/lib/x86_64-linux-gnu/libopus.so.0 (0x00007f04ea76f000)
        libx264.so.152 => /usr/lib/x86_64-linux-gnu/libx264.so.152 (0x00007f04ea3ca000)
        libopenh264.so.7 => /usr/local/lib/x86_64-linux-gnu/libopenh264.so.7 (0x00007f04ea0b4000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f04e9e95000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f04e9aa4000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f04edef6000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f04e98a0000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f04e9440000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f04e921d000)

vscode launch.json

vscode中的 launch.json中修改program和args即可以运行调试。

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(gdb) Launch",
      "type": "cppdbg",
      "request": "launch",
      "program": "${workspaceFolder}/build/decode/decode3",
      "args": [
        "${workspaceFolder}/decode/256x144.mp4", "${workspaceFolder}/decode/256x144-yuv420p.yuv"
      ],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}/",
      "environment": [ ],
      "externalConsole": false,
      "MIMode": "gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        },
        {
          "description": "Set Disassembly Flavor to Intel",
          "text": "-gdb-set disassembly-flavor intel",
          "ignoreFailures": true
        }
      ]
    }
  ]
}

你可能感兴趣的:(ffmpeg)