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
底层就会解析出相应PIDsection数据,存储到pmt table中。
每次pmt的刷新,会将信息存到curprog中,相应的信息会传递给subtitle service结构体,MW_DTV_Subtitle::m_Services,通过队列存储起来:u16Sub_Pidu8subtitling_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 serviceseg,不同语言,或者normal/hearingimpaired)才有用,否则与composition_page_id一样

根据subtitlePIDu16PID)就开始了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);
        }
    }
}

到这里就进入了subtitledecode部分了

2.      __decode()   
Mapi_dvb_subtitle_decoder.cpp(参考EN_300743)
codemapi_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的结构如下:
(, 下载次数: 453)