Skip to content

Add disk management, SD card replay/download, and alarm search#396

Open
lorek123 wants to merge 19 commits into
QuantumEntangledAndy:masterfrom
lorek123:feature/disk-subcommand
Open

Add disk management, SD card replay/download, and alarm search#396
lorek123 wants to merge 19 commits into
QuantumEntangledAndy:masterfrom
lorek123:feature/disk-subcommand

Conversation

@lorek123
Copy link
Copy Markdown

Summary

  • Disk management (MSG 102/103): neolink disk <camera> list and disk format to inspect and format SD cards
  • SD card replay & download (MSG 5/7/8/13-16/123/143): Full playback pipeline — file listing, download to MP4 with VFR-correct muxing, audio, and AI detection metadata
  • Alarm video search (MSG 175): Server-side filtering by alarm/AI type with replay alarm-search
  • E1 camera fixes: Protocol v2 header handling, partial-region AES decryption, graceful error handling for unsupported features

New subcommands

# Disk
neolink disk <camera> list
neolink disk <camera> format --disk 0

# Replay: list days / files
neolink replay <camera> days --start 2026-02-01 --end 2026-02-13
neolink replay <camera> files --date 2026-02-13

# Replay: download by filename (works on E1)
neolink replay <camera> download --name <file> --output out.mp4

# Replay: download by time range (NVR models; E1 returns 400)
neolink replay <camera> download-by-time --start 2026-02-13 --output out.mp4

# Alarm/AI search
neolink replay <camera> alarm-search --start 2026-02-13

Details

  • File listing: MSG 14/15 with pagination, AI tag display (people, vehicle, dog_cat, etc.), --ai-filter for client-side filtering
  • MP4 muxing: GStreamer pipeline with per-frame PTS from BcMedia timestamps, H.264/H.265 codec detection, AAC audio, metadata tags (camera name, date, AI detections)
  • E1 decryption: Partial-region AES decrypt using encryptPos/encryptLen from Extension XML; protocol v2 payload_offset for continuation packets (class 0x698d)
  • Record type fix: Separate FILE_SEARCH_RECORD_TYPES (manual,sched,md,pir,io) for MSG 14 — E1 cameras reject AI-specific tags in file search requests
  • Error handling: MSG 14 error 400 → "No files for this day"; MSG 175 error 405 → "not supported"; MSG 143 error 400 → suggests replay download instead
  • Wireshark dissector: Updated baichuan.lua with replay message ID decoding

Tested on

  • Reolink E1 (firmware v3.1.0.4450_2509011489)
    • disk list, days, files, download (MP4 with H.264 + AAC) all working
    • alarm-search gracefully reports "not supported"
    • download-by-time gracefully reports "not supported" (MSG 143 not implemented on E1)

Test plan

  • neolink disk <camera> list shows SD card info
  • neolink replay <camera> days --start <date> lists recording days
  • neolink replay <camera> files --date <date> lists files with AI tags and correct sizes
  • neolink replay <camera> download --name <file> --output test.mp4 produces playable MP4
  • Date with no recordings shows "No files for this day." instead of error
  • replay alarm-search returns results or "not supported" message
  • replay download-by-time returns clear error on cameras that don't support MSG 143

lorek123 and others added 7 commits February 5, 2026 00:32
- Add MSG_ID_HDD_INFO_LIST (102) and MSG_ID_HDD_INIT_LIST (103) in bc/model
- Add HddInfoList, HddInfo, FormatExpandCfg, HddInitList, HddInit XML types
- Add bc_protocol/disk.rs: get_hdd_list(), format_disk(init_ids, full_format)
- Add disk subcommand: 'neolink disk [list]' and 'neolink disk format --disk N [--full]'
- Default subcommand is list when omitted
- Fix UnintelligibleReply/UnintelligibleXml display and unused_assignments warnings
- Fix BcSubscription and MqttReplyRef lifetime elision warnings
Implement SD card replay and download for E1/E320 cameras:
- New `replay` subcommand with search, list, download, and play modes
- BC protocol replay flow (MSG 5/7/8/13-16/123) with BcMedia stream parsing
- GStreamer-based MP4 muxing with per-frame PTS for variable frame rate
- Fix E1 decryption: always read payload_offset for v2 protocol packets
- Fix over-decryption: only decrypt [encryptPos, encryptPos+encryptLen)
- Enhanced Wireshark dissector with replay message types and encryption fields
- BcMedia format documentation (BCMEDIA_REPLAY_FORMAT.md)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The camera's recordType field carries AI detection labels (people,
vehicle, face, dog_cat, package, visitor, etc.) alongside trigger
types (md, sched, manual, pir). These are now embedded as MP4 tags:
- GStreamer: Keywords (AI tags), Comment (full recordType), Description
  (start/end time), Title (camera name), Encoder (neolink replay)
- ffmpeg fallback: -metadata comment and description flags
- File listing: AI detections highlighted with [AI: ...] suffix

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Tag events sent via appsrc.send_event() don't reliably propagate to
the muxer. Use mp4mux's TagSetter interface (set before Playing state)
to write tags directly into the MP4 udta/meta atoms.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Recordings triggered only by AI detection (without md/sched) were missed
because the default record_type was "manual,sched,md". Now defaults to all
known types. Adds --ai-filter to `replay files` for client-side filtering
by AI detection tag (e.g. --ai-filter people,vehicle,dog_cat).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Implements the findAlarmVideo protocol (MSG 175 / 0xAF) which allows
searching recordings by alarm/detection type on the camera itself.
Adds FindAlarmVideo and EventAlarmType XML types, alarm_video_search_start
and alarm_video_search_next protocol methods, and the `alarm-search`
CLI subcommand with --alarm-types filtering.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Fix MSG 14 regression: separate FILE_SEARCH_RECORD_TYPES (manual,
  sched,md,pir,io) from ALL_RECORD_TYPES. E1 cameras reject unknown
  AI-specific tags in file search with error 400.
- Handle MSG 14 error 400 gracefully as "no files for this day"
- Handle MSG 175 error 405 gracefully as "not supported"
- Downgrade per-packet replay logs from info to debug
- Remove E1 strip diagnostic logging from replay stream
- Reduce binary progress logging from every 20 to every 200 packets
- Fix file size display: show KB for files under 1MB
- Remove debug eprintln! from main.rs replay dispatch

Co-Authored-By: Claude Opus 4.6 <[email protected]>
janost added a commit to MutuallyAssuredDeployment/neolink that referenced this pull request Mar 18, 2026
Upstream PR QuantumEntangledAndy#396. Adds three major capabilities:
- Disk management (MSG 102/103): list and format SD cards
- SD card replay & download (MSG 5/7/8/13-16/123/143): full playback
  pipeline with VFR-correct MP4 muxing and AI detection metadata
- Alarm video search (MSG 175): server-side filtering by alarm type

Also includes E1 camera fixes: protocol v2 header handling, partial-region
AES decryption, and graceful error handling. Crypto refactored to store
key+IV and create fresh cipher per packet for E1 replay compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
janost added a commit to MutuallyAssuredDeployment/neolink that referenced this pull request Mar 18, 2026
PR QuantumEntangledAndy#396's de.rs changes introduced a partial-decryption approach designed
for E1 replay, but this broke live FullAes video streams. The camera only
encrypts the first `encryptLen` bytes of each BC packet while continuation
packets are plaintext. PR QuantumEntangledAndy#396's logic incorrectly applied full AES
decryption to plaintext continuation packets, corrupting video data.

Reverts to the original 6e05e78 binary handling: full decrypt + truncate
for FullAes with encrypted_len, raw passthrough for all other binary
packets. Adds StreamData::from_parts for replay compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
janost added a commit to MutuallyAssuredDeployment/neolink that referenced this pull request Mar 19, 2026
@MasterPlexus MasterPlexus mentioned this pull request Mar 29, 2026
@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 1, 2026

For pressed user as me and tester i produced draft release
https://github.com/surfzoid/neolink/releases

@MasterPlexus
Copy link
Copy Markdown

I just compiled with this pull, and could confirm i can connect with disk list to the sd-card on my argus 3. but unfortunately the replay command is unknown... Is the initial description may not correct and the command is now a different one?

~/neolink$ ./neolink replay Cam1 download-by-time --start 2026-04-03 --output out.mp
[2026-04-02T17:21:23Z INFO  neolink] Neolink 0.6.3-rc.3 (unknown commit) release
error: unrecognized subcommand 'replay'

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

I just compiled with this pull, and could confirm i can connect with disk list to the sd-card on my argus 3. but unfortunately the replay command is unknown... Is the initial description may not correct and the command is now a different one?

~/neolink$ ./neolink replay Cam1 download-by-time --start 2026-04-03 --output out.mp
[2026-04-02T17:21:23Z INFO  neolink] Neolink 0.6.3-rc.3 (unknown commit) release
error: unrecognized subcommand 'replay'

download by file worked for me on argus 3, i will work on my bash script #367

@MasterPlexus
Copy link
Copy Markdown

https://github.com/surfzoid/neolink/releases

trying your link, but there are no releases...

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

surfzoid/neolink/releases

trying your link, but there are no releases...

did you click on "asset 5" ?

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

./neolink replay --config ./config.toml parking files --date 2026-02-13
0120260213184700 1 MB subStream people,other [AI: people]
./neolink replay --config ./config.toml parking download --name 0120260213184700 --output 2026-02-13.mp4
ls
2026-02-13.mp4 config.toml getfiles* neolink* neolink.d

@MasterPlexus
Copy link
Copy Markdown

surfzoid/neolink/releases

trying your link, but there are no releases...

did you click on "asset 5" ?

ah sorry. its under tags, not releases...

@MasterPlexus
Copy link
Copy Markdown

I just compiled with this pull, and could confirm i can connect with disk list to the sd-card on my argus 3. but unfortunately the replay command is unknown... Is the initial description may not correct and the command is now a different one?

~/neolink$ ./neolink replay Cam1 download-by-time --start 2026-04-03 --output out.mp
[2026-04-02T17:21:23Z INFO  neolink] Neolink 0.6.3-rc.3 (unknown commit) release
error: unrecognized subcommand 'replay'

download by file worked for me on argus 3, i will work on my bash script #367

ok, it looks like i made a mistake during my clone. I rebuild now from scretch with a fresh clone... (there i see also the replay in main.rs, which was not the case in my old clone)...

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

I just compiled with this pull, and could confirm i can connect with disk list to the sd-card on my argus 3. but unfortunately the replay command is unknown... Is the initial description may not correct and the command is now a different one?

~/neolink$ ./neolink replay Cam1 download-by-time --start 2026-04-03 --output out.mp
[2026-04-02T17:21:23Z INFO  neolink] Neolink 0.6.3-rc.3 (unknown commit) release
error: unrecognized subcommand 'replay'

download by file worked for me on argus 3, i will work on my bash script #367

ok, it looks like i made a mistake during my clone. I rebuild now from scretch with a fresh clone... (there i see also the replay in main.rs, which was not the case in my old clone)...

Why do you want duplicate?

@MasterPlexus
Copy link
Copy Markdown

ok, so far the commands are working, but i got most likely service not available 400 responses on all trys (files, days, download). which commands are working for you currently? in your example you have "parking" as part of the command, but this is not here in the description, and so far not avalible in my build... may I will try your version...

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

ok, so far the commands are working, but i got most likely service not available 400 responses on all trys (files, days, download). which commands are working for you currently? in your example you have "parking" as part of the command, but this is not here in the description, and so far not avalible in my build... may I will try your version...

parking is my cam name

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

neolink.zip
the version i used

@MasterPlexus
Copy link
Copy Markdown

Thanks. it now worked also for me. just no mp4 stream... to be rechecked ;)

@lorek123
Copy link
Copy Markdown
Author

lorek123 commented Apr 2, 2026

Hi @MasterPlexus,

For the "no mp4 stream" issue — I think I know what's happening. The download code has a heuristic to detect whether the camera is sending an MP4 container (like the E1 does) vs. raw BcMedia frames (like older cameras). That heuristic is too aggressive and likely misidentifies your Argus 2's BcMedia stream as a
container format, which causes the output file to be assembled incorrectly and be unplayable.

To confirm, could you run the download command with debug logging and share the output?

RUST_LOG=debug neolink replay --config=config.toml download --name --output test.mp4 2>&1 | head -100

I'm specifically looking for a log line that says something like:
Replay: packet 2 not ftyp (decrypted: [xx xx xx xx ...]), treating as container/raw

If you see that line, that confirms the bug. The hex bytes in brackets would also be helpful to include.

Thanks for testing!

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

 --output out.mp4

There is some instability, not ever the same result with a bash script, perhaps my build isn't so good with gstreamer dep

image

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

Here it is my bash script , is dirty but work, you need to adjust save root path and cam


#!/bin/bash
#https://github.com/QuantumEntangledAndy/neolink
cd $(dirname -- "$( readlink -f -- "$0"; )")
DAT=$(date +%Y-%m-%d)
SaveRoot="/mnt/smbrouter/cam3/reolink/"

function Final {
	SavePath=$SaveRoot$CamName/$DAT
	mkdir -p $SavePath
	cp -f XML $SavePath/FileList.txt
	mv -f XML $SavePath
	filels=$SavePath/XML
	sed -i 's/^\s*.//g' $filels
	NewFs=$(awk -F" " '{print $1}' $filels)
	echo  $NewFs > $filels
	sed -i -e 's/\s\{1,\}$//' -e 's/\s\+/\n/g' $filels
	
	{
		read
		while IFS=, read -r Files
		do 
		echo $Files
			./neolink replay --config ./config.toml $CamName download --name $Files --output $SavePath/$Files.mp4
		done
	} < $filels


}

CamName=parking
./neolink replay --config ./config.toml parking files --date $DAT> XML
Final

CamName=hangard
./neolink replay --config ./config.toml hangard files --date $DAT> XML
Final

CamName=tracteurs
./neolink replay --config ./config.toml tracteurs files --date $DAT> XML
Final

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 2, 2026

My cams are
Argus PT Firmware Version v3.0.0.4033_25010232
Argus 3 Firmware Version 0130_705_572_474
Argus 3 Firmware Version v3.0.0.669_21102601 (the one i got mp4)

@MasterPlexus
Copy link
Copy Markdown

ok. not sure why I thought we have argus 3 cams. I have argus 2:
[2026-04-02T20:40:53Z INFO neolink::common::neocam] Cam1: Model Argus 2
[2026-04-02T20:40:53Z INFO neolink::common::neocam] Cam1: Firmware Version 0112_262_237_24

Anyhow, access possible, and I can download the files. but the files are scrambled. Even that I know they are stored on sd-card as mp4 files. So may the cam transcode it again, or the file will be krypted during transfer... I need to check that...

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 3, 2026

@lorek123 perhaps enable "issue" on your fork could be more efficient.
Did you set an argument to select sub or mainstream or perhaps use the one set in config file?

@MasterPlexus
Copy link
Copy Markdown

OK, no error on neolink side. was an error in my script not to take care to extract the real file name, and garbage was part of it (like the size, md, and so on). Now it worked.

Detect video codec from BcMedia IFrame/PFrame video_type field and
thread it through the entire mux pipeline. H.265 streams now use
h265parse + video/x-h265 caps in GStreamer (previously hardcoded to
h264parse), fixing "No valid frames found" / "non-existing SPS 32"
errors on mainStream cameras.

Also adds is_likely_valid_h265_nal() for H.265 NAL validation and
updates ffmpeg fallback to use -f hevc / .replay.h265 extension.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@lorek123
Copy link
Copy Markdown
Author

lorek123 commented Apr 6, 2026

@surfzoid the mainStream issue is now fixed. The problem was that mainStream on cameras like Argus 3 / Argus PT uses H.265/HEVC video, but the code was hardcoded to pipe everything through h264parse and video/x-h264 caps — causing GStreamer to fail with "No valid frames found" and "non-existing SPS 32".

The fix detects the codec from the BcMedia frame headers and automatically uses h265parse + video/x-h265 for H.265 streams, and the ffmpeg fallback also handles HEVC now.

Please test with the latest build from the feature/disk-subcommand branch — mainStream replay/download should produce valid MP4 files now.

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 6, 2026

@lorek123

2026-04-05 tracteurs -----------------------------------------
0120260405124500 from camera tracteurs -----------------------------------------
[2026-04-06T20:33:25Z INFO  neolink] Neolink 8fcad4c3414184c51a77b28e96723bd88cff9727 release
[2026-04-06T20:33:25Z INFO  neolink::utils] tracteurs: Connecting to camera at UID: ***************
[2026-04-06T20:33:25Z INFO  neolink_core::bc_protocol] tracteurs: Trying local discovery
[2026-04-06T20:33:25Z INFO  neolink::replay] Replay download: name=0120260405124500 stream=mainStream (stops on response 300 or --duration)
[2026-04-06T20:33:25Z INFO  neolink::replay] Replay play: name=0120260405124500 stream=mainStream speed=1
[2026-04-06T20:33:25Z INFO  neolink_core::bc_protocol] tracteurs: Local discovery success *************** at 205.36.8.63:16956
[2026-04-06T20:33:25Z INFO  neolink::utils] tracteurs: Logging in
[2026-04-06T20:33:25Z INFO  neolink::utils] tracteurs: Connected and logged in
[2026-04-06T20:33:27Z INFO  neolink::common::camthread] tracteurs: Camera time is already set: 2026-04-06 22:33:22.0 -01:00:00
[2026-04-06T20:33:29Z INFO  neolink::common::neocam] tracteurs: Model Reolink Argus PT
[2026-04-06T20:33:29Z INFO  neolink::common::neocam] tracteurs: Firmware Version v3.0.0.4033_25010232
[2026-04-06T20:33:29Z INFO  neolink::replay] Replay: file duration 15 s (from file list), will stop when complete
[2026-04-06T20:33:29Z INFO  neolink::replay] Replay: expected file size 6843098 bytes (from file list), will stop when complete
[2026-04-06T20:33:29Z INFO  neolink::replay] Replay: file recordType = other
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: seek (MSG 123) done
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: start_time 2026-04-05 12:45:00
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: sending MSG 5 start_replay name=0120260405124500 channel=0 streamType=mainStream
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: MSG 5 sent, waiting for first response...
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: camera accepted (200), streaming...
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: skipping 32 byte replay header (first packet)
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: 1 packets, 0 KB received
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: packet 2 first 8 bytes (decrypted): [30, 30, 64, 63, 48, 32, 36, 34]
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: 2 packets, 38 KB received
[2026-04-06T20:33:30Z INFO  neolink_core::bc_protocol::replay] Replay: 3 packets, 77 KB received
[2026-04-06T20:33:30Z INFO  neolink::replay] Replay: stream codec = H264
[2026-04-06T20:33:30Z INFO  neolink::replay] Replay: wrote frame 1 to output
[2026-04-06T20:33:30Z INFO  neolink::replay] Replay: wrote frame 2 to output
[2026-04-06T20:33:30Z INFO  neolink::replay] Replay: wrote frame 3 to output
[2026-04-06T20:33:30Z INFO  neolink::replay] Replay: wrote frame 4 to output
[2026-04-06T20:33:30Z INFO  neolink::replay] Replay: wrote frame 5 to output
[2026-04-06T20:33:31Z WARN  neolink::common::pushnoti] Issue connecting to push notifications server: Http(reqwest::Error { kind: Decode, source: Error("expected value", line: 1, column: 1) })
[2026-04-06T20:33:31Z INFO  neolink::replay] Replay: wrote frame 30 to output
[2026-04-06T20:33:33Z INFO  neolink::replay] Replay: wrote frame 60 to output
[2026-04-06T20:33:35Z INFO  neolink_core::bc_protocol::replay] Replay: 200 packets, 2481 KB received
[2026-04-06T20:33:35Z INFO  neolink::replay] Replay: wrote frame 90 to output
[2026-04-06T20:33:36Z INFO  neolink::replay] Replay: wrote frame 120 to output
[2026-04-06T20:33:37Z WARN  neolink::common::pushnoti] Issue connecting to push notifications server: Http(reqwest::Error { kind: Decode, source: Error("expected value", line: 1, column: 1) })
[2026-04-06T20:33:38Z INFO  neolink::replay] Replay: wrote frame 150 to output
[2026-04-06T20:33:39Z INFO  neolink_core::bc_protocol::replay] Replay: 400 packets, 4810 KB received
[2026-04-06T20:33:40Z INFO  neolink::replay] Replay: wrote frame 180 to output
[2026-04-06T20:33:41Z INFO  neolink::replay] Replay: wrote frame 210 to output
[2026-04-06T20:33:43Z WARN  neolink::common::pushnoti] Issue connecting to push notifications server: Http(reqwest::Error { kind: Decode, source: Error("expected value", line: 1, column: 1) })
[2026-04-06T20:33:45Z INFO  neolink::replay] Replay: 15s duration reached, sending replay stop (MSG 7) and closing file.
[2026-04-06T20:33:45Z INFO  neolink::replay] Replay: sending MSG 7 (stop) with 5s timeout
[2026-04-06T20:33:45Z INFO  neolink::replay] Replay: MSG 7 (stop) completed successfully in 168.845334ms
[2026-04-06T20:33:45Z INFO  neolink::replay] Replay: actual avg fps from timestamps = 15.04 (declared fps = 0)
[2026-04-06T20:33:45Z INFO  neolink::replay::gst] Replay GStreamer: set metadata tags on mp4mux TagSetter
[2026-04-06T20:33:45Z INFO  neolink::replay::gst] Replay GStreamer: pushed 15616 ms of AAC audio
[2026-04-06T20:33:45Z WARN  neolink::replay] Replay: GStreamer mux failed: GStreamer error: Error { structure: Some(GstMessageError { gerror: (GError) ((GError*) 0x7f1548001d00), debug: (gchararray) "../libs/gst/base/gstbaseparse.c(1423): gst_base_parse_sink_event_default (): /GstPipeline:pipeline0/GstH264Parse:h264parse0" }), source: Some((Object { inner: TypedObjectRef { inner: 0x7f1554429a10, type: GstH264Parse } }, "h264parse0")), error: Error { domain: gst-stream-error-quark, code: 5, message: "No valid frames found before end of stream" }, debug: Some("../libs/gst/base/gstbaseparse.c(1423): gst_base_parse_sink_event_default (): /GstPipeline:pipeline0/GstH264Parse:h264parse0"), details: None }, trying ffmpeg
[2026-04-06T20:33:45Z INFO  neolink::replay] Replay: muxing with ffmpeg at 15.040 fps (fallback)
[h264 @ 0x3dcdef80] missing picture in access unit with size 78
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] non-existing SPS 1 referenced in buffering period
[h264 @ 0x3dcdef80] non-existing SPS 0 referenced in buffering period
[h264 @ 0x3dcdef80] missing picture in access unit with size 210417
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] non-existing SPS 1 referenced in buffering period
[h264 @ 0x3dcdef80] non-existing SPS 0 referenced in buffering period
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 630
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 1098
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 969
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6544
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7987
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6788
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7499
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6660
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4421
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9059
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4299
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4635
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5227
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8871
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4156
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4767
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5270
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7744
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 3955
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4036
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4237
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 28361
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 28234
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 25964
[h264 @ 0x3dcdef80] missing picture in access unit with size 383
[h264 @ 0x3dcdef80] no frame!
    Last message repeated 1 times
[h264 @ 0x3dcdef80] missing picture in access unit with size 155
[h264 @ 0x3dcdef80] missing picture in access unit with size 50
[h264 @ 0x3dcdef80] no frame!
    Last message repeated 1 times
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] non-existing SPS 5 referenced in buffering period
[h264 @ 0x3dcdef80] non-existing SPS 0 referenced in buffering period
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
    Last message repeated 1 times
[h264 @ 0x3dcdef80] missing picture in access unit with size 183682
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] non-existing SPS 5 referenced in buffering period
[h264 @ 0x3dcdef80] non-existing SPS 0 referenced in buffering period
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
    Last message repeated 1 times
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 3718
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 14855
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8764
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4851
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 3202
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 14287
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8670
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11981
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9885
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9410
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8177
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11673
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 2650
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 12166
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9935
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10567
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9870
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 12565
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6225
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 15264
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4747
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11421
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9424
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11986
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6024
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11578
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4993
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10802
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10247
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 12350
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9182
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 13844
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8934
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 13675
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5086
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11827
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10202
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 12306
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5727
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 15991
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6139
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 12969
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10926
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 13166
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9063
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 16256
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7355
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 17483
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7465
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 13688
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7558
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 13989
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11967
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 15462
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11432
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 15629
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9465
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 12988
[h264 @ 0x3dcdef80] missing picture in access unit with size 50
[h264 @ 0x3dcdef80] no frame!
    Last message repeated 1 times
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] non-existing SPS 5 referenced in buffering period
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] non-existing SPS 6 referenced in buffering period
[h264 @ 0x3dcdef80] non-existing SPS 0 referenced in buffering period
    Last message repeated 1 times
[h264 @ 0x3dcdef80] non-existing SPS 1 referenced in buffering period
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] missing picture in access unit with size 301415
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] non-existing SPS 5 referenced in buffering period
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] non-existing SPS 6 referenced in buffering period
[h264 @ 0x3dcdef80] non-existing SPS 0 referenced in buffering period
    Last message repeated 1 times
[h264 @ 0x3dcdef80] non-existing SPS 1 referenced in buffering period
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5490
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8045
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7331
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7930
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5894
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8166
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7670
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7775
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4933
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 9271
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7496
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8989
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5150
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10993
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6394
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10043
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6716
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10878
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5325
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10648
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6345
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11308
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5833
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10187
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6503
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10035
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6935
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10728
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6440
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10925
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6434
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10764
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6138
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11612
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 3880
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11051
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4848
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 11145
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4205
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 14418
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6131
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10699
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7163
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10438
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7424
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10287
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4610
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 13780
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 4118
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 12914
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6520
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 13168
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 6425
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 12150
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5919
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 13279
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 8746
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 5895
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 50
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
    Last message repeated 1 times
[h264 @ 0x3dcdef80] non-existing SPS 6 referenced in buffering period
[h264 @ 0x3dcdef80] non-existing SPS 0 referenced in buffering period
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] missing picture in access unit with size 375582
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
    Last message repeated 1 times
[h264 @ 0x3dcdef80] non-existing SPS 6 referenced in buffering period
[h264 @ 0x3dcdef80] non-existing SPS 0 referenced in buffering period
[h264 @ 0x3dcdef80] Picture timing SEI payload too large
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7112
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 7033
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 2692
[h264 @ 0x3dcdef80] no frame!
[h264 @ 0x3dcdef80] missing picture in access unit with size 10696
[mp4 @ 0x3dcef5c0] dimensions not set
Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument
Error initializing output stream 0:1 -- 

Wrote 234 frames to /mnt/smbrouter/cam3/reolink/tracteurs/2026-04-05/0120260405124500.mp4 (video, mux failed)
[2026-04-06T20:33:45Z INFO  neolink_core::bc_protocol::stream] StreamData::drop: starting
[2026-04-06T20:33:45Z INFO  neolink_core::bc_protocol::stream] StreamData::drop: abort_handle cancelled
[2026-04-06T20:33:45Z WARN  neolink_core::bc_protocol::stream] StreamData::drop: handle is NOT finished, detaching (task may continue)
[2026-04-06T20:33:45Z INFO  neolink_core::bc_protocol::stream] StreamData::drop: complete
[2026-04-06T20:33:45Z INFO  neolink_core::bc_protocol::replay] Replay stream ended: 555 packets, 6581984 bytes binary
0120260405133333 from camera tracteurs -----------------------------------------

Some cameras (e.g. Reolink Argus PT) send H.265 video data but label
it as "H264" in BcMedia frame headers — a firmware bug that caused
h264parse and ffmpeg to fail with "No valid frames found" / "no frame!".

Add detect_codec_from_nal_bytes() which identifies the real codec by
looking for H.265-exclusive NAL types (VPS=32/SPS=33/PPS=34, byte0
0x40/0x42/0x44) or H.264 SPS/PPS/IDR. Used in both the buffered
decode path (try_decode_bcmedia_nals) and the live streaming path to
override the video_type field when it disagrees with the actual data.

Also derive PartialEq+Eq on VideoType to enable comparison.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@lorek123
Copy link
Copy Markdown
Author

lorek123 commented Apr 7, 2026

@surfzoid found another issue — the Argus PT has a firmware bug where it labels H.265 video frames as "H264" inside the BcMedia stream headers. Our codec detection trusted that label, so the stream was piped through h264parse → complete decode failure.

New fix: instead of trusting the header label, we inspect the actual NAL bytes. H.265 VPS/SPS/PPS have NAL unit types 32–34 (first byte after start code = 0x40/0x42/0x44), which cannot appear in H.264. If the NAL data contradicts the header, we use what the data actually is and log a warning like:

WARN neolink::replay: BcMedia header says H264 but NAL bytes indicate H265 — using detected codec

Please test with the latest feature/disk-subcommand build — mainStream should now produce a valid H.265 MP4 even on cameras with this firmware bug.

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 7, 2026

@lorek123 wonderful, good job. I will fired an alarm on my third cam to full validate but i m optimistic :-)

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 7, 2026

@lorek123 On my third cam, Argus 3 Firmware Version 0130_705_572_474 i got the video ok.
Just for the discovery, i just add the --stream mainStream option to the get files list command not for download and so i got first "0120260407123011 1 MB subStream io, md", neolink get an response 400 unreconized by device, the file was zero size, after adding --stream mainStream to the get file function, i got "0120260407123017 5 MB mainStream io, md" and video file was correct. So, for this cam/fw main and sub stream are 2 diferents files.

On cameras like Argus 3, mainStream and subStream recordings are stored
as separate files. Listing with --stream subStream (old default) and
then downloading with --stream mainStream would return 400 because the
file names differ between streams.

Now 'replay files' queries both streams when --stream is not specified,
merging results in a single listing. Users can still pass --stream
mainStream/subStream to query a specific stream only. The output
already shows the stream type per file so users can pass the correct
--stream to the download/play command.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@lorek123
Copy link
Copy Markdown
Author

lorek123 commented Apr 8, 2026

@surfzoid good catch on the stream-specific file listing! The replay files command was defaulting to subStream, so you'd get subStream filenames that don't work with --stream mainStream for download.

Fixed: replay files now queries both mainStream and subStream by default and shows all files together (the stream type is already shown in each line, e.g. 1 MB subStream io, md vs 5 MB mainStream io, md). You can still pass --stream mainStream or --stream subStream to filter to one stream only.

Please test with the latest build!

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 8, 2026

That's only cosmetic, i'm not sure it's usefull, wait and see the build.

@surfzoid
Copy link
Copy Markdown

surfzoid commented Apr 8, 2026

@lorek123 your last comit is ok.
I tested with my script whose have the mainstream flag for the getfile command.
My scripts come with a Zenity front end feel free to test it here #367 (reply in thread)

@MasterPlexus
Copy link
Copy Markdown

Could it be that the responding list of files is stopping at 40 entrys? there are more videos on the cam, but files get only 40 entrys maximum back (I'm still one commit behind).

@surfzoid
Copy link
Copy Markdown

Could it be that the responding list of files is stopping at 40 entrys? there are more videos on the cam, but files get only 40 entrys maximum back (I'm still one commit behind).

40 per days ! you should adjust your setup!

@MasterPlexus
Copy link
Copy Markdown

Tell that the hedgehogs :D

@MasterPlexus
Copy link
Copy Markdown

Could it be that the responding list of files is stopping at 40 entry's? there are more videos on the cam, but files get only 40 entry's maximum back (I'm still one commit behind).

@lorek123 I had a look and consulted Gemini, which explains to me, that in the get files handle no pagination is established like in the pub async fn alarm_video_search_next. Unfortunately I'm not really stable in Rust, so I could not not try to implement it... So would be great if you could have a look. Of course if you have time, thanks anyhow to all your efforts!

get_file_list_by_handle now loops calling MSG 15 with the same handle
until the camera returns an empty batch or a non-200 response, matching
the alarm_video_search_next pagination pattern.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@lorek123
Copy link
Copy Markdown
Author

@MasterPlexus The file list pagination is now fixed. Previously MSG 15 was only called once per handle, capping results at the camera's single-page limit (~40 files). The code now loops MSG 15 with the same handle until the camera returns an empty batch, so all files for the day will be returned regardless of count.

The fix is in the latest commit on the branch. @surfzoid's build should pick it up automatically.

@MasterPlexus
Copy link
Copy Markdown

@MasterPlexus The file list pagination is now fixed. Previously MSG 15 was only called once per handle, capping results at the camera's single-page limit (~40 files). The code now loops MSG 15 with the same handle until the camera returns an empty batch, so all files for the day will be returned regardless of count.

The fix is in the latest commit on the branch. @surfzoid's build should pick it up automatically.

I pulled, rebuild, and tested it: worked perfectly now! Thanks!

For the direct download part, I'm thinking about to try to use network sn.if.fer on my android, to check if the app is able to send this kind of step, and to see how the payload may looks like. I assume a parameter is may missed for the trigger of the Download... Other way could be to de.com.pile a firmware where we know this functionality is part of. but currently I don't know which can do it, and not shure how hard the firmwares are ob#fus*cated. But of course this has time ;)

@lorek123
Copy link
Copy Markdown
Author

@MasterPlexus I briefly used https://github.com/emanuele-f/PCAPdroid, I can recommend it if you want to analyse app network traffic. For RE I never had a chance to take a look at the firmware, but dlls and so's from from desktop/android apps are handled pretty well by Claude code + Ghidra MCP combo. I'll take a look in the meantime for the direct download option.

@MasterPlexus
Copy link
Copy Markdown

I found on reolink support page, that the reolink PC client has direct download possibilities. So I guess the best is to try to sniff on that stage.

I will give it a try (but it will take a Moment)

If others will try: https://support.reolink.com/articles/900000645323-How-to-Download-All-Recordings-at-Once-for-Reolink-Devices/

@MasterPlexus
Copy link
Copy Markdown

Hi @lorek123 . I tried a little bit, not easy. Anyhow, just as an Idea, could it may be that the cam is expecting to have the UID set instead of zeros for the direct download?

The BC_DOWNLOAD_BY_NAME_INFO struct has a 32-byte cUID field at offset
0x04 that was left zeroed. Some cameras (e.g. Argus 2) may require the
actual UID to accept MSG 8. Now fetches the UID from the camera before
building the payload, matching the layout of BC_DOWNLOAD_BY_TIME_INFO.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@lorek123
Copy link
Copy Markdown
Author

@MasterPlexus Good call on the UID — the BC_DOWNLOAD_BY_NAME_INFO struct has a 32-byte cUID field at offset 0x04 that was zeroed in our payload. Just pushed a fix that fetches the camera UID and fills it in before sending MSG 8. Worth trying on your Argus 2 — grab the latest from @surfzoid's build once it rebuilds, or pull and compile.

@surfzoid
Copy link
Copy Markdown

@MasterPlexus Good call on the UID — the BC_DOWNLOAD_BY_NAME_INFO struct has a 32-byte cUID field at offset 0x04 that was zeroed in our payload. Just pushed a fix that fetches the camera UID and fills it in before sending MSG 8. Worth trying on your Argus 2 — grab the latest from @surfzoid's build once it rebuilds, or pull and compile.

i had sync your commit with my fork, build is automatically started and should be ok in few minutes

@MasterPlexus
Copy link
Copy Markdown

@MasterPlexus Good call on the UID — the BC_DOWNLOAD_BY_NAME_INFO struct has a 32-byte cUID field at offset 0x04 that was zeroed in our payload. Just pushed a fix that fetches the camera UID and fills it in before sending MSG 8. Worth trying on your Argus 2 — grab the latest from @surfzoid's build once it rebuilds, or pull and compile.

Thanks. I tied it after a pull, but unfortunately it does not change anything.

I have some questions die to the sniffing:
I assume the traffic is a)ssl'let via https, and b) that the payload is not directly xml structure, right? I tried to get the decrypted data via sniffing, but there is no clear text, so I assume the packages may needed to be translated from byte code to xml. My question is, is there a method to make that with less effort? I guess there are methods in neolink, but I don't know now how to call them may on a manual stored byte stream.is there somewhere may a manual how it was done to build then neolink?

@MasterPlexus
Copy link
Copy Markdown

I have a new idea which I will test tomorrow. I need to check how the file name really looks like on the SD card. May the request did not accept the only numeric code as a request. I assume we need to send the real name of the file on the SD card... Will check tomorrow, and give a feedback.

@MasterPlexus
Copy link
Copy Markdown

I have a new idea which I will test tomorrow. I need to check how the file name really looks like on the SD card. May the request did not accept the only numeric code as a request. I assume we need to send the real name of the file on the SD card... Will check tomorrow, and give a feedback.

The Filenames are set on my argus 2 in this way: Rec_20260409_235436_151_M.mp4 wich looks like different then just the number code. anyhow, as the stream and convert approach is working it looks like this does not change something to use the real file names..

@surfzoid
Copy link
Copy Markdown

surfzoid commented May 4, 2026

on Model Reolink Argus 3, sometime i get :

Error: Could not get file list from camera

Caused by:
    Camera responded with Service Unavaliable: Msg of type 15 returned code 400

Perhaps network micro-outage?
Then Neolink freeze sometime.

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.

3 participants