Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

scrcpy Administrator & Developer Guide

Generated May 2026 from Genymobile/scrcpy at 247a37d

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

scrcpy (screen copy) is a high-performance client-server application that displays and controls Android devices from a desktop computer. The client is a native C application rendering through SDL2 and FFmpeg; the server is an Android Java application injected onto the device via adb. All communication flows over adb connections (USB or TCP/IP), requiring no root access and no app installation on the device.

This guide covers architecture, build system, configuration, deployment, security considerations, and developer internals for scrcpy v3.3.4 (commit 247a37d).


Table of Contents


Architecture Overview

scrcpy operates as a two-component system: a host-side C client and a device-side Java server. The client pushes the server JAR to the device, launches it via adb shell, and establishes socket connections for video, audio, and control streams.

┌─────────────────────────────────────────────────────────────────┐
│                        HOST (Desktop)                           │
│                                                                 │
│  main.c ──► cli.c (parse args) ──► scrcpy.c (orchestration)    │
│                                        │                        │
│            ┌───────────────────────────┼──────────────────┐     │
│            │                          │                   │     │
│       server.c               demuxer.c (x2)        controller.c │
│    (push JAR, launch,     (video + audio)        (control msgs) │
│     establish sockets)         │                       │        │
│            │              decoder.c              control_msg.c   │
│            │                  │                       │         │
│            │         ┌───────┴────────┐               │        │
│            │         │                │               │        │
│            │    display.c /      recorder.c           │        │
│            │    screen.c (SDL)   (FFmpeg mux)         │        │
│            │         │                                │        │
│            │    audio_player.c                        │        │
│            │    (SDL audio)                           │        │
│            │                                          │        │
│            │    ┌──────────────────────┐               │        │
│            │    │  HID subsystem       │               │        │
│            │    │  hid/ (kb,mouse,pad) │               │        │
│            │    │  uhid/ (Linux UHID)  │               │        │
│            │    │  usb/ (AOAv2)        │               │        │
│            │    └──────────────────────┘               │        │
│            │                                          │        │
│            │    v4l2_sink.c (Linux)                    │        │
│            │    file_pusher.c (drag & drop)            │        │
└────────────┼──────────────────────────────────────────┼────────┘
             │              ADB (USB / TCP)              │
             │         ┌────────────────────┐            │
             ▼         ▼                    ▼            ▼
┌─────────────────────────────────────────────────────────────────┐
│                      DEVICE (Android)                           │
│                                                                 │
│  /data/local/tmp/scrcpy-server.jar                              │
│                                                                 │
│  Server.java (entry point)                                      │
│       │                                                         │
│       ├── Options.java (parse server-side options)               │
│       │                                                         │
│       ├── video/                                                │
│       │    ScreenCapture / CameraCapture / NewDisplayCapture    │
│       │    └── SurfaceEncoder ──► Streamer ──► socket           │
│       │                                                         │
│       ├── audio/                                                │
│       │    AudioDirectCapture / AudioPlaybackCapture             │
│       │    └── AudioEncoder / AudioRawRecorder ──► socket       │
│       │                                                         │
│       ├── control/                                              │
│       │    ControlMessageReader ──► Controller                  │
│       │    └── injects via InputManager, ClipboardManager, etc. │
│       │                                                         │
│       └── wrappers/ (hidden Android API access via reflection)  │
│            ActivityManager, ClipboardManager, DisplayControl,   │
│            DisplayManager, InputManager, PowerManager,          │
│            ServiceManager, StatusBarManager, SurfaceControl,    │
│            WindowManager, ContentProvider                       │
└─────────────────────────────────────────────────────────────────┘

Connection establishment

  1. The client pushes scrcpy-server.jar to /data/local/tmp/scrcpy-server.jar on the device via adb push.
  2. The client starts the server via adb shell with appropriate arguments.
  3. By default, the client uses adb reverse to make the device connect back to the host (the client listens, the server connects). The --force-adb-forward flag reverses this so the client connects to a forwarded port instead.
  4. The socket name prefix used is scrcpy_.
  5. Separate socket connections are established for video, audio, and control streams.

Data flow summary

Stream Direction Protocol
Video Device → Host Encoded frames (H.264/H.265/AV1) via packet stream
Audio Device → Host Encoded frames (Opus/AAC/FLAC/RAW) via packet stream
Control Host → Device Serialized control messages (touch, key, clipboard, etc.)
Device messages Device → Host Clipboard content, ACKs

Note

scrcpy does not install anything on the device. The server JAR is pushed to a temporary location and executed via adb shell. No permanent modifications are made.


System Requirements

Host requirements

Component Minimum Notes
OS Linux, macOS, Windows V4L2 sink is Linux-only; OTG/UHID requires Linux
ADB Any recent version Must be in PATH or set via ADB env var
SDL2 2.x Display and audio output
FFmpeg libavcodec, libavformat, libavutil, libswresample Video/audio decoding and recording
libusb Optional Required for AOAv2 (USB HID) and OTG mode
Meson + Ninja Build-time only Client build system

Device requirements

Component Requirement
Android API 21+ (Android 5.0 Lollipop)
USB debugging Must be enabled in Developer Options
Audio capture Android 11+ (API 30) for audio forwarding

Build-time requirements

Component Purpose
Meson Client build system
Ninja Build backend
C compiler GCC or Clang for client
pkg-config Dependency resolution
Android SDK compileSdk 36 for server
Gradle Server build (or use build_without_gradle.sh)
Java JDK Server compilation

Important

The server targets compileSdk: 36, minSdk: 21, targetSdk: 36. The server has zero runtime dependencies beyond the Android SDK itself; junit:junit:4.13.2 is used for tests only.


Configuration Reference

CLI options (complete list)

All options are passed to the scrcpy client binary. The client translates them into server arguments where applicable.

Video options

Option Default Description
--video-codec h264 Video codec: h264, h265, or av1
--video-bit-rate 8M Video encoding bit rate (e.g., 8M, 2M)
--video-source display Video source: display or camera
--video-buffer 0 (ms) Video buffering delay for jitter compensation
--max-size 0 (unlimited) Limit both dimensions to this value (preserving aspect ratio)
--max-fps (none) Maximum framerate cap
--capture-orientation 0 Capture orientation in degrees
--display-orientation 0 Display orientation in degrees
--record-orientation 0 Recording orientation in degrees
--display-id 0 Android display ID to mirror
--no-video (flag) Disable video forwarding
--no-video-playback (flag) Disable video playback (but still allow recording)
--video-codec-options (none) Codec-specific options (key=value, comma-separated)
--video-encoder (auto) Force a specific video encoder

Audio options

Option Default Description
--audio-codec opus Audio codec: opus, aac, flac, or raw
--audio-bit-rate 128K Audio encoding bit rate
--audio-source output Audio source: output (device playback) or mic
--audio-buffer 50 (ms) Audio buffering delay
--audio-output-buffer 5 (ms) SDL audio output buffer size
--no-audio (flag) Disable audio forwarding
--no-audio-playback (flag) Disable audio playback (but still allow recording)
--audio-codec-options (none) Audio codec-specific options
--audio-encoder (auto) Force a specific audio encoder

Recording options

Option Default Description
--record / -r (none) Record to file (format inferred from extension)
--record-format (auto) Force recording format: mp4, mkv, m4a, mka, opus, aac, flac, wav
--no-playback (flag) Disable both video and audio playback (recording-only mode)

Input options

Option Default Description
--keyboard (auto) Keyboard input mode: sdk, uhid, aoa, disabled
--mouse (auto) Mouse input mode: sdk, uhid, aoa, disabled
--gamepad (auto) Gamepad input mode: uhid, aoa, disabled
--mouse-bind bhsn:++++ (SDK) / ++++:bhsn (AOA/UHID) Mouse button bindings
--shortcut-mod lalt,lsuper Shortcut modifier key(s)
--no-control (flag) Disable device control (mirror only)
--no-key-repeat (flag) Do not forward repeated key events

Connection options

Option Default Description
--serial / -s (auto) Device serial number (or ANDROID_SERIAL env)
--tcpip (none) Connect via TCP/IP (optionally specify host[:port])
--force-adb-forward (flag) Use adb forward instead of adb reverse
--tunnel-host (auto) Host for tunnel setup
--tunnel-port (auto) Port for tunnel setup

Display options

Option Default Description
--window-title (auto) Custom window title
--window-x (auto) Initial window X position
--window-y (auto) Initial window Y position
--window-width (auto) Initial window width
--window-height (auto) Initial window height
--window-borderless (flag) Remove window decorations
--always-on-top (flag) Keep window above others
--fullscreen / -f (flag) Start in fullscreen
--no-window (flag) Do not display a window
--rotation (auto) Window rotation

Device control options

Option Default Description
--turn-screen-off / -S (flag) Turn device screen off on start
--stay-awake / -w (flag) Keep device awake while connected
--show-touches / -t (flag) Enable "Show touches" on device
--power-off-on-close (flag) Turn off device screen on close
--no-power-on (flag) Do not wake device on start
--no-cleanup (flag) Do not restore device state on exit
--push-target /sdcard/Download/ Target directory for file pushes (drag & drop)
--new-display (none) Create a new virtual display

Miscellaneous options

Option Default Description
--verbosity / -V info (debug in debug builds) Log level: verbose, debug, info, warn, error
--version / -v (flag) Print version
--help / -h (flag) Print help
--pause-on-exit false Pause terminal on exit: true, false, if-error
--prefer-text (flag) Prefer text injection for input
--raw-key-events (flag) Inject raw key events
--forward-all-clicks (flag) Forward right and middle clicks to device
--legacy-paste (flag) Use legacy paste method
--no-downsize-on-error (flag) Do not retry with smaller size on encoding error
--crop (none) Crop the device screen (format: width:height:x:y)
--render-driver (auto) SDL render driver name
--list-encoders (flag) List available encoders
--list-displays (flag) List available displays
--list-cameras (flag) List available cameras
--list-camera-sizes (flag) List available camera sizes
--otg (flag) OTG mode (USB HID only, no mirroring)
--v4l2-sink (none) V4L2 device path for video output (Linux only)
--v4l2-buffer 0 (ms) V4L2 output buffer delay
--time-limit (none) Maximum session duration
--camera-id (none) Camera ID to use
--camera-size (auto) Camera capture size
--camera-facing (none) Camera facing: front, back, external
--camera-ar (none) Camera aspect ratio
--camera-fps (none) Camera capture framerate
--camera-high-speed (flag) Use high-speed camera capture

Environment variables

Variable Purpose
ADB Path to the adb binary. Overrides the default adb found in PATH.
ANDROID_SERIAL Device serial number. Equivalent to --serial / -s.
SCRCPY_SERVER_PATH Path to the scrcpy-server JAR on the host. Overrides the default installed location (PREFIX/share/scrcpy/scrcpy-server).
SCRCPY_ICON_PATH Path to a custom window icon file.

Exit codes

Code Meaning
0 Normal exit
1 Start failure (could not initialize, connect, or launch server)
2 Device disconnected during session

Default ADB port

The default ADB port for TCP/IP connections is 5555.


Deployment & Scaling

Building from source

Building the server

The server is an Android Java application built with Gradle:

# Standard Gradle build
cd server
./gradlew assembleRelease

The server can also be built without Gradle using the Android SDK directly:

cd server
./build_without_gradle.sh

Note

The server build produces a JAR file. ProGuard rules are defined in server/proguard-rules.pro for release builds.

Building the client

The client uses Meson and Ninja:

# Configure
meson setup build --buildtype=release

# Build
ninja -C build

# Install
sudo ninja -C build install

Build options are defined in meson_options.txt and can be set during configuration:

meson setup build --buildtype=release -Doption_name=value

Using install_release.sh

The install_release.sh script automates the full process: downloads a prebuilt server binary, builds the client with Meson and Ninja, and installs everything:

./install_release.sh

Cross-compilation

Cross-compilation configurations are provided for Windows targets:

File Target
cross_win32.txt Windows 32-bit
cross_win64.txt Windows 64-bit

Usage:

meson setup build-win64 --cross-file cross_win64.txt --buildtype=release
ninja -C build-win64

Warning

Cross-compilation requires the appropriate cross-compiler toolchain (e.g., MinGW-w64) and cross-compiled versions of all dependencies (SDL2, FFmpeg, libusb).

Packaging

Linux desktop integration

The app/data/ directory contains standard Linux desktop integration files:

  • scrcpy.desktop — standard desktop entry
  • scrcpy-console.desktop — desktop entry that keeps terminal open
  • icon.png, icon.svg, icon.ico — application icons in multiple formats
  • bash-completion/scrcpy — Bash tab completion
  • zsh-completion/_scrcpy — Zsh tab completion

Windows packaging

  • scrcpy-windows.manifest — Windows application manifest
  • scrcpy-windows.rc — Windows resource file (icon, version info)
  • open_a_terminal_here.bat — helper batch file
  • scrcpy-console.bat — launch with console window
  • scrcpy-noconsole.vbs — launch without console window

Man page

A man page is provided at app/scrcpy.1 for Unix-like systems.

Server deployment on device

The server JAR is pushed to /data/local/tmp/scrcpy-server.jar on the device. On the host, the client looks for the server binary at:

  1. The path specified by SCRCPY_SERVER_PATH environment variable
  2. PREFIX/share/scrcpy/scrcpy-server (standard install location)

Operations

Running scrcpy

Basic usage

# Mirror default device over USB
scrcpy

# Mirror specific device
scrcpy -s DEVICE_SERIAL

# Mirror over TCP/IP
scrcpy --tcpip=192.168.1.100:5555

# Record while mirroring
scrcpy --record=session.mp4

# Mirror without audio
scrcpy --no-audio

# Mirror-only, no control
scrcpy --no-control

Display modes

# Fullscreen
scrcpy --fullscreen

# Always on top, borderless
scrcpy --always-on-top --window-borderless

# No display window (recording only)
scrcpy --no-window --record=capture.mp4

# Limit resolution
scrcpy --max-size=1024

# Mirror secondary display
scrcpy --display-id=1

Camera mirroring

# List available cameras
scrcpy --list-cameras

# Mirror front camera
scrcpy --video-source=camera --camera-facing=front

# Specific camera at specific size
scrcpy --video-source=camera --camera-id=0 --camera-size=1920x1080

Monitoring

FPS counter

scrcpy includes a built-in FPS counter (fps_counter.c) that can be enabled to log frame rates during a session. Verbosity level debug or lower will show frame timing information.

scrcpy --verbosity=debug

Log verbosity levels

Level Content
verbose All internal tracing
debug Debug information including frame timing
info Normal operational messages (default)
warn Warnings only
error Errors only

Updating

scrcpy is a single-version deployment: the client and server must match. When updating:

  1. Build or download the new client binary.
  2. Ensure the matching server JAR is available at the expected path.
  3. The old server on the device is overwritten on each connection (pushed fresh every time).

Caution

The client and server versions must be identical. A version mismatch will cause connection failures or undefined behavior.

File transfer

Drag and drop files onto the scrcpy window to push them to the device:

  • Regular files are pushed to the directory specified by --push-target (default: /sdcard/Download/).
  • APK files are automatically installed via adb install.

This is handled by file_pusher.c, which uses adb push under the hood.


Performance Tuning

Video encoding

Codec selection

Codec Flag Notes
H.264 --video-codec=h264 Default. Widest hardware support.
H.265 (HEVC) --video-codec=h265 Better compression, may not be available on all devices.
AV1 --video-codec=av1 Best compression, limited device support.

Bit rate tuning

The default video bit rate is 8M (8 Mbps). Adjust based on use case:

# Low bandwidth / low latency
scrcpy --video-bit-rate=2M

# High quality recording
scrcpy --video-bit-rate=16M

Resolution limiting

# Limit to 1024px on the longest dimension
scrcpy --max-size=1024

# Cap framerate
scrcpy --max-fps=30

Tip

Reducing --max-size and --max-fps significantly decreases encoding load on the device and bandwidth usage, improving latency on slower connections.

Audio buffering

The audio pipeline uses a regulator (audio_regulator.c) that compensates for jitter using libswresample-based sample rate adjustment. When underflow occurs, silence is inserted to prevent audio glitches.

Parameter Default Effect
--audio-buffer 50 ms Jitter buffer before playback. Higher = smoother but more latency.
--audio-output-buffer 5 ms SDL output buffer. Higher = less CPU but more latency.
# Minimize audio latency (may cause glitches on poor connections)
scrcpy --audio-buffer=20 --audio-output-buffer=2

# Maximize audio stability
scrcpy --audio-buffer=200 --audio-output-buffer=20

Video buffering

Parameter Default Effect
--video-buffer 0 ms Delay buffer for jitter compensation. 0 = no buffering (lowest latency).

The delay buffer (delay_buffer.c) holds frames to smooth out jitter. The frame buffer (frame_buffer.c) is a thread-safe single-frame buffer that always holds the latest decoded frame, dropping older frames when the display cannot keep up.

# Add 50ms video buffer for unstable connections
scrcpy --video-buffer=50

Codec options

Pass encoder-specific options directly to the device encoder:

# Set H.264 profile and level
scrcpy --video-codec-options=profile=1,level=2048

Encoder selection

List and select specific hardware/software encoders:

# List available encoders
scrcpy --list-encoders

# Force specific encoder
scrcpy --video-encoder=OMX.qcom.video.encoder.avc

Note

The packet merger (packet_merger.c) reassembles codec packets that may be split across multiple reads. This is transparent to the user but is relevant when debugging encoding issues.

Screen-off mode performance

Using --turn-screen-off / -S disables the device display, which can affect encoding performance on some devices (see GitHub issue #3376). If you observe performance degradation, test without this flag.


Security

Hidden Android API access

The server accesses non-public Android APIs via Java reflection through the wrappers/ package. This is the mechanism that allows scrcpy to function without root and without installing an APK.

Wrapped system services

Wrapper Android Service Purpose
ActivityManager activity Task management
ClipboardManager clipboard Clipboard sync
ContentProvider Content resolver Content access
DisplayControl Display service Display control
DisplayManager display Display enumeration
InputManager input Touch/key injection
PowerManager power Wake/sleep control
ServiceManager servicemanager Service resolution
StatusBarManager statusbar Status bar control
SurfaceControl Surface compositor Screen capture
WindowManager window Window management

Warning

These wrappers use reflection to access hidden (@hide) Android APIs. These APIs are not part of the public Android SDK and may change or be removed in any Android version. The server targets compileSdk: 36 but must handle API differences across Android versions (API 21+).

Network security

ADB connection model

scrcpy communicates exclusively over adb. There is no independent network protocol.

  • USB mode: All traffic flows over the USB cable. No network exposure.
  • TCP/IP mode (adb tcpip / --tcpip): ADB listens on port 5555 (default) on the device's network interface. This is an ADB-level concern, not scrcpy-specific.

Caution

When using ADB over TCP/IP, the ADB connection is unencrypted and unauthenticated on the network. Anyone on the same network can connect to the device. Use TCP/IP mode only on trusted networks. Consider using a VPN or SSH tunnel for remote connections.

Socket communication

  • The client and server communicate via Unix domain sockets tunneled through adb (using adb reverse or adb forward).
  • Socket name prefix: scrcpy_
  • No TLS or encryption is applied at the scrcpy level; security relies on the adb transport layer.

Permissions model

scrcpy requires only that USB debugging be enabled on the device. It does not require:

  • Root access
  • Device unlock (though initial ADB authorization requires user approval on the device)
  • Any installed APK

The server runs as the shell user, which has elevated privileges compared to normal apps (this is what enables input injection, screen capture, and clipboard access without root).

Data handling

  • No data persistence on device: The server JAR at /data/local/tmp/scrcpy-server.jar is the only file written to the device. It is overwritten on each connection.
  • Clipboard sync: When clipboard sync is enabled (default), clipboard content is transmitted between host and device. Use --no-control to disable all device control including clipboard sync.
  • File push: Files dragged onto the window are pushed via adb push to the push target directory.

Developer Internals

Repository structure

scrcpy/
├── app/
│   ├── meson.build                    # Client build definition
│   ├── scrcpy.1                       # Man page
│   ├── scrcpy-windows.manifest        # Windows manifest
│   ├── scrcpy-windows.rc              # Windows resource file
│   ├── data/
│   │   ├── icon.ico, icon.png, icon.svg   # App icons
│   │   ├── scrcpy.desktop                 # Linux desktop entry
│   │   ├── scrcpy-console.desktop         # Console desktop entry
│   │   ├── open_a_terminal_here.bat       # Windows helper
│   │   ├── scrcpy-console.bat             # Windows console launcher
│   │   ├── scrcpy-noconsole.vbs           # Windows no-console launcher
│   │   ├── bash-completion/scrcpy         # Bash completions
│   │   └── zsh-completion/_scrcpy         # Zsh completions
│   ├── src/                           # Client C source (67 files)
│   └── tests/                         # Client unit tests (11 files)
├── server/
│   ├── build.gradle                   # Server Gradle build
│   ├── build_without_gradle.sh        # Build without Gradle
│   ├── proguard-rules.pro             # ProGuard config
│   ├── meson.build                    # Server Meson integration
│   ├── scripts/build-wrapper.sh       # Build wrapper
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── aidl/                  # AIDL interfaces
│       │   └── java/com/genymobile/scrcpy/
│       │       ├── Server.java        # Entry point
│       │       ├── Options.java       # Server options
│       │       ├── audio/             # Audio capture & encoding
│       │       ├── control/           # Control message handling
│       │       ├── device/            # Device interaction
│       │       ├── opengl/            # OpenGL support
│       │       ├── util/              # Utilities
│       │       ├── video/             # Video capture & encoding
│       │       └── wrappers/          # Hidden API wrappers
│       └── test/                      # Server unit tests
├── config/
│   ├── android-checkstyle.gradle      # Checkstyle Gradle integration
│   └── checkstyle/checkstyle.xml      # Checkstyle rules
├── doc/                               # 18 topic-specific docs
├── gradle/wrapper/                    # Gradle wrapper
├── meson.build                        # Root Meson build
├── meson_options.txt                  # Client build options
├── build.gradle                       # Root Gradle build
├── cross_win32.txt                    # Win32 cross-compilation
├── cross_win64.txt                    # Win64 cross-compilation
└── install_release.sh                 # Automated install script

Module reference (client)

Core orchestration

Module Purpose
main.c Entry point, argument parsing dispatch
cli.c / cli.h Complete CLI option parsing and validation
scrcpy.c / scrcpy.h Main orchestration: initializes all subsystems, connects components
options.h Options struct definition and defaults

Server management

Module Purpose
server.c / server.h Push server JAR, launch via adb shell, establish socket connections
adb/adb.c / adb.h ADB command execution, device listing, port management
adb/adb_parser.c Parse ADB output (device list, etc.)
adb/adb_tunnel.c Tunnel setup (reverse/forward)

Video pipeline

Module Purpose
demuxer.c / demuxer.h Receive and demultiplex encoded packets from server
decoder.c / decoder.h FFmpeg-based video/audio decoding
display.c / display.h SDL texture management and rendering
screen.c / screen.h SDL window management, resize, rotation
frame_buffer.c / frame_buffer.h Thread-safe latest-frame buffer (drops old frames)
delay_buffer.c / delay_buffer.h Jitter compensation buffer
packet_merger.c / packet_merger.h Reassemble split codec packets

Audio pipeline

Module Purpose
audio_player.c / audio_player.h SDL audio callback playback
audio_regulator.c / audio_regulator.h Real-time audio buffering with libswresample compensation, silence insertion on underflow

Input and control

Module Purpose
input_manager.c / input_manager.h Process SDL events, dispatch to appropriate processor
controller.c / controller.h Serialize and send control messages to server
control_msg.c / control_msg.h Control message serialization format
device_msg.c / device_msg.h Device-to-host message deserialization
hid/hid_keyboard.c HID keyboard protocol
hid/hid_mouse.c HID mouse protocol
hid/hid_gamepad.c HID gamepad protocol
uhid/ Linux UHID kernel module interface
usb/ AOAv2 USB protocol, libusb integration
usb/scrcpy_otg.c OTG mode (direct USB HID, no mirroring)

Recording and output

Module Purpose
recorder.c / recorder.h FFmpeg muxing to mp4/mkv/m4a/mka/opus/aac/flac/wav
v4l2_sink.c / v4l2_sink.h Output to v4l2loopback device (Linux only)

Utilities

Module Purpose
file_pusher.c / file_pusher.h Drag-and-drop file/APK transfer via adb push
fps_counter.c / fps_counter.h Frame rate measurement and logging
util/str.c / strbuf.c String utilities and string buffer
util/binary.c Binary read/write helpers
util/vector.c / vecdeque.c Dynamic array and deque data structures

Trait system (interface pattern)

scrcpy implements a trait-based interface pattern in C using function pointers in structs. This enables polymorphic composition of pipeline stages.

Frame traits

Trait Header Methods
sc_frame_sink trait/frame_sink.h open(), close(), push() -- receives decoded frames
sc_frame_source trait/frame_source.h add_sink(), remove_sink() -- dispatches frames to sinks

Packet traits

Trait Header Methods
sc_packet_sink trait/packet_sink.h open(), close(), push() -- receives encoded packets
sc_packet_source trait/packet_source.h add_sink(), remove_sink() -- dispatches packets to sinks

Input traits

Trait Header Methods
sc_key_processor trait/key_processor.h Key event processing interface
sc_mouse_processor trait/mouse_processor.h Mouse event processing interface
sc_gamepad_processor trait/gamepad_processor.h Gamepad event processing interface

This system allows components to be composed flexibly. For example, a demuxer (packet source) can feed packets to both a decoder and a recorder simultaneously. A decoder (frame source) can feed frames to both a display and a V4L2 sink.

Demuxer (packet_source)
  ├──► Decoder (packet_sink + frame_source)
  │       ├──► Display (frame_sink)
  │       └──► V4L2 Sink (frame_sink)
  └──► Recorder (packet_sink)

Server module reference

Package Key Classes Purpose
(root) Server, Options Entry point, option parsing
audio/ AudioCapture, AudioDirectCapture, AudioPlaybackCapture, AudioEncoder, AudioRawRecorder Audio capture and encoding
video/ ScreenCapture, CameraCapture, NewDisplayCapture, SurfaceEncoder, Streamer Video capture and encoding
control/ Controller, ControlMessageReader Input injection
device/ Device interaction helpers Device state management
opengl/ OpenGL utilities GPU-accelerated processing
util/ Utility classes String utils, binary helpers
wrappers/ 11 wrapper classes Hidden Android API access via reflection

AIDL interfaces

  • IOnPrimaryClipChangedListener.aidl -- clipboard change notifications
  • IDisplayWindowListener.aidl -- display window events

Code style and quality

  • Server code style: Enforced via Checkstyle (config/checkstyle/checkstyle.xml), integrated through config/android-checkstyle.gradle.
  • Client code style: C99 standard, consistent naming conventions (sc_ prefix for scrcpy types).
  • ProGuard: Release server builds use ProGuard rules from server/proguard-rules.pro.

Testing

Client tests

Located in app/tests/, 11 test files:

Test Coverage
test_adb_parser ADB output parsing
test_audiobuf Audio buffer operations
test_binary Binary read/write utilities
test_cli CLI argument parsing
test_control_msg_serialize Control message serialization
test_device_msg_deserialize Device message deserialization
test_orientation Orientation calculations
test_str String utilities
test_strbuf String buffer operations
test_vecdeque Vector deque data structure
test_vector Dynamic vector data structure

Running client tests:

meson setup build
ninja -C build
meson test -C build

Server tests

Located in server/src/test/:

Test Coverage
ControlMessageReaderTest Control message deserialization
DeviceMessageWriterTest Device message serialization
BinaryTest Binary utilities
CodecOptionsTest Codec option parsing
CommandParserTest Command parsing
StringUtilsTest String utilities

Running server tests:

cd server
./gradlew test

Build system details

Meson build (client)

The root meson.build defines the overall project. app/meson.build specifies the client target with all source files, dependencies, and build options.

Key Meson dependencies resolved via pkg-config:

  • sdl2
  • libavcodec, libavformat, libavutil, libswresample
  • libusb-1.0 (optional)

Build options are defined in meson_options.txt.

Gradle build (server)

  • Android Gradle Plugin: 8.13.0
  • compileSdk: 36
  • minSdk: 21
  • targetSdk: 36
  • Version: 3.3.4
  • Test dependency: junit:junit:4.13.2

Tip

The server can be built without Gradle using server/build_without_gradle.sh, which invokes the Android SDK tools directly. This is useful in CI environments or when Gradle is not available.


Integration Points

V4L2 sink (Linux only)

scrcpy can output video to a V4L2 loopback device, making the Android screen appear as a virtual webcam:

# Load v4l2loopback kernel module
sudo modprobe v4l2loopback

# Stream to V4L2 device
scrcpy --v4l2-sink=/dev/video2

# With buffering
scrcpy --v4l2-sink=/dev/video2 --v4l2-buffer=50

The V4L2 sink (v4l2_sink.c) implements the sc_frame_sink trait, receiving decoded frames from the decoder and writing them to the V4L2 device. It can operate alongside the normal display window, or with --no-window for headless streaming.

# Headless V4L2 streaming (no display window)
scrcpy --v4l2-sink=/dev/video2 --no-window

# V4L2 + recording simultaneously
scrcpy --v4l2-sink=/dev/video2 --record=capture.mp4

OTG mode

OTG mode (usb/scrcpy_otg.c) provides direct USB HID input without any mirroring or ADB connection. The host sends keyboard, mouse, and gamepad input directly over USB using the AOAv2 (Android Open Accessory v2) protocol.

# OTG mode with keyboard and mouse
scrcpy --otg

# OTG mode with specific device
scrcpy --otg -s DEVICE_SERIAL

Important

OTG mode requires libusb and only works on Linux. It bypasses ADB entirely -- the device appears as a USB accessory. No video/audio mirroring occurs in OTG mode.

HID input modes

scrcpy supports three input injection methods, selectable independently for keyboard, mouse, and gamepad:

Mode Method Requirements Behavior
sdk Android InputManager API ADB connection Translates to Android key/touch events. Works everywhere but may not handle all key combinations.
uhid Linux UHID kernel module Linux host, ADB Creates virtual HID devices via /dev/uhid. Physical-level input simulation.
aoa AOAv2 USB protocol Linux host, USB, libusb USB HID over AOAv2. Physical-level input, works even when screen is off.
# UHID keyboard + mouse
scrcpy --keyboard=uhid --mouse=uhid

# AOA keyboard + mouse
scrcpy --keyboard=aoa --mouse=aoa

# Mixed: UHID keyboard, SDK mouse
scrcpy --keyboard=uhid --mouse=sdk

Virtual display

scrcpy can create a new virtual display on the device instead of mirroring an existing one:

# Create a new virtual display
scrcpy --new-display

# Specify virtual display resolution
scrcpy --new-display=1920x1080

This uses the NewDisplayCapture server component, which creates an Android virtual display and captures its content.

Recording integration

Recording works independently of display and can capture to multiple container formats:

Extension Format Content
.mp4 MP4 Video + Audio
.mkv Matroska Video + Audio
.m4a M4A Audio only
.mka Matroska Audio Audio only
.opus Opus Audio only
.aac AAC Audio only
.flac FLAC Audio only
.wav WAV Audio only
# Record video + audio to MP4
scrcpy --record=session.mp4

# Record audio only
scrcpy --no-video --record=audio.opus

# Record without display
scrcpy --no-playback --record=capture.mkv

Known issues (from GitHub)

Issue Description
#3376 --turn-screen-off (-S) may cause performance loss on some devices
#4821 Proprietary apps may show black screen (DRM-protected content)
#6742 30 FPS cap reported on Samsung MediaTek devices
#6682 Screenshot triggering
#6632 Native window resize behavior
#6767 Custom keyboard layout support
#6759 Aspect ratio during resize
#1706 Using scrcpy without ADB