一个针对日本的数字电视应用(ISDBT)里字幕处理有一些问题,规范文档庞大又复杂,读起来还觉得语焉不详。接手遗留项目尝试处理字幕显示的问题,边读spec边看代码,先猜测、试图理解既有逻辑,再分析问题产生的原因,寻找解决方案。

文档是ARIB STD-B24 Version 5.1 Volume 1(Data Coding and Transmission Specification for Digital Broadcasting)。文档中出现的"02/0"表示0x20,“07/15"表示0x7F。

1. 一个data group里的多个data unit
按照规范文档定义(见文档的Table 9-1
Data group),一个字幕数据(one caption data)最多由256个data groups组成。data
group结构里有6位的group id,2位的group version,8位的group link number(从0开始),8位的last
group link number(标明最后一个group)。但实际上绝少见到一个data
group放不下的字幕数据。目前的实现只考虑了一个data group。

根据group id,group可以分为caption management group和caption statement group(见文档的Table 9-2 Correspondence to caption data and data group identification),这两类data group结构都在最后包含了若干个data unit(见文档的Table 9-3 Structure management data和Table 9-10 Caption statement data)。

观察码流发现,大部分情况一个data group里只有一个data unit,但还是不止一次地看到同一个data group里有两个data unit。出现这种情况时,第一个data unit都是0x0C开始、包含字体大小、颜色和字符编码的数据(data unit的不同类型参见文档的Table 9-12 Types of data unit,这里只讨论0x20,即statement body),第二个data unit都是一个TIME命令(9D 20 XX 0C,这里是十六进制表示,下同)。之前的实现假设一个data group里如果有多个data unit,每个data unit也都是0x0C开始、包含字体大小、颜色和字符编码的数据,如果只有命令而没有字符编码数据则会被丢弃。

怎么理解只有TIME命令的data unit?目前只能认为是补充前一条data unit(0x0C开始、包含字体大小、颜色和字符编码的数据)。

观察码流还发现另一种情形,data group里只有一个data unit,这个data unit的数据也只有一个0x0C。前面一直没有提到0C命令,这里讨论一下。在文档的Table 7-14 Control function character set code table中可以看到,0C是清屏命令(CS),Table 7-15 C0 control set中定义为“Display area of the display screen is erased”。在之前的实现里,没有字符数据的data unit都被丢弃了。可是为什么会送出一个单独的0x0C呢?在某一个码流里还看到连续两个这样的data group,只有一个data unit,里面只有一个0x0C。

根据0C的定义,我们可以这样理解每一个包含字符数据的data unit,0x0C开头意即清除上一条字幕,开始准备显示当前字幕。TIME命令后如果跟随0x0C(9D 20 XX 0C),意即presentation了duration的时间后清除(TIME命令的分析见下文)。单独的一个0x0C是不是意味着,没有要显示的字 幕,但也要清除上一条字幕呢?目前只能这样去实现了。

2. caption management group中是否有DC
通过解析
DMF(display mode)来判断DMF之后是否有一个单字节的DC(display condition
designation)(见文档的Table 9-3 Structure management data),文档的Table 9-5
Display mode和Table 9-6 Designation of display
condition解释了DMF和DC,可还是没看懂DC。观察码流,DMF的值总是10(十进制),按照规范文档定义,DMF等于12、13或14时,
后一个字节是DC。

3. TIME命令
按照文档“ARIB STD-B24 Version 5.1 Volume
1”的解释,9D是TIME命令(见文档的Table 7-14 Control function character set code
table),在Table 7-16 C1 control set中定义了三种情况,观察测试用的一些码流,情况(1)最常见,即"TIME
02/0 P2”,情况(5)“TIME 02/8 P2"和情况(6)“TIME
02/9"不多见,这里只分析情况(1)。三种情况的解释请见下面的注释代码段。

“TIME 02/0 P2"的命令模式意味着遇到9D 20 XX这个模式,取出XX的低6位作为P2,P2设置字幕显示的duration时间,单位是0.1秒,取值范围是从0x40到0x7F。

观察实际的码流,最常见到的命令模式是9D 20 XX 0C。也比较好理解,即当前字幕显示P2/10.0秒之后清屏。之前的实现把0C作为该模式之必要。

可是,在某一个码流里发现这样的情况:9D 20 7F 9D 20 7F 9D 20 7F 9D 20 44
0C。按照之前的处理逻辑,第一组9D
20的P2后不是0C,于是放弃把9D当作TIME命令来处理,跳过9D,继续解析20和7F(20会被作为空格处理,7F本是删除,这里忽略不作处
理),直到最后一个9D,能找到那个0C,才会把44取出来计算P2,而计算出来的duration时间是0.4秒。

这很奇怪,0.4秒的presentation时间让人几乎无法看清,这字幕就没有意义了。规范文档里没有提到连续多次送来TIME
02/0命令该如何解析。连续几天没有想出所以然,突然有一天在反复阅读规范文档时想到,会不会是累加。因为P2的取值范围是0x40到
0x7F,0x7F表示6.3秒,如果需要表达大于6.3秒的duration时间,岂不是需要累加表示。如果是这样,连续的9D
20命令模式中除最后一个外,前面的P2都应该是7F,这需要观察更多码流文件来验证,现在不具备这个条件。如果这样理解,我们发现的这个情况
中,duration时间应该是19.3秒。

              /* TIME, Table 7-15 C0 control set
(1) Wait for process: TIME 02/0 P2
Processing of code as of this code is stopped for set duration by parameter
P2. Parameter P2 is in the range of 04/0 to 07/15 and set by binary of 6 bit
from b6 to b1. (b7 and b8 are not used.) Designating time should be 0.1 sec.
(5) Time control mode(TMD): TIME 02/8 P2
TIME 02/8 04/0: Free
TIME 02/8 04/1: Real
TIME 02/8 04/2: Offset
TIME 02/8 04/3: Unique
(6) Presentation start time(STM), Playback time(DTM), Offset time(OTM),
Performance time(PTM), Display end time(ETM):
TIME P P11-P1i I1 P21-P2j I2 P31-P3k I3 P41-P4m I F
P = 02/9 I = 02/0 I1-I3 = 03/11
P11-P1i = 03/0-03/9 (decimal)time
P21-P2j = 03/0-03/9 (decimal)minute
P31-P3k = 03/0-03/9 (decimal)second
P41-P4m = 03/0-03/9 (decimal)millisecond
F = 04/0 STM, DTM
04/1 OTM
04/2 PTM
04/3 ETM
At performance time, I3, P41 --- P4m is not sent out.*/

4. 多行显示字幕
字符编码数据中如果遇到0x0D,认为是要换行,多数码流里用0D命令来显示人物对话,譬如电影电视剧中AB两人的对话,一般0D前后的字幕还会用不同的颜色显示。

还有一种情况需要换行,即根据data
unit中的字体大小设定、或者应用本身的设置,视频画面的宽度不够在一行里显示所有字符,需要做截断换行处理。之前的实现对字幕显示位置做了限制,只能
显示两行字幕,于是当第一行字幕(0xOD前)需要截断换行时,本该显示的第二行(0x0D)字幕就无法显示了。目前调整为放宽限制至三行。如果0x0D
前后的字符数据都有点长、需要截断换行,0x0D后的字幕将会被截断,只能部分显示。

5. 清除字幕的判断条件
字幕显示的时间可以用音视频同步的参考时钟来和视频同步,字幕数据也来自
PES包,有自己的pts(presentation time
stamp)。但是由于未知原因,我们获取到字幕数据时,其pts已经落后于参考时钟。也就是说,总是晚一步贴字幕。这个问题尚未解决。

目前的处理逻辑是,获取到字幕数据,转成图片,确定往视频帧上贴图的位置,放到队列里,渲染视频帧时如果字幕队列里有内容(read
index),取出来比较其pts和参考时钟,该显示了就贴图,然后看该字幕是否有上文提到的duration信息(9D 20
XX),如果有,将其pts加上duration后和参考时钟比较,如果过期就清除。

仅仅这样还不够,如果当前字幕没有duration信息怎么办?观察码流发现,很多场景字幕不带有duration信息,我们猜测认为,这种情况下
是要依赖下一条将要显示的字幕到了该显示的时间来取代当前字幕,相当于为其清屏(每条字幕都是0C开头)。因此,不带有duration信息的字幕将一直
显示,直到其下一条字幕需要显示了。

这种场景的典型例子就是一人或多人不停地说话,后一条字幕替换前一条。如此猜测,也包含这样一个假定,如果这样集中的说话或对话结束了,接下来无人
说话或者干脆插播广告,最后一条字幕是一定会带有duration信息的。如果没有,这条字幕将一直显示着。之前我们的实现经常错误地丢弃了
duration信息,就出现这样的问题,补丁方案是对没有duration信息的字幕,赋默认值3秒。现在去掉了这个补丁,因为它会影响下一条字幕的显
示。

这又带来一个问题,如果当前字幕的duration时间比较长,譬如有10秒,而期间下一条字幕的pts已经到了该显示的时间。谁的优先级高?目前的实现是当前字幕的duration优先级高。

前面提到过,有单独的data unit,并且只有一个0x0C,而这个0x0C也有pts,这又意味着什么?目前的实现是清屏(即贴这个空字幕)时间要看0x0C的pts,而不是接受到0x0C立刻清屏。

ISDBT中CC的处理疑问的更多相关文章

  1. cocos2d-html5学习笔记(六)--alpha2中cc.Sequence.create中的bug

    cocos2d-html5学习笔记(六)--alpha2中cc.Sequence.create中的bug http://blog.csdn.net/allenice1/article/details/ ...

  2. 关于SQL注入中编码问题的疑问

    提到SQL注入的绕过,编码是其中最普通的一种方法,最常用的URL编码.之前一直有个疑问,编码与未编码到底有哪些地方存在区别? 以下是本人自己对URL编码的一些见解,可能有错误的地方欢迎大佬们指正. 什 ...

  3. 关于HashMap中的扰动函数的疑问

    最近再看jdk8的hashmap源码,当看到这一步的时候有点疑问,去网上搜了一下,看到的所有文章基本上都是一篇抄一篇的(反正目前各大社区就是这么个状况),那个意思就是让高16位也参与运算,增加结果的随 ...

  4. KMP算法中的几个疑问

    KMP算法next数组求解实现 首先我们通过应用场景将KMP算法中用到的名词做一个说明: 在一个字符串(string1)中查询是否存在另一个字符串(string2). 在字符串匹配算法中,我们通常将字 ...

  5. cocos2dx+lua中cc.EventListenerMouse:create()的bug

    今天在调试项目的时候用到了鼠标事件的监听 在创建事件监听器的时候出了问题 cc.EventListenerMouse:create() 这句返回值为nil 原来这是cocos2dx引擎的一个bug,t ...

  6. 关于C++中操作符重载的疑问 :四个运算符=, ->, [], ()不可以重载为全局函数(友员函数)

    转载自:http://blog.csdn.net/u014610226/article/details/47679323     以下是对C++中不能重载为友元函数的四个运算符进行了详细的分析介绍,需 ...

  7. C++解析(25):关于动态内存分配、虚函数和继承中强制类型转换的疑问

    0.目录 1.动态内存分配 1.1 new和malloc的区别 1.2 delete和free的区别 2.虚函数 2.1 构造函数与析构函数是否可以成为虚函数? 2.2 构造函数与析构函数是否可以发生 ...

  8. 关于gc日志中Desired Survivor的疑问和对象晋升老年代的小结

    问题背景 (下面的所有内容都是根据书上的Serial/Serial Old收集器下的情况) 在<深入理解JVM>一书中的——3.6.3长期存活的对象将进入老年代的介绍中, 一个例子的jvm ...

  9. HashMap中的hash算法中的几个疑问

    HashMap中哈希算法的关键代码 //重新计算哈希值 static final int hash(Object key) { int h; return (key == null) ? 0 : (h ...

随机推荐

  1. POJ 2610

    #include<iostream> #include<iomanip> using namespace std; int main() { //freopen("a ...

  2. macbook 安装oracle RAC

    http://blog.itpub.net/29047826/viewspace-1268923/ http://blog.itpub.net/24930246/viewspace-1426856/

  3. 课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 3、Python Basics with numpy (optional)

    Python Basics with numpy (optional)Welcome to your first (Optional) programming exercise of the deep ...

  4. 多线程之CountDownLatch和CyclicBarriar使用

    CountDownLatch和CyclicBarriar是java.util.concurrent包下面提供的多线程同步工具,两者有点相似,相当于计数器,但是用处还是有区别的. CountDownLa ...

  5. MySQL笔记(2)---InnoDB存储引擎

    1.前言 本节记录InnoDB的相关知识点. 2.InnoDB存储引擎简介 2.1版本 MySQL5.1开始,允许用动态方式加载引擎,这样存储引擎的更新可以不受MySQL数据库版本的限制.下面是各个I ...

  6. Redis笔记(4)独立功能的实现

    1.前言 本节记录一下redis的一些功能上的实现,包括发布订阅.事务.Lua脚本.排序.二进制位数组.慢查询日志和监视器. 2.发布订阅 上一章介绍sentinel的时候说到了sentinel会订阅 ...

  7. Editplus php

    一.配置PHP帮助手册 1.打开Editplus,[工具]-->[配置用户工具],在[添加工具]子菜单下选择[HTML帮助(*.chm)(T)],文件路径选择php的chm帮助文件路径. 这样在 ...

  8. Element ui tree结合Vue使用遇到的一些问题(一)

    下图是一个后台管理系统,展示的是角色列表 当我点击编辑的时候,弹出一个模态框,如下图 功能需求:点击编辑按钮,弹出模态框,选择权限那块,默认选中当前角色拥有的权限. 问题:第一次点击编辑按钮时,不会选 ...

  9. 使用Nagios打造专业的业务状态监控

    想必各个公司都有部署zabbix之类的监控系统来监控服务器的资源使用情况.各服务的运行状态,是否这种监控就足够了呢?有没有遇到监控系统一切正常确发现项目无法正常对外提供服务的情况呢?本篇文章聊聊我们如 ...

  10. 31-hadoop-hbase-mapreduce操作hbase

    有一些大的文件,需要存入HBase中,其思想是先把文件传到HDFS上,利用map阶段读取<key,value>对,可在reduce把这些键值对上传到HBase中. HbaseMapper: ...