How video-use Handles Portrait vs Landscape Source Videos in the Render Pipeline

video-use automatically detects video orientation using ffprobe and switches the FFmpeg scaling dimension to ensure portrait videos scale by height while landscape videos scale by width, preserving aspect ratio without cropping.

The video-use repository provides a Python-based rendering pipeline for automated video editing workflows. When processing mixed-orientation footage, the tool handles portrait versus landscape source videos differently to maintain proper aspect ratios throughout the render pipeline.

Detecting Portrait Orientation with ffprobe

The orientation detection logic resides in helpers/render.py. The function is_portrait_source() executes ffprobe on the first video stream to extract the width and height dimensions, then compares these values to determine if the content is vertical.


# helpers/render.py

def is_portrait_source(video: Path) -> bool:
    """Return True if the video's height > width (portrait / vertical)."""
    ...
    w, h = map(int, out.stdout.strip().split(","))
    return h > w

This utility returns True when the source height exceeds the width, flagging the video as portrait. The detection occurs at lines 134-136 of helpers/render.py and serves as the orientation gate for all subsequent scaling decisions.

Adaptive Scaling Logic in extract_segment

Inside the extract_segment() function, the boolean result from is_portrait_source() controls which dimension is fixed to the target resolution while the other dimension scales proportionally using FFmpeg's -2 placeholder.

The logic branches based on whether the render operates in draft mode (720p) or final/preview mode (1080p):

portrait = is_portrait_source(source)
if draft:
    scale = "scale=-2:1280" if portrait else "scale=1280:-2"
else:
    scale = "scale=-2:1920" if portrait else "scale=1920:-2"

This implementation appears at lines 173-177 of helpers/render.py.

Draft Mode Scaling (720p)

For portrait sources in draft mode, video-use applies scale=-2:1280, locking the height to 1280 pixels while automatically calculating the proportional width. For landscape sources, it uses scale=1280:-2, fixing the width at 1280 pixels.

Final and Preview Mode Scaling (1080p)

In final output or preview generation, the scaling targets 1080p resolution. Portrait videos receive scale=-2:1920 (height-locked), while landscape videos receive scale=1920:-2 (width-locked).

Integrating Orientation-Aware Scaling into the Filter Chain

The chosen scale string is appended to the per-segment filter chain (vf_parts) before the segment undergoes encoding. This ensures that portrait videos render with a fixed height (1080px or 1280px) while landscape videos render with a fixed width (1920px or 1280px).

The rest of the pipeline—including HDR tonemapping, color grading via grade_filter, and audio fades—remains unchanged regardless of orientation. The aspect ratio preservation happens transparently at the scaling stage without affecting downstream processing.

Practical Implementation Examples

To detect a portrait source manually:

from pathlib import Path
from helpers.render import is_portrait_source

video_path = Path("assets/example.mp4")
if is_portrait_source(video_path):
    print("Portrait video – will be scaled by height")
else:
    print("Landscape video – will be scaled by width")

When running the full pipeline, orientation handling is automatic:

python helpers/render.py my_edl.json -o final.mp4

The command executes extract_segment(), which internally calls is_portrait_source() and selects the appropriate scale filter.

Summary

  • Orientation detection occurs via is_portrait_source() in helpers/render.py, which compares ffprobe width and height values.
  • Portrait sources trigger height-locked scaling (scale=-2:1280 for draft, scale=-2:1920 for final) while landscape sources use width-locked scaling (scale=1280:-2 or scale=1920:-2).
  • The extract_segment() function automatically applies the correct FFmpeg scale filter based on the detection result.
  • Per-segment filter chains (vf_parts) incorporate the scale string before encoding, ensuring aspect ratio preservation without stretching or cropping.

Frequently Asked Questions

How does video-use determine if a video is portrait or landscape?

The is_portrait_source() function in helpers/render.py executes ffprobe on the first video stream and parses the width and height values. It returns True when the height exceeds the width, indicating a portrait orientation.

What FFmpeg scale values does video-use use for portrait videos?

For portrait sources, video-use uses scale=-2:1280 in draft mode (720p) and scale=-2:1920 in final or preview mode (1080p). The -2 placeholder instructs FFmpeg to automatically calculate the proportional width while maintaining the original aspect ratio.

Does video-use crop or stretch videos when handling different orientations?

No, video-use never crops or stretches video content. By utilizing FFmpeg's -2 placeholder in the scale filter, the tool ensures the unspecified dimension scales proportionally to the fixed dimension, preserving the original aspect ratio without distortion.

Can I manually override the portrait detection in video-use?

While the pipeline automatically handles orientation detection in helpers/render.py, you could manually specify a scale filter when calling extract_segment() directly. However, this is rarely necessary as the built-in is_portrait_source() logic accurately handles mixed-orientation sources throughout the render pipeline.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →