22号晚上在vu刷ip,想看能不能刷出ip不是45的
开几个都还是一个区的,作罢,点进最底下一个,destroy,yes一气呵成
出来就懵了,列表里cost怎么都是$0.01
当时血崩,靠删错了
我这里好像改了几个文章,也想不起来改了啥了
bp从7号到22号收集的view,banner,splash没了,番剧数据我20号拉到本地改东西,是唯一的备份
pass那里少了个公告,之前搞的表单倒是早了,没事
之后我看着研究下,搞个三天一次自动snapshot吧…稳一点
22号晚上在vu刷ip,想看能不能刷出ip不是45的
开几个都还是一个区的,作罢,点进最底下一个,destroy,yes一气呵成
出来就懵了,列表里cost怎么都是$0.01
当时血崩,靠删错了
我这里好像改了几个文章,也想不起来改了啥了
bp从7号到22号收集的view,banner,splash没了,番剧数据我20号拉到本地改东西,是唯一的备份
pass那里少了个公告,之前搞的表单倒是早了,没事
之后我看着研究下,搞个三天一次自动snapshot吧…稳一点
游戏没啥兴趣,已删,不再更新
用仓鼠太太的芙蕾雅镇一下
感觉自己就很无聊(
下午做了点纯体力劳动,解了一波卡面
https://pan.baidu.com/s/1aC0YmjqgBd7tBgECDXM1kQ
就真的是纯体力,没有加密,所有素材全部unity3d格式放在raw里,批量一跑就完事了
拿着AssetsBundleExtractor跑batchexport,然后批量选中assets,导出所有的Texture2D
CardBattle和CardL都是Sprite裁剪的形式,不过每个都是固定位置,就用chrome的自动下载跑了一批canvas裁剪
估计也没人再写了
You can:
You can’t:
想了挺久分段mp4的播放有什么解决方案,看着flvjs眼馋,然后一直想坑,但是又懒于开工
于是趁着这个五一,刚好前两周学校里的好几科期中也考完了,开坑!
说是五一开坑,其实二十多号复制了个segment-mp4-player的时候就已经开始去翻着找mp4格式说明了。
以前听过song神说过mp4的box地狱,但是并不特别懂。正式看资料以后才算是真正理解。
具体细节就不说了,真的好奇就看文档啊
读取moov的时候,为了省事,我直接上了一个递归函数,一劳永逸,然后只要把boxName给switch一下具体parse就可以了。
其实mp4的格式真正读起来不会特别复杂,理清层级关系,明白自己在做什么,要获取什么,也就能顺路完成。
相比起读数据,我倒是觉得读完后整理数据才是真正的大头,比如把关键帧梳理出一个timestamp->fileposition的表才是最考验逻辑的。写的时候整个人脑子处于一种混乱的状态,最后是在顶不住选择了稳妥的列逻辑,一步步理出数据
至于主要数据流的mdat部分,这部分完全就是一整片数据堆砌。同样,这里是另一个需要强逻辑的地方,每次读sample都需要先在已有的moov数据里面找到对应offset是谁的采样、采样时间戳是多少、采样有多大。我在这里直接选择了提前生成一个chunkMap,读取起来那叫一个爽快
一路写代码的途中也是经常和xqq大佬交流(骚扰),也学到了很多
大概也就是这么些,说到底写出来还是个自用的东西,这年头自己做视频播放谁还专门整分段mp4
Day 1 (Mar.4th)
这次改canvas绘制是直接在ccl的基础上添加,出来的成品是准备双模式兼容的
并且,按照一贯canvas绘制习惯,带高dpi优化
Day 2 (Mar.5th)
Day 3 (Mar.6th)
格式为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";