Назад | Перейти на главную страницу

PHP NginX - Буферизация вывода - Потоковое видео

(Поскольку он содержит некоторую кодировку, но также касается конфигурации nginx, я думаю, что было бы лучше иметь ее в serverfault).

У меня есть несколько видеофайлов на моем сервере, которые хранятся в папке внутри моей файловой системы, и я использую PHP для чтения видеофайла и отправки его напрямую пользователям, использующим NginX в качестве WebServer.

Большинство видеофайлов прямые трансляции который я генерирую с помощью 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;
    }
}

Для каждого клиента, который читает видеофайлы с моего сервера, я регистрирую соединение и могу предсказать, находится ли он еще в сети или не использует

Функция connection_aborted () из PHP (в двух словах, если скрипт php все еще запущен)

Теперь проблема:

NginX по умолчанию fastcgi_buffering on; и это вызывает у меня проблемы, когда я предлагаю фильмы клиентам. Когда я хочу обслуживать файлы потоковой передачи в реальном времени, это нормально, так как я хочу, чтобы некоторые буферы уменьшали вероятность возникновения задержки, когда PHP считывает содержимое файлов потоковой передачи.

Но в фильмах он просто анализирует весь фильм (даже если он составляет 2 ГБ) напрямую в буферы и не может предсказать, получил ли клиент ответ или нет. Скрипт php завершается всего за секунду, а затем nginx передает фильм клиенту, поэтому журнал подключения, о котором я говорил ранее, был завершен в течение одной секунды.

Если я повернусь fastcgi_buffering off; все работает так, как я хочу, но я заметил некоторые задержки в Live Streaming Serving.

Лучше всего было бы иметь fastcgi_buffering on; в прямых трансляциях и fastcgi_buffering off; в фильмах. Но я понятия не имею, как это сделать.

Я попытался ob_implicit_flush (правда); но я думаю, что это не работает ни с 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;
}
?>

Проблема здесь в том, что PHP не знает о состоянии подключения клиента, буферах и т. Д., Которые необходимы для потоковой передачи.

Nginx fastcgi_buffer* параметры имеют смысл только для nginx, они указывают только размеры входного буфера nginx для данных, поступающих через интерфейс FastCGI.

Если вход (данные потока в вашем случае), поступающий через FastCGI, больше, чем буферы памяти, выделенные с помощью директив, то nginx сохраняет вывод во временный файл на диске.

Вы можете попытаться реализовать задержки вручную на стороне PHP, но, поскольку вы не знаете о статусе потоковой передачи клиента, вы не можете точно реализовать задержки.

Если ваши видео кодируются с помощью MPEG4, я рекомендую вам использовать ngx_http_mp4_module. Это реализует потоковую передачу видео прямо внутри nginx.