Stuck with implementing DVR

15 views
Skip to first unread message

Bart Jenn

unread,
Feb 6, 2026, 7:05:52 PMFeb 6
to Mistserver.org
Hi!

I'm stuck with the implementation of a DVR (following the documentation). The stream is working fine, its also pushing the TS segments and m3u8 file in the desired folders.

From the the stream created for the DVR I can browse and see the m3u8 as expected. But I cannot get the output to work. The standard player in the standard HTML page keeps showing: Stream is offline. 

When trying to open the DVR stream, the following error message is logged and leaves me clueless: 


[07 Feb 2026, 00:33:01MistInHLS:name-dvr (8300) [INFO] Input booting (../build/src/input/input.cpp:411)
[07 Feb 2026, 00:33:01MistInHLS:name-dvr (8300) [EXTREME] URL: ///mnt/network_share/name/name.m3u8 (../build/lib/url.cpp:156)
[07 Feb 2026, 00:33:01MistInHLS:name-dvr (8300) [FAIL] Logging unclean exit reason: Failed to load HLS playlist, aborting (../build/lib/config.cpp:62)
[07 Feb 2026, 00:33:01MistInHLS:name-dvr (8300) [WARN] Input closing unclean, reason: Failed to load HLS playlist, aborting (../build/src/input/input.cpp:827)
[07 Feb 2026, 00:33:01MistInHLS:name-dvr (8300) [INSANE] Opening page /MstTRGRINPUT_ABORT in client mode without auto-backoff (../build/lib/shared_memory.cpp:317)
[07 Feb 2026, 00:33:01MistInHLS:name-dvr (8300) [VERYHIGH] No triggers for INPUT_ABORT found

Balder Vietor

unread,
Feb 9, 2026, 3:22:41 AMFeb 9
to Mistserver.org
Hey!

That error happens for a few reasons, ranging from no permission to open the location/file to something invalid being in the m3u8 or TS data making it error out or even crash.
A network shared folder should be fine assuming MistServer has permission to read from it, I would assume it can find it otherwise it would've mentioned that there's no such file..
Since the stream itself is working fine, I'm assuming it might be the m3u8, but it would be best to have a short sample to verify it. 

Could you perhaps share the contents of the .m3u8 and the first 3 segments? 

Sometimes it can also help if you set the "split" duration to something less than 60:

/tmp/example/$datetime_$currentMediaTime.ts?split=6&m3u8=../index.m3u8

The split option can be found under "Timing" options when setting up the push, which is a bit of an unfortunate placing. 
2026-02-09-09-21-34-selection.png

Alternatively it might be a smart idea to verify the .m3u8 as a whole by attempting to open it in a player like: VLC, ffplay, mplayer, etc. 

With kind regards,
Balder


Bart Jenn

unread,
Feb 9, 2026, 3:41:15 PMFeb 9
to Mistserver.org
Hey Balder,

The permissions for reading and writing to the network share are fine. Also the networknshare in connected with 2.5Gb/s, no problems there.

This is the current push target config for the DVR: /mnt/network_share/$basename/$yday/$hour/$minute_$segmentCounter.ts?split=24&m3u8=../../$basename.m3u8&targetAge=600&maxEntries=25&noendlist=true&append=true&waittrackcount=1 

I have let the stream running long enough to create 4 segments. This is the contents of the .m3u8:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:29
#EXT-X-MEDIA-SEQUENCE:23
#EXT-X-PROGRAM-DATE-TIME:2026-02-09T19:50:54.702Z
#EXTINF:28.732,
040/19/50_23.ts
#EXT-X-PROGRAM-DATE-TIME:2026-02-09T19:51:23.434Z
#EXTINF:27.234,
040/19/51_24.ts
#EXT-X-PROGRAM-DATE-TIME:2026-02-09T19:51:50.668Z
#EXTINF:27.266,
040/19/52_25.ts
#EXT-X-PROGRAM-DATE-TIME:2026-02-09T19:52:17.934Z
#EXTINF:17.900,
040/19/53_26.ts


When copying all 4 segments (including folder structure) locally and playing the .m3u8 locally in VLS, the playlist works without issues. 

Could it be that the DVR stream which serves the .m3u8 playlist, can only be available when the stream becomes inactive? Because as soon as the stream becomes inactive after stopping to give it an input, this can be seen in the log of the DVR stream:
09 Feb 2026, 20:53:32MistInHLS:name-dvr (20367) [WARN] Input closing unclean, reason: Failed to load HLS playlist, aborting (../build/src/input/input.cpp:827)
[09 Feb 2026, 20:53:35MistInHLS:name-dvr (20368) [INFO] Input booting (../build/src/input/input.cpp:411)
[09 Feb 2026, 20:53:35MistInHLS:name-dvr (20368) [FAIL] Logging unclean exit reason: Failed to load HLS playlist, aborting (../build/lib/config.cpp:62)
[09 Feb 2026, 20:53:35MistInHLS:name-dvr (20368) [WARN] Input closing unclean, reason: Failed to load HLS playlist, aborting (../build/src/input/input.cpp:827)
[09 Feb 2026, 20:53:38MistInHLS:name-dvr (20369) [INFO] Input booting (../build/src/input/input.cpp:411)
[09 Feb 2026, 20:53:38MistInHLS:name-dvr (20369) [INFO] Setting program unix start time to '2026-02-09T19:50:54.702Z' (1770666654702) (../build/src/input/input_hls.cpp:1422)
[09 Feb 2026, 20:53:38MistInHLS:name-dvr (20369) [INFO] Adding variant playlist: -> /mnt/network_share/name/name.m3u8 (../build/src/input/input_hls.cpp:199)
[09 Feb 2026, 20:53:38MistInHLS:name-dvr (20369) [INFO] Playlist #1: Adding new segment #24 to playlist entries

Aside from the above: once the DVR stream is started and the DVR stream becomes available, it keeps shutting down due to inactivity while the player in the browser is still loading. Eventually the player receives "stream is offline".
[09 Feb 2026, 21:07:38MistInHLS:name-dvr (20588) [INFO] Booting new session I6c712da801909abb86525a2f87dbb3eaaeb32ea10060195bf34e581ab8db2452 (../build/lib/comms.cpp:392)
[09 Feb 2026, 21:07:38MistSession (20592) [INFO] Started new session I6c712da801909abb86525a2f87dbb3eaaeb32ea10060195bf34e581ab8db2452 in 0.205 ms (../build/src/session.cpp:294)
[09 Feb 2026, 21:07:39MistInHLS:name-dvr (20588) [INFO] Track 1, page 0 (0d00h00m00s.064 - 0d00h00m55s.978) buffered in 733ms (../build/src/input/input.cpp:1740)
[09 Feb 2026, 21:07:39MistInHLS:name-dvr (20588) [INFO] (2621/2621 parts, 1891246 bytes) (../build/src/input/input.cpp:1742)
[09 Feb 2026, 21:07:39MistInHLS:name-dvr (20588) [INFO] Track 0, page 8 (0d00h00m28s.732 - 0d00h00m55s.999) buffered in 262ms (../build/src/input/input.cpp:1740)
[09 Feb 2026, 21:07:39MistInHLS:name-dvr (20588) [INFO] (818/818 parts, 20745345 bytes) (../build/src/input/input.cpp:1742)
[09 Feb 2026, 21:07:54MistSession (20568) [INFO] Logging clean exit reason: Session inactive for 15 seconds (../build/lib/config.cpp:60)
[09 Feb 2026, 21:07:54MistSession (20568) [INFO] Shutting down session I23f916b1866221d84cc4b24a91c95d1353d65e721ab07d71f24fa96c58da34c2: Session inactive for 15 seconds (../build/src/session.cpp:470)
[09 Feb 2026, 21:08:04MistOutMP4:name-dvr (20594) [WARN] Waiting at /MstDatagemhelmcv26-dvr@1_0 byte 1891246 (../build/src/output/output.cpp:2649)
[09 Feb 2026, 21:08:04MistOutMP4:name-dvr (20594) [WARN] Dropping AAC track 1@k0 (nextP=4294967295, lastP=0): EOP: data wait timeout (../build/src/output/output.cpp:2277)
[09 Feb 2026, 21:08:04MistOutMP4:name-dvr (20594) [WARN] Waiting at /MstDatagemhelmcv26-dvr@0_8 byte 20729974 (../build/src/output/output.cpp:2649)
[09 Feb 2026, 21:08:05MistInHLS:name-dvr (20588) [INFO] Track 1, page 0 (0d00h00m00s.064 - 0d00h00m55s.978) buffered in 689ms (../build/src/input/input.cpp:1740)
[09 Feb 2026, 21:08:05MistInHLS:name-dvr (20588) [INFO] (2621/2621 parts, 1891246 bytes) (../build/src/input/input.cpp:1742)
[09 Feb 2026, 21:08:29MistOutMP4:name-dvr (20594) [WARN] Waiting at /MstDatagemhelmcv26-dvr@1_0 byte 1891246 (../build/src/output/output.cpp:2649)
[09 Feb 2026, 21:08:29MistOutMP4:name-dvr (20594) [WARN] Dropping AAC track 1@k0 (nextP=0, lastP=0): EOP: data wait timeout (../build/src/output/output.cpp:2277)
[09 Feb 2026, 21:08:29MistOutMP4:name-dvr (20594) [WARN] Waiting at /MstDatagemhelmcv26-dvr@0_8 byte 20729974 (../build/src/output/output.cpp:2649)
[09 Feb 2026, 21:08:35MistInHLS:name-dvr (20588) [INFO] Logging clean exit reason: no activity for 30s (> 30s)

Browser log:
Schermafbeelding 2026-02-09 213912.png

The general idea for using the DVR config is to create a rewind function on the live stream. Perhaps there is a different way to achieve rewind of about 30min on a live stream? 

With kind regards,
Bart 
Op maandag 9 februari 2026 om 09:22:41 UTC+1 schreef Balder Vietor:

Balder Vietor

unread,
Feb 10, 2026, 4:08:18 AMFeb 10
to Mistserver.org
Hey Bart,

Interesting, that is a use case that should just work. I've copied over the push target you shared and set up my own stream (obviously changed the target location though) and I can verify what you're trying should have worked. With these settings the HLS playlist should keep the last 600 seconds received in buffer, never "close" the playlist (meaning marking it as ended) and re-add to the playlist once it's restarted.
The only "danger" here would be if the stream ends up with different encoding settings between repushes or if the naming scheme would overwrite previous segments from an old stream with the new one. The last one shouldn't really apply unless you're doing multiple repushes within the same minute. 

Now a downside to this method is that because this input has a shifting buffer (segments being added & removed) and it is told to never "close" the playlist it will consider itself a live stream even when no longer updating. This can definitely trigger some time-out behaviours, I'm thinking this combined with the network storage is perhaps causing this. This type of DVR window is mostly meant for 24/7 streams and isn't expected to lose its source for long durations.
If the stream does end at some point I would recommend removing the `noendlist=true` flag, allowing it to close. This would allow you to use the last 600 seconds (with the current setup) as a VoD while the stream is offline. It gets destroyed the moment the stream goes online again to only contain the "new" stream. 

Now the weird part or what seems to be going wrong in your case is that it's claiming it failed to load in the HLS playlist. This should only happen if the playlist is corrupted or linking towards files that are not available in some way. Which is a tad suspicious. I would try out something perhaps a bit non-standard and record into the shared memory storage. This is where MistServer stores most of its stream data in the first place & should serve this usage quite well. The only thing you might want to do is increase the shared memory storage to 70-90% of your RAM as the default is to use a maximum of 50% of your RAM. This setting is harmless as shared memory only uses what it's actually using & these files will delete themselves upon reboot or when the stream continues. 

Try a push target like this:
/tmp/$basename/$yday/$hour/$minute_$segmentCounter.ts?split=24&m3u8=../../$basename.m3u8&targetAge=600&maxEntries=25&noendlist=true&append=true&waittrackcount=1 

Checking shared memory size:
df -h
this should show you all your storage on the server. Then find the line mentioning /dev/shm. It would look similar to this:
tmpfs            16G  251M   16G   2% /dev/shm

You can increase this easily through fstab:
Permanent change to shared memory can be done through fstab.

/etc/fstab should include a line for /dev/shm → Set this to a maximum of 80% of your RAM (You can go higher, but leave at least 10% for your system services to avoid out of memory crashes). 

Example:
tmpfs                   /dev/shm                tmpfs   size=16g        0 0
One-time command, does not persist between boots: 
sudo mount -o remount,size=14G /dev/shm/

If the stream is behaving fine when recording here, that means that there's something in the timing in accessing the network drive, or there might even be moments where it cannot access the drive at all. I would suspect the timing however. If this still fails then the only thing I can imagine messing this up is if the ingest is somehow unreliable and starting/stopping multiple times. HLS playlists do get somewhat broken if they start containing segments not within 10% of the target duration. 

Alternative
As for an alternative, the best way to handle 30 minutes of rewind time on a live stream is to actually just increase the Buffer/DVR window of the live stream itself. This would put all the stream information in RAM as well, which is a much faster storage, assuming you have enough RAM to fit the stream. As an example you'd need ~1gb of Shared memory/RAM available for 730 seconds of 10mbps. Viewers on this stream/buffer do not add to the requirements, so if you do not have many streams needing this buffer size I would recommend just raising the buffer setting for the live stream:
You'd need a buffer of 1800000 for this.

buffertime.png

The only downside here is that buffer does get destroyed if the stream ends. We are planning to add a caching feature to allow streams to exist for longer durations, but we're not quite done with it yet. That would make this use case far easier.

Bart Jenn

unread,
Feb 11, 2026, 8:02:57 AMFeb 11
to Mistserver.org
Hi Balder,

Much appreciated your elaborated response. I'm happy to read that development is planned to add a caching feature.
I've ran through your proposed tests and these worked without any issues. I therefor ruled out MistServer to be the culprit and reconfigured the network share which is used for the DVR storage. After reconfiguration and tweaking, this setup now also works without the errors seen before. Everything is running stable.
(for those who encountered the same, reconfigure your network share to use NFS. It looks like the most stable option for this use case)
My apologies for seeking the problem at the MistServer side. 

Side question; I'm looking into triggers to "misuse" on the event a stream becomes available (e.g. STREAM_READY) to turn on a physical "ON AIR" status light. For the light to turn on, it needs any sensible JSON or FORM ENCODED (preferable custom structure) data via HTTP POST to send by MistServer to my API endpoint (sort of webhook idea). Would triggers be suitable for this or any other creative angle to look at to achieve this?

Example:
# Example with form encoded format curl https://<domain>/v1/devices/0123456789abcdef01234567/on-air \ -d arg=on\ -H "Authorization: Bearer :access_token" # Same example with JSON curl https://<domain>/v1/devices/0123456789abcdef01234567/on-air \ -H "Authorization: Bearer :access_token" \ -H "Content-Type: application/json" \ -d "{\"arg\": \"on\"}"

Best regards,
Bart
Op dinsdag 10 februari 2026 om 10:08:18 UTC+1 schreef Balder Vietor:

Balder Vietor

unread,
Feb 12, 2026, 6:39:08 AMFeb 12
to Mistserver.org
Hey Bart,

Happy you found the issue! And no worries about seeking the problem at MistServers side, any feedback or use-cases help us determine if we should make additional checks or clarify things as well. So even if a problem does not end up at our side it does offer an opportunity to improve our own software/implementation. So I'll make some notes about whether we can check for this and (hopefully) provide a helpful message when errors occur. 

For the side question:
Triggers are absolutely meant for this, but I will have to admit that we are still in the process of updating all triggers to provide JSON data as well. Most of our older ones simply a HTTP post body with the values separated by newlines, I believe STREAM_READY and STREAM_END both falls under this as well. 
I am currently working on the documentation for the triggers, while not completely verified yet (expect spelling mistakes, i do have dyslexia) the page itself might help:

It should at least (hopefully) give an idea on when a trigger fires and which one you'd like to use. 

STREAM_READY specifically sends the following:
stream name (string)
input type (string)

Make sure to use STREAM_END to figure out when the stream goes offline.
stream name (string)
downloaded bytes (integer)
uploaded bytes (integer)
total viewers (integer)
total inputs (integer)
total outputs (integer)
viewer seconds (integer)


Reply all
Reply to author
Forward
0 new messages