Adding fixes to renderer
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
"""[end:handle] explicit end markers: a video started with end_on=end_marker
|
||||
stops at the first [end:handle] placed after it."""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from gnommo.transformer import _extract_video_events, MarkerTiming
|
||||
from gnommo.models import VideoSource, CutoutDefinition
|
||||
|
||||
|
||||
def check(name, cond):
|
||||
print(f" {'PASS' if cond else 'FAIL'} {name}")
|
||||
assert cond, name
|
||||
|
||||
|
||||
VIDEOS = {"fart": VideoSource(source_file="fart.mp4", cutout="fullscreen", layer="below")}
|
||||
CUTOUTS = {"fullscreen": CutoutDefinition(x=0, y=0, height=1080, width=1920)}
|
||||
|
||||
|
||||
def mt(mid, t, ov=None):
|
||||
return MarkerTiming(mid, t, "text", 1.0, ov)
|
||||
|
||||
|
||||
# 1. [vfb:fart, end_on=end_marker] @10 ; [end:fart] @25 → ends at 25
|
||||
events, warns = _extract_video_events(
|
||||
[mt("vfb:fart", 10.0, {"end_on": "end_marker"}), mt("end:fart", 25.0)],
|
||||
VIDEOS, CUTOUTS, {}, 100.0,
|
||||
)
|
||||
check("[end:fart] is not itself a video event", len(events) == 1)
|
||||
check("video starts at 10.0", abs(events[0].start_time - 10.0) < 1e-6)
|
||||
check("video ends at the [end:fart] marker (25.0)", abs(events[0].end_time - 25.0) < 1e-6)
|
||||
check("no warnings", not warns)
|
||||
|
||||
# 2. earliest [end:fart] AFTER the start wins; an earlier one is ignored (reuse handle)
|
||||
events2, _ = _extract_video_events(
|
||||
[
|
||||
mt("end:fart", 5.0), # before start → ignored
|
||||
mt("vfb:fart", 10.0, {"end_on": "end_marker"}),
|
||||
mt("end:fart", 20.0), # first after start
|
||||
mt("end:fart", 40.0),
|
||||
],
|
||||
VIDEOS, CUTOUTS, {}, 100.0,
|
||||
)
|
||||
check("uses first end marker after start (20.0)", abs(events2[0].end_time - 20.0) < 1e-6)
|
||||
|
||||
# 3. fallback: end_on=end_marker but no [end:fart] → next video + warning
|
||||
videos3 = {**VIDEOS, "other": VideoSource(source_file="o.mp4", cutout="square")}
|
||||
cutouts3 = {**CUTOUTS, "square": CutoutDefinition(x=0, y=0, height=864, width=864)}
|
||||
events3, warns3 = _extract_video_events(
|
||||
[mt("vfb:fart", 10.0, {"end_on": "end_marker"}), mt("vst:other", 30.0)],
|
||||
videos3, cutouts3, {}, 100.0,
|
||||
)
|
||||
fart_ev = next(e for e in events3 if e.video_id == "fart")
|
||||
check("fallback ends at next video (30.0)", abs(fart_ev.end_time - 30.0) < 1e-6)
|
||||
check("warns about the missing [end:fart]", any("end_on=end_marker" in w for w in warns3))
|
||||
|
||||
print("\nAll [end:handle] tests passed.")
|
||||
@@ -0,0 +1,42 @@
|
||||
"""CSS-like cutout placement: object-fit (cover/contain) + object-position."""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from gnommo.renderer import _fit_filter
|
||||
|
||||
|
||||
def check(name, cond):
|
||||
print(f" {'PASS' if cond else 'FAIL'} {name}")
|
||||
assert cond, name
|
||||
|
||||
|
||||
# Defaults reproduce the long-standing cover+center string exactly (no render churn).
|
||||
check(
|
||||
"cover/center == legacy scale+crop",
|
||||
_fit_filter(864, 864, 1.0, "cover", "center")
|
||||
== "scale=864:864:force_original_aspect_ratio=increase,crop=864:864:(iw-864)/2:(ih-864)/2",
|
||||
)
|
||||
check(
|
||||
"cover applies zoom",
|
||||
_fit_filter(864, 864, 1.5, "cover", "center").startswith("scale=1296:1296:"),
|
||||
)
|
||||
|
||||
# cover anchors the crop by position.
|
||||
check("cover/top crops from bottom (y=0)", ":(iw-864)/2:0" in _fit_filter(864, 864, 1.0, "cover", "top"))
|
||||
check("cover/bottom (y=ih-H)", ":(iw-864)/2:(ih-864)" in _fit_filter(864, 864, 1.0, "cover", "bottom"))
|
||||
check("cover/left (x=0)", "crop=864:864:0:(ih-864)/2" in _fit_filter(864, 864, 1.0, "cover", "left"))
|
||||
check("cover/right (x=iw-W)", "crop=864:864:(iw-864):(ih-864)/2" in _fit_filter(864, 864, 1.0, "cover", "right"))
|
||||
|
||||
# contain shrinks to fit and pads; position places the padded video.
|
||||
check(
|
||||
"contain/top fits inside, pads to top",
|
||||
_fit_filter(864, 864, 1.0, "contain", "top")
|
||||
== "scale=864:864:force_original_aspect_ratio=decrease,pad=864:864:(ow-iw)/2:0:color=0x00000000",
|
||||
)
|
||||
check("contain ignores zoom", "scale=864:864:" in _fit_filter(864, 864, 2.0, "contain", "center"))
|
||||
check("contain/bottom pads to bottom", ":(ow-iw)/2:(oh-ih):" in _fit_filter(864, 864, 1.0, "contain", "bottom"))
|
||||
check("contain/left pads to left", "pad=864:864:0:(oh-ih)/2" in _fit_filter(864, 864, 1.0, "contain", "left"))
|
||||
|
||||
print("\nAll object-fit/object-position tests passed.")
|
||||
Reference in New Issue
Block a user