Serviço OTT¶
Emite fluxos por protocolos baseados em HTTP — HLS, MPEG-DASH (desde a versão 1.12) e MPEG-TS over HTTP. Suporta HTTPS (SSL). A emissão é ativada na aba OTT das configurações de Stream.
As URLs de conexão têm o formato:
http://host:port/http/stream/login/password — autorização por login e senha
http://host:port/http/stream/login — autorização por login (token)
http://host:port/http/stream/ — autorização por IP
host e port são definidos nas configurações do http server.
stream — ID do stream. Não confundir com o número de ordem na lista de streams. O ID é exibido no topo da página de estatísticas do stream e na coluna ID da lista de streams; é definido na criação do stream e nunca muda.
Analogamente para HLS e DASH:
Na página de estatísticas do stream são exibidas as URLs dos protocolos conectados (como template) e seu status atual. O acesso não autorizado é proibido; os clientes devem estar registrados em Peers.
Para HLS estão disponíveis parâmetros adicionais na URL (opcionais):
[URL]?a=1&s=40&m=40&v=5
a: 1 — caminhos absolutos na playlist (padrão), 0 — caminhos relativos.
s: duração da playlist dinâmica (s), 40 s por padrão.
m: duração mínima do playlist dinâmico (s), por padrão 40 s. O tamanho máximo do playlist dinâmico é 60 s. Se o tamanho atual do buffer de chunks for menor que o mínimo solicitado, será retornado erro 404. Isso é feito para que o HLS inicie a partir de um buffer de chunks já preenchido no servidor.
v: versão do protocolo HLS na playlist. Por padrão 5; alguns clientes HLS podem exigir uma versão diferente.
Para compatibilidade com alguns clientes HLS é possível adicionar o nome de arquivo index.m3u8 à URL, ex.: http://host:port/hls/stream/login/password/index.m3u8.
O servidor HLS tem dois modos — Peer mode e OTT mode.
Peer mode — modo com segmentação (chunks) simples. Recomendado para peering / distribuição de fluxos.
OTT mode — modo com segmentação otimizada para transmissão OTT e início rápido dos players. A carga de CPU é maior; recomendado para transmissão.
É possível habilitar SSL (HTTPS) no servidor HTTP nas configurações do servidor.
Chunk Min Interval e Chunk Max Interval
No modo OTT é feita análise do fluxo em PAT/PMT/SPS/PPS/IFrame e os chunks são cortados pelo critério de início rápido dos players. A análise começa em min interval e, se por alguma razão os dados não forem encontrados, o chunk é forçosamente cortado em max interval.
HLS Adaptive Multistream
A partir da versão 1.10 há suporte a HLS Adaptive Multistream e, da 1.12, a DASH Adaptive Multistream
Para fluxos adaptativos é configurada uma playlist HLS separada. Para isso:
Nos fluxos que serão incluídos na playlist adaptativa, ative o HLS com OTT Mode.
No menu principal aparecerá a seção de fluxos adaptativos. Nela adicione um fluxo e indique todos os fluxos que devem entrar nessa playlist.
Para os fluxos pode ser definido um parâmetro de bitrate. Por padrão 0 significa usar o valor medido; caso contrário, pode ser definido explicitamente.
Para playlists adaptativas a URL é diferente:
Aos peers (clientes) pode-se impor restrições de acesso aos fluxos adaptativos, assim como aos comuns. A permissão para um fluxo adaptativo inclui a permissão para todos os fluxos que o compõem.
Modelo de cache para OTT HLS e DASH.¶
O servidor produz respostas em três categorias, distintas pelo tempo de vida do conteúdo e pela adequação ao cache em nós intermediários (reverse proxy, CDN, cache do cliente).
1. Modelo de cache¶
1.1. Recursos e cabeçalhos HTTP¶
Recurso |
URL |
Content-Type |
Cache-Control |
|---|---|---|---|
Segmento TS |
|
|
|
DASH MPD |
|
|
|
HLS master |
|
|
|
HLS media |
|
|
|
302 Redirect |
|
— |
|
Raw TS |
|
|
não definido; não é cacheado |
1.2. Características dos segmentos TS¶
O identificador keyID é formado como CRC64(startTime || streamID) e é globalmente único. A URL do segmento endereça conteúdo imutável — em requisições repetidas da mesma URL é retornado um fluxo de bytes idêntico (enquanto o segmento permanecer dentro da janela deslizante).
A diretiva immutable suprime a revalidação condicional pelo cliente (If-None-Match, If-Modified-Since). O valor max-age=60 é compatível com o típico timeShiftBufferDepth=40s.
1.3. Características dos manifestos¶
max-age=1 limita o limite superior de obsolescência do conteúdo no cache em um segundo. Em conjunto com proxy_cache_lock on (nginx), picos de requisições ao manifesto coalescem em uma única requisição ao origin por segundo.
1.4. Variabilidade do conteúdo¶
Com absPath=0 (padrão; sem o parâmetro de URL «a»), os manifestos HLS media e DASH MPD não contêm o identificador de sessão no corpo. O conteúdo do manifesto é idêntico entre sessões pertencentes a uma mesma combinação (stream, param). Isso permite que o cache do reverse-proxy reutilize a entrada entre sessões com a normalização da chave de cache.
Com absPath=1 (parâmetro de URL «a=1»), o corpo do manifesto contém URLs absolutas, incluindo esquema, host e identificador da sessão. O conteúdo torna-se específico da sessão; a possibilidade de reutilização do cache entre sessões deixa de existir.
2. Comportamento dos clientes¶
Cliente |
URL de atualização do manifesto |
Impacto no número de sessões |
|---|---|---|
VLC 3.x HLS |
|
Uma sessão por reprodução |
VLC 3.x DASH |
|
Tratado por session reuse (ver 3.3) |
ffmpeg 5.x HLS |
|
Uma sessão por reprodução |
ffmpeg 5.x DASH |
|
Tratado por session reuse (ver 3.3) |
dash.js, hls.js |
|
Uma sessão por reprodução |
3. Mecanismos especializados¶
3.1. Redirect HTTP 302 para DASH¶
Uma requisição da forma /dash/<stream>/<login>/<pass>/index.mpd retorna a resposta 302 Found com o cabeçalho Location: /h<sess>/index.mpd. O corpo da resposta é vazio. A autenticação e a alocação da sessão acontecem na fase de processamento do redirecionamento.
Clientes que suportam cache de redirecionamento acessam diretamente a URL da sessão nas requisições subsequentes. Clientes que não suportam repetem a requisição de redirecionamento. O custo do reprocessamento do redirecionamento limita-se à verificação de autenticação e às operações de session reuse.
3.2. Session reuse para DASH¶
No processamento da requisição /dash/.../index.mpd, executada sob login-id L para stream-id S e a flag adaptive=A, se em _ottClientList já existir uma sessão DASH com o mesmo (L, S, A), seu sessID é retornado. Não é criada nova sessão e nenhum slot maxConn é consumido.
Aplica-se apenas a DASH. Para HLS não é necessário um mecanismo de reuse separado: clientes HLS atualizam a media playlist via URL de sessão e não disparam applyNewOTTSess a cada refresh.
3.3. Reutilização de segmentos entre sessões¶
O caminho /h<sess>/<keyID>.ts é independente de sess na resolução do keyID em conteúdo: keyID identifica univocamente o segmento dentro das ChunkList registradas (ver _ottStreamList). O Nginx com cache key normalizada (removendo o prefixo /h<sess>/) atende todas as requisições do mesmo keyID a partir de uma única entrada de cache.
4. Parâmetros da requisição¶
Parâmetro |
Valor padrão |
Impacto |
|---|---|---|
|
|
|
|
|
|
|
|
Comprimento mínimo da janela para emitir o manifesto |
|
|
|
Alterar o parâmetro via query string atualiza os valores armazenados na sessão na próxima chamada de applyNewOTTSess.
5. Características de carga¶
A carga no origin escala com o número de streams distintos assistidos simultaneamente. O aumento do número de clientes assistindo o mesmo stream não aumenta o número de requisições ao origin quando há reverse-proxy cache com chave de cache normalizada.
Cenário |
Taxa de requisições ao origin (ref.) |
|---|---|
1 cliente por fluxo X |
MPD: 0.4 req/s, segment: 0.2 req/s |
N clientes em um mesmo fluxo X (cache ativo) |
MPD: 1 req/s, segment: 0.2 req/s |
N clientes ffmpeg em modo replay no mesmo fluxo |
MPD: 1 req/s (com |
N clientes em N fluxos distintos |
MPD: 0.4·N req/s, segment: 0.2·N req/s |
6. Nginx como reverse proxy com cache¶
6.1. Configuração base¶
proxy_cache_path /var/cache/nginx/pss_segments
levels=1:2 keys_zone=pss_segments:100m
max_size=20g inactive=30m use_temp_path=off;
proxy_cache_path /var/cache/nginx/pss_manifests
levels=1:2 keys_zone=pss_manifests:10m
max_size=256m inactive=5m use_temp_path=off;
upstream pss_backend {
server 127.0.0.1:41972;
keepalive 64;
}
map $uri $pss_cache_key {
~^/h[0-9a-f]{16}(?<tail>/.+\.(ts|m3u8))$ "stream:$tail";
default $uri;
}
server {
listen 80;
server_name stream.example.com;
location ~* "^/h[0-9a-f]{16}(/[0-9]+)?/[0-9a-f]+\.ts$" {
proxy_cache pss_segments;
proxy_cache_key $pss_cache_key;
proxy_cache_valid 200 60s;
proxy_cache_valid 404 403 0s;
proxy_cache_lock on;
proxy_cache_use_stale updating error timeout;
proxy_cache_revalidate on;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://pss_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering on;
}
location ~* "(^/h[0-9a-f]{16}(/[0-9]+)?/index\.(m3u8|mpd)$|^/(hls|dash)/.*\.(m3u8|mpd)$)" {
proxy_cache pss_manifests;
proxy_cache_key $pss_cache_key;
proxy_cache_valid 200 1s;
proxy_cache_valid 404 403 0s;
proxy_cache_lock on;
proxy_cache_lock_timeout 2s;
proxy_cache_use_stale updating;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://pss_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
location / {
proxy_pass http://pss_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_buffering off;
proxy_read_timeout 3600s;
}
}
6.2. Função das diretivas¶
Diretiva |
Finalidade |
|---|---|
|
Serializa as requisições upstream em cache misses simultâneos para a mesma chave |
|
Devolve a cópia obsoleta às requisições paralelas durante a atualização do cache |
|
Usa |
|
Proíbe o cache de erros de autorização e 404 |
|
Mantém um pool de conexões persistentes ao origin |
|
Para segmentos; ativa o bufferização da resposta no nginx |
|
Para a seção |
6.3. Cálculo de max_size do cache de segmentos¶
Valor de referência: bitrate × timeShiftBufferDepth × distinct_streams × 2
Exemplo: 10 fluxos × 8 Mbps × 40 s × 2 ≈ 800 MB. Recomenda-se uma margem de 10× para absorver a variabilidade do bitrate.
6.4. Terminação TLS¶
O servidor do Perfect Streamer aceita conexões nas portas HTTP e HTTPS. Com terminação TLS no nginx, o upstream usa a porta HTTP. O encaminhamento dos cabeçalhos X-Forwarded-Proto e X-Forwarded-Host é obrigatório para a composição correta de URLs absolutas quando absPath=1.
server {
listen 443 ssl http2;
server_name stream.example.com;
ssl_certificate /etc/letsencrypt/live/stream.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stream.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location ... {
proxy_pass http://pss_backend;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Host $host;
# + директивы кеширования из 6.1
}
}
server {
listen 80;
server_name stream.example.com;
return 301 https://$host$request_uri;
}
Para HTTPS entre nginx e origin aplicam-se proxy_ssl_verify e proxy_ssl_trusted_certificate. Em conexões loopback a criptografia é redundante.
6.5. Multi-host¶
Quando um único processo nginx atende vários server_name, $host é adicionado à cache key para isolar o conteúdo:
map $uri $pss_cache_key {
~^/h[0-9a-f]{16}(?<tail>/.+\.(ts|m3u8))$ "$host:stream:$tail";
default "$host:$uri";
}
O tamanho de keys_zone é dimensionado em 8000 chaves/MB. Para instalações multi-host com milhares de fluxos, recomenda-se keys_zone=...:300m ou mais.
7. Cache do cliente¶
Cache-Control: immutable é processado pelos navegadores Chrome/Firefox/Safari. O cache do cliente devolve o segmento sem requisição condicional em acessos repetidos (incluindo seek para trás dentro do buffer do player).
Service Workers podem aplicar a estratégia cache-first baseada no conteúdo de Cache-Control. Os players DASH (dash.js, Shaka) usam MSE através de SourceBuffer; o segmento colocado no buffer permanece disponível sem nova requisição HTTP até sair da janela deslizante.
Para requisições cross-domain, o cabeçalho Access-Control-Allow-Origin: * permite o cache em shared caches sem Vary: Origin. Ao trocar o valor ACAO para um Origin específico passa a ser necessário Vary: Origin, o que reduz a eficiência do shared cache.
8. Distribuição via CDN¶
Perfect Streamer é compatível com CDNs em modo pull-from-origin (Cloudflare, Akamai, Fastly, BunnyCDN, Amazon CloudFront).
Origin shield. Recomenda-se colocar um ou mais nós shield entre o edge do CDN e o origin para reduzir a taxa de requisições ao origin quando os clientes estão distribuídos globalmente.
Purge. Segmentos content-addressed não precisam de purge. Quando os metadados do stream mudam (codec, resolução), os manifestos atualizam dentro de max-age=1 sem purge explícito.
Cache warming. Em caso de pico esperado em um stream específico, é admissível pré-aquecer a CDN a partir de vários pontos geográficos antes do início da transmissão.
Geodistribuição. Os segmentos (max-age=60) são bem adequados para cache geograficamente distribuído. Os manifestos (max-age=1) toleram atraso de entrega de até um segundo — aceitável para live non-low-latency.
9. Monitoramento¶
9.1. X-Cache-Status¶
Adicionar add_header X-Cache-Status $upstream_cache_status; em cada location com cache. Valores:
Valor |
Descrição |
|---|---|
|
Resposta do cache |
|
Não estava em cache; obtido do origin e armazenado |
|
Expirado, atualizado |
|
Cópia stale entregue à requisição paralela durante a atualização |
|
|
|
Origin retornou 304 Not Modified |
|
|
9.2. Formato do access-log¶
log_format pss_cache '$remote_addr $status $request_method "$request" '
'$body_bytes_sent rt=$request_time ut=$upstream_response_time '
'cache=$upstream_cache_status key=$pss_cache_key';
server {
access_log /var/log/nginx/pss.log pss_cache;
}
9.3. Métricas¶
O módulo nginx-vts exporta métricas por zona no formato Prometheus:
GET /status/format/prometheus
Limites recomendados para alertas:
Métrica |
Limite |
Causa possível |
|---|---|---|
Segment HIT rate |
< 90 % em 5 minutos |
Normalização de cache key quebrada; |
Manifest MISS rate |
> 50 % em 1 minuto |
|
Upstream response time p95 |
> 500 ms em 1 minuto |
Sobrecarga do origin |
Cache zone fill |
> 90 % em 10 minutos |
Aproximação de |
10. Diagnóstico¶
Sintoma |
Causa provável |
Solução |
|---|---|---|
Taxa HIT de segmento baixa |
|
Verificar cabeçalhos e regex na diretiva |
404 em segmentos após sair da janela |
404 em cache para segmento que saiu da janela deslizante |
Adicionar |
Atraso do início da reprodução 2–5 s |
|
Reduzir para 1–2 s; ativar |
O manifesto não atualiza |
|
Definir explicitamente |
Crescimento de TIME_WAIT no upstream |
Falta |
Adicionar |
403 em |
O cliente resolve URLs relativas a partir da URL pré-redirect |
O servidor emite |
11. Segurança¶
11.1. Session URL¶
A URL no formato /h<sess>/... cumpre a função de token de sessão — não exige reautenticação. O tempo de vida é limitado pelo idle timeout (valor 30 s). Em caso de inatividade, a sessão é removida pela tarefa cleaner.
Requisitos:
HTTPS em todos os caminhos OTT (
/hls/,/dash/,/h<sess>/) em produçãoO Session ID no cabeçalho
Locationdo 302 não é cacheado (no-cache, no-store)
11.2. Rate limiting¶
limit_req_zone $binary_remote_addr zone=dash_top:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=hls_top:10m rate=5r/s;
server {
location /dash/ {
limit_req zone=dash_top burst=20 nodelay;
proxy_pass http://pss_backend;
}
location /hls/ {
limit_req zone=hls_top burst=20 nodelay;
proxy_pass http://pss_backend;
}
}
URLs de sessão (/h<sess>/) não exigem rate limiting — o processamento é barato e as respostas são cacheadas.
11.3. Cache de respostas com erros¶
proxy_cache_valid 200 60s;
proxy_cache_valid 301 302 0s;
proxy_cache_valid 404 403 0s;
proxy_cache_valid any 1s;
Proíbe o cache de redirecionamentos (sess único em Location) e de respostas de erro de autorização ou recurso ausente.
11.4. Restrição do acesso de rede ao origin¶
A porta 41972 (41982 para HTTPS) deve estar fechada ao tráfego externo. Configurações aceitáveis:
Bind do Perfect Streamer em
127.0.0.1(com nginx local)Regra de firewall:
iptables -A INPUT -p tcp --dport 41972 ! -s 10.0.0.0/8 -j DROP
12. Integração com middleware¶
12.1. Modelo prefix-login¶
O Perfect Streamer permite delegar a identificação de usuário a middleware/sistema de billing via o mecanismo prefix-login. Um conector externo ao sistema de billing não está incluído nesta versão.
Configuração do usuário embedded:
{
"id": 9,
"login": "sub",
"password": "xxx",
"is-prefix": true,
"max-conn-http-hls": 1,
"accept-stream": [ ... ]
}
Com is-prefix: true o servidor aceita URLs cujo login segue <prefix><billing_user_id>:
/dash/test1/sub42/xxx/index.mpd
/hls/test1/sub43/xxx/index.m3u8
12.2. Formato das estatísticas¶
<clients>
<client login-id="-1974387287" login="sub" match-login="sub42"
sess-id="11331..." ott-type="dash" stream-id="10000" .../>
<client login-id="-2147031294" login="sub" match-login="sub43"
sess-id="11132..." ott-type="dash" stream-id="10000" .../>
</clients>
O campo login-id contém o hash do login URL. login é o valor configurado. match-login é o login URL usado pelo cliente.
12.3. Limitações do prefix-login¶
Senha compartilhada. Todos os subscribers do pool prefix usam uma mesma senha. O comprometimento dá acesso a qualquer
<prefix><string>.Granularidade de ACL.
accept-streamaplica-se a todo o pool prefix; não há ACL por assinante sem billing externo.Rotação da senha. Alterá-la desconecta todos os subscribers ativos. Para substituição gradual são necessários temporariamente dois prefix-logins.
13. Legendas WebVTT¶
A fonte das legendas é DVB Teletext / DVB Subtitling do MPEG-TS de entrada. As faixas de legendas Teletext devem estar presentes nas seções Media Information ou Original Media Information. A seção Analyzer também permite verificar se os pacotes dos PIDs correspondentes estão ativos.
Para OTT HLS/DASH o modo OTT deve estar ativado (em Peer mode as legendas WebVTT não estão disponíveis). Na seção Output # OTT o contador de chunks OTT WebVTT buffer chunk count deve ficar diferente de zero.
Para diagnosticar as legendas, ativar Analyze e Trace no stream. Ao iniciar o fluxo, o log do stream deve exibir:
Start Teletext subtitle decoder
[ttxsubdec] ttx: pid=331 magazine=8 page=0x88 lang=***
Em seguida, o log registra o texto decodificado das legendas.
13.1. URL dos segmentos VTT¶
Esquema |
URL |
Conteúdo |
|---|---|---|
HLS master |
|
|
HLS subtitle playlist |
|
lista |
Segmento VTT HLS |
|
VTT com X-TIMESTAMP-MAP estilo HLS |
DASH MPD AdaptationSet |
em |
|
Segmento VTT DASH |
|
VTT com X-TIMESTAMP-MAP estilo DASH |
<keyHex> é o hex de 16 caracteres de CRC64(startTime, streamID, pid). <seq> é o número decimal do chunk no subtitle storage (contador separado do video storage).