## Link to GitHub Issue or related Pull Request, if one exists
#0
## Description of change
Moves the API capture readback off the game's Present thread while a
video stream client is connected.
The readback is a `LockRect` plus a memcpy of the whole back buffer,
roughly 635us at 720p and 1270us at 1080p. On the Present thread that
comes out of the game's frame budget: TDJ (at 120Hz) dropped to 117fps
with a 60fps stream running, and reading on a pool thread instead gave
the full 120 back.
Only streaming takes the off-thread path, gated on a new
`capture_pump::screen_claimed()`.
Screenshots, one-off API captures, and `THREAD_BAN` games all keep the
existing inline read for compat reasons. A pool thread in `LockRect`
while the Present thread sat inside `GetRenderTargetData` deadlocks DDR
X2 for example.
`CLAIMED[]` becomes `std::atomic<bool>` so the capture path does not
take a lock on the Present thread. The read pool has a single worker so
frames cannot be enqueued out of order, and both capture pools are never
destroyed so a late read cannot queue onto a torn-down pool.
The capture pipeline itself is unchanged: `GetRenderTargetData` is still
synchronous on the Present thread.
## Testing
DDR X2
World
IIDX TDJ
SDVX VM
## Link to GitHub Issue or related Pull Request, if one exists
fixes#875
## Description of change
Adds `-apistream`, an optional HTTP video stream of the mirrored screen.
It listens on the API port +2.
Two endpoints, sharing the same `screen`, `fps` and `q` parameters:
/stream.mjpg JPEG frames, for clients with no container support
/stream.h264 H.264 annex-b, for an app driving MediaCodec or
VideoToolbox itself
One encoder per connection, fed by a per-screen pump that always hands
over the newest frame, so a slow reader drops frames instead of building
a backlog. `capture.get_jpg` behaviour is unchanged.
Additional documentation for developers:
https://github.com/spice2x/spice2x.github.io/wiki/Video-Stream
## Testing