本文目录导读:

在PHP项目中实现直播录制与回放功能,通常需要结合流媒体服务器(如Nginx-RTMP、SRS、ZLMediaKit)和前端播放器(如Video.js、LivePlayer)来完成,以下是完整的实现方案和技术选型指南。
整体架构
直播推流 → 流媒体服务器 → 录制模块 → 文件存储 → PHP API → 前端播放
↓
实时转码
核心组件选型
流媒体服务器推荐
| 服务器 | 适合场景 | 特点 |
|---|---|---|
| SRS | 推荐首选 | 高性能、支持HLS/FLV/WebRTC,内置录制功能 |
| Nginx + RTMP模块 | 轻量级需求 | 配置简单,但功能相对单一 |
| ZLMediaKit | 高并发场景 | C++开发,性能极强 |
录制方案
服务器端自动录制(推荐)
使用SRS的dvr插件或Nginx-RTMP的录制指令:
SRS配置示例:
# srs.conf
listen 1935;
max_connections 1000;
vhost __defaultVhost__ {
dvr {
enabled on;
dvr_path /usr/local/srs/record/[app]/[stream]/[2006]-[01]-[02]-[15].[05].[06].flv;
dvr_plan session; # 每个推流生成一个文件
dvr_duration 0; # 0表示持续录制直到推流结束
dvr_wait_keyframe on;
}
http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
}
}
Nginx-RTMP录制配置:
rtmp {
server {
listen 1935;
application live {
live on;
record all;
record_path /var/record;
record_unique on;
record_suffix _%Y%m%d_%H%M%S.flv;
}
}
}
通过FFmpeg录制(灵活性高)
// PHP调用FFmpeg录制
$cmd = "ffmpeg -i rtmp://localhost/live/{stream_id} -c copy -f flv /var/record/{stream_id}_".time().".flv";
exec($cmd . " > /dev/null 2>&1 &");
PHP后端实现
数据库设计
CREATE TABLE `live_records` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`room_id` int(11) NOT NULL COMMENT '直播间ID',
`stream_id` varchar(100) NOT NULL COMMENT '流标识', varchar(255) DEFAULT NULL COMMENT '录制标题',
`start_time` datetime NOT NULL COMMENT '开始录制时间',
`end_time` datetime DEFAULT NULL COMMENT '结束录制时间',
`duration` int(11) DEFAULT '0' COMMENT '时长(秒)',
`file_path` varchar(500) DEFAULT NULL COMMENT '录制文件路径',
`status` tinyint(4) DEFAULT '0' COMMENT '0录制中 1已完成',
`file_size` bigint(20) DEFAULT '0' COMMENT '文件大小(bytes)',
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_stream` (`stream_id`),
KEY `idx_room` (`room_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
录制控制API
class RecordController {
// 开始录制
public function startRecord($roomId, $streamId) {
// 调用系统命令或API通知录制服务器
$cmd = "curl -X POST http://127.0.0.1:1985/api/v1/dvr/start -d '{
\"vhost\": \"__defaultVhost__\",
\"app\": \"live\",
\"stream\": \"{$streamId}\"
}'";
$result = exec($cmd);
// 记录到数据库
DB::table('live_records')->insert([
'room_id' => $roomId,
'stream_id' => $streamId,
'start_time' => date('Y-m-d H:i:s'),
'status' => 0
]);
}
// 停止录制
public function stopRecord($streamId) {
$cmd = "curl -X POST http://127.0.0.1:1985/api/v1/dvr/stop -d '{
\"vhost\": \"__defaultVhost__\",
\"app\": \"live\",
\"stream\": \"{$streamId}\"
}'";
exec($cmd);
// 更新记录
$record = DB::table('live_records')->where('stream_id', $streamId)
->where('status', 0)->first();
if ($record) {
$endTime = date('Y-m-d H:i:s');
DB::table('live_records')->where('id', $record->id)->update([
'end_time' => $endTime,
'duration' => strtotime($endTime) - strtotime($record->start_time),
'status' => 1,
'file_path' => "/record/{$streamId}.flv"
]);
}
}
}
回放列表API
// 获取回放列表
public function getRecordList($roomId, $page = 1, $limit = 20) {
$list = DB::table('live_records')
->where('room_id', $roomId)
->where('status', 1)
->orderBy('start_time', 'desc')
->paginate($limit);
return response()->json([
'code' => 0,
'data' => $list,
'message' => 'success'
]);
}
// 获取单个录制详情
public function getRecordDetail($recordId) {
$record = DB::table('live_records')->find($recordId);
return response()->json([
'code' => 0,
'data' => [
'id' => $record->id,
'title' => $record->title,
'start_time' => $record->start_time,
'duration' => $this->formatDuration($record->duration),
'file_url' => $this->getFileUrl($record->file_path),
'status' => $record->status
]
]);
}
前端播放实现
播放器选择
<!-- 使用Video.js播放HLS -->
<link href="https://vjs.zencdn.net/7.20.3/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/7.20.3/video.min.js"></script>
<video id="record-player" class="video-js vjs-default-skin" controls preload="auto" width="640" height="360">
<source src="https://your-domain.com/record/stream_id.m3u8" type="application/x-mpegURL">
</video>
<script>
var player = videojs('record-player');
</script>
直播回放点播
// 动态切换回放
function playRecord(recordId) {
fetch(`/api/record/detail?id=${recordId}`)
.then(response => response.json())
.then(data => {
if (data.code === 0) {
player.src({
src: data.data.file_url,
type: 'application/x-mpegURL'
});
player.play();
}
});
}
高级功能
录制文件转码
// 使用FFmpeg将flv转mp4
public function convertToMp4($inputFile, $outputFile) {
$cmd = "ffmpeg -i {$inputFile} -c copy -movflags +faststart {$outputFile} 2>&1";
exec($cmd, $output, $returnVar);
if ($returnVar === 0) {
return true;
}
return false;
}
云端存储集成
// 使用阿里云OSS
use OSS\OssClient;
public function uploadToOss($localFile, $ossKey) {
$client = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
$result = $client->uploadFile($bucket, $ossKey, $localFile);
return $result['oss-request-url'];
}
断点续传
// 分段上传
public function chunkUpload($file, $chunkIndex, $totalChunks) {
$tempPath = storage_path('chunks/' . $file['unique_id']);
file_put_contents($tempPath . '.' . $chunkIndex, file_get_contents($file['tmp_name']));
if ($chunkIndex == $totalChunks - 1) {
$finalFile = storage_path('records/' . $file['unique_id'] . '.mp4');
for ($i = 0; $i < $totalChunks; $i++) {
file_put_contents($finalFile, file_get_contents($tempPath . '.' . $i), FILE_APPEND);
unlink($tempPath . '.' . $i);
}
}
}
部署建议
服务器配置优化
# Nginx配置
server {
listen 80;
server_name live.example.com;
# 视频文件缓存
location /record {
root /var/www/records;
expires 7d;
add_header Cache-Control "public, immutable";
# 支持断点续传
add_header Accept-Ranges bytes;
}
# 直播流代理
location /live {
flv_live on;
chunked_transfer_encoding on;
add_header 'Access-Control-Allow-Origin' '*';
root /tmp;
}
}
高性能传输
// 使用分片读取大文件
public function streamVideo($filePath) {
header('Content-Type: video/mp4');
header('Content-Length: ' . filesize($filePath));
$fp = fopen($filePath, 'rb');
while (!feof($fp)) {
echo fread($fp, 8192);
ob_flush();
flush();
}
fclose($fp);
}
常见问题与解决方案
录制文件损坏
- 原因: 推流异常中断
- 解决: 启用
dvr_wait_keyframe参数,使用ffmpeg修复
回放卡顿
- 解决:
- 使用HLS分片播放
- 部署CDN加速
- 调整
dvr_duration为10秒分片
存储空间不足
- 解决:
- 自动清理规则
- 使用对象存储OSS/COS
- 设置录制时长限制
完整的PHP直播录制与回放方案需要以下组件配合:
- 流媒体服务器: SRS(推荐)或Nginx-RTMP
- 录制存储: 本地服务器或云端OSS
- PHP后端: 实现录制控制和回放管理
- 前端播放: Video.js或HLS.js
- 转码服务: FFmpeg转换格式
- CDN加速: 提升播放体验
对于中小型项目,推荐使用SRS + FFmpeg + PHP的组合,可快速实现高可用的直播录制与回放功能。