canvas弹幕绘制纪实

Day 1 (Mar.4th)

这次改canvas绘制是直接在ccl的基础上添加,出来的成品是准备双模式兼容的

并且,按照一贯canvas绘制习惯,带高dpi优化

初版流程:直接fillText
起初倒是可以,但是在加描边的时候,因为strokeText效果不理想,换shadoeBlur的时候,直接卡飞了,经过google,学到了预渲染的方法可以解决shadow的高性能消耗
改动:使用canvas存储预渲染,此时另一人给我遇到了正反buffer渲染(先离屏渲染再copy防止闪屏)。这一点其实使用requestAnimationFrame的话基本上不会碰到,但我初次理解的时候理解错了,用了setInterval渲染离屏canvas而再rAF copy
在google的时候,看到一条drawImage里,绘制canvas转出来的data url比直接canvas快,于是换用了img存储预渲染

 

Day 2 (Mar.5th)

发觉了对正反buffer的认知错误后,取消了interval,直接在rAF里结尾copy
在尝试的时候,发现初始渲染会“阻塞”浏览器,然后使用了promise进行异步预渲染

 

Day 3 (Mar.6th)

在再一次的性能测试的时候,发现虽然draw data image比canvas快个0.02-0.05ms,但是toDataURL会卡5-30ms…纯属得不偿失。同时也发现promise异步并不能解决卡顿,因为原因是js单线程,而核心正在执行其他任务(toDataURL),所以也就无法高帧渲染。结果去掉了转img的过程,并且考虑到渲染还是要消耗大约2-5ms,所以添加了队列,每16ms(1/60s)中最大只消耗8ms用于预渲染,超出则等待下一帧

关于b站新弹幕格式.pb

格式为google protocol buffer (protobuf)

地址格式为{cid}-{part}.pb,每part包含3分钟的弹幕内容,即边播放边加载模式,如-3.pb包含第6-9分弹幕

在bilibiliPlayer.min.js中有大部分field id的定义,但文件中出现了id12-14

pb格式弹幕 Field常量
1  row (Row)
2  chat_server (string)
3  chat_id (varint32)
4  mission (varint32)
5  max_limit (varint32)
6  source (string)
7  ds (varint32)
8  de (varint32)
9  max_count (varint32)
10 realname (varint32)
11 sectionlen (varint32)(一般为180)
//猜测id
12 duration (float)
13 total_count (varint32)
14 pb_version (varint32)(目前常量1)

pb格式弹幕row Field常量
1  playtime (float)
2  mode (varint32)
3  fontsize (varint32)
4  color (varint32)
5  times (varint32)
6  poolid (varint32)
7  hash (string)
8  dmid (varint32)
9  msg (string)
10 uid (varint32)(暂未出现)
11 uname (string)(暂未出现)

其中varint32为变长度int32格式,具体为每字节只有后7位存储数据,第1位为指示位,为1时继续读取下一字节

function readVarInt32($fp){
	$b=0;
	$result=0;
	
	do{
		$b=unpack('C',fread($fp,1))[1];
		$result  = $b & 0x7f;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<7;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<14;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<21;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<28;
		if(!( $b & 0x80 ))
			break;
		
		for($i=0;$i<5;$i++){
			$b=unpack('C',fread($fp,1))[1];
			if(!( $b & 0x80 ))
				break;
		}
	}while(false);
	return $result;
}

文件读取代码样本

<?php
/*
 BiliBili pb danmaku reader
 @author esterTion(esterTionCN@gmail.com)
*/
$pb=fopen('http://comment.bilibili.com/14328539-1.pb','r');

function readVarInt32($fp){
	$b=0;
	$result=0;
	
	do{
		$b=unpack('C',fread($fp,1))[1];
		$result  = $b & 0x7f;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<7;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<14;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<21;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<28;
		if(!( $b & 0x80 ))
			break;
		
		for($i=0;$i<5;$i++){
			$b=unpack('C',fread($fp,1))[1];
			if(!( $b & 0x80 ))
				break;
		}
	}while(false);
	return $result;
}
function readString($fp){
	$strLength=readVarInt32($fp);
	return fread($fp,$strLength);
}
$types=array(
	'VARINT'=>0,
	'FIXED64'=>1,
	'DELIMITED'=>2,
	'START_GROUP'=>3,
	'END_GROUP'=>4,
	'FIXED32'=>5
);
$rowCount=0;
while(true){
	$id=fread($pb,1);
	if($id==='')
		break;
	$id=unpack('C',$id)[1];
	$type = $id & 7;
	$id = $id >> 3;
	switch($id){
		case 1:
			$rowLength=readVarInt32($pb);
			echo 'row length:'.$rowLength.' ';
			$end=ftell($pb)+$rowLength;
			$row=array();
			while(ftell($pb) < $end){
				$id=unpack('C',fread($pb,1))[1];
				$id = $id >> 3;
				switch($id){
					case 1:
						$row['playtime']=unpack('f',fread($pb,4))[1];
					break;
					case 2:
						$row['mode']=readVarInt32($pb);
					break;
					case 3:
						$row['fontsize']=readVarInt32($pb);
					break;
					case 4:
						$row['color']=substr(pack('N', readVarInt32($pb) ),2);
					break;
					case 5:
						$row['timestamp']=readVarInt32($pb);
					break;
					case 6:
						$row['poolid']=readVarInt32($pb);
					break;
					case 7:
						$row['hash']=readString($pb);
					break;
					case 8:
						$row['dmid']=readVarInt32($pb);
					break;
					case 9:
						$row['msg']=readString($pb);
					break;
					case 10:
						$row['uid']=readVarInt32($pb);
					break;
					case 11:
						$row['uname']=readString($pb);
					break;
				}
			}
			print_r($row);
			$rowCount++;
		break;
		case 2:
			echo '[chat_server] => '.readString($pb)."\n";
		break;
		case 3:
			echo '[chat_id] => '.readVarInt32($pb)."\n";
		break;
		case 4:
			echo '[mission] => '.readVarInt32($pb)."\n";
		break;
		case 5:
			echo '[max_limit] => '.readVarInt32($pb)."\n";
		break;
		case 6:
			echo '[source] => '.readString($pb)."\n";
		break;
		case 7:
			echo '[ds] => '.readVarInt32($pb)."\n";
		break;
		case 8:
			echo '[de] => '.readVarInt32($pb)."\n";
		break;
		case 9:
			echo '[max_count] => '.readVarInt32($pb)."\n";
		break;
		case 10:
			echo '[realname] => '.readVarInt32($pb)."\n";
		break;
		case 11:
			echo '[sectionlen] => '.readVarInt32($pb)."\n";
		break;
		default:
			switch($type){
				case 0:
					echo '--Unknown ID '.$id.' with varint32 value '.readVarInt32($pb)."\n";
				break;
				case 1:
					echo '--Unknown ID '.$id.' with fixed 64bit data hex '.bin2hex(fread($pb,8))."\n";
				break;
				case 5:
					echo '--Unknown ID '.$id.' with fixed 32bit data hex '.bin2hex(fread($pb,4))."\n";
				break;
				default:
					echo '--Unknown ID '.$id.' with type '.$type."\n";
			}
	}
}
echo $rowCount.' rows in file'."\n";

 

水大佬的cdnvpn各种n都炸了

周一晚上的时候,突然间就发现高通打不开了,试了几下无果然后就去dns切回源站了

然后找大佬,表示整体出问题了,连带vpn也炸了QQ图片20170215235525

捣鼓了几下自己服务器上加了个服务,结果长城这司马的垃圾经常连不上,真的是整个人都醉的不行

后来再问大佬表示不准备再挂cdn了,就这样用吧

今天还试了一下东京机房,结果速度感觉并不好,还是决定不搬就放lax

SSD!SSD!

年过完了,买了个480g的ssd

哎呀科技真的是个好东西,电脑开机快多了

包括mac虚拟机,运行不卡,5秒挂起,怎一个爽字了得

后面又去了一下机械上的系统简直慢到不能忍受,仿佛要死了一般

IMG_4853-

 

假期就是填坑的季节

考完试了放假了,于是就开始填自己想了很久的坑了

首先是html5播放器,在不懈的魔改之下,已经被加了各种功能,什么websocket啊、进度条预览啊、弹幕屏蔽之类啊的

还没有实现右键菜单,这都是计划事项

今天从下午开始就在重写番剧数据的存储,之前是直接json,但是服务器小内存,打开个10M的json再decode一下就gg。光是设计二进制格式就整了快一小时,估计是c功夫不够。

以及还有一个天国的消息中心的坑还在放置

 


回家后找着水萌巨佬搞了个长宽专线加速vpn,巨佬就是不一样