本文演示了使用gdb定位avformat_find_stream_info函数破坏codecpar变量的问题
1.查看音频或视频stream index【以下以视频为例】
./ffprobe demo.avi 2>&1 | grep Stream
Stream #0:0: Video: h264 (High) (H264 / 0x34363248), yuv420p(progressive), 1920x1080, 4021 kb/s, 25 fps, 25 tbr, 25 tbn, 50 tbc
以上视频的stream index=0
2.修改ffmpeg,在avformat_find_stream_info中将codecpar置NULL
vim libavformat/utils.c -> avformat_find_stream_info
av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN);
ic->streams[0]->codecpar=NULL; //*破坏 codecpar
max_stream_analyze_duration = max_analyze_duration;
3.编译ffmpeg debug版本
./configure --enable-debug
make -j
4.启动gdb
bash
gdb --args ./ffmpeg_g -i demo.avi -qp 10 out.avi -y
5.在avformat_find_stream_info下断点
(gdb) b avformat_find_stream_info
Breakpoint 1 at 0x7ce180: file libavformat/utils.c, line 3623.
6.运行
(gdb) r
Starting program: ./ffmpeg_g -i demo.avi -qp 10 out.avi -y
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
ffmpeg version n4.3.4 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-44)
configuration: --enable-debug
libavutil 56. 51.100 / 56. 51.100
libavcodec 58. 91.100 / 58. 91.100
libavformat 58. 45.100 / 58. 45.100
libavdevice 58. 10.100 / 58. 10.100
libavfilter 7. 85.100 / 7. 85.100
libswscale 5. 7.100 / 5. 7.100
libswresample 3. 7.100 / 3. 7.100
Breakpoint 1, avformat_find_stream_info (ic=0x22ca500, options=0x22cc500) at libavformat/utils.c:3623
warning: Source file is more recent than executable.
3623 {
Missing separate debuginfos, use: debuginfo-install bzip2-libs-1.0.6-13.el7.x86_64 glibc-2.17-326.el7_9.x86_64 libXau-1.0.8-2.1.el7.x86_64 libdrm-2.4.91-3.el7.x86_64 libva-1.8.3-1.el7.x86_64 libxcb-1.13-1.el7.x86_64 zlib-1.2.7-19.el7_9.x86_64
7.查看变量
(gdb) print(*(AVFormatContext*)ic)
$1 = {av_class = 0x128d300 <av_format_context_class>, iformat = 0x1892fe0 <ff_avi_demuxer>, oformat = 0x0, priv_data = 0x22cb040, pb = 0x22d31c0, ctx_flags = 0, nb_streams = 1, streams = 0x22cb100,
filename = "demo.avi", '\000' <repeats 1009 times>, url = 0x22cacc0 "demo.avi", start_time = -9223372036854775808, duration = -9223372036854775808, bit_rate = 0, packet_size = 0, max_delay = -1, flags = 2097156,
probesize = 5000000, max_analyze_duration = 0, key = 0x0, keylen = 0, nb_programs = 0, programs = 0x0, video_codec_id = AV_CODEC_ID_NONE, audio_codec_id = AV_CODEC_ID_NONE, subtitle_codec_id = AV_CODEC_ID_NONE,
max_index_size = 1048576, max_picture_buffer = 3041280, nb_chapters = 0, chapters = 0x0, metadata = 0x22cc440, start_time_realtime = -9223372036854775808, fps_probe_size = -1, error_recognition = 1, interrupt_callback = {
callback = 0x4a5fa0 <decode_interrupt_cb>, opaque = 0x0}, debug = 0, max_interleave_delta = 10000000, strict_std_compliance = 0, event_flags = 0, max_ts_probe = 50, avoid_negative_ts = -1, ts_id = 0, audio_preload = 0,
max_chunk_duration = 0, max_chunk_size = 0, use_wallclock_as_timestamps = 0, avio_flags = 0, duration_estimation_method = AVFMT_DURATION_FROM_PTS, skip_initial_bytes = 0, correct_ts_overflow = 1, seek2any = 0,
flush_packets = -1, probe_score = 100, format_probesize = 1048576, codec_whitelist = 0x0, format_whitelist = 0x0, internal = 0x22cab80, io_repositioned = 0, video_codec = 0x0, audio_codec = 0x0, subtitle_codec = 0x0,
data_codec = 0x0, metadata_header_padding = -1, opaque = 0x0, control_message_cb = 0x0, output_ts_offset = 0, dump_separator = 0x22ca010 ", ", data_codec_id = AV_CODEC_ID_NONE, open_cb = 0x0,
protocol_whitelist = 0x22ca2b0 "file,crypto,data", io_open = 0x77bdf0 <io_open_default>, io_close = 0x77bde0 <io_close_default>, protocol_blacklist = 0x0, max_streams = 1000, skip_estimate_duration_from_pts = 0,
max_probe_packets = 2500}
(gdb) print(*(AVStream *)((*(AVFormatContext*)ic)->streams[0]))
$2 = {index = 0, id = 0, codec = 0x22cb580, priv_data = 0x22cbf00, time_base = {num = 1, den = 25}, start_time = 0, duration = 1656, nb_frames = 1656, disposition = 0, discard = AVDISCARD_DEFAULT, sample_aspect_ratio = {num = 0,
den = 1}, metadata = 0x0, avg_frame_rate = {num = 25, den = 1}, attached_pic = {buf = 0x0, pts = 0, dts = 0, data = 0x0, size = 0, stream_index = 0, flags = 0, side_data = 0x0, side_data_elems = 0, duration = 0, pos = 0,
convergence_duration = 0}, side_data = 0x0, nb_side_data = 0, event_flags = 0, r_frame_rate = {num = 0, den = 0}, recommended_encoder_configuration = 0x0, codecpar = 0x22cba00, info = 0x22cb4c0, pts_wrap_bits = 64,
first_dts = -9223372036854775808, cur_dts = 9223090561878065151, last_IP_pts = -9223372036854775808, last_IP_duration = 0, probe_packets = 2500, codec_info_nb_frames = 0, need_parsing = AVSTREAM_PARSE_HEADERS, parser = 0x0,
last_in_packet_buffer = 0x0, probe_data = {filename = 0x0, buf = 0x0, buf_size = 0, mime_type = 0x0}, pts_buffer = {-9223372036854775808 <repeats 17 times>}, index_entries = 0x22db2e0, nb_index_entries = 1656,
index_entries_allocated_size = 41495, stream_identifier = 0, program_num = 0, pmt_version = 0, pmt_stream_idx = 0, interleaver_chunk_size = 0, interleaver_chunk_duration = 0, request_probe = 0, skip_to_keyframe = 0,
skip_samples = 0, start_skip_samples = 0, first_discard_sample = 0, last_discard_sample = 0, nb_decoded_frames = 0, mux_ts_offset = 0, pts_wrap_reference = -9223372036854775808, pts_wrap_behavior = 0,
update_initial_durations_done = 0, pts_reorder_error = {0 <repeats 17 times>}, pts_reorder_error_count = '\000' <repeats 16 times>, last_dts_for_order_check = -9223372036854775808, dts_ordered = 0 '\000',
dts_misordered = 0 '\000', inject_global_side_data = 0, display_aspect_ratio = {num = 0, den = 0}, internal = 0x22cad00}
(gdb) print ((*(AVStream *)((*(AVFormatContext*)ic)->streams[0]))->codecpar)
$3 = (AVCodecParameters *) 0x22cba00
(gdb) print *(AVCodecParameters*)((*(AVStream *)((*(AVFormatContext*)ic)->streams[0]))->codecpar)
$4 = {codec_type = AVMEDIA_TYPE_VIDEO, codec_id = AV_CODEC_ID_H264, codec_tag = 875967048, extradata = 0x0, extradata_size = 0, format = -1, bit_rate = 4021700, bits_per_coded_sample = 24, bits_per_raw_sample = 0, profile = -99,
level = -99, width = 1920, height = 1080, sample_aspect_ratio = {num = 0, den = 1}, field_order = AV_FIELD_UNKNOWN, color_range = AVCOL_RANGE_UNSPECIFIED, color_primaries = AVCOL_PRI_UNSPECIFIED,
color_trc = AVCOL_TRC_UNSPECIFIED, color_space = AVCOL_SPC_UNSPECIFIED, chroma_location = AVCHROMA_LOC_UNSPECIFIED, video_delay = 0, channel_layout = 0, channels = 0, sample_rate = 0, block_align = 0, frame_size = 0,
initial_padding = 0, trailing_padding = 0, seek_preroll = 0}
8.监控 codecpar 变量
(gdb) watch ((*(AVStream *)((*(AVFormatContext*)ic)->streams[0]))->codecpar)
Watchpoint 2: ((*(AVStream *)((*(AVFormatContext*)ic)->streams[0]))->codecpar)
9.继续运行【如果变量被修改,程序会停住】
(gdb) c
Continuing.
Watchpoint 2: ((*(AVStream *)((*(AVFormatContext*)ic)->streams[0]))->codecpar)
Old value = (AVCodecParameters *) 0x22cba00
New value = (AVCodecParameters *) 0x0
avformat_find_stream_info (ic=0x22ca500, options=0x22cc500) at libavformat/utils.c:3646
3646 if (!max_analyze_duration) {
10.查看调用栈
(gdb) bt
#0 avformat_find_stream_info (ic=0x22ca500, options=0x22cc500) at libavformat/utils.c:3646
#1 0x0000000000496e7b in open_input_file (o=o@entry=0x7fffffffe0a0, filename=<optimized out>) at fftools/ffmpeg_opt.c:1184
#2 0x000000000049b9cf in open_files (inout=0x1298fb1 "input", open_file=0x496290 <open_input_file>, l=<optimized out>, l=<optimized out>) at fftools/ffmpeg_opt.c:3299
#3 ffmpeg_parse_options (argc=argc@entry=7, argv=argv@entry=0x7fffffffe5a8) at fftools/ffmpeg_opt.c:3339
#4 0x000000000048f5fd in main (argc=7, argv=0x7fffffffe5a8) at fftools/ffmpeg.c:4849
10.查看代码上下文
(gdb) list
3641
3642 av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN);
3643 ic->streams[0]->codecpar=NULL;
3644 max_stream_analyze_duration = max_analyze_duration;
3645 max_subtitle_analyze_duration = max_analyze_duration;
3646 if (!max_analyze_duration) {
3647 max_stream_analyze_duration =
3648 max_analyze_duration = 5*AV_TIME_BASE;
3649 max_subtitle_analyze_duration = 30*AV_TIME_BASE;
3650 if (!strcmp(ic->iformat->name, "flv"))