Spaces:
Running
Running
[ffmpeg-restream] monotonic seq (PR #64)
Browse files- ffmpeg_relay.py +17 -2
ffmpeg_relay.py
CHANGED
|
@@ -64,6 +64,7 @@ class FfmpegRelay:
|
|
| 64 |
self.started_at = time.time()
|
| 65 |
self.failures = 0
|
| 66 |
self.restarting = False
|
|
|
|
| 67 |
self.resolved = _resolve_redirect(url, self._headers_dict())
|
| 68 |
self._ensure_dir()
|
| 69 |
|
|
@@ -167,12 +168,26 @@ class FfmpegRelay:
|
|
| 167 |
self.restarting = False
|
| 168 |
|
| 169 |
def playlist_text(self):
|
| 170 |
-
"""Return current playlist content (empty string if relay warming up).
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
try:
|
| 172 |
with open(self.playlist, "r", encoding="utf-8") as f:
|
| 173 |
-
|
| 174 |
except Exception:
|
| 175 |
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
|
| 177 |
def segment(self, name):
|
| 178 |
"""Return (bytes, status) for a local segment file."""
|
|
|
|
| 64 |
self.started_at = time.time()
|
| 65 |
self.failures = 0
|
| 66 |
self.restarting = False
|
| 67 |
+
self.last_served_seq = -1
|
| 68 |
self.resolved = _resolve_redirect(url, self._headers_dict())
|
| 69 |
self._ensure_dir()
|
| 70 |
|
|
|
|
| 168 |
self.restarting = False
|
| 169 |
|
| 170 |
def playlist_text(self):
|
| 171 |
+
"""Return current playlist content (empty string if relay warming up).
|
| 172 |
+
MEDIA-SEQUENCE is served monotonically non-decreasing across restarts:
|
| 173 |
+
if ffmpeg restarted and reset sequence to 0, we bump it to
|
| 174 |
+
last_served_seq+1 so hls.js never sees a backward jump (which causes
|
| 175 |
+
a discontinuity error -> brief giât at exactly the restart moments)."""
|
| 176 |
try:
|
| 177 |
with open(self.playlist, "r", encoding="utf-8") as f:
|
| 178 |
+
text = f.read()
|
| 179 |
except Exception:
|
| 180 |
return ""
|
| 181 |
+
m = re.search(r"#EXT-X-MEDIA-SEQUENCE:(\d+)", text)
|
| 182 |
+
if m:
|
| 183 |
+
seq = int(m.group(1))
|
| 184 |
+
if seq < self.last_served_seq:
|
| 185 |
+
seq = self.last_served_seq
|
| 186 |
+
# keep serving a forward-moving sequence
|
| 187 |
+
self.last_served_seq = max(self.last_served_seq, seq)
|
| 188 |
+
text = text.replace("#EXT-X-MEDIA-SEQUENCE:%d" % int(m.group(1)),
|
| 189 |
+
"#EXT-X-MEDIA-SEQUENCE:%d" % self.last_served_seq, 1)
|
| 190 |
+
return text
|
| 191 |
|
| 192 |
def segment(self, name):
|
| 193 |
"""Return (bytes, status) for a local segment file."""
|