PHP NginX - Buffer de Saída - Video Streaming

1

(Como contém alguns códigos, mas também é sobre a configuração do nginx, acho que seria melhor tê-lo no serverfault).

Eu tenho alguns arquivos de vídeo no meu servidor que estão armazenados em uma pasta dentro do meu sistema de arquivos e estou usando PHP para ler o arquivo de vídeo e enviá-lo diretamente para os usuários usando NginX como WebServer.

A maioria dos arquivos de vídeo são transmissões ao vivo que eu gero usando o FFmpeg, mas também tenho alguns filmes .

Live Streaming Files : Há divisões em segmentos e com o php eu leio o arquivo m3u8, recebo os arquivos * .ts e os estou transmitindo usando o PHP enquanto o FFmpeg ainda está sendo executado em segundo plano .

Arquivos de filme : apenas um arquivo estático

Eu tenho algumas perguntas sobre a configuração do nginx / php.

Minha configuração do NginX é a seguinte:

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

Para cada cliente que lê arquivos de vídeos do meu servidor eu registro a conexão e posso prever se ele ainda está online ou não usando o

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

Agora o problema:

O NginX tem por padrão o fastcgi_buffering on; e isso está me causando um problema quando estou exibindo filmes para os clientes. Quando eu quero servir arquivos Live Streaming isso é bom, pois eu quero alguns buffers para reduzir as chances de ocorrer um atraso enquanto o PHP está lendo o conteúdo dos arquivos de streaming ao vivo.

Mas nos filmes ele apenas analisa o filme inteiro (mesmo que seja 2gb), diretamente para buffers e não pode prever se o cliente recebeu a resposta ou não. O script php termina em apenas um segundo e depois o nginx está servindo o filme para o cliente, então o log de conexão sobre o qual eu falei antes foi encerrado em um segundo.

Se eu ativar fastcgi_buffering , tudo estará funcionando como quero, mas vi alguns atrasos na transmissão ao vivo.

O melhor seria ter fastcgi_buffering ativado em transmissões ao vivo e fastcgi_buffering; em filmes. Mas eu realmente não tenho ideia de como fazer isso.

Eu tentei ob_implicit_flush (true); mas isso não funciona com o NginX, eu acho. Na verdade, eu não posso jogar com qualquer função flush () etc.

O arquivo PHP Streaming usa a seguinte técnica para enviar um arquivo de vídeo para o cliente

<?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;
}
?>
    
por user3393046 15.07.2014 / 12:53

1 resposta

0

O problema aqui é que o PHP não tem conhecimento sobre o status da conexão do cliente, buffers, etc, que são necessários para o streaming.

As opções nginx fastcgi_buffer* são significativas apenas para nginx, elas especificam apenas tamanhos de buffer de entrada nginx para dados que chegam pela interface FastCGI.

Se a entrada (fluxo de dados no seu caso) vindo via FastCGI for maior que os buffers de memória alocados com as diretivas, então o nginx armazena a saída em um arquivo temporário no disco.

Você pode tentar implementar atrasos manuais no lado do PHP, mas como você não tem conhecimento do status de streaming do cliente, não é possível implementar os atrasos com precisão.

Se os seus vídeos estiverem codificados com MPEG4, recomendo que você use ngx_http_mp4_module . Isso implementa streaming de vídeos diretamente dentro do nginx.

    
por 15.07.2014 / 14:26