DVR / Arquivo

Desde a versão 1.13, Perfect Streamer inclui um DVR integrado — um arquivo de fluxo persistente em disco, paralelo à saída OTT normal (HLS / DASH). O arquivo é gravado automaticamente, sem processo separado, e reproduzido pelas mesmas URLs OTT que o live — única diferença: o parâmetro query.

Recursos:

  • Gravação de cada fluxo OTT ao arquivo no armazenamento escolhido.

  • Reprodução HLS, DASH e Low-Latency HLS do arquivo (VOD) nas mesmas URLs que o live (DASH e LL-HLS — em CMAF, no OTT/HLS/LL-HLS/LL-Dash).

  • Legendas (WebVTT) — gravadas junto com chunks TS.

  • Vários armazenamentos — um fluxo é vinculado a um; fluxos distintos podem gravar em discos distintos.

  • Limpeza automática por tempo de retenção e uso do disco.

  • EPG-aligned VOD — arquivo conforme evento EPG referenciado.

  • VOD adaptativo — suportado para grupos adaptativos.

O DVR não requer licença separada. Ativado por fluxo adicionando vinculação ao armazenamento.

O DVR não substitui a transmissão ao vivo. Se um fluxo possui arquivo, o cliente recebe uma playlist ao vivo com o mesmo comportamento de quando não há DVR. O arquivo só começa a reproduzir quando o cliente solicita explicitamente o modo VOD por meio de um parâmetro de consulta da URL (ver abaixo).

Configuração do armazenamento

Um armazenamento é um registro na seção Configuration / DVR Storage. Cada registro descreve um diretório em disco onde PSS grava arquivos. Um fluxo usa um armazenamento.

Ao adicionar um armazenamento, configura-se:

Name — nome exibido.

Dir Path — caminho do diretório em disco. Após criar o registro, o caminho não pode ser alterado — para mover o arquivo, apagar o registro e criar um novo. Os arquivos existentes não são tocados em disco ao apagar o registro.

Max Usage, % — limiar de uso do disco (padrão 90 %). Ao exceder, inicia limpeza size-based (ver abaixo). Mín 1 %, máx 100 %.

Cleanup Interval, seg — período da tarefa de limpeza (padrão 10 seg). A cada tick corta-se primeiro o mais antigo que a profundidade de retenção; depois, se exceder Max Usage, chunks antigos.

Disk Pressure Grace, seg — segundos que Used % deve exceder Max Usage continuamente antes do Size-based cleanup (padrão 60 seg). Filtra picos curtos.

Disk Pressure Cut, seg — limite superior por tick de limpeza: segundos de vídeo por fluxo apagáveis de uma vez (padrão 300 seg). O resto passa ao próximo tick.

Disk Emergency Bytes — limiar de espaço livre abaixo do qual o armazenamento entra em Error e a gravação para (padrão 2 GiB). Recuperação auto se espaço livre ≥ 2 × este valor.

Alarm Disk-Full Hysteresis, % — a margem abaixo de Max Usage até à qual a limpeza baseada em tamanho reduz o preenchimento, para que Used % não oscile mesmo junto ao limiar (2 % por padrão).

A maioria dos valores padrão serve para instalações típicas; geralmente basta ajustar Max Usage e Dir Path.

Faz sentido criar um armazenamento por disco. Se no mesmo disco forem indicados vários registros com subdiretórios distintos, eles competirão pelo espaço livre — o disco é compartilhado, mas a limpeza é própria de cada armazenamento.

Vinculação de um fluxo ao armazenamento

Nos ajustes Stream / OTT aparece uma seção DVR:

Storage — lista suspensa de armazenamentos; 0 significa «arquivo desativado para este fluxo».

Storage Hours — profundidade do arquivo para este fluxo, em horas, de 1 a 2160 (até 90 dias). Os chunks mais antigos que esse valor são apagados a cada tick da tarefa de limpeza (Rolling cleanup).

Storage Min Hour — limiar de proteção inferior (horas). A limpeza nunca apaga chunks mais novos, mesmo sob pressão Max Usage. Útil se a lógica de negócio exige gravação recente garantida, ex. «as últimas 2 horas sempre presentes».

Alteração de Storage em tempo real:

  • definir 0 — desativa o arquivo; os chunks em disco são mantidos, novos não são gravados. As sessões VOD passam a responder 404;

  • escolher outro armazenamento — o fluxo se desvincula do antigo e passa a gravar no novo. Os arquivos do antigo não são migrados.

Mudanças em Storage Hours e Storage Min Hour se aplicam de imediato — a limpeza usa o novo valor no próximo tick.

Após configuração, o fluxo grava o arquivo automaticamente ao entrar em Running.

VOD: reprodução do arquivo

O arquivo é reproduzido pelas mesmas URLs que o live HLS / DASH (ver seção OTT service) — só muda o parâmetro query.

URLs e parâmetros

URLs para HLS, DASH e Low-Latency HLS (DASH e LL-HLS — em CMAF, requerem o modo OTT/HLS/LL-HLS/LL-Dash):

Sem parâmetros query — live normal com janela deslizante. Com o parâmetro t — modo VOD.

Parâmetro

Função

t=<epoch>

Hora de início VOD (Unix epoch, seg). t=0 — desde o início do arquivo. A presença de t (mesmo t=0) ativa o modo VOD.

d=<sec>

Duração da janela VOD, seg. d=0 ou ausente — «até o momento atual». Só faz sentido com t.

epg=<epoch>

EPG-aligned VOD: o servidor localiza o evento EPG ativo no momento dado e usa seus start e duration como bordas da janela. Incompatível com t e d (substituição server-side). Ver abaixo.

a, s, m, v

Parâmetros live padrão (ver OTT service); s e m são ignorados em modo VOD.

Comportamento conforme t e d:

t

d

Janela

Condição 404

nenhum

—

live (janela deslizante)

—

0

nenhum / 0

[início arquivo, agora]

DVR não vinculado

0

> 0

[início arquivo, +d]

DVR não vinculado

> 0

nenhum / 0

[t, agora]

DVR não vinculado

> 0

> 0

[t, t+d]

DVR não vinculado

Normalização das bordas:

  • t anterior ao início do arquivo — start é alinhado automaticamente ao primeiro chunk disponível (a limpeza pode ter cortado). Não é 404 — entrega-se o que resta.

  • t no futuro ou janela toda antes do arquivo — playlist vazia mas válida (HLS: só header + EXT-X-ENDLIST; DASH: @type="static", mediaPresentationDuration="PT0S").

  • Os chunks são selecionados estritamente pelo instante de início do chunk que cai no intervalo semiaberto [t, t+d) — não há segmentos parciais.

VOD em um fluxo sem arquivo (ou cujo armazenamento está em Error) — 404 imediato em master playlist / MPD. Nenhuma sessão é criada.

Texto de erro no corpo 404 (visível em logs do servidor e HTTP body):

  • VOD: stream not running — o fluxo está na config mas não em Running.

  • VOD: no DVR archive — o fluxo não tem armazenamento ou está em Error.

  • VOD: DVR detached — o fluxo se desvinculou do armazenamento entre requisições.

  • VOD: EPG event not found — sem evento para ?epg=.

Playlist HLS VOD — fechada (o player vê a duração e pode buscar):

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:5.000,
...
#EXT-X-ENDLIST

Esses marcadores não estão na playlist live — essa é a única diferença.

MPD DASH VOD — estático: @type="static", mediaPresentationDuration fixo, <SegmentURL> explícitos. O DASH live permanece @type="dynamic".

Se o intervalo escolhido tem lacunas no arquivo (p. ex. reinício de gravação ou limpeza no meio), o MPD DASH é dividido em vários <Period> — um por trecho contíguo. Os players (VLC, dashjs, Shaka) cruzam os limites de período sem configuração especial.

EPG-aligned VOD

Se o fluxo está vinculado a uma fonte EPG (campos EPG Source e EPG Channel nos ajustes), o cliente pode solicitar o arquivo por um instante contido em um evento EPG:

O servidor localiza o evento EPG ativo no epoch dado e usa seus start e duration como bordas da janela VOD. Útil para catálogos: a UI sabe a hora do evento mas não precisa calcular bordas exatas.

Se o fluxo não está vinculado a EPG ou não há evento ativo — 404 ``VOD: EPG event not found``. t e d são ignorados se há epg.

Fluxos adaptativos

Os grupos adaptativos (ver HLS Adaptive Multistream) aceitam os mesmos parâmetros VOD:

Na master playlist (HLS) só entram variantes com armazenamento DVR configurado. As sem DVR são puladas (no log aparece VOD: variant N has no DVR); a montagem segue com as demais.

Na variante DASH, cada qualidade vira um <Representation> distinto em <Period> comuns; o player troca de qualidade sem reabrir o manifesto.

Comportamento do player

O VOD HLS / DASH do arquivo toca em players padrão: VLC, hls.js, dashjs, Shaka, ffmpeg. A busca na timeline funciona.

Se o player pede um segmento já apagado pela limpeza, o servidor retorna 404 para esse segmento (não 500). VLC, hls.js, dashjs pulam o segmento e seguem no próximo.

Recursos adicionais:

  • Proteção de sessões ativas: enquanto há sessão VOD aberta, a limpeza não apaga chunks na sua janela (ver abaixo).

  • Live-edge bridge: se um cliente em sessão VOD solicitar um segmento além do limite direito da janela VOD — por exemplo, avança na timeline ao atingir o fim do arquivo — o servidor entrega automaticamente o segmento da memória live. Sem redirecionamentos e sem reautenticação.

  • Cache de playlist: em requisições repetidas do mesmo VOD index.m3u8 / index.mpd, o servidor retorna resposta idêntica byte a byte — sem reconstruir. Adequado para CDN à frente do PSS.

Legendas no arquivo

Se o fluxo traz legendas (DVB Subtitling, Teletext ou WebVTT) e a opção OTT WebVTT está ativa, as legendas são arquivadas em paralelo aos chunks TS — em arquivos .vtt ao lado de .ts.

Em modo live, a master playlist contém EXT-X-MEDIA:TYPE=SUBTITLES; em modo VOD, o servidor retorna uma playlist VOD de legendas (com ENDLIST) e segmentos .vtt nas mesmas URLs.

Particularidades:

  • HLS: o cabeçalho X-TIMESTAMP-MAP é preservado no início de cada .vtt (exigido pela spec HLS).

  • DASH: o cabeçalho X-TIMESTAMP-MAP é removido em tempo real (ligado ao PCR absoluto, conflita com a âncora DASH; senão, VLC mostra legendas vazias).

  • Em grupo adaptativo: se o sub-stream ativo não grava legendas, os segmentos VTT retornam 404. Na próxima variante, o player pode receber legendas de novo.

As legendas se desativam via OTT WebVTT no fluxo, ou não ativando HLS em modo OTT/HLS.

Limpeza e retenção

PSS usa quatro estratégias de limpeza, executadas a cada tick da tarefa de limpeza (padrão a cada 10 seg):

  1. Rolling cleanup (por fluxo): por fluxo, apagam-se chunks mais antigos que Storage Hours. Roda sempre, mesmo com disco semivazio.

  2. Size-based cleanup (por armazenamento): quando Used % excede Max Usage continuamente por Disk Pressure Grace seg, os chunks mais antigos são cortados proporcionalmente entre fluxos vinculados. Por tick: Disk Pressure Cut seg de vídeo por fluxo. Nunca chunks mais novos que Storage Min Hour.

  3. Emergency disk-full cut: se o espaço livre cai abaixo de Disk Emergency Bytes, a limpeza age agressivamente e pode apagar até chunks protegidos por sessão. A gravação para até o espaço livre voltar com histerese × 2.

  4. Orphan scan: no disco podem permanecer arquivos não contabilizados no índice (após uma parada abrupta do PSS). O coletor percorre os subdiretórios dos fluxos e remove esses arquivos “esquecidos” — a primeira passagem pouco após o início do serviço, depois uma vez por hora e sempre que a pressão de disco for acionada. Como proteção contra uma corrida com a escrita, arquivos com menos de 60 s são ignorados.

Nota. As tarefas de limpeza rodam em segundo plano; o usuário normalmente não age. Se o arquivo cresce mais rápido do que é cortado, reduzir Storage Hours nos fluxos ou aumentar Disk Pressure Cut.

Proteção de sessões VOD ativas

Ao abrir uma sessão VOD, em cada armazenamento envolvido registra-se um «slot de proteção» com a hora de início da janela. As limpezas Rolling e size-based não tocam chunks na janela da sessão aberta. O slot é liberado automaticamente ao fechar (FIN, timeout).

Isso significa:

  • Se o cliente mantém a sessão VOD por muito tempo, pode buscar a qualquer instante na sua janela — os chunks não «somem sob ele».

  • A limpeza por Max Usage pode não levar Used % ao limiar enquanto a sessão estiver ativa; ao cliente sair, a limpeza alcança.

  • Emergency disk-full cut e Storage Min Hour contornam a proteção: se o disco está quase sem livre, os chunks são apagados e o cliente recebe 404 nos segmentos afetados (o player os pula).

  • Após reiniciar o PSS, os slots de proteção somem — a limpeza retoma de imediato.

Vários armazenamentos

Pode-se criar qualquer número de registros DVR Storage — um por diretório / disco. Os fluxos se vinculam a armazenamentos distintos de forma independente. A limpeza e limiares (Max Usage, Disk Pressure) operam por armazenamento.

Casos de uso:

  • Tiering por valor: armazenamento SSD rápido para canais premium com grande profundidade, HDD capacitivo para o resto.

  • Disco dedicado ao arquivo: para que a gravação DVR não concorra com o disco do sistema ou arquivos temporários.

  • Separação por projeto: um disco para o lote nº 1, outro para o nº 2 — simplifica migração e auditoria.

Trocar a vinculação do fluxo (campo Storage em Stream / OTT) comuta a gravação em tempo real. Os arquivos antigos ficam intactos no disco anterior — podem ser apagados manualmente ou retomar a gravação revertendo o fluxo.

Estado do armazenamento e monitoramento

A seção Data / DVR Storage List (e a API GET /data/dvr-storage-list) mostra por armazenamento:

  • State — Ready / Error (mais o estado intermediário Not Ready em um armazenamento recém-adicionado).

  • Total / Free / Used Bytes — espaço livre e ocupado no disco.

  • Used % — porcentagem atual de uso.

  • Archived Bytes — tamanho total dos chunks indexados de todos fluxos vinculados (sem orphans).

  • Pressure Since Sec — momento (epoch) em que Used % primeiro excedeu Max Usage neste episódio; 0 significa «sem pressão».

  • Active Task — a operação de manutenção em segundo plano em execução neste momento: gc-orphans (remoção de arquivos órfãos), disk-pressure-trim (corte sob pressão de disco) ou none, e há quantos segundos ela já está em execução. Operações de curta duração (< 2 s) não piscam na interface.

  • Last cleanup — um resumo das últimas execuções de limpeza: há quanto tempo ocorreu a anterior recolha de ficheiros órfãos (e quantos foram eliminados) e o último corte sob pressão de disco (quanto espaço foi libertado).

  • Attached streams — a lista dos fluxos associados; para cada um são exibidos o nome, o indicador de gravação em curso (active), a profundidade de arquivo configurada (retention-hours) e o preenchimento real (archived-sec e archived-bytes). A soma de archived-bytes de todos os fluxos é igual a Archived Bytes de todo o armazenamento.

Estados:

  • Ready — o diretório está disponível, a gravação e a limpeza ocorrem normalmente.

  • Error — o diretório de armazenamento está indisponível (desmontado, sem permissões, erro do sistema de arquivos) ou há espaço livre criticamente baixo no disco; a gravação é interrompida. A recuperação é automática — assim que o diretório fica novamente disponível e surge espaço livre suficiente.

Se o armazenamento entrou em Error, verifique se o diretório do arquivo está montado e se há espaço livre no disco — o PSS não sai sozinho desse estado até que o problema seja resolvido fisicamente.

Preenchimento do arquivo ao longo do tempo:

  • No nível do stream (Data / Stream) está disponível a métrica storage-gap-percent — a proporção de lacunas de tempo no arquivo acumulado: 0 % significa gravação contínua, valores mais altos significam que há descontinuidades no arquivo (reinícios da fonte, trechos cortados pela limpeza).

  • O endpoint GET /data/dvrstat retorna um histograma do preenchimento do arquivo por intervalos de tempo, com a marcação de eventos de gravação (início/parada da fonte, mudança de PMT, comutações de embaralhamento, reconstrução do índice, execução de limpeza) e de atividade de legendas — para desenhar a linha do tempo do arquivo DVR na interface de administração.

Proteção contra perda acidental

Várias operações do admin causam perda do arquivo ou cessação da entrega VOD. Antes de executá-las, a UI mostra confirmação modal:

  • Excluir DVR Storage — todos os fluxos vinculados perdem acesso VOD; os arquivos ficam no disco mas são inacessíveis via PSS sem o registro.

  • Trocar o fluxo para outro armazenamento — o VOD sobre o arquivo antigo deixa de funcionar.

  • Desvincular o fluxo do armazenamento (Storage = 0) — mesmo efeito.

  • Reduzir Max Usage — pode disparar a limpeza size-based e apagar chunks antigos.

  • Reduzir Storage Hours / Storage Min Hour — pode tirar parte do arquivo do rolling-window.

Decisão deliberada do produto: a operação é possível mas com confirmação, e os arquivos apagados ficam no disco (restauráveis de backup). Colocar o arquivo em servidor de arquivos / RAID separado reduz muito o risco de perda irreversível.

Limitações da versão atual

  • Uma sessão VOD aberta pelo cliente não acompanha o live edge — se vieram chunks durante a sessão, o cliente deve repedir a playlist (comportamento padrão HLS / DASH).

  • Atribuir um armazenamento por disco é o recomendado — vários registros com subdiretórios distintos disputam o espaço.

  • Os segmentos são endereçados por hash (HLS sobre MPEG-TS) ou pelo modelo $Number$.m4s com um init.mp4 comum (live DASH sobre CMAF) / por <SegmentURL> explícitas para .m4s (VOD DASH). Alterar o tamanho do chunk entre live e VOD não exige reabrir a URL.

  • O orphan scanner roda por hora; para acelerar, reiniciar PSS.