SuperIC社区_
标题: DVB_subtitle解析流程浅 [打印本页]
作者: icezhou 时间: 2016-5-31 14:34
标题: DVB_subtitle解析流程浅
参考ISO13818-1,EN-300743,从TS流解析开始,结合MS6328的code将DVB Subtitle的解析过程简单梳理了一下。
一、TS PAT PMT PES(参考ISO13818-1)
1. 由TS包中取出PAT表
从搜台开始pat 解析:
MW_DVB_SI_PSI_Parser ::_ScanStar()下m_pPatParser->Start(PAT_SCAN_TIMEOUT)
这里mapi_demux_section_filter*m_pSecFilter = m_pDemux->AllocateSectionFilter()返回一个demux section filter 指针
这个section指定了:
stSecConfig.u16PID = PID_PAT;
stSecConfig.au8MatchByte[0] = TID_PAS; //table id
指定pat相应的section
(//这里的section,用来分段传输psi中各个table信息的结构,是去掉了TS 包头以后的TS payload 数据)
SI以及MPEG-2 PSI tables在被插入TS 包之前会被分段成一个或多个section。Section是可变长度的,每个table的section被限制在1024 bytes,除了EIT 表的section为4096bytes。Refer to《en_300468》
这里是取TS中PSI数据,区别于PES数据)
注意:有效负载(payload):指包中跟在包头后面的bytes。比如:TS 包的有效负载包括一个PES_packet_header 和PES_packtet_data_bytes; 或者,一个指针域(pointer_field)和 PSI_secti** 或者 私有数据。
一个PES 包的有效负载只包含PES_packtet_data_bytes。另外,TS 包的包头和调整区域(adaptation fields)不是有效负载。
…
m_pSecFilter->Init(stSecConfig)
m_pSecFilter->Start()
…
解析完pat,得到有用的信息,兵存储于Pat Table结构中:
mapi_si_PAT_parser:

arse()
{
PatTbl.ServiceIDInfo[u16ServiceIndex].u16ServiceID
PatTbl.ServiceIDInfo[u16ServiceIndex].u16PmtPID
u16ServiceIndex++;
PatTbl.u16ServiceCount = u16ServiceIndex
}
2. 由PAT得到对应的PMT
在_PatReady()下会将对应的从pat解析时得到的PmtPID存储如pCurProg 信息中 (serviceIID,OriginalNetworkId,TransportStream_id,NetworkId),PMT 会根据curprog.u16PmtPID来解析。
_PMT_Monitor()下sm_pCurPmtParser->Start(xx, PMTPID, xx)
mapi_si_PMT_parser::Start()
stSecConfig.u16PID = u16PMTPid;
stSecConfig.au8MatchByte[0]= TID_PMS; //table id
底层就会解析出相应PID的section数据,存储到pmt table中。
每次pmt的刷新,会将信息存到curprog中,相应的信息会传递给subtitle service结构体,MW_DTV_Subtitle::m_Services,通过队列存储起来:u16Sub_Pid,u8subtitling_type。
3. 根据PMT得出subtitle相关信息
有了PMT信息,就可以得出subtitle的信息了,所以当打开一个相应的subtitle时,就可以通过索引找到存储起来的subtitle信息。
….
if(m_pDVBSubtitle_decoder->Connect() ==TRUE)
{
m_pDVBSubtitle_decoder->SetCA_PageID(u16composition_page_id,u16ancillary_page_id); //composion_pageid ancillary_pageid
m_pDVBSubtitle_decoder->Open(u16PID, bFileIn);
m_enOpenType =EN_OPEN_SUBTITLE_DVB;
bSuccess = TRUE;
}
注:ancillary_page_id只对于一个subtitle流中复合多个subtitle services(eg,不同语言,或者normal/hearingimpaired)才有用,否则与composition_page_id一样
根据subtitle的PID(u16PID)就开始了subtitle的解析。
二、Subtitle 解析
1. 下面是PES的处理
MW_DVBSubtitleDecoder::Connect()
这里创建subtitle的render相关,并且会create 一个线程(__sbt_thread())来处理subittle的数据。
__sbt_thread():
MW_DVBSubtitleDecoder::__process_PES()
<1>.在MW_DTV_Subtite::Init()下会有m_pDVBSubtitle_decoder->AllocatePESFilter()会分配一个PESFilter,注意与上面的SectionFilter区别。
<2>. m_pPES_Filter->Open(u16PID)这里会传递需要解析的PID给相应的Pesfilter,然后再根据pes包头取得数据存处于buffer(一个完整的PES packet)。
这里 Stream_id必须是0xBD,表示private_stream_1(具体可查看iso13818-1 Table2-18)
<3>__compute_PTS(buffer)
取得PTS_DTS_flags(2bit)(pu8bff[7]& 0xc0 == 0x80 或者 0xc0)
当此值为‘10’,表示PTS fields存在与PES 包头
当此值为‘11’,表示PTS fields和DTS fields都存在与PES 包头
当此值为‘00’,表示PTS或者DTS fields都不会存在与PES包头
‘01’是禁止的
PTS 33bit,分3部分,DTS 也是33bit,同样是由3部分组成,这里我们只取PTS,用不到DTS(具体可以参考iso13818-1关于PES packet结构的spec)
if(((pu8bff[7] & 0xc0) == 0x80) || ((pu8bff[7] & 0xc0) ==0xc0))
{
u32tmp = pu8bff[9];
u32PTSLow = (u32tmp& 0x06);
u32PTSLow <<=29;
u32tmp = pu8bff[10];
u32tmp <<= 22;
u32PTSLow |= u32tmp;
u32tmp = pu8bff[11]& 0xfe;
u32tmp <<= 14;
u32PTSLow |= u32tmp;
u32tmp = pu8bff[12];
u32tmp <<= 7;
u32PTSLow |= u32tmp;
u32tmp = pu8bff[13]& 0xfe;
u32tmp >>= 1;
u32PTSLow |= u32tmp;
}
(当然,还有PTS的特殊情况,这里就用到了system time clock(STC)的概念
理想情况下:如果解码器的时钟频率与编码器匹配,那么解码速率就与编码时一致。这时候任何正确的 PCR(由TS取得)就可以用作解码器的STC。但实际情况是不可能匹配的。一种方法是通过phase-lockedloop(PLL)来强制解码器的clock与收到的数据流一致。)
然后会将取得的一个完整的PES:buffer数据以及PTS压入一个队列DataQueue,_push(pu8Buf, u16Len, u32PTS)
mapi_dvb_subtitle_decoder::Main(MAPI_U32u32STC)
…
pSubtitle->__GetCurrentPTS(&u32STC);
mapi_interface::Get_mapi_dvb_subtitle()->Main(u32STC);
…
这个main函数就是处理DataQueue中的数据
void mapi_dvb_subtitle_decoder::Main(MAPI_U32 u32STC)
{
if(DataQueue_CheckPTS(u32STC)) //查找DataQueue中所有PTS,若有一小于当前STC,则满足条件
{
QueueElement qeCur;
if(_pop(&qeCur) ==MAPI_TRUE)
{
__decode(&qeCur);
_freeQueueElement(&qeCur);
}
}
}
到这里就进入了subtitle的decode部分了
2. __decode()
Mapi_dvb_subtitle_decoder.cpp(参考EN_300743)
从code中mapi_dvb_subtitle_decoder::__decode(QueueElement*qe){}可见解析流程:
__decode_PES_Header()->__decode_Segment()->__render_Display()->__resetObject()
(这段可参考pes_packet结构)
<1>pes prefix,并取得pes length
m_sbt_stream.SkipLen(4);
m_sbt_stream.GetWord(&m_u16_PES_length);
指针向后移动6个字节
<2>__decode_PES_Header()
这里取得pes headerlen,做一些校验,并根据headerlen 将PES header剔除
找出PESheader的界限?
<3>__decode_CheckStreamID()
这里开始就是剔除了PES header的数据,开始解析subtitling segment数据
当是DVB subtitle stream时,PES_packet_data_bytes的结构如下: