NVENC (ffmpeg 6.1 + drivers actuales) emite los keyframes forzados por
-force_key_frames como I-frames NO-IDR; el muxer HLS solo corta en IDR,
así que cada segmento se estiraba en silencio al GOP por defecto
(250 frames ≈ 10.4 s @24fps) mientras la playlist server-side seguía
prometiendo 2 s por segmento. Con los PTS reales ~5× fuera del mapa de
la playlist, los seeks aterrizaban donde podían y los subtítulos se
desincronizaban en cuanto se mezclaban segmentos de runs distintos
(seek-restart) en el mismo dir.
Medido: 3 segmentos por 30 s de encode en vez de 15; con -forced-idr 1
exactamente 15, y post-fix seg-150/151/158 arrancan en 300.0/302.0/316.0
clavados. Afecta a TODO el HLS por NVENC histórico (no era del rate
control nuevo: la config de bitrate fijo producía lo mismo). QSV recibe
su grafía -forced_idr. Las entradas de caché viejas nunca llegaron a
sellarse (el conteo de segmentos no cuadraba), así que no hay migración:
solo sesiones vivas estaban afectadas.
- HLSSessionConfig.StartSec (sync StreamSession.startSec): el primer
ffmpeg arranca ya seekeado en el punto de resume (-ss +
-output_ts_offset + -start_number, misma maquinaria que el
seek-restart) en vez de encodear desde seg-0 para morir en el
seek-restart inmediato del player (doble spawn, resume lento).
readyMax se pre-siembra al índice de arranque; el ready-watcher
compara ReadyCount() > WriterStartIdx() para no marcar "ready" antes
del primer segmento real. startSec >= duración → arranque desde 0
(resume obsoleto de un fichero reemplazado).
- Rate control: capped constant-quality donde el encoder lo hace bien —
libx264 -crf 23, NVENC -cq 23 -b:v 0 — con el mismo -maxrate de
siempre y -bufsize 2x (antes 1x estrangulaba picos). Escenas fáciles
emiten muchos menos bits (menos stalls vía funnel/LTE); el peor caso
no cambia. QSV/VideoToolbox/VAAPI conservan el triple de bitrate fijo
probado (sus knobs de calidad tienen gotchas de vendor).
- Limpieza: wrapper buildHLSFFmpegArgs y guard startIdx<0 muertos.