A Proof of Concept (PoC) Android application built with Flutter for playing RTSP streams using VLC native player through platform channels.
- Overview
- Architecture
- Features
- Quick Start
- Configuration
- Implementation Details
- RTSP Stream Configuration
- Testing
- Troubleshooting
- Future Extensions
- Technical Specifications
This PoC demonstrates real-time RTSP video streaming on Android devices using Flutter UI and native VLC player integration via Kotlin platform channels. The application provides a clean, modern interface for connecting to RTSP streams with automatic error handling and reconnection capabilities.
- Platform: Android (API 21+)
- Framework: Flutter with Kotlin native integration
- Video Engine: LibVLC 3.5.4
- Protocol: RTSP over TCP
- Rendering: Hardware-accelerated texture-based video rendering
- Latency: ~400-600ms (configurable)
graph TB
subgraph "Flutter Layer (Dart)"
A[UI Components] --> B[Texture Widget]
A --> C[State Management]
B --> D[Platform Channel]
C --> D
end
subgraph "Platform Channel Bridge"
D --> E[MethodChannel]
E --> F[Event Callbacks]
end
subgraph "Android Native Layer (Kotlin)"
E --> G[MainActivity]
G --> H[VlcPlayer Manager]
H --> I[LibVLC Wrapper]
I --> J[Texture Management]
I --> K[Event Listener]
end
subgraph "VLC Native Library"
I --> L[LibVLC Core]
L --> M[RTSP Protocol Handler]
L --> N[H264 Decoder]
L --> O[Video Renderer]
end
M --> P[RTSP Server]
style A fill:#42A5F5
style L fill:#66BB6A
style P fill:#FFA726
sequenceDiagram
participant U as User
participant F as Flutter UI
participant PC as Platform Channel
participant K as Kotlin Layer
participant V as VLC Player
participant S as RTSP Server
U->>F: Tap "Start Stream"
F->>PC: invokeMethod('startStream')
PC->>K: Forward request
K->>V: Initialize LibVLC
K->>V: Create Texture
V->>S: Connect RTSP (TCP)
S-->>V: Stream data (H264)
V->>K: Return Texture ID
K->>PC: Success + Texture ID
PC->>F: Update state
F->>U: Display video
V-->>K: Event: PLAYING
K-->>PC: Notify event
PC-->>F: Update status
F-->>U: Show "Stream Active"
graph LR
subgraph "Flutter (lib/main.dart)"
A[RtspPlayerPage] --> B[Video Preview Area]
A --> C[Control Buttons]
A --> D[Status Indicator]
end
subgraph "Kotlin (android/)"
E[MainActivity.kt] --> F[Channel Handler]
G[VlcPlayer.kt] --> H[LibVLC Init]
G --> I[Media Player]
G --> J[Event Handler]
end
A --> E
E --> G
style A fill:#E3F2FD
style E fill:#FFF3E0
style G fill:#E8F5E9
- Real-time RTSP Streaming: Low-latency video streaming over RTSP protocol
- Hardware Acceleration: Efficient H264 decoding using device hardware
- Automatic Error Recovery: Connection loss detection with reconnection dialog
- TCP Transport: Reliable streaming using RTSP over TCP
- Texture-based Rendering: Smooth video playback using Flutter Texture widget
- Modern Material Design 3 UI
- Connection status indicator (colored dot)
- Stream URL display
- Start/Stop controls
- Automatic reconnection dialog
- Visual feedback for all states (idle, connecting, connected, error)
stateDiagram-v2
[*] --> Idle
Idle --> Connecting: User taps Start
Connecting --> Connected: VLC Playing event
Connecting --> Error: Connection failed
Connected --> Stopping: User taps Stop
Connected --> Disconnected: Connection lost
Stopping --> Idle: Stream stopped
Disconnected --> Idle: User dismisses dialog
Disconnected --> Connecting: User taps Reconnect
Error --> Idle: User dismisses error
Idle --> [*]
- Flutter SDK (latest stable)
- Android SDK (API 21+)
- Android device or emulator
- Network access to RTSP server
# 1. Install dependencies
flutter pub get
# 2. Connect Android device
flutter devices
# 3. Run the application
flutter run
# 4. For release build
flutter build apk --release- Launch the app
- Tap the green "Avvia Lettura" (Start Stream) button
- Wait 2-3 seconds for buffering
- Video will appear in the preview area
- Tap red "Ferma" (Stop) button to disconnect
Default configuration in lib/main.dart:
final String _rtspUrl = 'rtsp://10.189.148.218:554';To change the URL, modify this value and rebuild the application.
Default resolution in lib/main.dart (line ~80):
final result = await platform.invokeMethod('startStream', {
'url': _rtspUrl,
'width': 1280, // Adjust as needed
'height': 1024, // Adjust as needed
});Configure VLC behavior in android/app/src/main/kotlin/com/example/flutter_rtp/VlcPlayer.kt:
val options = ArrayList<String>().apply {
add("--rtsp-tcp") // Use TCP instead of UDP
add("--network-caching=1000") // Buffer time in ms
add("--rtsp-frame-buffer-size=500000") // Frame buffer size
add("--clock-jitter=5000") // Clock jitter tolerance
add("--clock-synchro=0") // Disable auto sync
add("--avcodec-hw=any") // Hardware decoding
add("--no-drop-late-frames") // Don't drop late frames
add("--no-skip-frames") // Don't skip frames
add("-vvv") // Verbose logging
}flutter_rtp/
βββ lib/
β βββ main.dart # Flutter UI and logic
βββ android/
β βββ app/
β βββ build.gradle.kts # VLC dependency
β βββ src/main/
β βββ AndroidManifest.xml # Network permissions
β βββ kotlin/com/example/flutter_rtp/
β βββ MainActivity.kt # Platform channel handler
β βββ VlcPlayer.kt # VLC wrapper
βββ README.md # This file
Key components:
- RtspPlayerPage: Main widget with state management
- Texture Widget: Displays video from native texture
- Platform Channel: Communication bridge to native code
- Event Callbacks: Handles stream events (playing, stopped, error)
MainActivity.kt - Platform channel handler:
private val CHANNEL = "com.example.flutter_rtp/vlc"
setMethodCallHandler { call, result ->
when (call.method) {
"startStream" -> // Initialize and start VLC
"stopStream" -> // Stop and cleanup VLC
}
}VlcPlayer.kt - LibVLC wrapper:
- Texture creation and management
- LibVLC initialization with options
- MediaPlayer setup and control
- Event handling (stopped, playing, error, buffering)
- Resource cleanup
pubspec.yaml:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8android/app/build.gradle.kts:
dependencies {
implementation("org.videolan.android:libvlc-all:3.5.4")
}AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>The application is optimized for the following RTSP stream configuration:
| Parameter | Value | Notes |
|---|---|---|
| Protocol | RTSP over TCP | Port 554 |
| Resolution | 1280x1024 | 5:4 aspect ratio |
| Codec | H264 | Hardware accelerated |
| Bitrate | 512 Kbit/s | Low bandwidth |
| Frame Rate | 5 fps | Low frame rate |
| GOP | 25 frames | I-frame interval |
| Quality | 70% | Compression quality |
graph TD
A[RTSP Server] -->|TCP Port 554| B[Network Layer]
B -->|H264 Stream| C[VLC Decoder]
C -->|Raw Frames| D[Texture Buffer]
D -->|Rendered| E[Flutter UI]
F[Network Caching<br/>1000ms] --> B
G[Frame Buffer<br/>500KB] --> C
H[Hardware Decoder] --> C
style A fill:#FFA726
style C fill:#66BB6A
style E fill:#42A5F5
Since the stream uses 5 fps (frames every 200ms), the application includes specific optimizations:
- High clock jitter tolerance:
--clock-jitter=5000 - Disabled auto sync:
--clock-synchro=0 - Increased buffer:
--network-caching=1000 - Live caching:
--live-caching=1000
Note: At 5 fps, the video will appear to update slowly - this is normal and expected behavior for such low frame rates.
# Flutter logs
flutter logs
# Android logs
adb logcat | grep -E "VlcPlayer|flutter"
# VLC specific logs
adb logcat | grep VlcPlayer- App launches without errors
- "Start Stream" button responds to tap
- Status changes to "Connessione in corso..." (Connecting)
- Video appears after 2-3 seconds
- Status indicator turns green when connected
- Video plays smoothly (considering 5 fps limitation)
- "Stop" button interrupts the stream
- Video disappears when stopped
- Status indicator turns red when disconnected
- Reconnection dialog appears on connection loss
Expected performance characteristics:
- Initial connection time: 2-3 seconds
- Buffering time: 1-2 seconds
- Latency: 1000ms (due to caching)
- Frame display rate: 5 fps (as per server config)
- CPU usage: Low (hardware acceleration)
- Memory usage: ~40MB (VLC library)
To test with VLC desktop as RTSP server:
- Open VLC Media Player
- Media β Stream
- Add a video file
- Select RTSP as streaming protocol
- Note the URL (e.g.,
rtsp://192.168.1.100:8554/test) - Update the URL in
main.dart - Run the app
Before testing the app:
# Ping the server
ping 10.189.148.218
# Check RTSP port
nc -zv 10.189.148.218 554
# Test with FFprobe
ffprobe -rtsp_transport tcp rtsp://10.189.148.218:554
# Test with VLC desktop
vlc rtsp://10.189.148.218:554graph TD
A[Issue] --> B{Black Screen?}
B -->|Yes| C[Check Network Connection]
C --> D[Verify RTSP Server]
D --> E[Check URL and Port]
A --> F{App Crashes?}
F -->|Yes| G[Flutter Clean]
G --> H[Pub Get]
H --> I[Rebuild]
A --> J{Connection Lost?}
J -->|Yes| K[Network Issue]
K --> L[Server Down]
L --> M[Check Logs]
A --> N{Choppy Video?}
N -->|Yes| O[Normal at 5fps]
O --> P[Check Hardware Acceleration]
style C fill:#FFE082
style G fill:#FFE082
style K fill:#FFE082
| Problem | Possible Cause | Solution |
|---|---|---|
| Black screen | Server not reachable | Verify IP, port, and network |
| App crashes | Corrupted build cache | Run flutter clean && flutter pub get |
| High latency | Low caching value | Increase network-caching in VlcPlayer.kt |
| Choppy video | Hardware decoder issues | Check logs, try disabling HW acceleration |
| No connection | Permission issues | Verify AndroidManifest.xml permissions |
| "OPENING" but not "PLAYING" | Server not responding | Test with VLC desktop first |
| "BUFFERING" stuck at 0% | Low bitrate or slow network | Increase network-caching |
Successful connection logs:
π MediaPlayer OPENING
β³ MediaPlayer BUFFERING: 0%
β³ MediaPlayer BUFFERING: 50%
β³ MediaPlayer BUFFERING: 100%
βΆοΈ MediaPlayer PLAYING
Error logs to watch for:
β MediaPlayer ERROR
π MediaPlayer STOPPED unexpectedly
β οΈ Connection timeout
mindmap
root((Extensions))
UI Features
Dynamic URL Input
Favorite URLs List
Multi-camera Grid
Picture-in-Picture
Playback Controls
Pause/Resume
Volume Control
Screenshot Capture
Video Recording
Advanced Features
Authentication Support
SSL/TLS RTSPS
Performance Stats
Network Monitoring
Platform Support
iOS Implementation
Web Support
Desktop Windows/Linux
- Dynamic URL Input: TextField for user-entered RTSP URLs
- Saved Favorites: Store frequently used stream URLs
- Playback Controls: Add pause, resume, and volume controls
- Screenshot Feature: Capture frames from the stream
- Multi-camera View: Grid layout for multiple streams
- Stream Recording: Save stream to local storage
- Statistics Overlay: Display FPS, bitrate, latency
- Authentication: Support for username/password RTSP
- Picture-in-Picture: Android PiP mode support
- iOS Support: Implement Swift/Objective-C platform channel
See code examples in EXTENSIONS.md for implementation details.
- OS: Android 5.0 (API 21) or higher
- RAM: 2GB minimum
- Storage: 100MB minimum for app
- Network: WiFi or mobile data connection
- Camera Server: RTSP-compatible server
| Component | Technology | Version |
|---|---|---|
| Framework | Flutter | Latest stable |
| Language (UI) | Dart | 3.x |
| Language (Native) | Kotlin | 1.9+ |
| Video Library | LibVLC | 3.5.4 |
| Build System | Gradle | 8.x |
| Target SDK | Android | 34 |
| Min SDK | Android | 21 |
graph LR
subgraph "Resource Usage"
A[CPU: Low] --> D[Hardware<br/>Acceleration]
B[Memory: ~40MB] --> E[VLC Library<br/>Size]
C[Network: 512Kbps] --> F[Stream<br/>Bitrate]
end
subgraph "Timing"
G[Connection: 2-3s]
H[Buffering: 1-2s]
I[Latency: 1000ms]
J[Frame: 200ms]
end
style D fill:#66BB6A
style E fill:#FFA726
style F fill:#42A5F5
| Aspect | Java Original | Flutter PoC | Advantage |
|---|---|---|---|
| UI Framework | XML Layouts | Flutter Widgets | Cross-platform ready |
| Rendering | SurfaceView | Texture Widget | Better integration |
| Development | Java | Dart + Kotlin | Modern languages |
| Hot Reload | No | Yes | Faster development |
| UI Responsiveness | Good | Excellent | Reactive framework |
| Code Maintainability | Standard | High | Cleaner architecture |
This is a Proof of Concept application. Check LibVLC licensing requirements for production use.
This is a PoC project demonstrating RTSP streaming capabilities in Flutter. For issues or questions:
- Check the troubleshooting section
- Review Flutter logs:
flutter logs - Verify RTSP server connectivity
- Test with VLC desktop player first
Project Status: β
Complete and ready for testing
Version: 1.0.0
Platform: Android Only
Type: Proof of Concept