Skip to content

v0.4.0 — Codec expansion

Choose a tag to compare

@Shironex Shironex released this 15 May 12:46
· 93 commits to main since this release

Codec expansion release. HEVC and AV1 join H.264 across NVENC + software paths, with a per-codec preset editor, three quality tiers (Fast / Balanced / Pristine), custom presets that survive an app restart, and a benchmark mode that scores 2–4 candidate profiles on a 10-second sample with size, encode time, and PSNR.

Headline feature: the encoder is no longer a single fixed pipeline. Pick H.264, HEVC, or AV1 — each gets its own hardware path (NVENC) and software fallback (libx264 / libx265 / libsvtav1), its own preset family, and its own quality scale. Save your favourite knob combination as a custom preset and apply it later in one click; spin up a benchmark to see which codec actually wins on your specific source.

Install

  • Windows — Moekoder-0.4.0-win-x64.exe. Still unsigned; SmartScreen will show More info → Run anyway on first launch.
  • macOS — Moekoder-0.4.0-mac-arm64.dmg. Still unsigned; after dragging into /Applications, run:
    xattr -cr /Applications/Moekoder.app
    to clear the Gatekeeper quarantine.
  • Linux — not shipped this release. Still on the roadmap.

If you're upgrading from v0.3.0, the auto-updater on Windows pulls this release in the background; the next launch comes up on v0.4.0. macOS users grab the DMG manually until code-signing lands.

New codecs

  • HEVC encode path — hevc_nvenc (10-bit main10) and libx265 software encoder. NVENC main10 emits format=yuv420p10le upstream for the encoder; libx265 inherits source pixel format.
  • AV1 encode path — av1_nvenc (RTX 40-series, gated by gpu.probe()'s per-encoder name list) and libsvtav1 software encoder with integer -preset 0..13.
  • HEVC + MP4 mux flag — -tag:v hvc1 appended on the HEVC + MP4 combination so QuickTime / iOS pick up the stream as HEVC.
  • Discriminated-union EncodingSettings — the shape is now tagged on codec, eliminating illegal combinations (libx265 + AV1, etc.) at compile time. Each branch carries only its valid hardware paths and codec-specific knobs (NVENC pN, libx265 preset family, SVT-AV1 0..13).

Settings → Encoding

A new section in Settings exposes every codec knob in one place:

  • Codec radio (H.264 / HEVC / AV1) and hardware-encoder picker, filtered against gpu.probe() so disabled options aren't even clickable.
  • Fast / Balanced / Pristine quick-set buttons per codec. Balanced defaults: H.264 CQ 19 / NVENC p4 (the v0.1 default), HEVC CQ 22 / 10-bit, AV1 CQ 28 / 10-bit. Fast drops the CQ ceiling + NVENC p2; Pristine raises the ceiling + p7. Nine presets total.
  • CQ slider clamped + labelled per codec (libsvtav1 goes to 63, the rest stop at 51).
  • Per-encoder preset knob (NVENC pN / libx265 preset family / SVT-AV1 0..13).
  • 10-bit toggle for HEVC + AV1 NVENC.
  • Container picker.

Settings persist as a single encoding profile blob in electron-store.

Settings → Custom presets

  • Name + save the live encoding profile, apply it later in one click, delete entries.
  • Up to 20 presets; names must be unique.
  • Each entry carries version: 1 from day one for forward-compat migrations.

Benchmark mode

  • Encodes a 10-second sample of a chosen video against 2–4 candidate profiles.
  • Reports per-row size, elapsed time, and PSNR (dB).
  • Reachable from the Encoding section's "Run benchmark" button.
  • Defaults to the user's currently-selected codec at Fast / Balanced / Pristine; an inline codec cycler lets you promote a slot to a different codec to compare across families.
  • Temp files live under <userData>/benchmark/<runId>/ and clean up on completion.
  • One-shot -lavfi psnr runner (ffmpeg/psnr.ts) parses average: from stderr with a 60-second hard cap to bound a malformed candidate.
  • Per-candidate failures surface in the result row rather than rejecting the whole run, so a single bad config doesn't lose the other rows.
  • New benchmark:run IPC with zod-validated tuple schema (max 4 candidates) and dedicated event channels (benchmark:progress, benchmark:log).
  • New EncodeJob.clipWindow — optional { startSec, durationSec } propagates into -ss <start> -t <duration> ahead of -i. Benchmark uses it; Single + Queue routes don't set it.

Changed

  • EncodingSettings is now a discriminated union over codec — every existing call site keeps compiling because the v0.1 H.264 NVENC defaults still satisfy the H.264 branch shape, but new code that touches partial overrides should call defaultsFor(codec) rather than spreading BALANCED_PRESET directly.
  • Filter chain pixel format is now codec-aware — NVENC h264 still emits format=yuv420p; HEVC + AV1 NVENC emit format=yuv420p10le when tenBit is set. libx265 + libsvtav1 software branches don't force a pixel format and inherit from the source.
  • App.tsx prefers the persisted encoding profile when present and falls back to the legacy onboarding-derived overrides only when the user hasn't opened the new Encoding section yet — no behavioural change for existing user flows.

Maintenance

  • Toolchain bumps — electron 41.2.1 → 42.0.1, vite 7 → 8 + @vitejs/plugin-react 4.7.0 → 6.0.2 (with resolve.dedupe + dropped minify:'esbuild' for vite 8 compat), vitest 3 → 4 in web + desktop (explicit include glob pinned for desktop), zod 3 → 4 in apps/desktop.
  • Node engine floor raised to >=22.12.0 to satisfy electron 42's runtime requirements.
  • Security fixes — Phase 1 safe bumps + Phase 2 pnpm overrides clear 4 high-severity CVEs (fast-uri <3.1.2, ip-address <10.1.1, devalue >=5.6.3 <5.8.1 pinned forward).

Tests

14 new vitest tests — 10 in args.test.ts (hevc_nvenc / hevc + libx265 / av1_nvenc / libsvtav1 branches, 8-bit fallback, MKV-strips-hvc1, clipWindow plumbing) and 4 in benchmark.test.ts (sequential runs, candidate failures don't kill the run, candidate cap, zero-candidate no-op). Test count: 190 (was 176).

Known limitations

  • Custom preset import / export to JSON file isn't shipped — deferred to v0.5.
  • Per-job overrides in the queue still aren't supported — every queue item uses the global encoding profile. Lands in v0.5 alongside import/export so the UI work happens together.
  • Per-codec preflight bitrate estimate isn't shipped; preflight stays pinned to the H.264 number (2500 kbps) and over-reserves disk for HEVC/AV1. Safe direction for a guard.
  • AV1 NVENC needs an RTX 40-series GPU. Pre-RTX-40 hardware sees the AV1 NVENC option disabled with a requires RTX 40-series tooltip; AV1 software (libsvtav1) is always available.
  • Benchmark mode runs candidates sequentially. Parallel candidates are tractable (the orchestrator already supports concurrency) but the benchmark deliberately serialises so the timing numbers aren't contaminated by GPU contention.
  • Same as v0.3.0: binaries are unsigned, auto-updater is Windows-only, no Linux build.

Source under the Moekoder Source Available License.