Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 70 additions & 2 deletions reference_importer_main/imageSequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@
from pathlib import Path

TIMECODE_REGEX = r"Duration: (\d{2}:\d{2}:\d{2}.\d)"

DIMENSIONS_SIZE_REGEX = r"Video.*[ ,](\d+)x(\d+)(,| \[)"
DIMENSIONS_SAR_REGEX = r"Video.*SAR (\d+):(\d+)"
DIMENSIONS_DAR_REGEX = r"Video.*DAR (\d+):(\d+)"
ROTATION_90_REGEX = r"displaymatrix.*90.*degrees"

class FfmpegError(Exception):
...

class MissingFfmpeg(FfmpegError):
...

class Dimensions:
w: int
h: int
sar_w: int
sar_h: int
dar_w: int
dar_h: int

class ImageSequencer:
def __init__(
Expand Down Expand Up @@ -91,6 +101,61 @@ def get_duration(self, video_file: str) -> str:
duration: str = str(match.groups(0)[0])
return duration

def get_dimensions(self, video_file: str) -> Dimensions:
"""Gets the dimensions of the video from the output of ffmpeg -i.

Args:
video_file: Video file.

Raises:
FfmpegError: If ffmpeg errors out and does not yield an output.
ValueError: If there is no match for the dimensions in ffmpeg's output.

Returns:
Dimensions of the video.
"""
command = f'"{self.ffmpeg_path}" -i "{video_file}"'
try:
output = str(
subprocess.run(
command,
shell=True,
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE,
check=False,
),
)

except subprocess.CalledProcessError as e:
_except_msg: str = "Unable to get ffmpeg output"
raise FfmpegError(_except_msg) from e

# re.search searches across the whole string (multiline output).
match: re.Match | None = re.search(DIMENSIONS_SIZE_REGEX, output)

if not match:
_except_msg: str = f"Unable to find Dimensions for video {video_file}"
raise ValueError(_except_msg)

dimensions = Dimensions()
dimensions.w = int(match.groups(0)[0])
dimensions.h = int(match.groups(0)[1])

match: re.Match | None = re.search(DIMENSIONS_SAR_REGEX, output)
dimensions.sar_w = int(match.groups(0)[0]) if match else 1
dimensions.sar_h = int(match.groups(0)[1]) if match else 1

match: re.Match | None = re.search(DIMENSIONS_DAR_REGEX, output)
dimensions.dar_w = int(match.groups(0)[0]) if match else 1
dimensions.dar_h = int(match.groups(0)[1]) if match else 1

# Swap w and h if we find rotation information
match: re.Match | None = re.search(ROTATION_90_REGEX, output)
if match:
dimensions.w, dimensions.h = dimensions.h, dimensions.w

return dimensions

def create_sequence(
self,
input_file: str,
Expand All @@ -99,9 +164,12 @@ def create_sequence(
end_trim: str,
output_file: str,
):
dimensions = self.get_dimensions(input_file)
scale_x = dimensions.w
scale_y = round(dimensions.h * (float(dimensions.sar_h) / float(dimensions.sar_w)))
command = (
f'"{self.ffmpeg_path}" -i "{input_file}" -r {frame_rate}'
f" -vf scale=1280:-1 -q:v 3 -ss {start_trim} -to {end_trim} "
f" -vf scale={scale_x}:{scale_y} -q:v 3 -ss {start_trim} -to {end_trim} "
f'"{output_file}"'
)
try:
Expand Down