PHPAPI直播流怎么处理

wen PHP项目 10

本文目录导读:

PHPAPI直播流怎么处理

  1. 核心架构:PHP vs 流媒体服务器
  2. 常见场景与PHP处理方式
  3. 重要限制与解决方案
  4. 推荐工作流程总结
  5. 实际生产建议

针对PHP处理直播流的问题,需要先明确一点:PHP本身并不适合直接处理高并发、低延迟的实时流媒体数据(如RTMP、HLS)。 PHP通常作为业务逻辑层和API网关,负责控制、调度、鉴权,而核心的流媒体转发、转码工作由专业的流媒体服务器(如Nginx-RTMP、SRS、FFmpeg)完成。

以下是PHP处理直播流的典型架构和实现方案:

核心架构:PHP vs 流媒体服务器

  1. 流媒体服务器(核心):负责接收推流、转码、分发。
    • 常用:Nginx + nginx-rtmp-moduleSRS (Simple-RTMP-Server)Live555Node-Media-Server
  2. PHP API服务(辅助):负责业务逻辑。
    • 生成推流/播放地址(鉴权Token)。
    • 管理直播间状态(创建、结束、禁播)。
    • 处理回调(推流开始/结束、录制完成等)。
    • 对接数据库和用户系统。

常见场景与PHP处理方式

场景1:生成和管理推流/播放地址(最常用)

这是PHP最擅长的领域,你不会让PHP直接推流,而是让它根据规则生成带有效期的URL,控制谁能推流、谁能观看。

流程:

  1. 用户请求创建直播间。
  2. PHP生成一个唯一的流名称(StreamKey),并将其与AppName用户ID过期时间关联存入Redis/MySQL。
  3. PHP返回一个推流地址给主播端(如OBS):rtmp://your-domain.com/live/{stream_key}?token={hash}
  4. PHP返回一个播放地址给观众端(如Video.js):http://your-domain.com/live/{stream_key}.flvhls/stream_key.m3u8

PHP代码示例(生成推流Token鉴权):

<?php
// 生成推流令牌,用于简单的防盗链
function generateStreamToken($userId, $streamKey, $expireTime) {
    $secret = 'your_very_secret_key_123!'; // 与流媒体服务器配置的密钥一致
    $data = $userId . $streamKey . $expireTime;
    $hash = hash_hmac('sha256', $data, $secret);
    return [
        'push_url' => "rtmp://live.yourdomain.com/live/{$streamKey}?token={$hash}&expire={$expireTime}",
        'play_url' => [
            'flv' => "http://play.yourdomain.com/live/{$streamKey}.flv",
            'hls' => "http://play.yourdomain.com/live/{$streamKey}.m3u8"
        ]
    ];
}
// 假设用户创建直播间
$userId = 12345;
$streamKey = uniqid('stream_', true); // 随机且唯一的流名
$expire = time() + 7200; // 2小时有效
$urls = generateStreamToken($userId, $streamKey, $expire);
echo json_encode($urls);
?>

关键配置(Nginx-RTMP):

# nginx.conf
rtmp {
    server {
        listen 1935;
        application live {
            live on;
            record off;
            # -- 鉴权(关键) --
            # 当推流时,Nginx会请求PHP的API检查Token
            on_publish http://your-api.com/auth/publish.php;
            # 录制、转码等...
            hls on;
            hls_path /tmp/hls;
        }
    }
}

PHP鉴权回调脚本(auth/publish.php):

<?php
// 假设请求是这个:http://your-api.com/auth/publish.php?name=stream_key&token=xxx&expire=xxx
$streamKey = $_GET['name'] ?? '';
$token = $_GET['token'] ?? '';
$expire = $_GET['expire'] ?? 0;
// 1. 检查时间是否过期
if ($expire < time()) {
    header('HTTP/1.0 403 Forbidden');
    echo "Token expired";
    exit;
}
// 2. 验证哈希
$secret = 'your_very_secret_key_123!';
$userInfo = getUserIdFromStreamKey($streamKey); // 从数据库获取
$expectedHash = hash_hmac('sha256', $userInfo['id'] . $streamKey . $expire, $secret);
if (!hash_equals($expectedHash, $token)) {
    header('HTTP/1.0 403 Forbidden');
    echo "Invalid token";
    exit;
}
// 3. 验证成功,允许推流
header('HTTP/1.0 200 OK');
echo "Authenticated";
exit;
?>

场景2:监听流状态回调(推流/断流事件)

流媒体服务器(如Nginx-RTMP、SRS)支持在推流开始、结束、录制完成时,通过HTTP通知我们的PHP服务。

Nginx配置:

application live {
    live on;
    # 推流开始回调
    on_publish http://your-api.com/callback/stream_start;
    # 推流结束回调
    on_publish_done http://your-api.com/callback/stream_end;
    # 录制完成回调
    on_record_done http://your-api.com/callback/record_done;
}

PHP回调处理(stream_end.php):

<?php
// 收到推流结束通知
$streamKey = $_POST['name'] ?? '';
$clientId = $_POST['clientid'] ?? '';
// 1. 更新数据库:将该直播间状态设为“已结束”或“离线”
$db->update('live_rooms', ['status' => 'offline', 'end_time' => date('Y-m-d H:i:s')], "stream_key = '$streamKey'");
// 2. 可以清理临时文件或发送WebSocket通知
// sendWebSocketNotification($streamKey, 'stream_ended');
echo "OK";
?>

场景3:处理录制文件(转码、存档、截图)

流媒体服务器可以自动录制直播流为FLV或MP4文件,PHP可以用于:

  1. 接收录制完成回调:处理并存储文件信息到数据库。

  2. 后台异步处理:使用exec()proc_open()调用FFmpeg进行视频截图、转码为小文件、生成水印等。

    <?php
    // 收到录制完成回调
    $inputFile = '/path/to/recorded/stream-12345.flv';
    $outputThumb = '/path/to/thumbs/stream-12345.jpg';
    // 注意:主进程不要阻塞,建议使用消息队列
    $cmd = "ffmpeg -i $inputFile -ss 00:00:10 -vframes 1 $outputThumb 2>&1";
    exec($cmd, $output, $returnCode);
    if ($returnCode === 0) {
        // 保存截图路径到数据库
    }
    ?>

重要限制与解决方案

限制 说明 解决方案
内存/时间 PHP有max_execution_time和内存限制,不适合处理长时间流的转码。 使用exec()调用外部命令(FFmpeg),或用消息队列(RabbitMQ/Redis)异步处理。
并发 PHP-FPM处理大量流媒体连接(如几千个观看者)会耗尽资源。 播放端不要直接连PHP,直接连Nginx/HLS/CDN,PHP只处理API请求。
WebSocket/RTMP PHP原生不支持低延迟的WebSocket或RTMP协议。 使用Swoole/Workerman(PHP常驻内存)或直接在流媒体服务器(Nginx-RTMP)配置。

推荐工作流程总结

主播(OBS)
    |
    | (推送RTMP流,带Token)
    V
流媒体服务器 (Nginx-RTMP / SRS)   <--- 推流回调通知 --->  PHP API服务
    |                                                    (鉴权、记录状态、发通知)
    | (自动HLS切片 / FLV分发)
    V
CDN / 直接访问
    |
    | (HTTP-FLV / HLS)
    V
观众 (Video.js / VLC)

实际生产建议

  1. 不要用PHP处理裸流数据:PHP的长连接、二进制数据处理能力弱。
  2. 使用成熟的流媒体方案
    • 推流:OBS、RTMP SDK(移动端直接用)。
    • 服务器:推荐 SRSNginx-RTMP(社区版够用)。
    • 播放器Vue/React 使用 Video.jsflv.js (HTTP-FLV)
  3. PHP的定位:写好RESTful API,做好鉴权 (推流Token, 播放Referer/时间戳) 和回调 (Webhook)。
  4. 大并发考虑:在PHP和流媒体服务器之间加一层消息队列(如Kafka/RabbitMQ)来缓冲回调请求,防止高频回调打挂PHP。

如果你能提供更具体的场景(是搭建一个完整的直播系统,还是处理某个特定流?),我可以给出更精确的代码或配置示例。

抱歉,评论功能暂时关闭!