# Data flow — Genymobile/scrcpy

> Canonical page: https://codevetter.com/unpack/scrcpy/data-flow

# Data flow — Genymobile/scrcpy

Scanned commit 19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac (2026-09-05). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Outbound (device->host): capture (screen/camera/mic) -> MediaCodec encoder -> Streamer writes a 4-byte codec id then 12-byte frame/session headers + raw packets onto the video/audio sockets -> client demuxer threads parse headers into AVPackets -> packet_source fans out to sinks (decoder -> screen/v4l2, recorder). Inbound (host->device): SDL input events -> processors build sc_control_msg -> controller queue -> serialized onto the control socket -> ControlMessageReader -> Controller.handleEvent -> Device/InputManager injection or UHID writes. The control socket is also used device->client for DeviceMessages (clipboard, ack, UHID output).
- Wire format: each stream starts with a 4-byte codec id (ASCII like 'h264'); then video gets a 12-byte session header (MSB set, width/height) and each media packet is a 12-byte header (64-bit PTS+flags: bit62 config, bit61 keyframe; 32-bit size) followed by raw packet data. — [app/src/demuxer.c#L12-138](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/demuxer.c#L12-L138) [server/src/main/java/com/genymobile/scrcpy/device/Streamer.java#L17-124](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java#L17-L124)
- Server video pipeline: SurfaceCapture (ScreenCapture / NewDisplayCapture / CameraCapture) feeds a Surface into SurfaceEncoder wrapping MediaCodec; encoded buffers go through Streamer.writePacket() to the video FileDescriptor. — [server/src/main/java/com/genymobile/scrcpy/Server.java#L139-160](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/Server.java#L139-L160) [server/src/main/java/com/genymobile/scrcpy/device/Streamer.java#L68-89](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java#L68-L89)
- Server audio pipeline: AudioCapture (AudioDirectCapture for mic-family sources, AudioPlaybackCapture otherwise) is encoded by AudioEncoder or sent raw by AudioRawRecorder through a Streamer onto the audio fd. — [server/src/main/java/com/genymobile/scrcpy/Server.java#L119-137](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/Server.java#L119-L137) [server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java)
- Client demuxer run_demuxer() reads the codec id (0 = stream disabled by device, 1 = config error), opens an AVCodecContext (LOW_DELAY, YUV420P for video, stereo 48kHz for audio), then loops pushing session updates and merged packets to all packet_source sinks. — [app/src/demuxer.c#L176-355](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/demuxer.c#L176-L355)
- H.264/H.265 config packets are merged into the following media packet by sc_packet_merger before dispatch; other codecs pass through. — [app/src/demuxer.c#L284-344](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/demuxer.c#L284-L344) [app/src/packet_merger.c](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/packet_merger.c)
- Sink fan-out is wired in scrcpy(): video_demuxer.packet_source -> video_decoder.packet_sink -> (optional video_regulator) -> screen.frame_sink and/or v4l2_sink; both demuxers also feed recorder.packet_sinks when --record is set. — [app/src/scrcpy.c#L532-589](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L532-L589) [app/src/scrcpy.c#L792-829](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L792-L829)
- Control uplink: sc_controller_push_msg() enqueues sc_control_msg (limit SC_CONTROL_MSG_QUEUE_LIMIT=60; only UHID_CREATE/UHID_DESTROY are non-droppable), run_controller serializes with sc_control_msg_serialize() into a static buffer and net_send_all()s to the control socket; RESIZE_DISPLAY is coalesced via a separate field. — [app/src/controller.c#L7-217](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/controller.c#L7-L217) [app/src/control_msg.c#L358-366](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/control_msg.c#L358-L366)
- Control downlink: ControlMessageReader.read() parses the same type byte + big-endian fields into ControlMessage objects, then Controller.handleEvent() dispatches to injectKeycode/injectTouch/injectScroll/clipboard/UHID/camera actions. — [server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java#L25-70](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java#L25-L70) [server/src/main/java/com/genymobile/scrcpy/control/Controller.java#L321-441](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/control/Controller.java#L321-L441)
- Device->client messages (clipboard text, clipboard ack, UHID output) are serialized by DeviceMessageWriter/DeviceMessageSender onto the control socket and deserialized in the client receiver thread, which schedules SDL clipboard writes on the main thread. — [app/src/device_msg.h#L14-45](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/device_msg.h#L14-L45) [app/src/receiver.c](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/receiver.c) [server/src/main/java/com/genymobile/scrcpy/control/DeviceMessageSender.java](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/control/DeviceMessageSender.java)
- Handshake metadata: the server sends a fixed 64-byte device name on the first connected socket (sendDeviceMeta), read by client device_read_info() into sc_server_info for use as the window title. — [server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L155-165](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L155-L165) [app/src/server.c#L596-610](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/server.c#L596-L610)
- Options flow: CLI -> scrcpy_options -> sc_server_params -> execute_server() renders 'key=value' args (with VALIDATE_STRING against shell metacharacters) -> Server Options.parse() switch reconstructs typed Options. — [app/src/server.c#L256-458](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/server.c#L256-L458) [server/src/main/java/com/genymobile/scrcpy/Options.java#L336-574](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/Options.java#L336-L574)
- Recorder muxing: packet sinks reference AVPackets into a queue; the recorder thread writes them with av_interleaved_write_frame() after rescaling from SCRCPY_TIME_BASE (1/1e6 us) to each stream's time_base, fixing non-monotonic PTS. — [app/src/recorder.c#L21-120](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/recorder.c#L21-L120)
- Session identity: client generates a 31-bit random scid per run; the device socket name 'scrcpy_%08x' lets multiple scrcpy instances coexist on one device. — [app/src/scrcpy.c#L276-283](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/app/src/scrcpy.c#L276-L283) [server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L47-54](https://github.com/Genymobile/scrcpy/blob/19c1261d2e2cbf2b5e6a71a8b64cc1dd3ede06ac/server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L47-L54)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
