(因为它包含一些编码,而且还涉及 nginx 配置,所以我认为最好将它放在 serverfault 中)。
我的服务器中有一些视频文件存储在文件系统内的文件夹中,我使用 PHP 读取视频文件并使用 NginX 作为 Web 服务器将其直接发送给用户。
大多数视频文件都是直播我使用 FFmpeg 生成,但我有一些电影也一样。
直播文件:它们被分成几个片段,我用 php 读取 m3u8 文件,得到 *.ts 文件,然后我使用 PHP 对它们进行流式传输,而 FFmpeg 仍在后台运行。
影片文件:只有一个静态文件
我对 nginx/php 配置有一些疑问。
我的 NginX 配置如下:
server {
listen 80;
index index.php index.html index.htm;
root /var/www;
server_tokens off;
chunked_transfer_encoding off;
location ~ \.php$ {
try_files $uri =404;
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php5-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
}
对于每个从我的服务器读取视频文件的客户端,我都会记录连接,并且我可以预测他是否仍然在线,或者不在线使用
PHP 中的 connection_aborted() 函数(简而言之,如果 php 脚本仍在运行)
现在的问题是:
NginX 默认fastcgi_buffering开启;当我向客户端提供电影时,这给我带来了问题。当我想提供实时流媒体文件时,这没问题,因为我希望有一些缓冲区来减少 PHP 读取实时流媒体文件内容时发生延迟的可能性。
但在电影中,它只是将整个电影(即使它有 2gb)直接解析到缓冲区,并且无法预测客户端是否收到响应。php 脚本在一秒钟内结束,然后 nginx 将电影提供给客户端,因此我之前谈到的连接日志在一秒钟内就结束了。
如果我转身fastcgi_buffering 关闭;一切都按我想要的方式运行,但是我发现实时流媒体服务存在一些滞后。
最好的办法是fastcgi_buffering开启;在直播和fastcgi_buffering 关闭;在电影里。但我真的不知道该怎么做。
我试过ob_implicit_flush( true );但我认为这对 NginX 也不起作用。事实上,我无法使用任何刷新()功能等
流式 PHP 文件使用以下技术将视频文件发送到客户端
<?php
# $video_file can be either a live stream or movie file.
$bytes = 0;
$stream = fopen( $video_file, "rb" );
while ( ! feof( $stream ) && ClientConnected() )
{
$response = stream_get_line( $stream, 8192 );
$bytes += strlen( $response );
echo $response;
}
fclose( $stream );
/*
$bytes have been sent
In movie files the bytes directly goes to the filesize of movie file if fastcgi_buffering is on.
*/
function ClientConnected()
{
if ( connection_status() != CONNECTION_NORMAL || connection_aborted() )
{
return false;
}
return true;
}
?>
答案1
这里的问题是 PHP 不了解流式传输所需的客户端连接状态、缓冲区等。
nginxfastcgi_buffer*
选项仅对 nginx 有意义,它们仅指定通过 FastCGI 接口传输的数据的 nginx 输入缓冲区大小。
如果通过 FastCGI 传输的输入(在您的情况下为流数据)大于使用指令分配的内存缓冲区,则 nginx 会将输出存储到磁盘上的临时文件中。
您可以尝试在 PHP 端实现手动延迟,但由于您不了解客户端流媒体状态,因此无法准确实现延迟。
如果你的视频是用 MPEG4 编码的,我建议你使用ngx_http_mp4_module
。这直接在 nginx 内部实现流式视频。
答案2
我可能有点迟到了,但万一它能帮助到其他人:正如本指南中解释的那样https://www.jeffgeerling.com/blog/2016/streaming-php-disabling-output-buffering-php-apache-nginx-and-varnish 你可以通过设置标头来指示 Nginx 针对此请求禁用其缓冲区
header('X-Accel-Buffering: no');
https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_buffering