A lightweight Windows screen-sharing and remote-control server. It captures a selected monitor with FFmpeg (gdigrab), encodes it as MPEG-1 video, and streams it over a WebSocket to any browser using JSMpeg. Authenticated browser clients can also send mouse and keyboard input back to the host, which replays it via the Win32 SendInput API.
- Screen capture of any detected monitor via FFmpeg's
gdigrabinput device - Real-time MPEG-TS/MPEG-1 video streaming to a browser (no plugins, via JSMpeg)
- Simple built-in HTTP server for serving the web client (
index.html,jsmpeg.min.js,app.ico) - WebSocket-based control channel for remote mouse movement, clicks, scroll, and keyboard input
- Username/password login with a per-session token to authorize the video stream
- Cross-platform build target (Win32 / x64, Debug / Release) via Visual Studio
ScreenSharing/
├── ScreenSharing.slnx # Visual Studio solution
├── ScreenSharing.vcxproj # Project file
├── ScreenSharing.vcxproj.filters
├── ScreenSharing.vcxproj.user
├── main.cpp # Server: capture, encode, WebSocket, input injection
├── json.hpp # nlohmann/json (single header)
├── index.html # Web client (login + video canvas)
├── jsmpeg_min.js # JSMpeg player (rename to jsmpeg.min.js, see below)
├── app.ico # Favicon served at /app.ico
└── auth.json # Login credentials (see Configuration)
- Windows 10/11
- Visual Studio 2022 (or newer) with the "Desktop development with C++" workload
- Platform toolset
v145, C++20 language standard
- Platform toolset
- Third-party libraries, expected at
../libs/relative to the project directory:- FFmpeg 6.1 (dev libs + headers) →
../libs/ffmpeg-6.1/include,../libs/ffmpeg-6.1/lib - websocketpp →
../libs/websocketpp - Asio 1.36.0 (standalone, header-only) →
../libs/asio-1.36.0/include - Boost 1.81.0 →
../libs/boost-1.81.0/include
- FFmpeg 6.1 (dev libs + headers) →
Adjust the AdditionalIncludeDirectories / AdditionalLibraryDirectories in the project's x64 configurations if your libraries live elsewhere.
Note: the include/library paths in the
.vcxprojare currently only defined for the x64 configurations. Build with platformx64(Debug or Release); the Win32 configurations will need the same paths added before they'll compile.
The following FFmpeg import libraries are linked: avcodec, avdevice, avfilter, avformat, avutil, postproc, swresample, swscale. The matching FFmpeg DLLs must be available at runtime (either next to the .exe or on PATH).
- Place the third-party libraries under
../libs/as described above (one directory above the project folder). - Open
ScreenSharing.slnxin Visual Studio. - Select the x64 platform and Debug or Release configuration.
- Build the solution.
- Copy the following files into the output directory next to
ScreenSharing.exeif they aren't already there:index.htmljsmpeg_min.jsrenamed tojsmpeg.min.js(the server andindex.htmlboth request/jsmpeg.min.js)app.icoauth.json- The FFmpeg runtime DLLs matching your FFmpeg 6.1 build
Login credentials are read from auth.json, which must sit next to the executable:
{
"user": "admin",
"pass": "123"
}If the file is missing or fails to parse, the server starts with empty credentials and a warning is printed to the console. Change these credentials before using this on anything but a local test.
- Run
ScreenSharing.exe. - The program lists detected monitors and their resolutions/offsets. Enter the index of the monitor you want to share.
- The server starts listening on port 9002.
- From a browser (on the same machine or another PC on the network), navigate to:
http://<host-ip>:9002 - Log in with the credentials from
auth.json. - On success, the video stream starts and the canvas becomes the input surface:
- Mouse movement, clicks, and scroll wheel are forwarded to the host
- Keyboard input is forwarded while the canvas has focus
- Press ESC in the server's console window to shut it down.
- Capture/Encode pipeline:
gdigrabcaptures the selected monitor region at 30 fps → decoded → scaled withswscale→ re-encoded as MPEG-1 video → muxed into an MPEG-TS stream in memory (via a customAVIOContextwrite callback) → broadcast as binary WebSocket frames to all authenticated video clients. - Control channel: every WebSocket connection to any path other than
/videois treated as a control connection. It starts unauthenticated and must send{"type":"login","user":...,"pass":...}. On success, the server generates a random session token and returns it; the client then opens a second WebSocket to/video?token=<token>to receive the video stream. Once a control connection is logged in, it may sendmousemove,mousedown,mouseup,wheel,keydown, andkeyupmessages, which are translated intoSendInputcalls on the host. - HTTP server: a minimal handler serves
/(index.html),/jsmpeg.min.js, and/app.icofrom the working directory; anything else returns 404.
This project is intended for use on a trusted local network (e.g., controlling your own PC from another device at home). Be aware of the following before exposing it more broadly:
- Credentials are stored in plain text in
auth.json. - The WebSocket and HTTP traffic is unencrypted (
ws://, notwss://), so credentials, the session token, the video stream, and input events are all visible to anyone who can observe the network. - There's no rate limiting or lockout on login attempts, no HTTPS/TLS, and the session token does not expire.
- Anyone who obtains a valid token can view the screen and inject arbitrary mouse/keyboard input.
Do not expose port 9002 directly to the internet without adding TLS, stronger authentication, and rate limiting.
- FFmpeg — screen capture, video decoding/encoding, muxing
- websocketpp — WebSocket server
- Asio — networking (used standalone by websocketpp)
- nlohmann/json — JSON parsing (
json.hpp) - JSMpeg — browser-side MPEG-1/TS video player
This project is licensed under the MIT License.