Skip to content

feat(slicing): slice_video — cut clips by time range with optional square resize#6

Merged
AmitMY merged 5 commits into
mainfrom
feat-slice-video
Jul 1, 2026
Merged

feat(slicing): slice_video — cut clips by time range with optional square resize#6
AmitMY merged 5 commits into
mainfrom
feat-slice-video

Conversation

@AmitMY

@AmitMY AmitMY commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Adds slice_video, requested for the sign-inference gateway so the cut+transform lives in the shared lib instead of being reimplemented per service.

from simple_video_utils.slicing import slice_video

# One MP4 (bytes) per (start, end) second range
clips = slice_video("video.mp4", [(0.0, 1.5), (2.0, 3.2)])

# Center-crop to a square + resize to 256x256 (model input)
clips = slice_video("video.mp4", [(0.0, 1.5)], size=256)
  • Reuses read_frames_exact for time-range decoding; encodes each clip to MP4 in memory.
  • size center-crops each frame to a square then resizes to size×size; omit it to keep the source resolution.
  • Empty slice → empty bytes at that index (order preserved).

Tests generate a video and assert clip count, default resolution, and 256×256 output. ruff check clean.

🤖 Generated with Claude Code


Note

Low Risk
New optional API in a utility module with validation and tests; no changes to auth, persistence, or existing frame APIs beyond reuse of read_frames_exact.

Overview
Adds slice_video in simple_video_utils/slicing so callers can export one in-memory MP4 per (start, end) second range, yielded lazily to avoid holding many clips at once.

Without size (or when the source is already a matching square and unrotated), clips are stream-copied via PyAV remux—fast and lossless, with cuts aligned to the keyframe at or before start. With size, the encode path uses read_frames_exact for the window, center-crops to a square, resizes, and re-encodes to H.264. Invalid slices (out of range, zero length, or no frames) raise ValueError.

The README gains a Slice into Clips example; tests/test_slicing.py covers multiple ranges, default resolution, square resize, the copy fast-path, and validation errors.

Reviewed by Cursor Bugbot for commit b13c786. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added video slicing support so users can export one or more MP4 clips from specific time ranges.
    • Optional square sizing now lets clips be center-cropped and resized for consistent output dimensions.
  • Documentation

    • Expanded the Usage guide with a “Slice into Clips” example showing how to create clips from start/end timestamps and use the optional size setting.
  • Tests

    • Added coverage for multiple clip ranges, default size preservation, and square resize behavior.

… resize

Cuts a video into one MP4 (bytes) per (start, end) second range, reusing
read_frames_exact for decoding. With size set, each frame is center-cropped
to a square and resized to size×size for models that expect square input.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new slice_video function in simple_video_utils/slicing.py that extracts MP4 clips from a source video for given time ranges, with optional center-crop/resize via PyAV encoding. Includes new integration tests and README documentation.

Changes

Video Slicing

Layer / File(s) Summary
Slicing implementation
simple_video_utils/slicing.py
Adds _center_crop_square, _encode_clip (PyAV-based MP4 encoding with optional square crop/resize), and the public slice_video(src, slices, size, codec) function that reads exact frames per time range and returns a list of MP4 bytes.
Integration tests for slicing
tests/test_slicing.py
Adds a temporary H.264 MP4 fixture, a _dims helper, and tests verifying clip count per range, default size preservation, and center-crop/resize to a requested square size.
README documentation
README.md
Adds a "Slice into Clips" usage subsection with Python examples for calling slice_video, including the optional size parameter.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding slice_video to cut clips by time range with optional square resizing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-slice-video

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread simple_video_utils/slicing.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/test_slicing.py (1)

31-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for empty-slice output.

Current tests only exercise slices that contain frames. Given slice_video's documented contract of returning b"" for slices with no frames (and the related bug found in _encode_clip when size is set), consider adding a case like slice_video(video, [(2.0, 2.5)]) (past the 1s source duration) asserting clips == [b""], both with and without size.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_slicing.py` around lines 31 - 44, Add a test case in
test_slicing.py for the empty-slice contract of slice_video, using a range past
the source duration so it produces no frames. Extend the existing slice_video
coverage in test_slice_returns_one_clip_per_range or a new test to assert clips
== [b""] for something like [(2.0, 2.5)], and repeat the assertion with size set
as well to cover the _encode_clip path when resizing is enabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@simple_video_utils/slicing.py`:
- Around line 22-28: The empty-slice behavior in _encode_clip is bypassed when
size is set, causing empty frame sequences to still produce container bytes.
Update _encode_clip so the empty-frames guard runs before any size-based
dimension setup or av.open() work, and return b"" whenever frames is empty
regardless of size. Keep the existing size handling for non-empty clips, but
ensure the contract described by _encode_clip and the slice path remains
consistent.

---

Nitpick comments:
In `@tests/test_slicing.py`:
- Around line 31-44: Add a test case in test_slicing.py for the empty-slice
contract of slice_video, using a range past the source duration so it produces
no frames. Extend the existing slice_video coverage in
test_slice_returns_one_clip_per_range or a new test to assert clips == [b""] for
something like [(2.0, 2.5)], and repeat the assertion with size set as well to
cover the _encode_clip path when resizing is enabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2e507718-b146-49e4-a324-54664867d15a

📥 Commits

Reviewing files that changed from the base of the PR and between dbe5fc8 and 1047ec2.

📒 Files selected for processing (3)
  • README.md
  • simple_video_utils/slicing.py
  • tests/test_slicing.py

Comment thread simple_video_utils/slicing.py Outdated
- size=None now remuxes (stream copy) instead of decode+re-encode: fast and
  lossless, cutting on the keyframe at/before start (may include a little
  pre-roll). A resize (size set) still re-encodes since it must touch pixels.
- Empty-slice returns b"" in both paths (the encode guard ran too late when
  size was set; the copy path checks the header duration).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread simple_video_utils/slicing.py Outdated
Comment thread simple_video_utils/slicing.py
- slice_video yields per clip (returns a lazy generator) so a long slice list
  never holds every clip in memory.
- Copy (no re-encode) not just when size is None but also when the source is
  already size x size — checked via the container header.
- Remux honors the stream's start_time offset (pts is on the absolute timeline).
- end < start raises ValueError up front in both paths (was silently b"" on copy).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread simple_video_utils/slicing.py
Comment thread simple_video_utils/slicing.py Outdated
Comment thread simple_video_utils/slicing.py Outdated
- Decide copy-vs-encode once from video_metadata (copy when size is None, or
  the source is already size x size and unrotated).
- Single streaming loop; each clip yielded lazily.
- Every slice must satisfy 0 <= start <= end <= duration; out-of-range raises
  ValueError instead of silently returning empty bytes.
- Remux honors the stream start_time; rotated square sources re-encode so the
  copy and resize paths never disagree on orientation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b69343a. Configure here.

Comment thread simple_video_utils/slicing.py
- Remove the codec parameter (always h264) — an unused knob.
- Consolidate the duplicated "no frames" raise: helpers return b"" and
  slice_video decides in one place.
- Reject zero/negative-length slices (end <= start) so the copy and encode
  paths agree, plus a test for it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AmitMY AmitMY merged commit b375a36 into main Jul 1, 2026
7 checks passed
@AmitMY AmitMY deleted the feat-slice-video branch July 1, 2026 13:10
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