Code swarm 是一个可视化项目,最常见的用途是把代码仓库的提交历史可视化,changesets 以时间顺序回放,每个发生变更的文件作为一个闪亮的光点从各处汇聚在对应的 committer 身上,把项目的演进历史以视频的方式形象地呈现出来,通常还会配上激动人心的背景音乐,令程序员们潸然泪下。
很多著名的开源项目比如 Python、 Subversion、 Django、 PostgreSQL、 Apache 等等都有 code swarm 视频,很多互联网公司也都有 code swarm 视频,比如 Twitter、 Last.fm。
可视化是一项伟大的技术,它使非专业人士也能形象地感受到“虚无事物”的发展历程,向致力于可视化的科学家和程序员致敬!
豆瓣发展至今已经有 7 年了,2008 年的时候 hongqn 做过一个 code swarm 视频,时至今日,豆瓣的工程师队伍已经壮大了数倍,再次做了 code swarm 视频。
这次我使用了 code_swarm 项目的一个 fork,这个 fork 最大的亮点是加入了头像支持,除了 committer 的 ID 之外,还可以显示头像,使辨识度更高,按照项目的简要文档可以很容易地为单仓库生成视频。
code_swarm 接受的输入是一个配置文件和一个 XML 格式的 events 序列,每一个发生变更的文件加上 commiter ID 和时间(1970-01-01 00:00:00 起的毫秒数 / UNIX timestamp * 1000)组成一个 event,最终的 events 文件会是类似这个样子:
<?xml version="1.0" encoding="utf-8"?>
<file_events>
<event date="1104508800000" author="bo" filename="/trunk/luz/doulist/douledit_ui.ptl"></event>
<event …></event>
</file_events>
为了生成 events 文件,需要先将代码仓库的变更历史导出,code_swarm 的 convert_logs.py 工具提供了对多种版本仓库的支持,可以从仓库导出历史并转换为 events log,不过不太符合我的需求。
为了把很多个代码仓库做为一个整体来呈现,需要把所有仓库的历史按时间顺序合并到一起,于是我将这个过程分成了四个串行的步骤:
- 从各个仓库导出历史
- 解析历史为中间格式并合并为一个文件:
<committer ID> <timestamp> <file path>
- 对中间格式的文件按时间排序
- 生成最终需要的 events log
这个过程不再赘述,每个步骤都比较简单,这中间比较比较麻烦的是,在不同的代码仓库中尤其是分布式版本仓库中同一个 committer 的 ID 可能是不一样的,甚至同一个 committer 会有很多个不同的 ID,需要 normalize 为辨识度最高的那一个,另外还有一些系统账号的自动 commit,也需要排除在外。
另外一个输入是配置文件,可以在 默认配置文件 基础上做调整,以达到比较好的可视效果,这个步骤是整个过程中耗时最长,也是耗费硬件资源最多的,为了在大屏幕上有一个较好的效果,可能还需要修改一些硬编码在代码中的参数、更换或微调整物理引擎,不同的项目不同的变更历史不同的 committer 数量需要使用的参数差别可能比较大,只能逐个调整并测试…
另外需要准备每个 committer 的头像,使用 PNG 格式,以 committer 的 ID 命名,需要注意的是,头像需要是正方形的,可以借助 PIL 或 imagemagick 来做辅助的切割和格式、大小转换,长宽相差比较多的头像可能需要手工裁剪才能得到比较好的可视效果。
code_swarm 直接实时地呈现视频,但并不是直接输出视频文件,而是生成一帧一帧的图片文件,这样比较方便对最终的视频做定制,比较遗憾的是,code_swarm 没有 headless 模式,没有办法选择不显示实时视频而只生成图片文件,所以这个过程会很慢,在我的 MBP 990 上生成 7 年 12780 帧图片需要 40 分钟以上…
图片生成之后,可以使用视频编码工具将图片合并为视频,强大的 mencoder 和 ffmpeg 都能轻松完成这个任务,比如使用 ffmpeg 生成 quicktime 格式的视频是这样:
ffmpeg -f image2 -r 43 -i ./code_swarm_frames/%05d.png \
-sameq ./codebang.mov -pass 2
其中 -r 43 是指每秒钟 43 帧,因为需要配乐,对音乐做裁剪相对麻烦并且影响听觉效果,所以可以直接生成与音乐长度相当的视频,这里的 43FPS 是总帧数除以音频文件秒数得到的,帧速可以使用小数,所以可以精确控制视频长度。
项目演进过程中肯定会发生很多大事件,以字幕的形式标注这些大事件是一个比较好的方法,srt 是最简单的字幕格式,每一节字幕是这样的:
1
00:00:07,414 --> 00:00:11,414
2005年3月6日 豆瓣上线
第一行是字幕序号,递增,第二行是起始时间和结束时间,精确到毫秒,控制字幕出现和隐去的时间,第三行之后是字幕,可以有多行。两节字幕之间以空行分割。因为有大事记,所以都会有具体的日期,根据视频的长度,和仓库变更的起始、结束日期,可以计算出每一节字幕在视频中的绝对位置,所以生成字幕这个步骤可以半自动化,在测试搭配不同长度的音乐时可以节省不少手工调整字幕的时间。
最后一个步骤是将视频、音频和字幕合成为一个文件,我使用了 mencoder:
mencoder -o codebang.avi -ovc lavc \
-lavcopts vcodec=mpeg4:mbd=2:vbitrate=16000 \
-oac mp3lame -lameopts cbr:br=320:q=0 -sub codebang.srt \
-utf8 -subfont-text-scale 2.5 -overlapsub \
-font "Hiragino Sans GB W6" -subpos 92 codebang.mov \
-audiofile background.mp3
要得到好的可视效果,这个过程实际上还是挺耗费精力的,不过很值得,工程师嘛,就这点追求…
更新:Code swarm 视频在 这里。