Nginx – PHP NginX – Output Buffering – Video Streaming

nginxPHPstreamingvideo

(Since it contains some coding but also it's concerning nginx configuration i think it would be the best to have it in serverfault).

I have some Video Files in my Server that are stored in a folder inside my filesystem and i am using PHP to read the Video File and send it directly to the users using NginX as WebServer.

Most of the Video Files are live streams which i generate using FFmpeg but i have some movies as well.

Live Streaming Files: There are splitted into segments and with php i read the m3u8 file, i get the *.ts files and i am streaming them using PHP while the FFmpeg is still running in background.

Movie Files: Just one static File

I have some questions regarding the nginx/php configuration.

My NginX config is the following:

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;
    }
}

For each Client that reading Videos Files from my Server i log the connection and i can predict if he is still online or no using the

connection_aborted() function from PHP
(In a few words, if php script is still running)

Now the Problem:

NginX has by default fastcgi_buffering on; and that is causing to me a problem when i am serving movies to the clients. When i want to serve Live Streaming Files this is fine since i want some buffers to reduce the chances for a lag to occured while PHP is reading the contents of the live streaming files.

But in movies it just parses the entire movie (even if it is 2gb), directly to buffers and can not predict if the client got the response or no. The php script ends in just a second and then nginx is serving the movie to the client so the connection log i talked about before has been ended within one second.

If i turn fastcgi_buffering off; everything is working as i want but i saw some lags in Live Streaming Serving.

The best would be to have fastcgi_buffering on; in live streams and fastcgi_buffering off; in movies. But i have really no idea how to do that.

I tried ob_implicit_flush( true ); but that doesnt work either with NginX i think. In fact, i can not play with any flush() function etc.

The Streaming PHP File uses the following technique to send a video file to the client

<?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;
}
?>

Best Answer

The problem here is that PHP has no knowledge on the client connection status, buffers etc, that are required for streaming.

The nginx fastcgi_buffer* options are meaningful for only to nginx, they specify only nginx input buffer sizes for data coming via the FastCGI interface.

If the input (stream data in your case) coming via FastCGI is larger than the memory buffers allocated with the directives, then nginx stores the output to a temporary file on disk.

You can try to implement manual delays in PHP side, but since you have no knowledge of client streaming status, you cannot implement the delays accurately.

If your videos are encoded with MPEG4, I recommend you to use ngx_http_mp4_module. This implementes streaming videos directly inside nginx.

Related Topic