studio / renderer /ffmpeg /normalize.py
Ava2lon's picture
Upload 170 files
345855e verified
Raw
History Blame
3.06 kB
from __future__ import annotations
from pathlib import Path
from renderer.core.config import Settings
from renderer.core.models import AssetMetadata
from renderer.ffmpeg.command import FFmpegCommand
from renderer.ffmpeg.runner import FFmpegRunner
from renderer.templates import PlatformProfile
class Normalizer:
def __init__(self, settings: Settings, runner: FFmpegRunner) -> None:
self.settings = settings
self.runner = runner
def needs_normalization(self, metadata: AssetMetadata, profile: PlatformProfile | None = None) -> bool:
width = profile.width if profile else self.settings.output_width
height = profile.height if profile else self.settings.output_height
fps = profile.fps if profile else self.settings.output_fps
return not (
metadata.width == width
and metadata.height == height
and round(metadata.fps or 0) == fps
and metadata.video_codec == "h264"
and (metadata.audio_codec in ("aac", None))
)
def normalize(self, path: str | Path, output: Path, duration: float | None = None, profile: PlatformProfile | None = None) -> Path:
width = profile.width if profile else self.settings.output_width
height = profile.height if profile else self.settings.output_height
fps = profile.fps if profile else self.settings.output_fps
crf = profile.crf if profile else self.settings.crf
vf = (
f"scale={width}:{height}:"
"force_original_aspect_ratio=increase,"
f"crop={width}:{height},"
f"fps={fps},format=yuv420p"
)
cmd = (
FFmpegCommand()
.add("-hide_banner")
.input(path)
.add("-vf", vf, "-c:v", "libx264", "-preset", self.settings.preset, "-crf", crf)
.add("-c:a", "aac", "-b:a", "128k", "-movflags", "+faststart")
)
if duration:
cmd.add("-t", duration)
command = cmd.overwrite().add(output).build()
self.runner.run(command)
return output
def image_to_video(self, path: str | Path, output: Path, duration: float, profile: PlatformProfile | None = None) -> Path:
width = profile.width if profile else self.settings.output_width
height = profile.height if profile else self.settings.output_height
fps = profile.fps if profile else self.settings.output_fps
crf = profile.crf if profile else self.settings.crf
vf = (
f"scale={width}:{height}:"
"force_original_aspect_ratio=increase,"
f"crop={width}:{height},"
f"fps={fps},format=yuv420p"
)
command = (
FFmpegCommand()
.add("-hide_banner", "-loop", "1", "-t", duration)
.input(path)
.add("-vf", vf, "-an", "-c:v", "libx264", "-preset", self.settings.preset, "-crf", crf)
.overwrite()
.add(output)
.build()
)
self.runner.run(command)
return output