restreamer: Allow cropping and scaling for full cuts

to enable vertical video. This lets us create YT Shorts or similar videos and download them.
mike/shorts
Mike Lang 2 years ago
parent 8ea985c07a
commit 07d1d2ed78

@ -314,6 +314,16 @@ def cut(channel, quality):
return "We have no content available within the requested time range.", 406 return "We have no content available within the requested time range.", 406
segment_ranges.append(segments) 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') type = request.args.get('type', 'fast')
if type == 'rough': if type == 'rough':
return Response(rough_cut_segments(segment_ranges, ranges), mimetype='video/MP2T') 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] encoding_args = ['-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '0', '-f', muxer]
if len(ranges) > 1: if len(ranges) > 1:
return "full cut does not support multiple ranges at this time", 400 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] start, end = ranges[0]
return Response(full_cut_segments(segment_ranges[0], start, end, encoding_args, stream=stream), mimetype=mimetype) return Response(full_cut_segments(segment_ranges[0], start, end, encoding_args, stream=stream), mimetype=mimetype)
else: else:

@ -283,6 +283,7 @@
</option> </option>
<option value="mpegts">MPEG-TS (slow, consumes server resources)</option> <option value="mpegts">MPEG-TS (slow, consumes server resources)</option>
</select> </select>
<input type="text" id="download-crop" />
<a id="download-link">Download Video</a> <a id="download-link">Download Video</a>
<a href="#" id="download-frame">Download Current Frame as Image</a> <a href="#" id="download-frame">Download Current Frame as Image</a>
</div> </div>

@ -304,6 +304,9 @@ window.addEventListener("DOMContentLoaded", async (event) => {
document.getElementById("download-type-select").addEventListener("change", () => { document.getElementById("download-type-select").addEventListener("change", () => {
updateDownloadLink(); updateDownloadLink();
}); });
document.getElementById("download-crop").addEventListener("change", () => {
updateDownloadLink();
});
document.getElementById("download-frame").addEventListener("click", (_event) => { document.getElementById("download-frame").addEventListener("click", (_event) => {
downloadFrame(); downloadFrame();
@ -1078,8 +1081,11 @@ function handleLeavePageWhilePending(event) {
return event.returnValue; return event.returnValue;
} }
function generateDownloadURL(timeRanges, downloadType, allowHoles, quality) { function generateDownloadURL(timeRanges, downloadType, allowHoles, crop, quality) {
const queryParts = [`type=${downloadType}`, `allow_holes=${allowHoles}`]; const queryParts = [`type=${downloadType}`, `allow_holes=${allowHoles}`];
if (crop != "" && downloadType === "mpegts") {
queryParts.push(`crop=${crop}`);
}
for (const range of timeRanges) { for (const range of timeRanges) {
let timeRangeString = ""; let timeRangeString = "";
if (range.hasOwnProperty("start")) { if (range.hasOwnProperty("start")) {
@ -1099,6 +1105,7 @@ function generateDownloadURL(timeRanges, downloadType, allowHoles, quality) {
function updateDownloadLink() { function updateDownloadLink() {
const downloadType = document.getElementById("download-type-select").value; const downloadType = document.getElementById("download-type-select").value;
const allowHoles = document.getElementById("advanced-submission-option-allow-holes").checked; const allowHoles = document.getElementById("advanced-submission-option-allow-holes").checked;
const crop = document.getElementById("download-crop").value
const timeRanges = []; const timeRanges = [];
for (const rangeContainer of document.getElementById("range-definitions").children) { for (const rangeContainer of document.getElementById("range-definitions").children) {
@ -1120,6 +1127,7 @@ function updateDownloadLink() {
timeRanges, timeRanges,
downloadType, downloadType,
allowHoles, allowHoles,
crop,
videoInfo.video_quality videoInfo.video_quality
); );
document.getElementById("download-link").href = downloadURL; document.getElementById("download-link").href = downloadURL;

Loading…
Cancel
Save