Commit Graph
4 Commits
Author SHA1 Message Date
hoelee 6e9671097b docs: scope the size policy to H.264 sources; publish the HEVC conversion policy
The installed skill had drifted ahead of the repo: SKILL.md carried the whole owner-requirements
section and references/hevc-conversion-policy.md was missing here entirely. Synced both.

Also states the boundary the policy needs: this skill's size hunt (SSIM-pinned quality, maxrate
1.0x source video bitrate, bpp tiering, matched audio) is for H.264 / MPEG-4 sources. YouTube's
VP9/AV1 sources are already near-optimal for their quality, so a re-encode can only grow them or
lose quality - the accepted answer there is 'same size, do not chase smaller', and the job reduces
to: never decode with *_cuvid, keep -fps_mode cfr, gate the output on pictures vs the source, and
source any repair from the pre-conversion snapshot backup rather than the converted file.
2026-10-07 05:06:59 +08:00
Hermes Agent 26e972af85 Add MIT license
A public repository with no license is "all rights reserved" by default: nobody may
legally use, modify or redistribute it. MIT grants exactly the permissions a public
utility repo implies, while the warranty disclaimer keeps liability with the user.

Copyright (c) 2026 Lee Teong Hoe (Hoelee Enterprise). Linked from the README.
2026-10-04 14:56:20 +08:00
Hermes Agent 3619adaf7c docs: the benefit case — ten real failures and the guard each produced
docs/WHY.md records the headline case and the guards, all traceable to failures this
pipeline actually hit rather than hypotheticals:

- the file that dropped 23.0% of frames while r_frame_rate == avg_frame_rate read
  exactly equal, and which a full library scan did not flag
- 27 invisible stutterers (1.2% of the library) with the same signature
- a detector that missed one of the two defect shapes (no ctts box) entirely
- a "lossless" remux that faithfully carried the stutter through -c copy
- a re-download that reproduced the defect, because the source mkv is already flat
- a video that played only its first 10 seconds after a short network copy, where
  getsize() returned stale metadata and size-based verification passed
- a 115-file batch lost to a full disk
- two concurrent encoders starving each other and dropping frames
- an iPad refusing an otherwise perfect file over hev1 vs hvc1
- Opus copied into an MP4

Also carries the reproduction (scripts/selftest.py), why a browser cannot be the
automated gate (Chrome decodes no HEVC, so an HEVC file reports 0/0 and looks perfect),
the 2x2 that proves the cause is container timing and not the bitstream, and cron /
Task Scheduler recipes with the reason each is safe to schedule.
2026-10-04 13:16:50 +08:00
Hermes Agent 0cdb54f910 universal-video-transcode: any file in, one iPad+Android-playable MP4 out
Give it a path; it reads the source, picks the recipe, encodes, and verifies the
result before accepting it.

The problem it exists to remove: a file can drop ~23% of its frames in a browser
while r_frame_rate == avg_frame_rate reads EXACTLY equal, so every fps-based check
calls it healthy and it never enters a repair queue. The cause is deterministic and
header-readable -- the MP4 composition-offset table is unusable, either a single
constant ctts entry (PTS == DTS + const) or no ctts box at all (PTS == DTS) -- so the
frame timestamps are in decode order and the decoder's reordered output frames carry
the wrong times.

- three recipes chosen from the source FILE, never the filename: lossless -c copy when
  the timeline allows it, AAC-only fix when just the audio is wrong, full HEVC (or
  x264 for reach) when the timeline cannot be copied
- quality policy: never upscale; HEVC -cq 27 measured at SSIM 0.9937 ~= source size;
  audio copied when already AAC, else AAC 256k
- the two flags that must never be dropped: -fps_mode cfr and -pix_fmt yuv420p
- verified before acceptance: duration, resolution, codec, hvc1 tag, 8-bit, uniform
  cadence, no flat composition offsets, full decode pass, and a read-back after the write
- built for cron: lock file (two concurrent NVENC jobs starve one encoder and DROP
  FRAMES), idempotent, leaves the input untouched on failure, aborts below 5 GB free
- scripts/selftest.py builds both defect shapes and asserts the detector, including a
  Matroska case that must NOT be flagged

Measured on the file that prompted this: 23.0% of frames dropped before, 0.0% after.
2026-10-04 13:01:14 +08:00