超详细解析FFplay之数据读取线程( 二 )

 
可以看到是在libavformat/avio.c:374?有正真触发到 。

超详细解析FFplay之数据读取线程

文章插图
 
avformat_find_stream_info的触发 。
read_thread
avformat_find_stream_info
decode_interrupt_cb
详细步骤如下:
#0 decode_interrupt_cb (ctx=0x7ffff7e36040) at fftools/ffplay.c:2715#1 0x00000000007b25bc in avformat_find_stream_info (ic=0x7fffd000094 0,options=0x0) at libavformat/utils.c:3693#2 0x00000000004a6ea9 in read_thread (arg=0x7ffff7e36040)从该调?栈可以看出来 avformat_find_stream_info也会触发ic->interrupt_callback的调?,具体可以看代码(libavformat/utils.c:3693?) 。
在avformat_find_stream_info函数里 。
超详细解析FFplay之数据读取线程

文章插图
 

超详细解析FFplay之数据读取线程

文章插图
 
触发的点 。
av_read_frame的触发耗时回调函数decode_interrupt_cb 。基本顺序流程如下:
read_thread
av_read_frame
read_frame_internal
ff_read_packet
flv_read_packet
av_get_packet
append_packet_chunked
avio_read
fill_buffer
read_packet_wrapper
ffurl_read
retry_transfer_wrapper
ff_check_interrupt
decode_interrupt_cb
详细步骤如下:
#0 decode_interrupt_cb (ctx=0x7ffff7e36040) at fftools/ffplay.c:271 5#1 0x00000000007d99b7 in ff_check_interrupt (cb=0x7fffd00014b0)at libavformat/avio.c:667#2 retry_transfer_wrapper (transfer_func=0x7dd950 <file_read>, size _min=1,size=32768, buf=0x7fffd0009710 "FLV0105", h=0x7fffd0001480) at libavformat/avio.c:374#3 ffurl_read (h=0x7fffd0001480, buf=0x7fffd0009710 "FLV0105", size=32768)at libavformat/avio.c:411#4 0x000000000068cd9c in read_packet_wrapper (size=<optimized out>,buf=<optimized out>, s=0x7fffd00011c0) at libavformat/aviobuf.c: 535#5 fill_buffer (s=0x7fffd00011c0) at libavformat/aviobuf.c:584#6 avio_read (s=s@entry=0x7fffd00011c0, buf=0x7fffd00dbf6d "177", size=45,size@entry=90) at libavformat/aviobuf.c:677 #7 0x00000000007a99d5 in append_packet_chunked (s=0x7fffd00011c0,pkt=pkt@entry=0x7fffdd9bca00, size=size@entry=90)at libavformat/utils.c:293#8 0x00000000007aa969 in av_get_packet (s=<optimized out>,pkt=pkt@entry=0x7fffdd9bca00, size=size@entry=90)at libavformat/utils.c:317#9 0x00000000006b350a in flv_read_packet (s=0x7fffd0000940,pkt=0x7fffdd9bca00) at libavformat/flvdec.c:1295#10 0x00000000007aad6d in ff_read_packet (s=s@entry=0x7fffd0000940,pkt=pkt@entry=0x7fffdd9bca00) at libavformat/utils.c:856---Type <return> to continue, or q <return> to quit---#11 0x00000000007ae291 in read_frame_internal (s=0x7fffd0000940,pkt=0x7fffdd9bcc00) at libavformat/utils.c:1582#12 0x00000000007af422 in av_read_frame (s=0x7fffd0000940,pkt=pkt@entry=0x7fffdd9bcc00) at libavformat/utils.c:1779#13 0x00000000004a68b1 in read_thread (arg=0x7ffff7e36040)at fftools/ffplay.c:3008 
avformat_open_input():打开媒体?件 。
int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat*fmt, AVDictionary **options);
avformat_open_input?于打开输??件(对于RTMP/RTSP/HTTP?络流也是?样,在ffmpeg内部都抽象为URLProtocol,这?描述为?件是为了?便与后续提到的AVStream的流作区分),读取视频?件的基本信息 。
需要提到的两个参数是fmt和options 。通过fmt可以强制指定视频?件的封装,options可以传递额外参数给封装(AVInputFormat) 。
//特定选项处理 if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_C ASE)) {av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVE RWRITE);scan_all_pmts_set = 1;}/* 3.打开?件,主要是探测协议类型,如果是?络?件则创建?络链接等 */ err = avformat_open_input(&ic, is->filename, is->iformat, &format_op ts); if (err < 0) {print_error(is->filename, err);ret = -1;goto fail;}if (scan_all_pmts_set)av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_C ASE); if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {av_log(NULL, AV_LOG_ERROR, "Option %s not found.n", t->key);ret = AVERROR_OPTION_NOT_FOUND;goto fail; }scan_all_pmts是mpegts的?个选项,表示扫描全部的ts流的"Program Map Table"表 。这?在没有设定该选项的时候,强制设为1 。最后执?avformat_open_input 。
使?gdb跟踪options的设置,在av_opt_set打断点 。
(gdb) b av_opt_set(gdb) r#0 av_opt_set_dict2 (obj=obj@entry=0x7fffd0000940, options=options@entry=0x7fffdd9bcb50, search_flags=search_flags@entry=0) at libavutil/opt.c:1588#1 0x00000000011c6837 in av_opt_set_dict (obj=obj@entry=0x7fffd0000940, options=options@entry=0x7fffdd9bcb50) at libavutil/opt.c:1605#2 0x00000000007b5f8b in avformat_open_input (ps=ps@entry=0x7fffdd9bcbf8, filename=0x31d23d0 "source.200kbps.768x320.flv", fmt=<optimized out>, options=0x2e2d450 <format_opts>) at libavformat/utils.c:560#3 0x00000000004a70ae in read_thread (arg=0x7ffff7e36040) at fftools/ffplay.c:2780...... (gdb) l if (!options)return 0; while ((t = av_dict_get(*options, "", t, AV_DICT_IGNORE_SUFFIX))) {ret = av_opt_set(obj, t->key, t->value, search_flags);if (ret == AVERROR_OPTION_NOT_FOUND)ret = av_dict_set(&tmp, t->key, t->value, 0);if (ret < 0) {av_log(obj, AV_LOG_ERROR, "Error setting option %s to value %s.n", t->key, t->value);(gdb) print **options$3 = {count = 1, elems = 0x7fffd0001200}(gdb) print (*options)->elems$4 = (AVDictionaryEntry *) 0x7fffd0001200(gdb) print *((*options)->elems)$5 = {key = 0x7fffd0001130 "scan_all_pmts", value = https://www.isolves.com/it/cxkf/kj/2020-09-15/0x7fffd0001150 "1"}(gdb)


推荐阅读