FFplay的一些接口函数

来源:互联网 发布:外交趣事 知乎 编辑:程序博客网 时间:2024/05/19 12:28

muxer/demuxerencoder/decoder在FFmpeg中的实现代码里,有许多相同的地方,而二者最大的差别是muxerdemuxer分别是不同的结

AVOutputFormatAVInputFormat,而encoderdecoder都是用的AVCodec结构。这个需要认识清楚。



1.// Open video file


av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)
我们通过第一个参数来获得文件名。这个函数读取文件的头部并且把信息保存到我们给的AVFormatContext结构体中。
最后三个参数用来指定特殊的文件格式,缓冲大小和格式参数,但如果把它们设置为空NULL或者0,libavformat将自
动检测这些参数。
call:
1.av_probe_input_format

av_probe_input_format->av_probe_input_format2: 探测文件或流格式找到合适的解复用器,会循环一个一个从注册下去的 AVInputFormat list中获取

AVInputFormat *fmt1->read_probe [avi_probe,flv_probe,mp3_probe...]:会判断文件头的字节和对应的av format是否对应

av_match_ext:会判断输入的文件后缀名和AVInputFormat 的extensions比较,当然这边不准,一般是>read_probe 没有判断出才尝试此依据。

比如:avi_read_probe会将文件的头几个字节和 'R', 'I', 'F', 'F',    'A', 'V', 'I', ' '比较
      
flv_read_probe会将文件的头几个字节和 'f', 'l', 'v'比较
      
MP3_read_probe相对负责,但也是匹配文件的头的buf
      
总之通过probe获取 av foramat是比较准的。
                
当然如果probe无法判断出的话通过av_match_ext匹配文件名后缀来判断:
 
比如

当前文件名为xxx.mp3会匹配AVInputFormat MP3的extensions值"mp2,mp3,m2a"

当前文件名为xxx.avi会匹配AVInputFormat avi的extensions值为空,所以无法通过extensions匹配

当前文件名为xxx.flv会匹配AVInputFormat avi的extensions值"mp2,mp3,m2a"

注:AVInputFormat 操作的都是原始的文件数据

如果是网络流数据会调用流媒体相关接口:




2.url_fopen:会先调用url_open,如果是文件当然是用标准的file接口,其他的会匹配是http(如http://www.baidu.com),udp等,匹配出对应的URLProtocol等。

获取到URLProtocol后会调用URLProtocol  xxx 中相关的接口open,seek等,其中URLProtocoxxl xxx是对应的IO 类型如file,http,udp等

获取到URLProtocol后将其赋给ByteIOContext。




3.ff_probe_input_buffer:探测流媒体传的是什么流媒体类型,需要什么解码资源准备等,由于流媒体数据是从网络中获取的,所以数据是一点一点获取到一个buf中的,做法有很多,ffmpeg采取的是


先获取2k数据然后probe探测(调用av_probe_input_format2),如果还没有探测出,再翻一倍4k数据probe,,,,翻倍loop 直到获取到一个AVInputFormat,如果到一个最大buf(1<<20)还探测不出来


就认为失败,找不到AVInputFormat。


以上1,2,3主要是探测出对应的AVInputFormat 和ByteIOContext,AVInputFormat其和对应的媒体类型已经相关了,如mp3,flv,avi,rm等都有自己对应的AVInputFormat。ByteIOContext也找到了,
如file,http,udp等 ,其中AVInputFormat最终的IO操作还是要用到ByteIOContext中的成员接口。





4.av_open_input_stream:已经探测出了stream 需要对应的解码器等信息后,需要构建一个AVFormatContext:此Context主要要明确有:

ByteIOContext:IO层面获取原始文件数据相关数据和接口

AVInputFormat:解复用相关,具体到了媒体文件的类型了

最后因为已经知道调用AVInputFormat->read_header(...),每个AVInputFormat 在调用read_header会新建AVStream,同时将对应的AVCodecContext codec获取到

然后赋值到AVStream,如果有多个类型会建多个AVStream。比如flv中有音频视频,则会建两个AVStream,并将每个stream对应codec_type,codec_id赋值到codec,当然因为是AVStream嘛,相
关的pts,nb_frames(avstream 数量)等都需要获取或赋值。

可能有些媒体类型没法在read_header中获取具体的codec_id,可能会到read_packet中才能知道具体的codec_id,但大体逻辑是如此。

note: AVStream->id不清楚有什么特殊的地方,大部分看到是id为0是视频,为1为音频,不知道其他值代表什么意思,后续请教大侠。




总结.
av_open_input_file
主要获取
AVInputFormat *iformat; ---->>>>mp3,flv,avi,...
ByteIOContext *pb;----->>>>>file,http,tcp,udp,rtp,md5等
AVStream **streams;----->>>>>pts,nbstream,AVCodecContext *codec----->>>>codec_type,codec_id



2.
av_find_stream_info:
call:
av_parser_init:暂时不知道av parser干嘛的

avcodec_find_decoder:之前av_open_input_file 只是获取了AVStream->AVCodecContext,通过AVCodecContext 的codec-id可以获取AVCodec *codec;

avcodec_open:获取到了AVCodec *codec可以调用其相关接口了,设置完善相应的codec参数,最后调用codec->init,主要也是做些相关的编解码准备。
每个CODEC_ID_xxx,都需要有一套AVCodec:PCM_S16LE,MP3,png,H263P,MPEG2VIDEO等
loop :////循环读数据填满codec,avstream,avpacket等的信息

av_read_frame_internal(ic, &pkt1);///获取1 frame的数据,如果这frame一般avpacket获取不全要多获取几次。

av_read_packet:第一次的话至少先要获取1 个packet。

av_parser_parse2:ffmpeg解码都需要一帧一帧完整地传给解码器,要么自己查找真传给解码器,要么调用av_parser_parse2查找,
注意2点:1.调用av_parser_parse2拿到一个完整帧对应的packet数据,因为帧数据可能比较大,一个packet承载不下需要多个packet。
2.拿到的是帧对应的数据,原始数据,并未解码的数据,可能是一个packet也可能是多个packet拼接重构的起来的数据,但并不是frame格式的数据。

compute_pkt_fields
ff_reduce_index
av_add_index_entry
add_to_pktbuf(&ic->packet_buffer, &pkt1, &ic->packet_buffer_end);
...完善codec等的信息



3.
av_read_frame:
call:
loop:av_read_frame_internal(。。。)->av_parser_parse2,直到拿到一个完整frame对应的数据包。

4.
avcodec_decode_video:

拿到了一个完整的frame数据包,将其解码为avframe格式数据,至此完成解码流程。



原创粉丝点击