Repository navigation
feat(media): read Hikvision SD-card recordings with mu-law sound - #1462
Merged
Merged
Conversation
Hikvision cameras and NVRs record MPEG program streams. iVMS-4200 / NVR exports start with a 40-byte "IMKH" header and FFmpeg's mpeg demuxer already reads them, whatever their extension (.mp4, .264). The recordings on a camera's SD card or a NAS (hiv00000.mp4) are the same stream without the header, and FFmpeg then reads their G.711 mu-law sound (stream type 0x91) as MP2 and fails. When a program stream's map lists mu-law sound and the header is missing, Filee gives FFmpeg the header in front of the file through the concat protocol, without copying the recording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BPxh5pgy6HfVPDtxbszvh3
KnifeLemon
approved these changes
Nov 13, 2026
KnifeLemon
left a comment
Owner
There was a problem hiding this comment.
Thanks, @Ugoyo. Small and well contained: the stream-map check is bounded and fails safe (anything unexpected goes to
FFmpeg as it does today), the | guard is there, and the recording is never copied.
Looks good, merging. A few notes, none blocking:
- Other entry points still get the raw file. The header is added only in
FfmpegConverter.ConvertAsync. Caption
(WhisperConverterruns-i step.InputPath), Live / Motion Photo (returns before the new line), Merge videos
(JoinAsync) and the Cut a clip editor (VideoFrames,ClipPreview) still pass the plain path, so a mu-law SD-card
recording keeps failing there. They fail today too, so this isn't a regression. #1463 needs the same input rewrite for
.nov, so one shared resolver for both would be a good follow-up. - #1463 touches the same line (
var input = ...inFfmpegConverter.cs) and the same spot indocs/ENGINES.md.
This one goes in first, so #1463 rebases on it:.novshould go toNovExport.InputForwith the plain path, not a
concat:string. InputForreads up to 256 KB of every FFmpeg input, audio included, with blocking I/O. Cheap locally; limiting it to
video sources or reading withRandomAccessis optional.- The FFmpeg-backed
A_hikvision_recording_converts_to_mp4_with_its_soundcases are skipped on every CI job, so CI covers
the sniffer only. A short realhiv*.mp4would be welcome if anyone has one.
8 of 12 tasks
Ugoyo
added a commit
to Ugoyo/Filee
that referenced
this pull request
Nov 13, 2026
Hikvision SD-card recordings (KnifeLemon#1462) and .nov exports now share the line where FfmpegConverter picks FFmpeg's input: a .nov goes to NovExport.InputFor with the plain path, every other file to HikvisionStream.InputFor. Schema 87 went to the Arduino sketches on main, so .nov takes 88. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BPxh5pgy6HfVPDtxbszvh3
Ugoyo
added a commit
to Ugoyo/Filee
that referenced
this pull request
Nov 13, 2026
From the review of KnifeLemon#1462: HikvisionStream read the first 256 KB of every FFmpeg input through a FileStream. It now reads with RandomAccess, and only the first four bytes unless they are a pack header, so an MP4 or a Matroska file costs one small read. The shared header of the Cut a clip editor is written once, under another name first, so a reader never sees half of it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BPxh5pgy6HfVPDtxbszvh3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this change?
Hikvision cameras and NVRs record MPEG program streams with H.264 / H.265 video and G.711 sound. Exports from iVMS-4200 and the NVR (
.mp4, sometimes.264) start with a 40-byteIMKHheader, and FFmpeg's mpeg demuxer already reads them by their content: Filee converts them today, whatever their extension (checked, see below). The recordings on a camera's SD card or a NAS (hiv00000.mp4, indexed byindex00.bin) are the same stream without the header. With A-law sound they convert too, but with mu-law sound (stream type 0x91 in the stream map) FFmpeg takes it for MP2 and the conversion fails ("Decode error rate 1 exceeds maximum", nothing written). FFmpeg only reads 0x91 as mu-law in files that start withIMKH(libavformat/mpeg.c,imkh_cctv).This PR adds
Media/HikvisionStream.cs. When a file starts with a pack header and a stream map in its first 256 KB lists mu-law sound, Filee gives FFmpegconcat:<header>|<file>: a 40-byteIMKHheader written to the job's work folder, followed by the recording. The recording itself is not copied. Everything else is handed to FFmpeg as before. A damaged or cut-short stream map leaves the file to FFmpeg as it is. Paths with|(the concat separator, not allowed in Windows names) are left alone. No new extension, so no settings migration.Old
4HKH.264files (Hikvision's own frame format, from early DS-series DVRs) and recordings made with stream encryption on can't be read: they still fail with FFmpeg's error.docs/ENGINES.mdsays so.Type of change
How was it tested?
dotnet format --verify-no-changes(anddotnet build -c Release)dotnet test: new tests pass. Run on Linux with the system's FFmpeg 6.1 (the mpeg demuxer's IMKH handling is the same in 9.0.2). Without this change, only the SD-card / mu-law case fails. The 5MediaTeststhat fail here fail onmaintoo (FFmpeg build missing codecs), plus the Core tests that need a non-root user.filee-cli convertwas used (Linux) on generated recordings.New tests:
HikvisionStreamTests(no FFmpeg): a header-less stream with mu-law needs the header (H.264 and H.265); A-law, AAC, an export that already hasIMKH, a program stream without a map, an ISO MP4 and an empty file don't; damaged maps (cut short, length past the end, entry info past the map) are left to FFmpeg; only the first 256 KB is looked at;InputForwrites the header and returns the concat input, and leaves other files and missing files alone.MediaTests.A_hikvision_recording_converts_to_mp4_with_its_sound: FFmpeg has no muxer for these, soHikvisionRecordingwrites one from FFmpeg-made H.264 frames and G.711 sound (pack header, system header and stream map before each key frame, 40 ms of sound per frame), with or withoutIMKH, A-law or mu-law, named.mp4or.264. Each converts to MP4 with 50 frames of 160x120 H.264, AAC sound, ~2 s.No real sample was used. I found no public sample with a clear licence on the hosts I could reach. The FFmpeg trac samples (#4182, #3566) and
streams.videolan.org/samples/IMKH/couldn't be downloaded from my environment. The generated files follow FFmpeg's demuxer and Hikvision's documented layout. A short realhiv*.mp4from an SD card would be the best confirmation, if anyone has one.Screenshots (UI changes)
None, no UI changes.
Checklist
src/Filee.App/Assets/i18n/*.jsonfiles (no new UI strings)THIRD-PARTY-NOTICES.md(none added)🤖 Generated with Claude Code