1

(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;
}
?>
user3393046
  • 121
  • 2
  • 10
  • Why not have two different virtual hosts, responding to two different `server_name`, one for movies and the other for streaming. Therefor, you can actually do X or Y stuff for each of those things. – w0rldart Jul 15 '14 at 11:04
  • Isn't possible to still have buffering on but very low buffs? Like only 300-400KB or something? So that the fopen/stream_get_line will be a bit slower so that it will not end in just a second when i am serving a movie file. Because as i said it gets 2GB in buffers. I tried with fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size But couldn't fix it. – user3393046 Jul 15 '14 at 11:23
  • I would like to provide an answer for your questions, but I do not posses experience in that matter. I suggested creating two virtualhosts, thinking that you can apply custom settings to each, and play with them the way you want. In my opinion, that's a really fast solution and clean. – w0rldart Jul 15 '14 at 11:36

1 Answers1

0

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.

Tero Kilkanen
  • 34,499
  • 3
  • 38
  • 58
  • But, we cant reduce the buffer size somehow to allow only some KBs instead of MB/GB? – user3393046 Jul 15 '14 at 12:47
  • You can decrease nginx FastCGI memory buffers to as small as 4 kB, but the disk buffer is only limited to available disk space. And if the disk space runs out, nginx will fail also. As I told in my answer, the buffer does not affect PHPs sending of data in any way. – Tero Kilkanen Jul 15 '14 at 14:06