DVB subtitle解析流程浅.docx_第1页
DVB subtitle解析流程浅.docx_第2页
DVB subtitle解析流程浅.docx_第3页
DVB subtitle解析流程浅.docx_第4页
DVB subtitle解析流程浅.docx_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

参考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.au8MatchByte0 = 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 toen_300468这里是取TS中PSI数据,区别于PES数据)注意:有效负载(payload):指包中跟在包头后面的bytes。比如:TS 包的有效负载包括一个PES_packet_header 和PES_packtet_data_bytes; 或者,一个指针域(pointer_field)和 PSI_sections 或者 私有数据。一个PES 包的有效负载只包含PES_packtet_data_bytes。另外,TS 包的包头和调整区域(adaptation fields)不是有效负载。 m_pSecFilter-Init(stSecConfig)m_pSecFilter-Start()解析完pat,得到有用的信息,兵存储于Pat Table结构中:mapi_si_PAT_parser:Parse()PatTbl.ServiceIDInfou16ServiceIndex.u16ServiceIDPatTbl.ServiceIDInfou16ServiceIndex.u16PmtPID u16ServiceIndex+;PatTbl.u16ServiceCount = u16ServiceIndex2. 由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.au8MatchByte0 = 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/hearing impaired)才有用,否则与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().在MW_DTV_Subtite:Init()下会有m_pDVBSubtitle_decoder-AllocatePESFilter()会分配一个PESFilter,注意与上面的SectionFilter区别。. m_pPES_Filter-Open(u16PID) 这里会传递需要解析的PID给相应的Pesfilter,然后再根据pes包头取得数据存处于buffer(一个完整的PES packet)。 这里 Stream_id必须是0xBD,表示private_stream_1(具体可查看iso13818-1 Table2-18) _compute_PTS(buffer)取得PTS_DTS_flags(2bit)(pu8bff7 & 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(pu8bff7 & 0xc0) = 0x80) | (pu8bff7 & 0xc0) = 0xc0) u32tmp = pu8bff9; u32PTSLow = (u32tmp & 0x06); u32PTSLow = 29; u32tmp = pu8bff10; u32tmp = 22; u32PTSLow |= u32tmp; u32tmp = pu8bff11 & 0xfe; u32tmp = 14; u32PTSLow |= u32tmp; u32tmp = pu8bff12; u32tmp = 1; u32PTSLow |= u32tmp;(当然,还有PTS的特殊情况,这里就用到了system time clock(STC)的概念理想情况下:如果解码器的时钟频率与编码器匹配,那么解码速率就与编码时一致。这时候任何正确的 PCR(由TS取得)就可以用作解码器的STC。但实际情况是不可能匹配的。一种方法是通过phase-locked loop(PLL)来强制解码器的clock与收到的数据流一致。)然后会将取得的一个完整的PES:buffer数据以及PTS压入一个队列DataQueue,_push(pu8Buf, u16Len, u32PTS)mapi_dvb_subtitle_decoder:Main(MAPI_U32 u32STC) 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结构)pes prefix,并取得pes length m_sbt_stream.SkipLen(4); m_sbt_stream.GetWord(&m_u16_PES_length); 指针向后移动6个字节_decode_PES_Header() 这里取得pes headerlen,做一些校验,并根据headerlen 将PES header剔除 找出PES header的界限? _decode_CheckStreamID() 这里开始就是剔除了PES header的数据,开始解析subtitling segment数据当是DVB subtitle stream时,PES_packet_data_bytes的结构如下: end_of_PES_data_field_marker 这个占不占空间呢? 貌似不占data_identifier 必须是0x20,subtitle_steam_id必须是0x00 _decode_Segment()这里取得page_id,segment_length,还记得上面open subtitle之前m_pDVBSubtitle_decoder-SetCA_PageID(u16composition_page_id,u16ancillary_page_id)这个接口吗?这是从PMT中取得的compositon_page_id,ancillary_page_id.在这里需要判断此segment的pageid是否等于上面之一,否则就跳过这个segment if(u16_page_id != m_u16CPID) & (u16_page_id != m_u16APID) / skip this segment, not whole PES m_sbt_stream.SkipLen(u16_segment_length); m_u16_PES_length -= u16_segment_length; Segment_length 是指segment_data_field()的数据bytes,其具体的数据结构是由segment_type指定Segment的第二个字节表示segment_type,,指定了这个segment 数据的类型1) case 0x14 display definition segment这里是假定显示的宽度是720pixels 显示的高度是576lines Segment 结构如下: 定义了display definition的一些相关 具体可参考(en300743 7.2.1)2)case 0x10 page composition segment 这个类型的sgement结构如下: _decode_Page():取得regioncount = u16_segment_length / 6 (page segment的长度是6个字节)通过循环,取得所有有效region的region id,以及该region显示的位置坐标(h,v)存处于一个m_page的结构体中 page_time_out:表示page instance存在的时间。主要是为了防止错误发生时(比如page instance其time out没有被重新定义或没有删除)导致page instance 一直显示page state: 0x00:normal case,用于page update,仅显page instance有改变的subtitle elements 此case下说明region_id已经存在,需要判断是否已经存在。当然一开始page state不会是nomal case的情况。? 0x01:acquisition point 用于page refresh ,显示下一个page instance要用到的所有的subtitle 元素 这里主要执行_resetObject() 重置object的索引,version等0x10 :mode change,用于new page,显示new page需要的所有subtitle 元素 这里需reset region,reset object,CLUT索引,screen buffer等 3)case 0x11 region compositon segment _decode_Region() Region_depth指定了pixel depth CLUT_id 指定了用于这个region的CLUTS Object_id 指定了这个region内显示的object(通过循环取得所有的object)Region_fill_flag定义为1后,说明该region需要用背景色填充,填充的颜色由region_8-bit_pixel-code,region_4-bit_pixel-code,region_2-bit_pixel-code指定;region_8-bit_pixel-code:指定8bit的CLUT表的入口,但仅仅当该region_depth是8 bit的时候才有效;region_4-bit_pixel-code:指定4 bit的CLUT表入口。当region depth是4bit可用;或者region depth是8bit,且region_level_of_compatibility是4bit的时候才有用;region_2-bit_pixel-code:指定2bit的CLUT表入口。单region depth为2bit,或者region_level_of_compatibility为2bit的时候可用。region_level_of_compatibility:表示解码器满足的最小CLUT类型(2bit、4bit、8bit) 如果page state是normal case的情况,说明region_id并没有改变(与已经解析出的region信息作比较),无需重新创建region (但是这里如果新来的region width/height 与已经解析出来的region的width/height不一样,需要替换并重新创建这个region) 如果 page state是mode change或acquisition point,需要重新解析region_id,重新创建region 这里解出的region_width region_height,不能超过上面DDS 段解除的display width,display height 根据取出的region_id,region_width,region_heigth,pixel_depth,来创建_createRegionBuffer(),最终通过DirectFB 来绘制一个window _createRegionBuffer()最终是通过IDirectFB*做了两件事CreateWindow、SetPallete。 也就是说一个新的region,就对应了一个新的IDirectFBWindow* 大致情况如下: If (可以显示了) /这个应该是表示这种surface是最终要显示出来的。 一般只需要创建一个可以显示的surface就可以了 1. 通过IDirectFB*取得IDirectFBDisplayLayer*,存为m_pDFBLayer;这样就可以用过m_pDFBLayer做进一步的操作了。2. m_pDFBLayer- SetCooperativeLevel(m_pDFBLayer, DLSCL_ADMINISTRATIVE)/设置合作级别。这里应该是表示管理权限,枚举出window,并管理它们3. m_pDFBLayer-GetConfiguration(m_pDFBLayer,&config)/获得当前layer的配置信息,如width、height、pixelformat等(这里的width、height来自与region_width、region_height)当然获取config是为了重新设置之,设置好后,需调用m_pDFBLayer-SetConfiguration()4. m_pDFBLayer-GetScreen(m_pDFBLayer,&p_screen);/取得screen指针然后再根据screen的方法p_screen-GetSize(p_screen,&screenwidth,&screenheight),取得screen的宽和高。获取screen的宽和高,主要是为了判断与当前video的宽和高的关系(MS6328这段代码没看懂?),然后通过m_pDFBLayer- SetScreenLocation(m_pDFBLayer,x,y,width,height)/来设置screen的位置5. m_pDFBLayer-Create(m_pDFBLayer,&desc,&m_pDFBWindow)/由layer来创建window,其中desc是一些配置信息6. m_pDFBWindow-GetSurface(m_pDFBWindow,&m_Windowsu8WinID.pSurface)/每次创建一个window,都获取一个surface,并存储到window数组中,所以一个region就对应一个window的数组元素,也对应一个surface7. m_pDFBWindow-SetOpacity(m_pDFBWindow-,0/0xff)0表示全透明,隐藏window,0xff表示不透明else /这种方式创建的surface不可以显示到屏幕上 /也就是创建一个region时,同时创建一个surface(由超级接口IDirectFB插口创建),并存储入数组里(宽高像素格式pitch等)直接由IDirectFB创建一个surface,存储到数组中m_pDFB-CreateSurface(m_pDFB, &surDesc,&m_Windowsu8WinID.pSurface) surDesc指定了一些配置信息在官网的例子中,看到surDesc.caps = DSCAPS_PRIMARY | DSCAPS_FLIPPING;,设置为primary surface,应该同上面是一样的功能?pixelformat:使用的是DSPF_LUT8width:region_widthheight:region_heigth在取得surface之后,设置surface的调色板1. m_Windowsu8WinID.pSurface-GetPalette(m_Windowsu8WinID.pSurface,&palette)/这里为什么无需SetPalette?Surface创建后就能直接得到GetPalette?2. 接着palette-SetEntries(palette,DFBColor*color,num_colors,offset)接着palette-Release(palette)/这个接口在官网的接口定义里没有找到?Region segment解析完后得到了一系列索引信息,object索引,CLUT索引等;具体的内容和颜色还需进一步解析相关的segment。我们知道surface代表一块预留的内存,用来保存像素数据,那么像素数据从哪里来呢?在解析object segment的时候,会将像素数据存储到surface对应的内存地址中。(具体见解析object)4)case 0x12 CLUT definition segment 循环解析出所有的cult信息,用YCbCrT 颜色系统存储,需转换成ARGB按公式将YCbCrT的信息转换成ARGB相关,T直接转换为A(透明度),Y=0表示透明(略写)5)case 0x13 object data segment object_coidng_method =0x00 编码方式是像素编码,这种是graphical object(一般是这种情况) object_coding_method=0x01 编码方式是字符编码,这种是字符格式的字幕 一个object 是由top field 和bottom field交错组成。 每一个对象,用于top filed 的pixel-data sub-block 和用于 bottom field的 pixel-data sub-block必须存储在相同的object_data_segment内。 如果bottom field没有数据,则取top field的数据作为bottom field的数据。 对于pixel-data sub_block的结构可参考 EN_300743 7.2.5,详细定义了pixel data的编码规则。在new region的时候创建了surface,那么这个时候可以获取到surface对应的存储像素数据的内存地址,往该内存地址写入数据即可。m_Windowsu8WinID.pSurface-Lock(m_Windowsu8WinID.pSurface, DSLF_WRITE, (void *) pu8Buffer, &u32pitch) /DSLF_WIRTE,表示该地址可写的权限、pu8Buffer是数据指针,u32pitch是行距写入像素数据的起始地址是这么计算的:pu8Buffer+ object_horizontal_position(region中取得)+ object_vertical_position*pitch这里涉及到图像压缩算法 run length encoding(行程编码):将一扫描行中的颜色值相同的相邻像素用一个计算值和那些像素值的颜色值来代替。比如aaabccccccddeee,用3a1b6c2d3e来代替比如run_lenght_3-10指示了2bit_pixel_code重复的次数。m_Windowsu8WinID.pSurface-Unlock(m_Windowsu8WinID.pSurface);/记得执行这步到这一步,surface的内存中已经有像素数据了,但是并不会立即显示出来。1.surface是单buffer的(这个怎么判断呢?)将每个region对应的surface,用StretchBlit()输入到OFFSCREEN特殊的surface:m_Windowsu8DstWinID.pSurface-StretchBlit(DstSurface,OFFSCREEN , pSrcDFBRect, pDstDFBRect)当然要使用StretchBlit之前,还需先用SetBlittingFlags(sur*,DSBLIT_NOFX)、SetRenderOptions(sur*,DSRO_SMOOTH_UPSCALE)这两个接口设置一下。3. surface是double bufferpSurface-GetCapabilities(m_Windowsu8DstWinID.pSurface, &surfaceCaps)/取得该surface的相关属性if(DSCAPS_DOUBLE = (surfaceCaps & DSCAPS_DOUBLE)/来判断是否是double bufferpSurface-Flip(m_Windowsu8DstWinID.pSurface, NULL, (DFBSurfaceFlipFlags)DSFLIP_NONE)/用Flip将数据强行送到屏幕显示最后别忘了pSurface-ReleaseSource(pSurface)/把该surface可能的引用全部释放掉尤其在用了StretchBlit()方法后PS:MS6328创建了两个特殊的surface:1. CreateWindow(ONSCREEN_GWIN_ID, &rect, MAPI_TRUE, m_pCallbackArgument);/表示这个surface是可以显示出来的,具体的步骤可见上述region 解析部分2. CreateWindow(OFFSCREEN_GWIN_ID, &rect, MAPI_FALSE, m_pCallbackArgument);/这个surface是不可以显示出来的作为转存数据使用。(上面每次new region创建的surface也是无需显示的,可显示的只要一个即可) 6)0x80 end of display set segment提供一种模糊的指示给解码器,表示display set已经传输完成。虽然没有什么实际用处,但这个segment是一定需要的。上面解析出来的相关数据,通过DirectFB就可以显示出subtitle了。三、 DVB subtitle system OverviewCLUT color look up table 颜色索引表,CLUT_id存在于每个region中,用于将object中的颜色伪码转换成实际显示的颜色。objects 的使用和配置是由region compositon segment定义的regions的使用和配置 是由 page compositon segment定义的,page compositon segment 包含了一系列供显示的region,每个都有特定的位置。此外,region可以被定义而不被使用。同一时间可以显示不止一个region。一个subtitle stream可以传输多个subtitle service(eg,不同语言,或者normal/hearing impaired)。在这种情况下,每个特定的subtitle service是用page-id来区分的。在同一个subtitle stream中不同subtitle service之间可以共享subtitling data。 当然更多的情况是用不同的PID区分不同的subtitle service。Figure 2: Example of two ways of conveying dual language subtitles (one using shared data) 图表2的情况是没有ancillary page的,看来只有同一个stream中有多个service时才会用到此辅助页面。 注意: 一个单独sbutitle stream是不能同时有高清(包含display_definition_segment)和标清的sbutitle service.在一个subtitle stream中,一个page id 是分配给每个segment。Segments可以只包含特

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论