分类: LINUX
2011-03-22 18:46:33
主要的分析内容包括如下两个方面:demuxer相关,解码器选取相关
1、demuxer相关
1.1 ffmpeg中选择demuxer的过程
av_open_input_file(**)->ff_probe_input_buffer(**)-->av_probe_input_format2(***)-->read_probe(), 其中read_probe是函数指针,不同的demuxer基本都会实现自己的read_probe,举例来说,mpegts对应的函数名是
mpegts_probe,根据read_probe的返回值来判断,选择得分(返回值)最大的demuxer。
其中在av_open_input_file函数中首先调用url_fopen(**)来判断参数中给定的视频流是
文件格式 (file)还是网络流格式(rtsp、rtp等),并调用相应的open函数来打开流,其中url_alloc(**)为格式探测函数,url_connect(**)—>uc->prot->url_open(**)为相应的流打开函数,其中uc->prot->url_open为函数指针,存储选中格式的open函数。格式判断方法比较简单:判断文件名中是否有“:”,有再判断具体是哪种流,没有的话按照文件格式来处理。
格式探测完毕并打开流之后(将uc->is_connected设置为1),url_open函数结束。接下来执行url_fdopen(**),在此过程中通过URLContext数据结构(不同的格式会有不同的读取包的方式)来初始化ByteIOContext,ByteIOContext是 AVFormatContext的成员,其成员包括流属性,已经对流的读取、写入、定位等函数指针。经过初始化此结构程序便可以读取实际的数据包来做进一步分析了。
下面以mpegts为例,看具体选择demuxer的过程。过程通过调用read_probe()来确定,在mpegts中是调用 libavformat/mpegts.c中的mpegts_probe(**)-->analyze(***),具体原理是读取一定数量的包(此
处是2048Byte,计算下来应该是10个包 204*10=2040),判断0x47出现的次数(0x47是mpegts的同步位),根据出现次数来计算分数(具体代码分析可参考引用的其他文章)。
如果匹配的话,肯定是满分,故而选择。
1.2psi分析
选择完毕demuxer(format)之后,下一步打开视频流并分析。主要分析PSI信息,即包含的频道及各个频道关联的具体视频或音频流的信息等。具体过程如下:
av_open_input_stream(**)-->read_header(), 其中read_header也是函数指针,在此处我们还以mpegts为例,实际调用的函数为mpegts_read_header(**),此过程主要
是分析ts流中有哪些视频流、音频流等参数(主要通过分析ts流中的pat sdt表等信息得出),调用过程为
:
mpegts_read_header(***)-->handle_packets(**)-->handle_packet(**),
其中在mpegts_read_header(**)中首先通过pegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);挂接sdt以及pat的处理函数,即sdt和pat是最初始的信息,在pat中才能得到pmt的pid以便进一步分析。在handle_packets中读取一个包然后调用handle_packet(**)处理。处理过程中调用write_section_data
接收pat等信息,当一个完整的pat接收完毕后,调用tss->section_cb(tss1, tss->section_buf, tss->section_h_size);来解析,此处section_cb便是通过mpegts_open_section_filter挂接的pat_cb(以pat为例,sdt分析方式一样)。分析过程得到pmt的pid并通过mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);将pmt的解析函数挂接上来,之后便可以读取pmt包并处理了。通过分析pmt便可以得到具体的媒体流并通过add_pes_stream(ts, pid, pcr_pid);函数来建立各个媒体流的信息,也得到了此ts中包含的媒体流的数量和id,在pmt_cb中还有一个很重要的函数是mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc);此函数通过mpegts_find_stream_type(st, pes->stream_type, MISC_types);可以定位到每个媒体流的具体解码器(主要是存储codec_id,其他在后面初始化),之后解码的时候便可以通过codec_id来选择具体的解码器了。增加流的操作中会调用tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);来挂接实际的解析pes的函数,之后便可以接收具体的pes包并解析实际的媒体数据。以上内容并不保证准确,需进一步确认。
经过此过程,便得到了基本的流信息(video
audio 数量及相应的ID),在读包后分析ID即可相应处理,达到解复用的目的了。分析参数得到流信息的过程描述如下:主要是两个表PAT和PMT,其中PAT存
储的频道信息,一个频道便有一个PMT,而PMT存储的是此频道由哪些流组成(视频流
音频流 以及相应的PID),以及流的具体格式(h264等),通过分析完每个PMT便得到了总的视频流及频道等信息。具体的关于sdt和pat、pmt的介绍可参照网上信息或查阅标准文档。
2、解码器相关
2.1解码器选择:
通过如上分析,已经得到了解码器的codec_id,根据codec_id选择即可
待续。。。
转载请注明!