flutter_virtual_background 1.0.1 copy "flutter_virtual_background: ^1.0.1" to clipboard
flutter_virtual_background: ^1.0.1 copied to clipboard

Platformweb

A powerful Flutter Web plugin for real-time AI-powered background removal and replacement with dual-engine support (MediaPipe & BodyPix) and video recording capabilities.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_virtual_background/flutter_virtual_background.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Virtual Background Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const VirtualBackgroundDemo(),
    );
  }
}

class VirtualBackgroundDemo extends StatefulWidget {
  const VirtualBackgroundDemo({super.key});

  @override
  State<VirtualBackgroundDemo> createState() => _VirtualBackgroundDemoState();
}

class _VirtualBackgroundDemoState extends State<VirtualBackgroundDemo> {
  VirtualBackgroundController? _controller;
  bool _isReady = false;
  bool _isRecording = false;
  String _recordingTime = '00:00';
  VirtualEngine _currentEngine = VirtualEngine.mediapipe;
  final bool _audioEnabled = true;

  @override
  void initState() {
    super.initState();
    _initializeCamera();
  }

  Future<void> _initializeCamera() async {
    _controller = VirtualBackgroundController(
      containerId: 'demo-camera-view',
      config: VirtualBackgroundConfig(
        enableAudio: _audioEnabled,
        initialEngine: _currentEngine,
        videoWidth: 1280,
        videoHeight: 720,
        onReady: () {
          setState(() => _isReady = true);
          _showSnackBar('Camera ready! 📸', Colors.green);
        },
        onRecordingStart: () {
          setState(() => _isRecording = true);
          _showSnackBar('Recording started! 🎥', Colors.red);
        },
        onRecordingStop: () {
          setState(() {
            _isRecording = false;
            _recordingTime = '00:00';
          });
          _showSnackBar('Recording saved! 💾', Colors.blue);
        },
        onRecordingError: (error) {
          _showSnackBar('Error: $error', Colors.red);
        },
        onTimerUpdate: (seconds) {
          final duration = Duration(seconds: seconds);
          setState(() {
            _recordingTime = "${duration.inMinutes.toString().padLeft(2, '0')}:"
                "${(duration.inSeconds % 60).toString().padLeft(2, '0')}";
          });
        },
      ),
    );

    try {
      await _controller!.initialize();
    } catch (e) {
      _showSnackBar('Initialization failed: $e', Colors.red);
    }
  }

  void _showSnackBar(String message, Color color) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        backgroundColor: color,
        duration: const Duration(seconds: 2),
      ),
    );
  }

  void _toggleEngine() async {
    final newEngine = _currentEngine == VirtualEngine.mediapipe
        ? VirtualEngine.bodypix
        : VirtualEngine.mediapipe;

    await _controller?.switchEngine(newEngine);
    setState(() => _currentEngine = newEngine);

    _showSnackBar(
      'Switched to ${newEngine.name.toUpperCase()}',
      Colors.orange,
    );
  }

  void _toggleRecording() {
    if (_isRecording) {
      _controller?.stopRecording();
    } else {
      _controller?.startRecording();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        title: const Text('Virtual Background Demo'),
        backgroundColor: Colors.black87,
        foregroundColor: Colors.white,
        actions: [
          // Engine indicator
          if (_isReady)
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Center(
                child: Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 12,
                    vertical: 6,
                  ),
                  decoration: BoxDecoration(
                    color: Colors.orange.withOpacity(0.2),
                    borderRadius: BorderRadius.circular(12),
                    border: Border.all(color: Colors.orange, width: 1),
                  ),
                  child: Text(
                    'ENGINE: ${_currentEngine.name.toUpperCase()}',
                    style: const TextStyle(
                      fontSize: 12,
                      fontWeight: FontWeight.bold,
                      color: Colors.orange,
                    ),
                  ),
                ),
              ),
            ),
        ],
      ),
      body: Stack(
        children: [
          // Camera View
          VirtualBackgroundView(
            controller: _controller,
            viewId: 'demo-camera-view',
          ),

          // Loading indicator
          if (!_isReady)
            const Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  CircularProgressIndicator(color: Colors.white),
                  SizedBox(height: 20),
                  Text(
                    'Initializing camera and AI engines...',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 16,
                    ),
                  ),
                ],
              ),
            ),

          // Recording Timer
          if (_isRecording)
            Positioned(
              top: 20,
              left: 0,
              right: 0,
              child: Center(
                child: Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 20,
                    vertical: 10,
                  ),
                  decoration: BoxDecoration(
                    color: Colors.red.withOpacity(0.9),
                    borderRadius: BorderRadius.circular(25),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.red.withOpacity(0.5),
                        blurRadius: 10,
                        spreadRadius: 2,
                      ),
                    ],
                  ),
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Container(
                        width: 12,
                        height: 12,
                        decoration: const BoxDecoration(
                          color: Colors.white,
                          shape: BoxShape.circle,
                        ),
                      ),
                      const SizedBox(width: 10),
                      Text(
                        _recordingTime,
                        style: const TextStyle(
                          color: Colors.white,
                          fontWeight: FontWeight.bold,
                          fontSize: 20,
                          letterSpacing: 2,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),

          // Control Panel
          Positioned(
            bottom: 30,
            left: 0,
            right: 0,
            child: Center(
              child: Container(
                padding: const EdgeInsets.all(20),
                decoration: BoxDecoration(
                  color: Colors.black.withOpacity(0.7),
                  borderRadius: BorderRadius.circular(30),
                ),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    // Switch Engine
                    _buildControlButton(
                      icon: Icons.psychology,
                      label: 'Engine',
                      color: Colors.orange,
                      onPressed: _isReady ? _toggleEngine : null,
                    ),
                    const SizedBox(width: 15),

                    // Select Background
                    _buildControlButton(
                      icon: Icons.image,
                      label: 'Background',
                      color: Colors.blue,
                      onPressed: _isReady
                          ? () => _controller?.selectBackground()
                          : null,
                    ),
                    const SizedBox(width: 15),

                    // Record Button
                    _buildRecordButton(),
                    const SizedBox(width: 15),

                    // Clear Background
                    _buildControlButton(
                      icon: Icons.close,
                      label: 'Clear',
                      color: Colors.grey,
                      onPressed: _isReady
                          ? () => _controller?.clearBackground()
                          : null,
                    ),
                  ],
                ),
              ),
            ),
          ),

          // Info Panel
          Positioned(
            top: 80,
            right: 20,
            child: Container(
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.black.withOpacity(0.7),
                borderRadius: BorderRadius.circular(12),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  _buildInfoRow(
                    Icons.camera_alt,
                    'Status',
                    _isReady ? 'Ready' : 'Initializing',
                    _isReady ? Colors.green : Colors.orange,
                  ),
                  const SizedBox(height: 8),
                  _buildInfoRow(
                    Icons.mic,
                    'Audio',
                    _audioEnabled ? 'Enabled' : 'Disabled',
                    _audioEnabled ? Colors.green : Colors.grey,
                  ),
                  const SizedBox(height: 8),
                  _buildInfoRow(
                    Icons.videocam,
                    'Recording',
                    _isRecording ? 'Active' : 'Inactive',
                    _isRecording ? Colors.red : Colors.grey,
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildControlButton({
    required IconData icon,
    required String label,
    required Color color,
    required VoidCallback? onPressed,
  }) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        FloatingActionButton(
          heroTag: label,
          onPressed: onPressed,
          backgroundColor: color,
          child: Icon(icon),
        ),
        const SizedBox(height: 8),
        Text(
          label,
          style: const TextStyle(
            color: Colors.white70,
            fontSize: 12,
          ),
        ),
      ],
    );
  }

  Widget _buildRecordButton() {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        FloatingActionButton.large(
          heroTag: 'record',
          onPressed: _isReady ? _toggleRecording : null,
          backgroundColor: _isRecording ? Colors.red : Colors.green,
          child: Icon(
            _isRecording ? Icons.stop : Icons.play_arrow,
            size: 40,
          ),
        ),
        const SizedBox(height: 8),
        Text(
          _isRecording ? 'Stop' : 'Record',
          style: const TextStyle(
            color: Colors.white70,
            fontSize: 12,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }

  Widget _buildInfoRow(
    IconData icon,
    String label,
    String value,
    Color color,
  ) {
    return Row(
      children: [
        Icon(icon, color: color, size: 16),
        const SizedBox(width: 8),
        Text(
          '$label: ',
          style: const TextStyle(
            color: Colors.white70,
            fontSize: 12,
          ),
        ),
        Text(
          value,
          style: TextStyle(
            color: color,
            fontSize: 12,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }
}
0
likes
140
points
20
downloads

Publisher

unverified uploader

Weekly Downloads

A powerful Flutter Web plugin for real-time AI-powered background removal and replacement with dual-engine support (MediaPipe & BodyPix) and video recording capabilities.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

MIT (license)

Dependencies

flutter, flutter_web_plugins, web

More

Packages that depend on flutter_virtual_background

Packages that implement flutter_virtual_background