1. 综述
ffmpeg框架对应MPEG-2 TS流的解析的代码在mpegts.c文件中,该文件有两个解复用的实例:mpegts_demuxer和mpegtsraw_demuxer,mpegts_demuxer对应的真实的TS流格式,也就是机顶盒直接处理的TS流,本文主要分析和该种格式相关的代码;mpegtsraw_demuxer这个格式我没有遇见过,本文中不做分析。本文针对的ffmpeg的版本是0.5版本。
2. mpegts_demuxer结构分析
AVInputFormat mpegts_demuxer = {au
"mpegts", //demux的名称
NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"),//如果定义了CONFIG_SMALL宏,该域返回NULL,也就是取消long_name域的定义。
sizeof(MpegTSContext),//每个demuxer的结构的私有域的大小
mpegts_probe,//检测是否是TS流格式
mpegts_read_header,//下文介绍
mpegts_read_packet,//下文介绍
mpegts_read_close,//关闭demuxer
read_seek,//下文介绍
mpegts_get_pcr,//下文介绍
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,//下文介绍
};
该结构通过av_register_all函数注册到ffmpeg的主框架中,通过mpegts_probe函数来检测是否是TS流格式,然后通过mpegts_read_header函数找到一路音频流和一路视频流(注意:在该函数中没有找全所有的音频流和视频流),最后调用mpegts_read_packet函数将找到的音频流和视频流数据提取出来,通过主框架推入解码器。
3. mpegts_probe函数分析
mpegts_probe被av_probe_input_format2调用,根据返回的score来判断那种格式的可能性最大。mpegts_probe调用了analyze函数,我们先分析一下analyze函数。
static int analyze(const uint8_t *buf, int size, int packet_size, int *index){
int stat[TS_MAX_PACKET_SIZE];//积分统计结果
int i;
int x=0;
int best_score=0;
memset(stat, 0, packet_size*sizeof(int));
for(x=i=0; i<size-3; i++){
if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && (buf[i+3] & 0x30)){
stat[x]++;
if(stat[x] > best_score){
best_score= stat[x];
if(index) *index= x;
}
}
x++;
if(x == packet_size) x= 0;
}
return best_score;
}
analyze函数的思路:
buf[i] == 0x47 && !(buf[i+1] & 0x80) && (buf[i+3] & 0x30)是TS流同步开始的模式,0x47是TS流同步的标志,(buf[i+1] & 0x80是传输错误标志,buf[i+3] & 0x30为0时表示为ISO/IEC未来使用保留,目前不存在这样的值。记该模式为“TS流同步模式”
stat数组变量存储的是“TS流同步模式”在某个位置出现的次数。
analyze函数扫描检测数据,如果发现该模式,则stat[i%packet_size]++(函数中的x变量就是用来取模运算的,因为当x==packet_size时,x就被归零),扫描完后,自然是同步位置的累加值最大。
mpegts_probe函数通过调用analyze函数来得到相应的分数,ffmpeg框架会根据该分数判断是否是对应的格式,返回对应的AVInputFormat实例。
4. mpegts_read_header函数分析
下文中省略号代表的是和mpegtsraw_demuxer相关的代码,暂不涉及。
static int mpegts_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
MpegTSContext *ts = s->priv_data;
ByteIOContext *pb = s->pb;
uint8_t buf[5*1024];
int len;
int64_t pos;
......
//保存流的当前位置,便于检测操作完成后恢复到原来的位置,
//这样在播放的时候就不会浪费一段流。
pos = url_ftell(pb);
//读取一段流来检测TS包的大小
len = get_buffer(pb, buf, sizeof(buf));
if (len != sizeof(buf))
goto fail;
//得到TS流包的大小,通常是188bytes,我目前见过的都是188个字节的。
//TS包的大小有三种:
//1) 通常情况下的188字节
//2)日本弄了个192Bytes的DVH-S格式
//3)在188Bytes的基础上,加上16Bytes的FEC(前向纠错),也就是204bytes
ts->raw_packet_size = get_packet_size(buf, sizeof(buf));
if (ts->raw_packet_size <= 0)

本文详细分析了ffmpeg中mpegts.c文件的mpegts_demuxer结构,主要探讨了mpegts_probe函数用于检测TS流的实现,以及mpegts_read_header函数如何找到音频和视频流并提取数据。此外,还介绍了mpegts_open_section_filter、handle_packets和handle_packet等关键函数的作用,揭示了ffmpeg对MPEG-2 TS流解析的内部工作机制。
最低0.47元/天 解锁文章
1274

被折叠的 条评论
为什么被折叠?



