From 07d1d2ed7817c83b7310bc3b7653c2b379bc2172 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Mon, 10 Oct 2022 05:55:17 +1100 Subject: [PATCH] restreamer: Allow cropping and scaling for full cuts to enable vertical video. This lets us create YT Shorts or similar videos and download them. --- restreamer/restreamer/main.py | 16 ++++++++++++++++ thrimbletrimmer/edit.html | 1 + thrimbletrimmer/scripts/edit.js | 10 +++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/restreamer/restreamer/main.py b/restreamer/restreamer/main.py index 1e66e16..d437cab 100644 --- a/restreamer/restreamer/main.py +++ b/restreamer/restreamer/main.py @@ -314,6 +314,16 @@ def cut(channel, quality): return "We have no content available within the requested time range.", 406 segment_ranges.append(segments) + crop = None + if crop in request.args: + if type not in ('mpegts', 'mp4'): + return "Crop can only be given for full cuts", 400 + try: + x, y, width, height = [int(n) for n in request.args['crop'].split(',')] + except ValueError: + return "Bad crop value", 400 + crop = x, y, width, height + type = request.args.get('type', 'fast') if type == 'rough': return Response(rough_cut_segments(segment_ranges, ranges), mimetype='video/MP2T') @@ -327,6 +337,12 @@ def cut(channel, quality): encoding_args = ['-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '0', '-f', muxer] if len(ranges) > 1: return "full cut does not support multiple ranges at this time", 400 + if crop is not None: + x, y, w, h = crop + encoding_args = [ + "-vf", + "crop={}:{}:{}:{},scale=1080:1920".format(w, h, x, y), + ] start, end = ranges[0] return Response(full_cut_segments(segment_ranges[0], start, end, encoding_args, stream=stream), mimetype=mimetype) else: diff --git a/thrimbletrimmer/edit.html b/thrimbletrimmer/edit.html index 508c0dc..19b3b78 100644 --- a/thrimbletrimmer/edit.html +++ b/thrimbletrimmer/edit.html @@ -283,6 +283,7 @@ + Download Video Download Current Frame as Image diff --git a/thrimbletrimmer/scripts/edit.js b/thrimbletrimmer/scripts/edit.js index 43fd2b9..5a1034b 100644 --- a/thrimbletrimmer/scripts/edit.js +++ b/thrimbletrimmer/scripts/edit.js @@ -304,6 +304,9 @@ window.addEventListener("DOMContentLoaded", async (event) => { document.getElementById("download-type-select").addEventListener("change", () => { updateDownloadLink(); }); + document.getElementById("download-crop").addEventListener("change", () => { + updateDownloadLink(); + }); document.getElementById("download-frame").addEventListener("click", (_event) => { downloadFrame(); @@ -1078,8 +1081,11 @@ function handleLeavePageWhilePending(event) { return event.returnValue; } -function generateDownloadURL(timeRanges, downloadType, allowHoles, quality) { +function generateDownloadURL(timeRanges, downloadType, allowHoles, crop, quality) { const queryParts = [`type=${downloadType}`, `allow_holes=${allowHoles}`]; + if (crop != "" && downloadType === "mpegts") { + queryParts.push(`crop=${crop}`); + } for (const range of timeRanges) { let timeRangeString = ""; if (range.hasOwnProperty("start")) { @@ -1099,6 +1105,7 @@ function generateDownloadURL(timeRanges, downloadType, allowHoles, quality) { function updateDownloadLink() { const downloadType = document.getElementById("download-type-select").value; const allowHoles = document.getElementById("advanced-submission-option-allow-holes").checked; + const crop = document.getElementById("download-crop").value const timeRanges = []; for (const rangeContainer of document.getElementById("range-definitions").children) { @@ -1120,6 +1127,7 @@ function updateDownloadLink() { timeRanges, downloadType, allowHoles, + crop, videoInfo.video_quality ); document.getElementById("download-link").href = downloadURL;