scrcpy_video_view
A Flutter plugin that renders a low-latency Android screen stream inside a macOS app. It reads H.264 packets directly from the scrcpy server, decodes them with VideoToolbox, and publishes the latest frame through a Flutter texture.
Android MediaCodec
│ H.264 over a scrcpy socket forwarded by adb
▼
Dart packet reader
│ Annex-B H.264 access units
▼
macOS VideoToolbox
│ CVPixelBuffer
▼
Flutter Texture
Demo
https://github.com/user-attachments/assets/d54d2d16-a5a7-448f-9a86-d61e0487e3f2
Platform support
| Platform | Status |
|---|---|
| macOS 10.15+ | Supported |
| Windows, Linux, iOS, Android, web | Not implemented |
Video is currently H.264-only and view-only. Audio and device control are not implemented.
Requirements
- Flutter with macOS desktop support
adbavailable onPATH, or supplied withadbPath- scrcpy available on
PATH, or supplied withscrcpyPath - An Android device with USB debugging enabled and authorized
- The macOS App Sandbox disabled in the host application
Verify the local setup before running the example:
adb devices -l
scrcpy --version
The plugin uses the installed scrcpy version and matching server binary. It does not enforce a version allowlist. Because scrcpy's client/server protocol is internal, a future release may require a compatibility update.
Installation
dependencies::
...
scrcpy_video_view: ^0.0.1
macOS entitlements
Set com.apple.security.app-sandbox to false in both
macos/Runner/DebugProfile.entitlements and
macos/Runner/Release.entitlements:
<key>com.apple.security.app-sandbox</key>
<false/>
This is required because the plugin launches local adb processes, pushes the
scrcpy server to the device, and connects to an adb-forwarded localhost socket.
Usage
Create one controller for the lifetime of the video view:
final controller = ScrcpyVideoController();
final devices = await controller.discoverDevices();
if (devices.isNotEmpty) {
await controller.start(devices.first.serial);
}
Render its texture:
ScrcpyVideo(
controller: controller,
fit: BoxFit.contain,
placeholder: const Center(child: Text('No video')),
)
Observe state, dimensions, errors, and diagnostic logs through the controller:
controller.addListener(() {
debugPrint('state: ${controller.state}');
debugPrint('size: ${controller.videoWidth} x ${controller.videoHeight}');
debugPrint('error: ${controller.error}');
});
Stop explicitly when appropriate and dispose the controller with its owning widget:
await controller.stop();
controller.dispose();
The native macOS implementation also records the active adb forward and server process so it can remove them if the application terminates before Dart cleanup runs.
Configuration
Executable paths and encoding parameters can be customized:
final controller = ScrcpyVideoController(
configuration: const ScrcpyVideoConfiguration(
adbPath: '/path/to/adb',
scrcpyPath: '/path/to/scrcpy',
serverPath: '/path/to/scrcpy-server',
maxSize: 1920,
maxFps: 60,
videoBitRate: 8 * 1000 * 1000,
),
);
If serverPath is omitted, the plugin checks SCRCPY_SERVER_PATH and common
Homebrew installation locations.
Handling errors
Failures use ScrcpyVideoException with a machine-readable
ScrcpyVideoErrorCode, so applications can present targeted recovery steps:
try {
await controller.start(serial);
} on ScrcpyVideoException catch (error) {
switch (error.code) {
case ScrcpyVideoErrorCode.adbNotFound:
showSetupMessage('Install Android platform tools.');
case ScrcpyVideoErrorCode.scrcpyNotFound:
showSetupMessage('Install scrcpy or configure scrcpyPath.');
case ScrcpyVideoErrorCode.noAuthorizedDevices:
showSetupMessage('Connect and authorize an Android device.');
case ScrcpyVideoErrorCode.unsupportedScrcpyProtocol:
showSetupMessage('Report your scrcpy version and controller logs.');
default:
showSetupMessage(error.message);
}
}
Available codes also distinguish adb command failures, missing server binaries,
connection failures, decoder failures, unexpected stream closure, unsupported
platforms, and uncategorized failures. The original low-level failure is
available through error.cause when one exists.
Example
The example includes device discovery, start/stop controls, logs, and the reusable video widget:
cd example
flutter run -d macos
Reporting compatibility problems
Open a bug report with the following information:
- scrcpy version
- Flutter version
- macOS and Android versions
- Device model
- Complete
controller.logsoutput
Please remove device serial numbers or other sensitive values before posting logs publicly.
Contributing
Contributions are welcome. Read CONTRIBUTING.md and the Code of Conduct before opening a pull request. For vulnerabilities, follow SECURITY.md instead of opening a public issue.
License and attribution
scrcpy_video_view is available under the BSD 3-Clause License.
This project is an independent integration built around Genymobile/scrcpy. It is not affiliated with or endorsed by the scrcpy project. scrcpy and its server are not bundled in this package.
Libraries
- scrcpy_video_view
- Low-latency Android screen streaming for Flutter on macOS.
- scrcpy_video_view_method_channel
- scrcpy_video_view_platform_interface