本文目录导读:

- 核心概念:区分“直播录制”与“录播回放”
- 方案一:基于流媒体服务器 + 文件存储(最主流、最稳定)
- 方案二:基于 WebRTC + 服务器录制(实时互动场景)
- 方案三:基于 Canvas / WebSocket 的“屏幕录制”(非音视频流)
- 方案四:基于 PHP 直接录制桌面(服务器端录制,需扩展)
- 关键问题与解决方案
- 总结:我应该选择哪种方案?
在PHP项目中实现录播回放功能,通常涉及录制和回放两个核心环节,由于PHP本身是服务器端脚本语言,不适合直接处理客户端的音视频流,因此实现方式主要取决于录播数据的来源(用户端录制还是服务器端录制)以及回放的目标(网页播放、App播放等)。
下面我将从架构设计、常见技术方案和具体实现步骤三个方面进行详细说明。
核心概念:区分“直播录制”与“录播回放”
- 录播(Recording): 指的是将直播过程中的音视频流或用户操作流(如屏幕、鼠标轨迹)保存为文件或数据的过程。
- 回放(Playback): 指的是将录制好的文件或数据重新渲染出来供用户观看。
基于流媒体服务器 + 文件存储(最主流、最稳定)
这是实现直播录播回放最经典、最可靠的方案,适用于视频会议、在线课堂、直播平台等场景。
架构流程:
- 推流端(录制): 主播使用 OBS、摄像头、App SDK 等将音视频流推送到流媒体服务器(如 SRS、Nginx-RTMP、Wowza)。
- 服务器端录制: 流媒体服务器配置自动录制功能,将直播流实时保存为 MP4、FLV 或 TS 文件。
- 文件存储: 录制完成的文件(如
2023-10-27_lesson.mp4)存储在服务器的本地磁盘或对象存储服务(OSS,如阿里云OSS、AWS S3)中,PHP后端将录制文件的路径、时长、直播ID等信息存入数据库。 - 回放端(播放): 用户通过网页或App发起回放请求,PHP后端从数据库查询文件URL,然后在前端使用 H5 Video 或 Flash 播放器(如 Video.js、阿里云播放器)播放该文件。
PHP 后端实现代码示例:
<?php
// 1. 录制完成后,将录制信息存入数据库
function saveRecordedVideo(string $liveId, string $filePath, int $duration): void
{
$db = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
$stmt = $db->prepare(
"INSERT INTO recorded_videos (live_id, file_path, duration, status, created_at)
VALUES (?, ?, ?, 'completed', NOW())"
);
$stmt->execute([$liveId, $filePath, $duration]);
}
// 2. 用户请求回放时,获取录制列表
function getRecordedVideosByLiveId(string $liveId): array
{
$db = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
$stmt = $db->prepare(
"SELECT id, live_id, file_path, duration, created_at
FROM recorded_videos
WHERE live_id = ? AND status = 'completed'
ORDER BY created_at DESC"
);
$stmt->execute([$liveId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 3. 返回播放链接(如果使用OSS,需生成签名URL)
function getPlayUrl(string $filePath, int $expiration = 3600): string
{
// 示例:使用阿里云OSS
$ossClient = new OSS\OssClient('accessKeyId', 'accessKeySecret', 'endpoint');
return $ossClient->signUrl('bucket-name', $filePath, $expiration);
}
// ---------- API 路由示例 ----------
// 路由: /api/live/{liveId}/recordings
$liveId = $_GET['live_id'] ?? '';
$recordings = getRecordedVideosByLiveId($liveId);
$results = [];
foreach ($recordings as $recording) {
$results[] = [
'id' => $recording['id'],
'duration' => $recording['duration'],
'play_url' => getPlayUrl($recording['file_path']),
'created_at'=> $recording['created_at'],
];
}
header('Content-Type: application/json');
echo json_encode(['code' => 200, 'data' => $results]);
前端(HTML5)播放代码示例:
<video id="my-player" class="video-js" controls preload="auto" width="640" height="360">
<source src="<?php echo $playUrl; ?>" type="video/mp4">
您的浏览器不支持视频播放。
</video>
<script src="https://vjs.zencdn.net/7.20.3/video.min.js"></script>
基于 WebRTC + 服务器录制(实时互动场景)
如果项目使用 WebRTC 进行实时音视频通信(例如一对一教学、视频面试),需要在服务端拉取 WebRTC 流并进行混流录制。
技术栈: Node.js(或 C++ 的 LiveKit、Janus)+ PHP
流程:
- WebRTC 客户端端到端连接,同时将媒体流发送到 Media Server。
- Media Server 使用 SFU(Selective Forwarding Unit) 模式将多路流混合录制为单个音视频文件。
- 录制完成后,Media Server 回调 PHP 接口,通知录制完成,携带文件路径。
- PHP 负责存储元数据,提供回放 API。
注意: 这种方案中,录制模块通常不由 PHP 完成,而是由专门的媒体服务器处理,PHP 主要承担元数据管理和播放鉴权的角色。
基于 Canvas / WebSocket 的“屏幕录制”(非音视频流)
此方案适用于操作回放场景,例如白板教学、PPT录制、代码演示、界面操作录制等,不保存音视频流,而是保存一系列动作指令。
实现原理:
- 录制: 在前端,通过 JavaScript 监听用户的鼠标移动、点击、键盘输入、DOM 变化等事件,将这些事件序列化为 JSON(
{type: 'mousemove', x: 100, y: 200, timestamp: 123456}),通过 WebSocket 或 AJAX 实时发送到 PHP 后端。 - PHP 存储: 将接收到的动作事件顺序存储到数据库(如 MySQL JSON 字段)或 Redis 列表中。
- 回放: 用户请求回放时,PHP 返回所有事件,前端 JavaScript 按照时间戳顺序,模拟执行这些动作(例如在 Canvas 上绘制鼠标轨迹、修改页面元素等)。
PHP 存储代码示例:
<?php
// 接收前端传来的事件
$event = json_decode(file_get_contents('php://input'), true);
// 记录到数据库
$db = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
$stmt = $db->prepare(
"INSERT INTO replay_events (session_id, event_type, event_data, event_time)
VALUES (?, ?, ?, ?)"
);
$stmt->execute([
$event['session_id'], // 录制会话ID
$event['type'], // 事件类型
json_encode($event['data']), // 事件数据
$event['timestamp'] // 客户端时间戳
]);
前端回放核心逻辑:
async function replay(sessionId) {
const events = await fetch(`/api/replay/${sessionId}`).then(r => r.json());
const startTime = events[0].timestamp;
for (const event of events) {
const delay = event.timestamp - startTime;
await new Promise(resolve => setTimeout(resolve, delay));
// 根据 event.type 执行对应的动画或操作
renderEvent(event);
}
}
基于 PHP 直接录制桌面(服务器端录制,需扩展)
如果你需要录制服务器端的应用界面(例如后台管理系统的操作演示),可以使用 PHP 执行系统命令调用 ffmpeg 或 OBS 进行录制。
PHP 代码示例(需谨慎使用):
<?php
// 录制远程桌面(假设服务器有 GUI 环境)
$outputFile = '/tmp/recording_' . time() . '.mp4';
$command = "ffmpeg -f x11grab -s 1920x1080 -i :0.0 -c:v libx264 -preset ultrafast $outputFile";
// 在后台执行,持续录制
exec("nohup $command > /dev/null 2>&1 & echo $!", $pidOutput);
$pid = $pidOutput[0];
// 在需要停止时,使用 $pid 杀掉进程
// exec("kill $pid");
注意: 这种方式性能开销大,生产环境极少使用,通常仅用于内网测试或特定后台监控。
关键问题与解决方案
| 问题 | 解决方案 |
|---|---|
| 文件过大,带宽压力大 | 使用 HLS(HTTP Live Streaming) 分片(将 MP4 拆成 .ts 片段 + .m3u8 索引),支持边下边播和拖动进度。 使用视频云转码服务(阿里云、腾讯云),将源文件转成多种清晰度(流畅、高清)。 部署 CDN 加速视频分发。 |
| 播放鉴权(防盗链) | PHP 生成签名URL(如阿里云OSS的 signUrl),限制时间、IP、Referer。使用Token认证:用户必须携带合法Token才能获取播放URL。 |
| 录制存储成本高 | 设置自动过期策略(如保存 30 天后自动删除或转入冷存储)。 对大文件进行压缩转码。 |
| 多路合并录制 | 对于会议场景,需要将多路流合并为一路视频,使用 Media Server(如 SRS 的 dvr 插件或专属合流服务)在服务器端完成。 |
我应该选择哪种方案?
-
场景:视频直播、在线教育、视频会议
- 推荐方案: 方案一(流媒体+文件存储) 或 专业视频云服务(阿里云视频点播、腾讯云点播)。
- 理由: 稳定、功能完善、转码/分发/鉴权一站搞定。
-
场景:白板教学、PPT、界面操作回放
- 推荐方案: 方案三(Canvas/WebSocket指令录制)。
- 理由: 数据量小、可精确回放每一步操作、支持暂停跳转、文件体积小。
-
场景:WebRTC 1v1 或小班课
- 推荐方案: 方案二(WebRTC + Media Server), PHP 负责业务逻辑。
- 理由: 原生支持 WebRTC 流录制,无需中转。
-
场景:后台系统操作演示
- 推荐方案: 使用第三方录屏软件(OBS、Loom)录制完成后上传,PHP 仅提供存储和播放功能。不推荐用 PHP 直接录制桌面。
核心建议: 除非你只是做简单的操作回放,否则 不要用 PHP 直接处理视频流,把流媒体处理交给专业的工具(FFmpeg、Media Server、云服务),PHP 专注于业务逻辑、数据管理和播放鉴权。