Fixed engine memory growing with every restart of the channel's processing after an ingest
interruption, and with every retry while waiting for a contribution, until the engine reached its
memory limit and restarted, briefly interrupting the stream
Fixed SCTE-35 ad breaks missing from HLS playlists when their cue arrives just after the splice
time, which dropped about every other break of some sources; such breaks now start at the next
segment boundary and still end at their scheduled time
Fixed SCTE-35 ad breaks in HLS playlists getting a second, different end when a return cue arrived
after the break had already ended, and ad breaks scheduled at the same moment going missing when
one of them was canceled or moved
Fixed Low-Latency HLS audio playlists listing one more partial segment per segment than configured,
the last only a few frames long: audio parts now hold whole audio frames, and the part target grows
to fit them, such as 0.405334 s instead of 0.4 s for 2-second segments split into 5 parts
Fixed the SCTE-35 EXT-X-DATERANGE tag that ends an ad break in HLS playlists sometimes having an
END-DATE 1 ms later than its START-DATE plus DURATION
Fixed channels with S3 DVR and VOD output keeping the previous session's media in memory at every
ingest reconnect, so the engine's memory grew for as long as the channel ran. The last hourly VOD
playlist on S3 now also ends with EXT-X-ENDLIST when the channel or its file ingest ends, or the
channel reconnects in a later hour, instead of staying open
Fixed S3 DVR and hourly VOD playlists leaving out the SCTE-35 EXT-X-DATERANGE tags, so players
of a distribution with DVR enabled never saw the channel's ad breaks; each tag now stays listed for
as long as the media it describes is in the playlist, also across channel restarts
Fixed Low-Latency HLS playback on Apple devices failing with an HTTP 400 error, mostly when
joining over a slow network: playlist requests asking for a partial segment a few parts ahead of
the live edge, as the HLS specification allows, were refused
Fixed Low-Latency HLS playlist requests that the stream could not satisfy within three target
durations, such as during an ingest interruption, returning an outdated playlist that CDNs could
keep serving for up to three more target durations after the stream recovered; they now fail with
HTTP 503 instead
Fixed Low-Latency HLS playlist requests for media past the end of an ended stream failing with an
HTTP 400 error instead of returning the final playlist
Fixed playback freezes during low-latency HLS bitrate switches on Apple devices
Added the DRM keys to the HLS multivariant playlist of protected channels, so players can request
licenses before loading a media playlist
Fixed SRT channels that stopped producing output, while still shown as playing, when the source
changed its track layout mid-stream; the channel now recovers on its own within seconds
Extended caching of ended HLS media playlists to one hour
Carried the source timecode of ingested video into Low-Latency HLS and HLS (CMAF) output: the first
frame of every segment and partial segment carries the timecode of its source frame as an ID3 timed
metadata event (TXXX frame optiview.live:timecode, formatted HH:MM:SS:FF)
Fixed a channel waiting for its RTMP contribution leaving a connection open on the RTMP server at
every retry when the server holds its reply to the engine's play request until a stream is
published; every attempt now closes its connection when it ends
Fixed EXT-X-PROGRAM-DATE-TIME running behind the wall clock, for as long as the channel kept
running, by however long the ingest took to deliver media after connecting, such as an RTMP source
whose server accepts the connection before its publisher is live. Latency measured from the program
date-time was overstated by the same amount; EXT-X-HESP-PROGRAM-DATE-TIME and the SCTE-35
EXT-X-DATERANGE dates are corrected alike
Fixed S3 DVR playlists opening with EXT-X-DISCONTINUITY when a channel restarted after being
stopped for longer than its DVR window, which kept Safari from starting playback, or left it
playing audio only, until the window had filled again; hourly VOD playlists that begin with a
restart are fixed alike. DVR playlists now also increment EXT-X-DISCONTINUITY-SEQUENCE as each
discontinuity leaves the window
Made the S3 DVR and VOD output cacheable like the engine's own HLS output: media playlists for half
a target duration (at least a second), multivariant playlists for two seconds in browsers and one
on CDNs like main.m3u8, and init segments for an hour; playlists no longer forbid caches from
serving them stale (must-revalidate). An ended hourly VOD playlist was cacheable until it
expired, keeping players on a stale copy when the channel restarted within the same hour
Fixed segments kept from before a restart in the S3 DVR window or hourly VOD playlist being paired
with the new init segment after an encoder configuration change: every channel start now uploads
its own init-<id>.mp4 instead of overwriting init.mp4
Fixed a channel restarted within the same hour adding segments to an hourly VOD playlist on S3 that
kept its EXT-X-ENDLIST, so players took it as complete; the playlist is reopened until the hour
or the channel ends
Fixed S3 DVR playlists ignoring the channel's DVR window and always keeping the last four hours:
they now keep the configured window, one hour unless set otherwise, as the discovery response
already reported
Fixed an RTMP ingest that accepts the connection but sends no data crash-looping the engine and
putting the channel in error: the channel now waits for the contribution, goes live as soon as
it arrives, and is stopped by its ingest idle timeout like channels with other ingest types
Allowed browsers to reuse multivariant playlists (main.m3u8, main.hesp.m3u8) and HESP
manifests (manifest.json) for up to two seconds while CDNs keep caching them for one
(Cache-Control: max-age=2, s-maxage=1), so a repeated request for the same manifest no longer
goes back to the CDN when the CDN reports its copy as a second old
Added RFC 9218 priority hints to every HLS response (priority: u=1 on playlists, u=2 to u=6
on media in ascending order of the rendition's bit rate), so Apple devices keep Low-Latency HLS
playback over HTTP/3 instead of falling back to standard latency. HESP-3 objects streamed while
in production are marked incremental (i), thumbnails are served at the lowest urgency (u=7)
so they never delay media, and error responses at the highest (u=1) so a player learns of a
missing object without waiting behind a segment
Fixed the HLS (TS) multivariant playlist omitting the CODECS attribute; every variant now
declares its H.264 profile and level and the AAC audio codec
Every error response now says how long a CDN may keep it: a 404 for a playlist or segment, which
the next segment or the next restart may bring into existence, lasts one second, so a CDN no
longer keeps serving one it picked up while the channel was restarting. Segments that have left
the DVR window are answered with 410 Gone, and paths the engine never serves or requests that
can never succeed stay 404 or 400, all cacheable for an hour; internal errors are not cacheable
Media playlists are now cacheable for half a target duration (at least a second), and the
responses to blocking playlist reloads (_HLS_msn) for three target durations; segments for an
hour rather than a day. Playlists no longer forbid a cache from serving them stale
(must-revalidate)
Added Low-Latency HLS and HESP-3 output to every channel, no configuration needed: main.m3u8 keeps
serving standard HLS, while main.hesp.m3u8 serves the same renditions with partial segments and the
HESP-3 tags. Every playlist accepts a latency query parameter (milliseconds) naming the end-to-end
latency the player asks for and is sized for it: HOLD-BACK (now declared on every playlist) and
PART-HOLD-BACK follow the buffer that latency leaves the player once the encoder's share is spent,
the HESP-3 multivariant playlist publishes that buffer as EXT-X-HESP-TARGET-BUFFER (at least 0.5 s),
and a buffer of more than four segment durations is served as standard HLS. Every media playlist of a
channel carries the same EXT-X-SERVER-CONTROL, as the HLS specification requires
HESP-3 media playlists signal how far the stream has progressed into the segment in production
(EXT-X-HESP-PROGRAM-DATE-TIME), and every media playlist response carries the engine's clock at
generation (x-hesp-origin-now), so a joining player lands at a predictable distance from live even
when the playlist was served from a cache
Added SCTE-35 ad break signaling to HLS, enabled by the new optional hls.scte35 config key (off by
default): splice_insert cues in an MPEG-TS ingest are exposed in every media playlist as
EXT-X-DATERANGE tags carrying the SCTE35-OUT / SCTE35-IN payloads, and segments are cut at the
splice points so an ad decision server can splice on segment boundaries. When off, the SCTE-35 PID of
the ingest is ignored
Added SCTE-35 time_signal cues from an MPEG-TS ingest to the EXT-X-DATERANGE tags of every
HLS media playlist, alongside the splice_insert cues. Advertisement, placement opportunity and
promo segmentation descriptors open a range with SCTE35-OUT and PLANNED-DURATION and close it
with SCTE35-IN, END-DATE and DURATION, paired by their segmentation event id; other
segmentation descriptors and time signals without any mark their time with SCTE35-CMD. A segment
boundary is cut at every time signal that carries an avail_descriptor, DTMF_descriptor or
segmentation_descriptor
EXT-X-DATERANGESTART-DATE and END-DATE attributes are now written in the same form as
EXT-X-PROGRAM-DATE-TIME: UTC with a Z suffix and millisecond precision, instead of +00:00 with
a varying number of fraction digits
Kept HLS playlists and published media available for 10 seconds after graceful shutdown, with
EXT-X-ENDLIST signaling the end of the stream
Fixed engine crashes when an MPEG-TS ingest carries an SCTE-35 section that fails validation;
such sections are now skipped with a warning without interrupting playback
Fixed SCTE-35 cues padded with alignment stuffing before their checksum being rejected instead
of forwarded to the HLS playlists
Fixed HESP playback failing to start when the player requested an initialization segment slightly
ahead of the live edge
Fixed SRT ingest in listener mode (?mode=listener) binding a random port instead of the configured one,
which left the channel restarting on "no live data" forever; localport in the ingest URL also no longer
crashes the engine
Fixed renditions whose aspect ratio differs from the source (such as a portrait 9:16 ladder fed by a
16:9 ingest) being encoded with non-square pixels, which Chrome rendered squeezed while Safari
rendered it correctly. Such renditions now keep square pixels and are padded with black bars to
fit, so they render identically in every browser
Sorted media playlists in HLS multivariant playlists by descending preference score
Fixed brief gaps between contiguous DVB-TTML subtitles when cue durations differ from packet timing
Fixed HLS multivariant playlists not declaring CLOSED-CAPTIONS=NONE on variants when no closed
captions are configured, as the specification requires
Removed the EXT-X-INDEPENDENT-SEGMENTS tag from HLS media playlists; it stays declared once in the
multivariant playlist, matching Apple's validation guidance
Improved the quality of GPU-encoded H.264 renditions at 720p and above, which were encoded with the
H.264 Main profile while CPU-encoded renditions of the same rung used High. All renditions at 720p and
above now use High at the same bitrate, a small quality gain at a 1080p 6.5 Mbps rung and a larger one
at lower bitrates. Renditions below 720p stay on Main for decoder compatibility, and the CODECS
attribute in HLS manifests changes accordingly for the affected renditions
Fixed H.265 and H.264 ingests the GPU decoder cannot handle (such as 4:2:2 chroma subsampling)
leaving the channel stuck in a reconnect loop; those streams now fall back to software decoding
Fixed language tags in HLS manifests not following the standard (e.g. en should be used instead of eng)
Fixed HLS SDR variants missing the video range declaration that players require when HDR variants are also offered
Changed an ingest that connects but sends no data to be treated the same as an ingest that does not connect: the
channel stays in the waiting state instead of showing an error, and stops after the ingest timeout