From be7a9cd1fae20895a2b1a8d831fbde8a0b1bd21c Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 26 Nov 2023 15:14:43 +1100 Subject: [PATCH] restreamer: Make media playlist streamed To deal better with very large playlists --- restreamer/restreamer/generate_hls.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/restreamer/restreamer/generate_hls.py b/restreamer/restreamer/generate_hls.py index dc92160..dd7cd9d 100644 --- a/restreamer/restreamer/generate_hls.py +++ b/restreamer/restreamer/generate_hls.py @@ -36,6 +36,8 @@ def generate_media(segments, base_url): """Generate a media playlist from a list of segments as returned by common.get_best_segments(). Segments are specified as hour/name.ts relative to base_url. """ + # segments may be an iterator, make it reusable + segments = list(segments) # We have to pick a "target duration". in most circumstances almost all segments # will be of that duration, so we get the most common duration out of all the segments @@ -48,10 +50,8 @@ def generate_media(segments, base_url): else: target_duration = datetime.timedelta(seconds=6) - lines = [ - "#EXTM3U", - "#EXT-X-TARGETDURATION:{:.3f}".format(target_duration.total_seconds()), - ] + yield "#EXTM3U\n" + yield "#EXT-X-TARGETDURATION:{:.3f}\n".format(target_duration.total_seconds()) # Note and remove any trailing None from the segment list - this indicates there is a hole # at the end, which means we should mark the stream as incomplete but not include a discontinuity. @@ -74,18 +74,19 @@ def generate_media(segments, base_url): # and it should start decoding fresh on the next segment. This is required when # someone stops/starts a stream and a good idea if we're missing a segment in a # continuous stream. - lines.append("#EXT-X-DISCONTINUITY") + yield "#EXT-X-DISCONTINUITY\n" else: # Each segment has two prefixes: timestamp and duration. # This tells the client exactly what time the segment represents, which is important # for the editor since it needs to describe cut points in these times. path = '/'.join(segment.path.split('/')[-2:]) - lines.append("#EXT-X-PROGRAM-DATE-TIME:{}".format(segment.start.strftime("%Y-%m-%dT%H:%M:%S.%fZ"))) - lines.append("#EXTINF:{:.3f},live".format(segment.duration.total_seconds())) - lines.append(urllib.parse.quote(os.path.join(base_url, path))) + lines = [ + "#EXT-X-PROGRAM-DATE-TIME:{}".format(segment.start.strftime("%Y-%m-%dT%H:%M:%S.%fZ")), + "#EXTINF:{:.3f},live".format(segment.duration.total_seconds()), + urllib.parse.quote(os.path.join(base_url, path)), + ] + yield "\n".join(lines) + "\n" # If stream is complete, add an ENDLIST marker to show this. if not incomplete: - lines.append("#EXT-X-ENDLIST") - - return "\n".join(lines) + '\n' + yield "#EXT-X-ENDLIST\n"