-
Couldn't load subscription status.
- Fork 2.6k
Description
Summary
CaptureMJPEG assumes MJPEG streams always include:
- a top-level
Content-Type: multipart/x-mixed-replace; boundary=... - and per-part
Content-Lengthheaders
Many valid MJPEG sources (e.g., FFmpeg’s -f mpjpeg, some IP cams, microcontroller streams) omit one or both. As a result, Mission Planner throws and the video pipeline stops.
Environment
- OS: Windows 10/11 (x64)
- Camera: Logitech BRIO (MJPEG 1280×720 @ 60 fps)
- FFmpeg: 8.0 (essentials build by gyan.dev)
- Mission Planner: current (master/latest)
- .NET Framework: (project targets 4.6–4.7)
Steps to Reproduce
-
Start a simple HTTP MJPEG stream (FFmpeg acts as a tiny server):
ffmpeg -f dshow -thread_queue_size 512 -rtbufsize 512M -framerate 60 -video_size 1280x720 -input_format mjpeg -i video="<WEBCAM_DEVICE>" -an -map 0:v:0 -c:v copy -f mpjpeg -boundary_tag frame -fflags nobuffer -muxdelay 0 -listen 1 http://<IP>:<PORT>/stream.mjpg
(This produces multipart MJPEG without per-part
Content-Length.) -
In Mission Planner, set video source to:
http://<IP>:<PORT>/stream.mjpg -
Observe: MP throws an exception and shows no video.
Expected behavior
Mission Planner should display the MJPEG stream even when:
Content-Typeis absent or lacksboundary=...- individual parts omit
Content-Length(client should read until the next boundary)
Actual behavior
MP crashes or stops the pipeline with:
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at MissionPlanner.Utilities.CaptureMJPEG.getUrl() in ...\CaptureMJPEG.cs:line 138
In other cases, MP logs a connection error if a browser has already connected (FFmpeg -listen 1 serves only one client):
System.Net.WebException: Unable to connect to the remote server
---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it 127.0.0.1:1889
Additional context
Browsers handle these streams fine. Many MJPEG servers legally omit per-part lengths; clients are expected to read until the next boundary delimiter (RFC 2046 multipart).
Some endpoints also omit the top-level Content-Type header; clients should detect the boundary from the first boundary line in the body (e.g., --frame).
Proposed fix
Make CaptureMJPEG tolerant to missing headers:
-
Boundary detection
- Parse from
Content-Typeif present. - If missing, sniff boundary from body (read lines until
--<token>).
- Parse from
-
Part reading
- If
Content-Lengthexists → read exact bytes (current behavior). - If missing → stream until the next boundary sequence
\r\n--<boundary>, without over-reading (network stream is non-seekable).
- If
-
Header parsing
- Case-insensitive dictionary; skip malformed lines gracefully.
-
HTTP request hardening
req.KeepAlive = true,req.Accept = "multipart/x-mixed-replace", optional read timeout.
Workarounds
-
Use a MJPEG server that always sets per-part
Content-Length(not always possible). -
Patch CaptureMJPEG per the proposed fix (see related PR).
Related PR
- PR: CaptureMJPEG: tolerate missing
Content-Type/Content-Lengthin MJPEG; add boundary sniffing & lengthless frame reads #3603
Implements boundary sniffing and lengthless frame reads, keeps behavior backward-compatible for compliant streams.