feat: retain streaming media and add opt-in automatic quality
This commit is contained in:
+21
-3
@@ -32,6 +32,9 @@ class StreamingServer:
|
||||
headers = {
|
||||
"av.mp4": "combined",
|
||||
"streaming.mp4": "combined",
|
||||
"cache.mp4": "combined",
|
||||
"quality-1080.mp4": "combined",
|
||||
"quality-720.mp4": "combined",
|
||||
"frame-step.mp4": "combined",
|
||||
"video.mp4": "video",
|
||||
"frame-step-video.mp4": "video",
|
||||
@@ -134,6 +137,19 @@ class StreamingServer:
|
||||
self.prefixes[key] = {kind: min(end, first_missing[kind]) for kind, end in ends.items()}
|
||||
return self.prefixes[key]
|
||||
|
||||
def _timestamp_offset(self, name: str, seconds: float) -> int:
|
||||
probe = subprocess.run(
|
||||
["ffprobe", "-v", "error", "-show_packets", "-show_format",
|
||||
"-show_entries", "format=start_time:packet=pts_time,pos", "-of", "json",
|
||||
str(self.fixtures / name)],
|
||||
capture_output=True, text=True, check=True, timeout=30,
|
||||
)
|
||||
metadata = json.loads(probe.stdout)
|
||||
origin = float(metadata.get("format", {}).get("start_time", 0))
|
||||
return min(int(packet["pos"]) for packet in metadata["packets"]
|
||||
if "pos" in packet and "pts_time" in packet
|
||||
and float(packet["pts_time"]) - origin >= seconds)
|
||||
|
||||
def _get(self, request):
|
||||
parsed = urlsplit(request.path)
|
||||
parts = unquote(parsed.path).strip("/").split("/")
|
||||
@@ -206,8 +222,10 @@ class StreamingServer:
|
||||
if token is not None:
|
||||
query = parse_qs(parsed.query)
|
||||
try:
|
||||
gate_at = int(query.get("after", ["131072"])[0]) if mode == "stall" else start
|
||||
except ValueError:
|
||||
gate_at = (self._timestamp_offset(name, float(query["after_seconds"][0]))
|
||||
if mode == "stall" and "after_seconds" in query else
|
||||
int(query.get("after", ["131072"])[0]) if mode == "stall" else start)
|
||||
except (ValueError, OverflowError):
|
||||
self._reply(request, 400, b"Invalid gate offset", "text/plain")
|
||||
return
|
||||
with self.lock:
|
||||
@@ -270,7 +288,7 @@ def main():
|
||||
parser.add_argument("fixtures", type=Path)
|
||||
args = parser.parse_args()
|
||||
required = ("av.mp4", "video.mp4", "audio.wav", "frame-step-video.mp4",
|
||||
"frame-step-audio.m4a", "streaming.mp4", "network-vod.m3u8")
|
||||
"frame-step-audio.m4a", "streaming.mp4", "cache.mp4", "network-vod.m3u8")
|
||||
missing = [name for name in required if not (args.fixtures / name).is_file()]
|
||||
if missing:
|
||||
parser.error("Missing streaming fixtures: " + ", ".join(missing))
|
||||
|
||||
Reference in New Issue
Block a user