共计 1311 个字符,预计需要花费 4 分钟才能阅读完成。
因为学校网速原因,导致很多视频都很难看高清的在线视频,就只能下载到电脑看本地视频了,但是这样就没法看弹幕了,所以就萌生了将B站弹幕转换成本地字幕形式播放的想法。
分别代表着:弹幕出现时间、弹幕类型、字体大小、字体颜色、创建时间、不清楚、创建者ID、弹幕ID。
接下来就是ass字幕的格式了
Dialogue: 1,0:02:02.84,0:02:08.84,Dedualt,,0000,0000,0000,,{\move(1024, 51, -1428, 51)}你以为雷总不上b站了
我们除了需要将原来的时间、颜色、字体大小做改变之外,最难的应该是确实字幕的位置和相应的动作了。
这里讲一下B站的字幕类型:
1. 1代表普通滚动弹幕
2. 4代表底部中间弹幕
3. 5代表顶部中间弹幕
还有其他一些高级弹幕,难度太大就不做处理了。
为了减少弹幕突然集中出现导致的弹幕重叠情况,将弹幕分组储存,分行输出,这样同一时间发出的弹幕可以在多行展示。
这里处理弹幕的算法是:先根据播放器屏幕大小和弹幕字体大小将屏幕分为固定行数,即line = width / fontsize
。得到固定行数之后,定义三组数组分别储存三种类型的弹幕,当每组数组内有固定行数个元素之后,也就是当前屏幕所有行数都存在弹幕时,即输出此行数组,并且将当前数组清除准备储存下一组数据,核心代码如下:
def ComposeComment(self, filename):
'''
组合弹幕,将不同类型的弹幕放到一个list
并且当list存满ROWS时输出给ConvertComment
'''
rows = [[] for i in xrange(3)]
# 弹幕类型
category_dic = {'1':0, '4':1, '5':2}
for index, comment in enumerate(self.ReadComment(filename), 1):
category = category_dic[comment[1]]
rows[category].append(comment)
if len(rows[category]) == ROWS:
yield rows[category]
rows[category] = []
for row in rows:
yield row
接下来就是计算弹幕的位置了,按照ComposeComment
函数输出的ROWS,计算出当前弹幕的X轴和Y轴的位置:
styles.append('\\move(%(width)d, %(row)d, %(neglen)d, %(row)d)' % {'width': WIDTH, 'row': index*SIZE, 'neglen': -math.ceil(len(text)*SIZE)})
动画的格式如下:
\move(<x1>, <y1>, <x2>, <y2>[, <t1>, <t2>])---移动效果
x1,y1---移动开始的位置
x2,y2---移动结束的位置
t1,t2---移动开始和结束时间,省略后以字幕开始和结束时间为准
核心问题解决后,剩下的就是时间戳、颜色的转换了,很简单就不贴代码了。
最后贴一张效果图:
参考资料:
* Danmaku2ASS
* bilibili弹幕转ass
* ASS格式