Add ability to crop videos

Full cuts only. Uploads just the cropped area. This can be used to make youtube "shorts".
mike/cropping
Mike Lang 2 years ago
parent 8e314eea94
commit d91e85ea47

@ -181,6 +181,7 @@ columns | type | role
`public` | `BOOLEAN NOT NULL DEFAULT TRUE` | edit input | Whether the uploaded video should be public or not, if the upload location supports that distinction. For example, on youtube, non-public videos are "unlisted". It also controls whether the video will be added to playlists, only public videos are added to playlists.
`video_ranges` | `{start TIMESTAMP, end TIMESTAMP}[]` | edit input | A non-zero number of start and end times, describing the ranges of video to cut. They will be cut back-to-back in the given order, with the transitions between as per `video_transitions`. If already set, used as the default range settings when editing.
`video_transitions` | `{type TEXT, duration INTERVAL}[]` | edit input | Defines how to transition between each range defined in `video_ranges`, and must be exactly the length of `video_ranges` minus 1. Each index in `video_transitions` defines the transition between the range with the same index in `video_ranges` and the next one. Transitions either specify a transition type as understood by `ffmpeg`'s `xfade` filter and a duration (amount of overlap), or can be NULL to indicate a hard cut.
`video_crop` | `{x, y, w, h INTEGER}` | edit input | If given, defines how the video should be cropped when editing.
`video_title` | `TEXT` | edit input | The title of the video. If already set, used as the default title when editing instead of `description`.
`video_description` | `TEXT` | edit input | The description field of the video. If already set, used as the default description when editing instead of `description`.
`video_tags` | `TEXT[]` | edit input | Custom tags to annotate the video with. If already set, used as the default when editing instead of `tags`.

@ -63,6 +63,7 @@ CUT_JOB_PARAMS = [
"public",
"video_ranges",
"video_transitions",
"video_crop",
"video_title",
"video_description",
"video_tags",
@ -400,12 +401,20 @@ class Cutter(object):
self.logger.debug("No encoding settings, using fast cut")
if any(transition is not None for transition in job.video_transitions):
raise ValueError("Fast cuts do not support complex transitions")
if job.video_crop is not None:
raise ValueError("Fast cuts do not support cropping")
cut = fast_cut_segments(job.segment_ranges, job.video_ranges)
else:
self.logger.debug("Using encoding settings for {} cut: {}".format(
"streamable" if upload_backend.encoding_streamable else "non-streamable",
upload_backend.encoding_settings,
))
encode_args = upload_backend.encoding_settings
if job.video_crop:
x, y, w, h = job.video_crop
encode_args = [
"-vf", "crop={}:{}:{}:{}".format(w, h, x, y)
] + encode_args
if len(job.video_ranges) > 1:
raise ValueError("Full cuts do not support multiple ranges")
range = job.video_ranges[0]

@ -64,6 +64,13 @@ CREATE TYPE thumbnail_mode as ENUM (
'CUSTOM'
);
CREATE TYPE box as (
x INTEGER,
y INTEGER,
w INTEGER,
h INTEGER
)
CREATE TABLE events (
id UUID PRIMARY KEY,
@ -88,6 +95,7 @@ CREATE TABLE events (
(video_ranges IS NULL AND video_transitions IS NULL)
OR CARDINALITY(video_ranges) = CARDINALITY(video_transitions) + 1
),
video_crop box,
video_title TEXT CHECK (state IN ('UNEDITED', 'DONE') OR video_title IS NOT NULL),
video_description TEXT CHECK (state IN ('UNEDITED', 'DONE') OR video_description IS NOT NULL),
video_tags TEXT[] CHECK (state IN ('UNEDITED', 'DONE') OR video_tags IS NOT NULL),

@ -242,6 +242,7 @@ def update_row(ident, editor=None):
]
edit_columns = non_null_columns + [
'allow_holes', 'uploader_whitelist', 'thumbnail_time', 'thumbnail_template', 'thumbnail_image'
'video_crop'
]
sheet_columns = [
'sheet_name', 'event_start', 'event_end',
@ -337,6 +338,8 @@ def update_row(ident, editor=None):
None if transition is None else tuple(transition)
for transition in new_row['video_transitions']
]
if new_row.get('video_crop') is not None:
new_row['video_crop'] = tuple(new_row['video_crop'])
# Convert binary fields from base64 and do basic validation of contents
if new_row.get('thumbnail_image') is not None:

Loading…
Cancel
Save