scrcpy_video_view 0.0.1
scrcpy_video_view: ^0.0.1 copied to clipboard
Low-latency Android screen streaming into Flutter textures using scrcpy and VideoToolbox on macOS.
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.