Snacks v2.2.4
Automated Video Library Encoder
Patch release upgrading FFmpeg from a 2023 build to the latest (transitioning Intel QSV from MediaSDK to oneVPL), adding per-encoder rate control tuning, video-only bitrate measurement, multi-point VAAPI/SVT-AV1 calibration, a configurable skip threshold setting, live settings updates without rescan, and several directory navigation and path validation fixes.
New Features
FFmpeg Upgrade — MediaSDK to oneVPL
- FFmpeg upgraded from 2023 build to latest -- the bundled FFmpeg moves from the legacy Intel MediaSDK backend to Intel oneVPL (Video Processing Library) for all QSV encoding. FFmpeg 7.0+ dropped MediaSDK support entirely, so this upgrade is required for QSV to function on current Intel drivers. Encoder names (
h264_qsv,hevc_qsv,av1_qsv) remain the same, but the underlying library is now oneVPL.
Per-Encoder Rate Control
- Dedicated rate control flags for each hardware encoder -- NVENC, AMF, QSV, and SVT-AV1 each get tailored VBR parameters instead of sharing a generic
-b:v/-minrate/-maxratetemplate. NVENC uses lookahead + adaptive QP, AMF usesvbr_peakwithenforce_hrdto work around an FFmpeg >= 7.1 bug where-maxrateis ignored in generic VBR, QSV usesextbrcwith lookahead for reliable maxrate enforcement, and SVT-AV1 usesrc=1VBR with a 5% inflation to compensate for systematic undershoot. - Crop re-encodes use the same per-encoder logic --
GetCropCompressionFlagsmirrors the main encoding path so black border removal encodes use the correct rate control for the active encoder.
Video-Only Bitrate Measurement
- Quick video-only bitrate probe for borderline files -- files near the target bitrate now get a fast 15-second
-c:v copypass to measure the true video stream bitrate, stripping audio and subtitle overhead (typically 1000–4000 kbps). This prevents incorrect skip/encode decisions caused by audio inflating the total bitrate.
Multi-Point Calibration
- VAAPI QP calibration samples two file locations -- instead of a single 60-second sample at 40%, calibration now takes two 30-second samples at 25% and 60% of the file and uses the peak bitrate for QP adjustment. Short files (< 90 seconds) fall back to a single proportional sample. Tolerance tightened from 20% to 15%.
- SVT-AV1 VBR bitrate calibration -- new
CalibrateSvtAv1BitrateAsyncruns iterative test encodes at two positions, scaling-b:vuntil measured average output is within 5% of target. Compensates for SVT-AV1's ~20–25% systematic undershoot in VBR mode.
Configurable Skip Threshold
SkipPercentAboveTargetsetting -- new encoder option (default 20%) controls how far above the target bitrate a file can be and still be skipped when it's already in the target codec. Replaces the hardcoded1.2xmultiplier. Exposed in the settings UI with a numeric input clamped 0–100%.
Live Settings Updates
- Settings changes take effect immediately --
SaveSettingsnow deserializes the saved JSON back into anEncoderOptionsand callsTranscodingService.UpdateOptions, so queued items pick up setting changes without starting a new scan. The processing loop reads from_lastOptionsinstead of the original scan options.
Cluster No-Savings Handling
- Worker nodes detect and report no-savings encodes -- when encoding succeeds but the output is larger than the original (deleted by
ConvertAsync), the worker reportsnoSavings: truein the completion payload. The master skips the download, marks the file asSkipped, releases the node, and cleans up all tracking state. JobCompletion.NoSavingsproperty -- new boolean on the completion model, propagated through theReportCompletionendpoint via a JSON body parameter.
Remote Job Log Persistence
- Cluster encoding logs written to disk --
ClusterServicenow appends remote job log lines to the same log file path used by local encodes (BuildLogFilePathmade public). Logs survive page refreshes and restarts.GetLogsfalls back to searching the logs directory by short ID for remote jobs not in the local_workItemsdictionary.
Bug Fixes
Directory Navigation
- Parent path computation respects library root --
BrowseSubdirectoriesnow computesparentPathserver-side instead of relying on client-side string splitting. Returnsnullwhen at the library root so the frontend shows the top-level listing, preventing navigation above the configured library path. - Bare Windows drive letters normalized -- the frontend appends
\to bare drive letters likeD:before navigating, preventing Windows from resolving to the process CWD on that drive. - Top-level directory listing no longer counts video files --
LoadDirectoriesreturnsvideoCount: 0and no longer filters out empty directories, removing a potentially slow recursive file count on large libraries.
Path Validation
- Trailing separator normalization on all path checks -- all
AllowAllPathsguards nowTrimEnd(Path.DirectorySeparatorChar)on both the request path and the library root before comparison, fixing edge cases where trailing slashes caused valid paths to be rejected.
Encoding
- Hardware encoder availability test with software fallback -- before starting an encode, non-software encoders are tested with
TestEncoderAsync. If the hardware encoder isn't available, the system falls back to the corresponding software encoder (libx264,libx265, orlibsvtav1) and disables hardware init flags for that encode. - 4K VBR bitrate window tightened -- 4K encodes now use
±200k/+500kinstead of±500k/+1000kfor min/max bitrate, reducing overshoot on high-definition content. bufsizedoubled across all encoder paths -- all rate control configurations now usebufsize = maxrate * 2instead ofbufsize = maxrate, giving the rate controller more room to smooth bitrate spikes.
Database
- Stale EF Core migration lock cleared on startup --
InitializeAsyncdeletes any leftover__EFMigrationsLockrow before running migrations, preventing startup hangs after a crash. Safe because Snacks is a single-instance app.
Frontend
- Version shown in footer -- the layout footer now displays
v2.2.4alongside the copyright. HistoryClearedSignalR event resets UI -- clears the localworkItemsandlogsmaps and reloads, so Clear History is reflected immediately without a page refresh.- SignalR reconnect reloads cluster config --
onreconnectednow callsloadClusterConfigin addition toloadWorkItems, ensuring cluster state is current after a connection drop. - Unpause kicks off queue processing --
SetLocalEncodingPaused(false)now firesProcessQueueAsyncfor any items already waiting, so unpausing doesn't require a new scan to resume work.
Files Changed
New Files
test-encoder/-- encoder test utilitiestest-encoding.bat-- encoding test script
Modified Files
Snacks/Controllers/ClusterController.cs--ReportCompletionaccepts JSON body withnoSavingsflagSnacks/Controllers/HomeController.cs-- version bump, path normalization fixes, parent path computation, live settings update, directory listing simplificationSnacks/Data/MediaFileRepository.cs-- clears stale EF Core migration lock on startupSnacks/Models/EncoderOptions.cs-- addedSkipPercentAboveTargetpropertySnacks/Models/JobAssignment.cs-- addedNoSavingstoJobCompletionSnacks/Services/ClusterDiscoveryService.cs-- version bumpSnacks/Services/ClusterNodeJobService.cs-- no-savings detection, conditional completion reporting, immediate cleanup for no-savings jobsSnacks/Services/ClusterService.cs--HandleRemoteCompletionAsyncno-savings path, remote log persistence,BuildLogFilePathusageSnacks/Services/TranscodingService.cs-- video-only bitrate measurement, per-encoder rate control, multi-point calibration, SVT-AV1 calibration, skip threshold setting, live options update, software fallback, hardware encoder test,BuildLogFilePathmade public, log directory fallback searchSnacks/Views/Shared/_EncoderOptions.cshtml-- skip threshold UI controlSnacks/Views/Shared/_Layout.cshtml-- version in footerSnacks/wwwroot/js/transcoding.js--HistoryClearedhandler, reconnect cluster reload, drive letter normalization, server-side parent navigation,SkipPercentAboveTargetsave/loadREADME.md-- version bumpelectron-app/package.json-- version bumpelectron-app/package-lock.json-- version bump
Full documentation: README.md