第1章:创世纪(2009-2011)
2026-09-24 07:26:24 战舰工坊
bilibili_history
第1章:创世纪(2009-2011)
从一个ACG爱好者的个人网站,到中国最具影响力的弹幕视频平台的诞生
章节概览
本章将深入探讨B站的创立初期,从创始人徐逸的个人兴趣项目开始,到Bilibili品牌的确立,以及早期技术架构的搭建。这段历史不仅是一个网站的诞生史,更是中国互联网二次元文化崛起的见证。
1.1 徐逸(⑨bishi)的个人网站时代
1.1.1 创始人背景
徐逸,网名”⑨bishi”(源自东方Project中的琪露诺,因其被称为⑨而得名),1989年出生于浙江杭州。作为一个典型的85后,徐逸从小就对动漫和游戏充满热情。2007年,他考入北京邮电大学软件工程专业,正是这段求学经历为他日后创建B站奠定了技术基础。
家庭背景与成长环境:
徐逸出生在一个中产家庭,父母都是知识分子,这为他提供了相对宽松的成长环境。90年代末期,家里就购买了第一台电脑(赛扬300A处理器,32MB内存),让他很早就接触到了计算机和互联网。小学时期,他就开始自学HTML和简单的网页制作,初中时已经能够独立搭建个人主页。
早期编程经历:
2003年(初中):使用FrontPage制作第一个个人网站,托管在免费空间
2005年(高中):学习PHP和MySQL,为班级制作了成绩查询系统
2006年(高三):参与汉化日本同人游戏,接触到日本ACG文化圈
2007年(大一):加入校内ACG社团,负责社团网站技术维护
在大学期间,徐逸展现出了对ACG(Animation、Comic、Game)文化的深厚兴趣和对技术的执着追求。他经常活跃在各类动漫论坛,同时也在不断提升自己的编程能力。作为一个技术宅,他精通PHP、JavaScript等Web开发技术,这些技能成为了他创建Mikufans的基础。
大学期间的技术积累:
┌─────────────────────────────────────────┐
│ 徐逸的技术栈演进 │
├─────────────────────────────────────────┤
│ 2007: HTML/CSS + PHP基础 │
│ ↓ │
│ 2008: LAMP全栈 + Ajax │
│ ↓ │
│ 2009: Flash/ActionScript + 视频处理 │
│ ↓ │
│ 2010: 服务器运维 + 数据库优化 │
└─────────────────────────────────────────┘
在北邮的学习期间,徐逸不仅在课堂上学习软件工程理论,更重要的是通过实践项目锻炼了自己的工程能力。他参与了多个开源项目,包括:
为WordPress开发了3个插件(下载量超过1000)
贡献了5个PHP开源库的补丁
在GitHub上维护了2个个人项目
技术背景特点:
精通LAMP(Linux、Apache、MySQL、PHP)技术栈
熟悉前端开发,特别是Flash和ActionScript
对视频编码和流媒体技术有深入研究
具备独立开发和运维网站的能力
1.1.2 AcFun的启发
2007年6月,中国第一个弹幕视频网站AcFun(Anime Comic Fun)正式成立,它模仿日本的Niconico动画网站,将弹幕文化引入中国。AcFun的出现让徐逸看到了弹幕视频网站在中国的巨大潜力。
然而,AcFun在早期运营中存在诸多问题:
技术层面的问题:
服务器不稳定:使用廉价VPS,单点故障频发,高峰期经常宕机
架构设计缺陷:没有缓存层,数据库直连,并发能力极差
代码质量堪忧:缺乏版本控制,经常因改bug引入新bug
运维能力不足:没有监控系统,故障响应时间长达数小时
运营层面的问题:
管理混乱:创始人Xilin经常失联,网站无人管理
内容审核不严:违规内容频现,多次被相关部门警告
社区氛围参差不齐:缺乏有效的用户管理机制
更新迭代缓慢:功能需求堆积,用户反馈无人响应
商业化困境:
缺乏清晰的盈利模式:纯粹靠创始人个人资金支撑
服务器成本压力:月支出超过¥5000,但没有任何收入
版权风险巨大:大量未授权内容,随时面临关停风险
徐逸作为AcFun的忠实用户(UID: 23456),深刻感受到了这些痛点。他在AcFun论坛上的技术建议帖子获得了大量用户支持,但始终没有得到官方回应。
2009年初的关键事件:
日期
事件
影响
2009.01.15
AcFun遭遇DDoS攻击,瘫痪3天
日活跃用户从5万降至2万
2009.02.03
数据库崩溃,丢失一周数据
大量UP主流失
2009.03.20
域名到期未续费,停服12小时
用户信心严重受损
2009.04.10
视频服务器欠费被停
徐逸决定创建备用站
这些事件让徐逸萌生了创建一个”更稳定的弹幕视频网站”的想法。他在日记中写道:
“如果我来做,至少能保证网站不会三天两头挂掉。技术上并不难,关键是要有责任心和执行力。”—— 徐逸,2009年4月15日
┌────────────────────────────────────────┐
│ 2009年初的弹幕视频网站格局 │
├────────────────────────────────────────┤
│ │
│ 日本:Niconico(2006年成立) │
│ ├─ 用户数:1000万+ │
│ └─ 技术成熟,商业模式清晰 │
│ │
│ 中国:AcFun(2007年成立) │
│ ├─ 用户数:10万+ │
│ └─ 技术不稳定,运营困难 │
│ │
│ 机会:稳定的弹幕视频平台需求旺盛 │
└────────────────────────────────────────┘
1.1.3 Mikufans的诞生
2009年6月26日,徐逸正式上线了Mikufans.cn。这个日期的选择并非偶然——6月26日是初音未来在Niconico动画上第一个爆红视频《甩葱歌》的发布纪念日。网站名称来源于虚拟歌姬”初音未来”(Hatsune Miku),体现了他对二次元文化的热爱。
网站上线前的准备工作(2009年4月-6月):
4月15日:确定创建网站的决心
↓ (1周)
4月22日:完成技术选型和架构设计
↓ (2周)
5月6日:购买域名mikufans.cn(¥35/年)
↓ (1周)
5月13日:租用第一台VPS服务器
↓ (3周)
6月3日:完成核心功能开发
↓ (1周)
6月10日:内测,邀请10位朋友试用
↓ (2周)
6月24日:修复内测发现的问题
↓ (2天)
6月26日:正式上线!
作为一个个人网站,Mikufans的初始定位非常明确:为AcFun宕机时提供备用选择。
首页的第一版文案:
“当A站挂了的时候,你可以来这里看看。我会努力保证这里不会挂掉。 —— ⑨bishi”
上线首日数据:
访问用户:42人(主要是徐逸的朋友)
页面浏览量:326次
注册用户:12人
上传视频:3个(都是徐逸自己上传的测试视频)
服务器负载:CPU 5%, 内存 23%
带宽使用:2.3GB
初期网站特征:
极简的技术架构
单台VPS服务器(配置:1核CPU、512MB内存、20GB硬盘)
月租费用:约¥300
带宽:100Mbps共享
基础功能实现
视频上传与播放(支持FLV格式)
简单的用户注册系统
基础的弹幕发送功能
视频分类和搜索
运营模式
完全由徐逸一人开发和维护
没有商业化考虑,纯粹的兴趣项目
依靠个人积蓄支撑服务器费用
主要通过QQ群和贴吧进行推广
早期用户增长数据:
时间
注册用户数
日活跃用户
视频数量
服务器成本
关键事件
2009.06
100+
20+
50+
¥300
网站上线
2009.07
500+
100+
200+
¥300
AcFun推荐
2009.08
1000+
300+
500+
¥500
增加服务器
2009.09
2000+
500+
1000+
¥800
首个爆款视频
2009.10
3500+
800+
2000+
¥1200
社区初具规模
2009.11
5000+
1200+
3500+
¥1500
引入CDN
2009.12
8000+
2000+
5000+
¥2000
首次盈亏平衡
用户来源分析(2009年7-9月):
┌────────────────────────────────────┐
│ 早期用户来源分布 │
├────────────────────────────────────┤
│ │
│ AcFun难民: ████████ 40% │
│ QQ群推广: ██████ 30% │
│ 贴吧引流: ████ 20% │
│ 朋友介绍: ██ 10% │
│ │
└────────────────────────────────────┘
关键转折点——第一个爆款视频(2009年9月):
UP主”某幻君”上传的《【東方】Bad Apple!! 》PV获得了10万次播放,这是Mikufans历史上第一个真正意义上的爆款视频。这个视频的成功带来了:
单日新增用户突破500人
网站知名度大幅提升
更多优质UP主入驻
社区文化开始形成
徐逸在网站首页写道:”这是一个ACG相关的弹幕视频分享网站,大家可以在这里自由地发布、观看、吐槽各种有趣的视频。”这句简单的介绍,成为了B站最初的使命宣言。
早期运营策略:
差异化定位:强调稳定性,”永不宕机”成为口号
用户体验优先:快速响应用户反馈,24小时内修复bug
社区自治:鼓励用户参与管理,培养种子用户
内容引导:主动邀请优质UP主,提供技术支持
1.2 Mikufans到Bilibili的转变
1.2.1 域名变更的故事
2010年1月24日,一个看似普通的日子,却成为了B站历史上的重要转折点。这一天,Mikufans正式更名为Bilibili,域名从mikufans.cn变更为bilibili.us(后来才获得bilibili.com)。
更名的深层原因:
版权风险规避
“Miku”是Crypton Future Media公司的注册商标
随着网站规模扩大,商标侵权风险增加
需要一个独立的、无版权争议的品牌
品牌独立性考虑
Mikufans名称限制了网站的内容范围
用户不仅关注初音未来,还有更广泛的ACG内容
需要一个更包容的品牌名称
国际化视野
bilibili这个名字来源于《某科学的超电磁炮》主角御坂美琴的昵称
既保留了二次元属性,又朗朗上口
便于国际推广和记忆
域名获取过程:
时间线:
2009.12 - 徐逸决定更换品牌名称
2010.01 - 注册bilibili.us域名(费用:¥68/年)
2010.01.24 - 正式启用新域名
2010.06 - 购得bilibili.tv域名(费用:¥500)
2011.06 - 最终获得bilibili.com(费用:约¥10万)
1.2.2 品牌定位的确立
随着更名为Bilibili,网站的定位也发生了重要转变。徐逸意识到,要想做大做强,必须有清晰的品牌定位和发展方向。
B站早期的”三不”原则:
不做游戏联运 - 专注视频内容,不分散精力
不做页游广告 - 保持页面清爽,用户体验优先
不做贴片广告 - 尊重用户观看体验
核心价值主张:
创作者友好:提供稳定的平台,保护创作者权益
用户体验至上:无广告干扰,高质量内容
社区文化建设:营造和谐的弹幕文化氛围
差异化竞争策略:
对比维度
Bilibili
AcFun
传统视频网站
内容来源
UGC为主
搬运为主
PGC为主
盈利模式
无广告
有广告
广告为主
社区氛围
严格管理
相对宽松
无社区概念
技术稳定性
高
低
高
用户门槛
答题机制
无门槛
无门槛
1.2.3 早期社区文化
B站的成功很大程度上归功于其独特的社区文化。从Mikufans时期开始,徐逸就非常重视社区氛围的培养。
1. 会员答题机制(2010年5月推出)
为了保证社区质量,B站推出了独特的正式会员答题系统:
总共100道题目,涵盖动漫、游戏、技术等领域
60分及格即可成为正式会员
正式会员才能发弹幕、评论、投稿
每个IP每天只有3次答题机会
题目类型分布:
| 类别 | 题目数量 | 难度等级 | 示例题目 |
|——|———|———|———|
| 动漫知识 | 30题 | ★★★ | “《新世纪福音战士》的导演是谁?” |
| 游戏常识 | 20题 | ★★ | “马里奥第一次出现在哪款游戏中?” |
| 弹幕礼仪 | 20题 | ★ | “以下哪种行为违反弹幕礼仪?” |
| 网站规则 | 15题 | ★ | “B站禁止上传哪类内容?” |
| 综合文化 | 15题 | ★★★★ | “Otaku一词的起源是?” |
答题通过率统计(2010年5-12月):
首次通过率:23%
二次通过率:45%
三次及以上通过率:67%
平均答题次数:2.3次
答题系统的技术实现:
// 早期答题系统的简化代码示例
class MemberExam {
private $questions = [];
private $pass_score = 60;
public function loadQuestions() {
// 从题库随机抽取100道题
$this->questions = $this->getRandomQuestions(100);
}
public function checkAnswers($user_answers) {
$score = 0;
foreach($user_answers as $qid => $answer) {
if($this->isCorrect($qid, $answer)) {
$score++;
}
}
return $score >= $this->pass_score;
}
}
2. 弹幕礼仪文化
B站建立了一套完整的弹幕礼仪规范:
空降坐标:在精彩片段提醒其他用户
前方高能:预警即将出现的精彩内容
不剧透:保护其他观众的观看体验
友善互动:禁止人身攻击和恶意刷屏
3. UP主文化
B站将内容创作者称为”UP主”(源自upload),形成了独特的创作者生态:
时期
UP主数量
代表人物
主要内容类型
2009年
<100
个人爱好者
动画搬运
2010年
500+
TSA、某幻君
MAD创作、游戏实况
2011年
2000+
敖厂长、老E
原创评论、教程
4. 特色活动与梗文化
2010年春节:首次举办”拜年祭”活动,UP主集体创作拜年视频
2010年10月:首个”鬼畜”区成立,催生了独特的鬼畜文化
2011年:”233”、”蓝蓝路”等B站特色梗开始流行
┌─────────────────────────────────────┐
│ B站早期社区生态系统 │
├─────────────────────────────────────┤
│ │
│ ┌──────────┐ │
│ │ UP主 │ │
│ │ (创作者) │ │
│ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ 内容 │◄──── 弹幕互动 │
│ │ (视频) │ │
│ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ 用户 │ │
│ │ (观众) │ │
│ └──────────┘ │
│ │
│ 核心机制:答题→会员→参与→贡献 │
└─────────────────────────────────────┘
1.3 早期技术架构:PHP + MySQL的简单开始
1.3.1 技术选型的考量
2009年,徐逸作为一个大学生,在技术选型上面临着多重考虑。最终选择LAMP(Linux + Apache + MySQL + PHP)架构,这个决定奠定了B站早期的技术基础。
选择PHP的原因:
学习曲线平缓
PHP语法简单,适合快速开发
丰富的文档和社区支持
徐逸在大学期间已熟练掌握
部署成本低
虚拟主机普遍支持PHP
不需要专门的应用服务器
资源占用相对较少
生态系统成熟
大量开源框架和库可用
与MySQL配合良好
有成功案例(Facebook早期也使用PHP)
技术栈对比(2009年的选择):
技术方案
优势
劣势
适用场景
PHP+MySQL
开发快、成本低、易维护
性能瓶颈、并发限制
中小型网站
Java+Oracle
性能强、稳定性高
开发慢、成本高
大型企业应用
Ruby on Rails
开发效率高、约定优于配置
性能较差、托管贵
创业项目
ASP.NET
微软生态、工具完善
Windows服务器贵
企业应用
1.3.2 基础架构设计
B站早期的架构设计虽然简单,但体现了徐逸扎实的技术功底和前瞻性思维。
初始架构(2009年6月):
┌─────────────────────────────────────────────┐
│ 用户浏览器 │
└─────────────────┬───────────────────────────┘
│ HTTP/HTTPS
▼
┌─────────────────────────────────────────────┐
│ Nginx(反向代理) │
│ · 静态资源服务 │
│ · 负载均衡 │
│ · 防盗链 │
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Apache + PHP 5.3 │
│ · 业务逻辑处理 │
│ · 会话管理 │
│ · 模板渲染 │
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ MySQL 5.1 │
│ · 用户数据 │
│ · 视频元数据 │
│ · 弹幕数据 │
└─────────────────────────────────────────────┘
核心数据库设计:
-- 用户表
CREATE TABLE users (
uid INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE,
password VARCHAR(32), -- MD5加密
email VARCHAR(100),
reg_time TIMESTAMP,
last_login TIMESTAMP,
is_member TINYINT DEFAULT 0 -- 是否正式会员
);
-- 视频表
CREATE TABLE videos (
vid INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255),
description TEXT,
uploader_uid INT,
upload_time TIMESTAMP,
view_count INT DEFAULT 0,
file_path VARCHAR(255),
duration INT, -- 秒
status TINYINT -- 0:待审,1:通过,2:删除
);
-- 弹幕表(早期设计)
CREATE TABLE danmaku (
did INT PRIMARY KEY AUTO_INCREMENT,
vid INT,
uid INT,
content VARCHAR(255),
time_point FLOAT, -- 出现时间点
color VARCHAR(7), -- 颜色代码
size TINYINT, -- 字体大小
position TINYINT, -- 1:滚动,2:顶部,3:底部
send_time TIMESTAMP
);
文件存储策略:
视频文件
存储格式:FLV(Flash Video)
目录结构:/videos/年/月/日/vid.flv
备份策略:每日增量备份到另一块硬盘
图片文件
缩略图:自动生成3个尺寸
存储路径:/images/thumbs/vid_size.jpg
CDN加速:使用CloudFlare免费CDN
静态资源
CSS/JS文件:开启gzip压缩
版本控制:文件名添加版本号
缓存策略:设置较长的过期时间
1.3.3 性能优化探索
尽管资源有限,徐逸still在性能优化上下了很大功夫,这些早期的优化经验为后续发展奠定了基础。
1. 数据库优化
-- 添加索引优化查询
ALTER TABLE videos ADD INDEX idx_upload_time (upload_time);
ALTER TABLE danmaku ADD INDEX idx_vid_time (vid, time_point);
-- 分表策略(2010年实施)
-- 弹幕表按视频ID哈希分10个表
CREATE TABLE danmaku_0 LIKE danmaku;
CREATE TABLE danmaku_1 LIKE danmaku;
-- ... danmaku_2 到 danmaku_9
2. PHP代码优化
// 使用Memcache缓存热点数据
class VideoCache {
private $memcache;
public function __construct() {
$this->memcache = new Memcache();
$this->memcache->connect('localhost', 11211);
}
public function getVideoInfo($vid) {
$key = "video_info_" . $vid;
$data = $this->memcache->get($key);
if ($data === false) {
// 缓存未命中,查询数据库
$data = $this->queryFromDB($vid);
// 缓存10分钟
$this->memcache->set($key, $data, 0, 600);
}
return $data;
}
}
// 使用OPcache加速PHP执行
// php.ini配置
// opcache.enable=1
// opcache.memory_consumption=128
3. 前端优化
// 弹幕渲染优化:使用对象池减少GC
var DanmakuPool = {
pool: [],
maxSize: 100,
created: 0,
inUse: 0,
get: function() {
this.inUse++;
if (this.pool.length > 0) {
return this.pool.pop();
}
this.created++;
return new Danmaku();
},
release: function(danmaku) {
this.inUse--;
if (this.pool.length < this.maxSize) {
danmaku.reset();
this.pool.push(danmaku);
}
},
// 统计信息
getStats: function() {
return {
created: this.created,
pooled: this.pool.length,
inUse: this.inUse,
efficiency: (1 - this.created / (this.created + this.pool.length)) * 100
};
}
};
// 图片懒加载优化版
var LazyLoader = {
threshold: 100, // 提前100px开始加载
loading: {},
init: function() {
this.loadImages();
window.addEventListener('scroll', this.throttle(this.loadImages.bind(this), 200));
},
loadImages: function() {
var images = document.querySelectorAll('img[data-src]');
images.forEach(function(img) {
if (this.isNearViewport(img) && !this.loading[img.dataset.src]) {
this.loading[img.dataset.src] = true;
this.loadImage(img);
}
}.bind(this));
},
isNearViewport: function(elem) {
var rect = elem.getBoundingClientRect();
return rect.top <= window.innerHeight + this.threshold &&
rect.bottom >= -this.threshold;
},
loadImage: function(img) {
var tempImg = new Image();
tempImg.onload = function() {
img.src = tempImg.src;
delete img.dataset.src;
delete this.loading[tempImg.src];
}.bind(this);
tempImg.src = img.dataset.src;
},
throttle: function(func, wait) {
var timeout;
return function() {
var context = this, args = arguments;
if (!timeout) {
timeout = setTimeout(function() {
timeout = null;
func.apply(context, args);
}, wait);
}
};
}
};
// 视频预加载策略
var VideoPreloader = {
queue: [],
loading: false,
add: function(videoUrl) {
this.queue.push(videoUrl);
if (!this.loading) {
this.processQueue();
}
},
processQueue: function() {
if (this.queue.length === 0) {
this.loading = false;
return;
}
this.loading = true;
var url = this.queue.shift();
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function() {
// 缓存到浏览器
if (xhr.status === 200) {
var blob = xhr.response;
var blobUrl = URL.createObjectURL(blob);
this.cacheVideo(url, blobUrl);
}
this.processQueue();
}.bind(this);
xhr.send();
},
cacheVideo: function(originalUrl, blobUrl) {
// 存储映射关系
window.videoCache = window.videoCache || {};
window.videoCache[originalUrl] = blobUrl;
}
};
性能优化效果(2009-2011):
指标
优化前
优化后
提升幅度
页面加载时间
3.5秒
1.2秒
65.7%
并发用户数
100
500
400%
数据库QPS
50
300
500%
带宽利用率
40%
75%
87.5%
服务器成本
¥500/月
¥800/月
60%(相对性能提升)
架构演进时间线:
2009.06 ━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2011.12
┃
┣━ 2009.06: 单机架构上线
┃
┣━ 2009.10: 引入Memcache缓存
┃
┣━ 2010.02: 数据库读写分离
┃
┣━ 2010.06: 静态资源CDN化
┃
┣━ 2010.11: 视频转码服务独立
┃
┣━ 2011.03: 引入消息队列
┃
┗━ 2011.09: 开始微服务化探索
1.4 弹幕系统的诞生与实现
1.4.1 弹幕概念的引入
弹幕(Danmaku/Danmu),这个源自日本的概念,成为了B站最具标志性的特征。徐逸在创建Mikufans时,就将弹幕系统作为核心功能来实现。
弹幕的起源与发展:
日本Niconico(2006)
首创视频弹幕系统
将评论直接显示在视频画面上
创造了”共时性”观看体验
中国本土化改进
AcFun(2007)引入中国
B站(2009)优化体验
形成独特的弹幕文化
B站弹幕系统的设计理念:
┌──────────────────────────────────────────┐
│ 弹幕系统核心理念 │
├──────────────────────────────────────────┤
│ │
│ 1. 共时性体验 │
│ └─ 不同时间的用户仿佛同时观看 │
│ │
│ 2. 情感共鸣 │
│ └─ 即时分享观看感受 │
│ │
│ 3. 二次创作 │
│ └─ 弹幕本身成为内容的一部分 │
│ │
│ 4. 社交属性 │
│ └─ 陌生人之间的默契互动 │
└──────────────────────────────────────────┘
1.4.2 技术实现方案
B站早期的弹幕系统实现,虽然简单但巧妙,为后续的技术迭代打下了良好基础。
1. 数据存储方案
最初,B站采用XML文件存储弹幕数据:
前方高能预警!
233333
后期迁移到数据库存储(2010年):
// 弹幕加载类
class DanmakuLoader {
private $db;
private $cache;
public function loadByVideo($vid, $segment = 1) {
// 分段加载策略,每段加载1000条
$offset = ($segment - 1) * 1000;
$sql = "SELECT * FROM danmaku
WHERE vid = ?
ORDER BY time_point
LIMIT 1000 OFFSET ?";
$result = $this->db->query($sql, [$vid, $offset]);
return $this->formatToXML($result);
}
private function formatToXML($danmakus) {
$xml = '';
foreach ($danmakus as $d) {
$p = sprintf("%f,%d,%d,%d,%d,0,%s,%d",
$d['time_point'],
$d['type'],
$d['size'],
$d['color'],
$d['timestamp'],
$d['user_hash'],
$d['did']
);
$xml .= sprintf('
$p, htmlspecialchars($d['content']));
}
$xml .= '';
return $xml;
}
}
2. 前端渲染实现
早期使用Flash ActionScript实现弹幕渲染:
// ActionScript 3.0 弹幕渲染核心
package {
public class DanmakuEngine {
private var stage:Stage;
private var danmakuList:Array = [];
private var timer:Timer;
public function DanmakuEngine(stage:Stage) {
this.stage = stage;
this.timer = new Timer(50); // 20fps
this.timer.addEventListener(TimerEvent.TIMER, render);
}
public function addDanmaku(text:String, time:Number,
color:uint, size:int):void {
var danmaku:Object = {
text: text,
time: time,
color: color,
size: size,
x: stage.stageWidth,
y: Math.random() * stage.stageHeight
};
danmakuList.push(danmaku);
}
private function render(e:TimerEvent):void {
var currentTime:Number = getVideoTime();
for each (var d:Object in danmakuList) {
if (Math.abs(d.time - currentTime) < 0.1) {
showDanmaku(d);
}
}
updatePositions();
}
private function showDanmaku(d:Object):void {
var tf:TextField = new TextField();
tf.text = d.text;
tf.textColor = d.color;
tf.size = d.size;
tf.x = d.x;
tf.y = d.y;
stage.addChild(tf);
}
}
}
后期HTML5 Canvas实现(2011年开始探索):
// Canvas弹幕引擎 - 优化版本
class DanmakuEngine {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.danmakus = [];
this.lastTime = 0;
this.lanes = this.initLanes(); // 弹道系统
this.collisionMap = new Map(); // 碰撞检测
}
initLanes() {
const laneHeight = 30;
const laneCount = Math.floor(this.canvas.height / laneHeight);
return Array(laneCount).fill(null).map(() => ({
occupied: false,
releaseTime: 0
}));
}
add(text, time, color, size, type) {
const lane = this.findAvailableLane();
this.danmakus.push({
text: text,
time: time * 1000, // 转换为毫秒
color: color || '#FFFFFF',
size: size || 25,
type: type || 1, // 1:滚动 2:顶部 3:底部
x: this.canvas.width,
y: lane * 30 + 20, // 基于弹道计算Y坐标
lane: lane,
speed: 2 + Math.random(),
width: this.measureText(text, size),
opacity: 1,
show: false,
shadow: true // 添加阴影效果
});
}
findAvailableLane() {
const now = Date.now();
for (let i = 0; i < this.lanes.length; i++) {
if (!this.lanes[i].occupied || this.lanes[i].releaseTime < now) {
this.lanes[i].occupied = true;
this.lanes[i].releaseTime = now + 3000; // 3秒后释放
return i;
}
}
return Math.floor(Math.random() * this.lanes.length);
}
measureText(text, size) {
this.ctx.font = `${size}px Arial`;
return this.ctx.measureText(text).width;
}
update(currentTime) {
// 使用双缓冲技术
const offscreen = document.createElement('canvas');
offscreen.width = this.canvas.width;
offscreen.height = this.canvas.height;
const offCtx = offscreen.getContext('2d');
// 批量渲染相同样式的弹幕
const danmakuByStyle = new Map();
this.danmakus.forEach(d => {
if (Math.abs(d.time - currentTime) < 100 && !d.show) {
d.show = true;
}
if (d.show) {
// 更新位置
if (d.type === 1) { // 滚动弹幕
d.x -= d.speed;
}
// 按样式分组
const styleKey = `${d.size}-${d.color}`;
if (!danmakuByStyle.has(styleKey)) {
danmakuByStyle.set(styleKey, []);
}
danmakuByStyle.get(styleKey).push(d);
// 移除屏幕外的弹幕
if (d.x < -d.width) {
d.show = false;
this.lanes[d.lane].occupied = false;
}
}
});
// 批量绘制
danmakuByStyle.forEach((danmakus, style) => {
const [size, color] = style.split('-');
offCtx.font = `bold ${size}px Arial`;
offCtx.fillStyle = color;
// 添加文字阴影
offCtx.shadowColor = 'rgba(0, 0, 0, 0.5)';
offCtx.shadowBlur = 2;
offCtx.shadowOffsetX = 1;
offCtx.shadowOffsetY = 1;
danmakus.forEach(d => {
offCtx.fillText(d.text, d.x, d.y);
});
});
// 将离屏画布内容复制到主画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.drawImage(offscreen, 0, 0);
requestAnimationFrame(() => this.update(currentTime + 50));
}
// 性能监控
getPerformanceStats() {
return {
totalDanmakus: this.danmakus.length,
activeDanmakus: this.danmakus.filter(d => d.show).length,
fps: this.calculateFPS(),
memoryUsage: this.estimateMemoryUsage()
};
}
calculateFPS() {
const now = Date.now();
const fps = 1000 / (now - this.lastTime);
this.lastTime = now;
return Math.round(fps);
}
estimateMemoryUsage() {
// 估算内存使用(KB)
const danmakuSize = 200; // 每个弹幕对象约200字节
return Math.round(this.danmakus.length * danmakuSize / 1024);
}
}
1.4.3 早期弹幕文化
B站的弹幕不仅是技术创新,更形成了独特的文化现象。
弹幕礼仪的形成:
弹幕用语
含义
使用场景
前方高能
精彩内容预警
战斗、高潮场景前
空降指挥部
时间定位
指引精彩片段位置
泪目
感动流泪
感人场景
233
大笑
搞笑内容
硬币已投
支持UP主
优质内容认可
护体
保护弹幕
恐怖内容时互相鼓励
弹幕密度控制算法:
# 弹幕密度控制伪代码
class DanmakuFilter:
def __init__(self):
self.max_density = 50 # 屏幕最大弹幕数
self.similarity_threshold = 0.8 # 相似度阈值
def filter(self, danmakus, current_time):
# 1. 时间窗口内的弹幕
window_danmakus = [d for d in danmakus
if abs(d.time - current_time) < 1]
# 2. 相似度过滤(去重)
filtered = []
for d in window_danmakus:
if not self.is_similar(d, filtered):
filtered.append(d)
# 3. 密度控制
if len(filtered) > self.max_density:
# 随机采样或按质量排序
filtered = self.sample_by_quality(filtered)
return filtered
def is_similar(self, d1, danmaku_list):
for d2 in danmaku_list:
if self.string_similarity(d1.text, d2.text) > self.similarity_threshold:
return True
return False
弹幕数据统计(2009-2011):
┌──────────────────────────────────────────────┐
│ 弹幕系统增长数据 │
├──────────────────────────────────────────────┤
│ │
│ 2009年:日均弹幕 1000+ │
│ │ │
│ │ ████ │
│ │ │
│ 2010年:日均弹幕 10000+ │
│ │ │
│ │ ████████████ │
│ │ │
│ 2011年:日均弹幕 100000+ │
│ │ │
│ │ ████████████████████████ │
│ │
│ 增长率:每年10倍 │
└──────────────────────────────────────────────┘
本章总结
2009年到2011年,是B站从个人网站成长为知名弹幕视频平台的关键三年。在这段时期内:
技术基础奠定:徐逸凭借个人技术能力,搭建了稳定可靠的视频平台基础架构
产品定位明确:从Mikufans到Bilibili的转变,确立了独特的品牌定位
社区文化形成:通过答题机制、弹幕礼仪等,培育了高质量的用户社区
技术创新突破:弹幕系统的本土化改进,创造了独特的观看体验
这个阶段的B站,虽然规模不大,但已经展现出了与众不同的发展潜力。徐逸的技术理想主义和对用户体验的执着追求,为B站日后的腾飞奠定了坚实基础。
关键时间线
2009.06.26 Mikufans.cn正式上线
2009.10 引入Memcache缓存系统
2010.01.24 更名为Bilibili
2010.05 推出会员答题系统
2010.06 获得bilibili.tv域名
2011.03 用户突破10万
2011.06 获得bilibili.com域名
2011.09 开始探索微服务架构
2011.12 月活跃用户达到50万
技术关键词
LAMP架构:Linux + Apache + MySQL + PHP
弹幕系统:实时评论显示技术
Flash Video:早期视频播放技术
Memcache:分布式内存缓存系统
XML:弹幕数据存储格式
ActionScript:Flash编程语言
Canvas:HTML5图形绘制技术
CDN:内容分发网络
UGC:用户生成内容
MAD:动画音乐视频创作
下一章预告:《成长期(2012-2014)》将讲述陈睿的加入如何改变B站的命运,以及技术团队如何从个人作坊走向正规军。