Skip to content

fix(render): preserve vertical aspect when source is portrait#23

Open
sidorovanthon wants to merge 1 commit intobrowser-use:mainfrom
sidorovanthon:fix/vertical-source-scale
Open

fix(render): preserve vertical aspect when source is portrait#23
sidorovanthon wants to merge 1 commit intobrowser-use:mainfrom
sidorovanthon:fix/vertical-source-scale

Conversation

@sidorovanthon
Copy link
Copy Markdown

@sidorovanthon sidorovanthon commented Apr 30, 2026

Problem

extract_segment in helpers/render.py hardcodes the scale filter to width-anchored:

if draft:
    scale = "scale=1280:-2"
else:
    scale = "scale=1920:-2"

This assumes a landscape source. When the source is portrait (e.g. a phone capture at 1080x1920), the filter upscales width to 1920 and -2 derives height to keep the aspect — producing 1920x3414 output instead of the expected 1080x1920.

This conflicts with the documented vertical social target in SKILL.md:

Common targets: ... 1080×1920@30 vertical social

Reproduction

  1. Source: 1080x1920 @ 60fps h264 (any iPhone/Android vertical capture)
  2. Build a single-range EDL pointing at it
  3. python helpers/render.py edl.json -o final.mp4
  4. ffprobe final.mp4width=1920, height=3414

Fix

Probe the source's width,height once and pick the scale axis from orientation:

  • portrait (height > width): scale=-2:1920 (or -2:1280 for draft)
  • landscape: unchanged (scale=1920:-2 / scale=1280:-2)

13 lines added in extract_segment, no behavior change for landscape sources.

Verified on a 1080x1920 70s clip: output is now 1080x1920 @ 24fps as expected, matching the documented spec.

Notes

Found while running video-use end-to-end on Windows with a vertical phone capture as part of normal usage — not synthesized for the PR.


Summary by cubic

Fixes scaling for portrait sources so exported video keeps the correct vertical aspect. Portrait clips now render as 1080x1920 in final and 720x1280 in draft, matching the SKILL.md vertical social target.

  • Bug Fixes
    • Detects orientation via ffprobe (reads width,height).
    • Applies scale=-2:1920 (or -2:1280 in draft) for portrait; keeps 1920:-2/1280:-2 for landscape.
    • Prevents over-tall outputs like 1920x3414; no change for landscape sources.

Written for commit d0b6989. Summary will update on new commits. Review in cubic

The scale filter in extract_segment hardcoded scale=1920:-2 (or
scale=1280:-2 in draft mode), which assumes a landscape source. Given
a portrait source like 1080x1920 from a phone, this upscaled width to
1920 and pushed height to 3414, producing an off-spec 1920x3414 output
instead of the expected 1080x1920.

Probe the source with ffprobe and pick the scale axis from orientation:
- portrait (h > w): scale=-2:1920 / scale=-2:1280
- landscape:        scale=1920:-2 / scale=1280:-2

This keeps native portrait sources at 1080x1920 in final/preview and
720x1280 in draft, matching the documented vertical social target in
SKILL.md.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="helpers/render.py">

<violation number="1" location="helpers/render.py:157">
P1: Portrait detection ignores rotation metadata, so rotated portrait phone clips can still be treated as landscape and scaled incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread helpers/render.py
Comment on lines +157 to +167
probe = subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_entries", "stream=width,height",
"-of", "csv=p=0:s=x", str(source)],
capture_output=True, text=True,
)
try:
sw, sh = (int(x) for x in probe.stdout.strip().split("x")[:2])
is_vertical = sh > sw
except Exception:
is_vertical = False
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Portrait detection ignores rotation metadata, so rotated portrait phone clips can still be treated as landscape and scaled incorrectly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At helpers/render.py, line 157:

<comment>Portrait detection ignores rotation metadata, so rotated portrait phone clips can still be treated as landscape and scaled incorrectly.</comment>

<file context>
@@ -154,10 +154,21 @@ def extract_segment(
     """
     out_path.parent.mkdir(parents=True, exist_ok=True)
 
+    probe = subprocess.run(
+        ["ffprobe", "-v", "error", "-select_streams", "v:0",
+         "-show_entries", "stream=width,height",
</file context>
Suggested change
probe = subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_entries", "stream=width,height",
"-of", "csv=p=0:s=x", str(source)],
capture_output=True, text=True,
)
try:
sw, sh = (int(x) for x in probe.stdout.strip().split("x")[:2])
is_vertical = sh > sw
except Exception:
is_vertical = False
try:
probe = subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_streams", "-of", "json", str(source)],
capture_output=True, text=True, check=True,
)
stream = json.loads(probe.stdout)["streams"][0]
sw = int(stream["width"])
sh = int(stream["height"])
rotation = int(stream.get("tags", {}).get("rotate", 0) or 0)
for sd in stream.get("side_data_list", []):
rotation = int(sd.get("rotation", rotation) or rotation)
is_vertical = (rotation % 180 != 0) or (sh > sw)
except Exception:
print("warning: could not detect source orientation; defaulting to landscape", file=sys.stderr)
is_vertical = False
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant