ArduPilot / ArduPilot/MissionPlanner
CaptureMJPEG fails when `Content-Type` and/or per-part `Content-Length` are missing (MJPEG over HTTP)
- Dominant language
- C#
- Stars
- 2.4k
- Forks
- 2.9k
- Avg merge
- 19h 16m
- Merged PRs (30d)
- 4
Description
## Summary
CaptureMJPEG assumes MJPEG streams always include:
- a top-level `Content-Type: multipart/x-mixed-replace; boundary=...`
- and per-part `Content-Length` headers
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
1. Start a simple HTTP MJPEG stream (FFmpeg acts as a tiny server):
```shell
ffmpeg -f dshow -thread_queue_size 512 -rtbufsize 512M -framerate 60 -video_size 1280x720 -input_format mjpeg -i video="" -an -map 0:v:0 -c:v copy -f mpjpeg -boundary_tag frame -fflags nobuffer -muxdelay 0 -listen 1 http://:/stream.mjpg
```
(This produces multipart MJPEG without per-part `Content-Length`.)
2. In Mission Planner, set video source to:
`http://:/stream.mjpg`
3. Observe: MP throws an exception and shows no video.
## Expected behavior
Mission Planner should display the MJPEG stream even when:
- `Content-Type` is absent or lacks `boundary=...`
- individual parts omit `Content-Length` (client should read until the next boundary)
## Actual behavior
MP crashes or stops the pipeline with:
```log
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):
```log
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:
1. **Boundary detection**
- Parse from `Content-Type` if present.
- If missing, **sniff boundary from body** (read lines until `--`).
2. **Part reading**
- If `Content-Length` exists → read exact bytes (current behavior).
- If missing → **stream until the next boundary** sequence `\r\n--`, without over-reading (network stream is non-seekable).
3. **Header parsing**
- Case-insensitive dictionary; skip malformed lines gracefully.
4. **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**: #3603
Implements boundary sniffing and lengthless frame reads, keeps behavior backward-compatible for compliant streams.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with CaptureMJPEG.cs, especially the getUrl() path around line 138, and compare it with related PR #3603. Reproduce the FFmpeg multipart MJPEG stream and inspect how headers, boundaries, and frame data are read. Done means streams without a top-level Content-Type or per-part Content-Length display without stopping the video pipeline.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- audio-video-rtc, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100