Skip to content

Re-encode a video to a smaller resolution as a new asset - #55

Merged
davior merged 1 commit into
mainfrom
claude/determined-johnson-ci4a3k
Oct 29, 2026
Merged

davior merged 1 commit into
mainfrom
claude/determined-johnson-ci4a3k

Conversation

@davior

@davior davior commented Oct 29, 2026

Copy link
Copy Markdown
Owner

What

A video's Info tab gains a Smaller copy row. You pick a target (1440p / 1080p / 720p / 480p / 360p) and one ffmpeg run in the job queue writes an H.264/AAC MP4 as a new asset. The original isn't touched. The point is to make a 4K original workable in a 1080p or 720p Video Creator project.

Decisions

  • The target is the frame's short side. GVC renders 9:16 and 1:1 as well as 16:9, so a portrait 4K phone video at "1080p" becomes 1080×1920, not 608×1080. The scale filter decides orientation from the decoded frame, because rotation flags can make the probed width and height disagree with what ffmpeg actually sees.
  • Down only. Only sizes below the source's are offered, and the server refuses an upscale with not_smaller.
  • The copy carries everything with it. Tags, description, summary, resolved attribution and the transcript are copied, and the transcript is also re-indexed for search. The usual next step is deleting the original to free the space, and a delete only clears the copy's parent_asset_id. Without the copies, everything inherited would go with the original. A test covers that whole workflow: downsize, delete the original, check the copy.
  • ffmpeg's -progress output drives the job's percent. A long 4K encode would otherwise run past job_stale_minutes and be swept as hung. Those same reports are where Cancel takes effect and kills ffmpeg.
  • setsar=1. Without it, rounding to an even width leaves non-square pixels: a 1002×750 source came out displaying 481 wide. GVC and most editors assume square pixels.
  • A running re-encode blocks deleting its source, as an extraction does.
  • New KIND_REENCODE / SOURCE_REENCODE. No migration, because neither column is constrained.

Tests

  • backend/tests/test_reencode.py: route refusals, plus real ffmpeg runs (landscape, portrait, odd aspect, cancel, garbage input, full disk, delete-the-original).
  • ReencodePanel.test.tsx: offered sizes, portrait handling, and the request sent.
  • Run locally: backend pytest -q 1457 passed; frontend format:check, lint, npm test (451) and build all clean.

Generated by Claude Code

A 4K original is too heavy to work with in a 1080p or 720p Video Creator
project. The Info tab gains "Smaller copy": pick 1440p/1080p/720p/480p/360p
(only sizes below the source are offered, and the server refuses an upscale)
and one ffmpeg run in the job queue writes an H.264/AAC MP4 as a new asset.

- The target is the frame's short side, so a portrait 4K phone video becomes
  1080x1920 rather than 608x1080: GVC renders 9:16 and 1:1 as well as 16:9.
- ffmpeg's -progress output drives the job's percent. A long 4K encode would
  otherwise outlive the stale sweeper, and those reports are also what lets
  Cancel kill ffmpeg.
- setsar=1: without it, rounding to an even width leaves non-square pixels
  (a 1002x750 source came out displaying 481 wide).
- The copy carries the original's tags, description, summary, resolved
  attribution and transcript, so the original can be deleted for the space
  without losing any of it. parent_asset_id stays as provenance only.
- A running re-encode blocks deleting its source, as an extraction does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1geD6HjkZNo9XQSHdawSb
@davior
davior marked this pull request as ready for review October 29, 2026 04:22
@davior
davior merged commit 0101480 into main Oct 29, 2026
3 checks passed
davior pushed a commit that referenced this pull request Oct 29, 2026
Each re-encode became a separate asset with a copy of the original's
metadata. What is wanted instead is YouTube-style versions: one asset,
with standard-resolution files hanging off it. The next commit builds that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1geD6HjkZNo9XQSHdawSb
davior pushed a commit that referenced this pull request Oct 29, 2026
A video asset gets a Versions tab: the original, and a row per standard
size below it (4K, 1440p, 1080p, 720p, 480p, 360p), each made by hand
with Create. A version is a file of the one asset (new `assetversion`
table), not an asset of its own, so there is nothing to copy or keep in
step: name, tags, attribution, transcript and clips stay on the asset.

- One ffmpeg run in the job queue (`make_version`), the encode from #55:
  short side as the target (portrait 4K -> 1080x1920), setsar=1 for square
  pixels, and ffmpeg's -progress driving percent, liveness and Cancel.
- "Make original" swaps a version's file in as the asset's own and
  deletes the big original: how space comes back. Same row and id, so
  tags, transcript and clips carry on; the timeline does not change.
- Deleting the asset deletes its versions and their files. A version
  being made blocks the delete and make-original.
- File counts and sizes: versions are their own group in the storage
  panel and in the library total, "Largest files" ranks by original
  plus versions and says how much is versions, and the stray sweep
  counts version files as referenced rather than deleting them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1geD6HjkZNo9XQSHdawSb
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.

2 participants