video_windows_webrtc 0.0.4 copy "video_windows_webrtc: ^0.0.4" to clipboard
video_windows_webrtc: ^0.0.4 copied to clipboard

PlatformWindows
unlisted

Um plugin sobre video para Windows

example/lib/main.dart

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

void main() {
  runApp(
    const MaterialApp(
      home: VMSStressTestApp(),
      debugShowCheckedModeBanner: false,
    ),
  );
}

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

  @override
  State<VMSStressTestApp> createState() => _VMSStressTestAppState();
}

class _VMSStressTestAppState extends State<VMSStressTestApp> {
  final int rows = 5;
  final int cols = 5;
  late final List<WebRTCVmsPlayer> _players;
  late final List<TextEditingController> _urlControllers;

  @override
  void initState() {
    super.initState();
    int total = rows * cols;
    _players = List.generate(total, (index) {
      return WebRTCVmsPlayer(
        onStateChanged: (state) {
          if (mounted) {
            setState(() {});
          }
        },
      );
    });
    _urlControllers = List.generate(total, (index) {
      return TextEditingController(text: linkVideo(index));
    });
  }

  String linkVideo(int index) {
    List<String> links = [
      "https://c.vms.tutorsa.cloud/rtc/v1/whep/?app=live&stream=associacaodas02&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://c.vms.tutorsa.cloud/rtc/v1/whep/?app=live&stream=associacaodas03&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live8.protenet.com.br/rtc/v1/whep/?app=live&stream=associacaomor21&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor06&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor07&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor08&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor11&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor12&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor13&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor14&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live9.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor18&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor00&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor01&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor02&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor03&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live3.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor04&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live42.analitico.app.br/rtc/v1/whep/?app=live&stream=atacadaolivre02&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live12.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor19&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live23.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor23&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live23.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor24&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live26.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor25&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live12.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaomor20&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live35.analitico.app.br/rtc/v1/whep/?app=live&stream=homologacaopt00&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live36.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaodas00&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
      "https://live36.analitico.app.br/rtc/v1/whep/?app=live&stream=associacaodas01&token=nSX45IJaVe0kP2TuUMh9ud8Xbf0wkw",
    ];
    if (index >= links.length) return "";
    return links[index];
  }

  @override
  void dispose() {
    for (var player in _players) {
      player.disconnect();
    }
    for (var urlController in _urlControllers) {
      urlController.dispose();
    }
    super.dispose();
  }

  void _playAll() {
    for (int i = 0; i < _players.length; i++) {
      if (_players[i].state == PlayerState.idle ||
          _players[i].state == PlayerState.error) {
        _players[i].connect(_urlControllers[i].text);
      }
    }
  }

  void _stopAll() {
    for (int i = 0; i < _players.length; i++) {
      _players[i].disconnect();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'VMS WebRTC Stress Test - ${rows * cols} Cameras (${rows}x${cols})',
        ),
        backgroundColor: Colors.blueGrey[900],
        foregroundColor: Colors.white,
        actions: [
          IconButton(
            icon: const Icon(Icons.play_arrow),
            onPressed: _playAll,
            tooltip: 'Play All',
          ),
          IconButton(
            icon: const Icon(Icons.stop),
            onPressed: _stopAll,
            tooltip: 'Stop All',
          ),
        ],
      ),
      backgroundColor: Colors.black,
      body: Column(
        children: List.generate(rows, (row) {
          return Expanded(
            child: Row(
              children: List.generate(cols, (col) {
                int index = row * cols + col;
                return Expanded(
                  child: Padding(
                    padding: const EdgeInsets.all(1.0),
                    child: PlayerCell(
                      player: _players[index],
                      urlController: _urlControllers[index],
                      index: index,
                    ),
                  ),
                );
              }),
            ),
          );
        }),
      ),
    );
  }
}

class PlayerCell extends StatelessWidget {
  final WebRTCVmsPlayer player;
  final TextEditingController urlController;
  final int index;

  const PlayerCell({
    super.key,
    required this.player,
    required this.urlController,
    required this.index,
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        if (player.state == PlayerState.idle ||
            player.state == PlayerState.error) {
          print(urlController.text);
          player.connect(urlController.text);
        } else {
          player.disconnect();
        }
      },
      child: Container(
        decoration: BoxDecoration(
          color: Colors.grey[900],
          border: Border.all(color: _getStatusColor(player.state), width: 1),
        ),
        child: Stack(
          children: [
            ClipRect(
              child: SizedBox.expand(
                child:
                    player.textureId != null &&
                        player.state == PlayerState.playing
                    ? FittedBox(
                        fit: BoxFit.cover,
                        child: SizedBox(
                          width: 1280,
                          height: 720,
                          child: Texture(textureId: player.textureId!),
                        ),
                      )
                    : Container(color: Colors.black),
              ),
            ),
            Positioned.fill(child: _buildOverlay()),
            Positioned(
              top: 2,
              left: 2,
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
                color: Colors.black54,
                child: Text(
                  "CAM ${index + 1}",
                  style: const TextStyle(color: Colors.white, fontSize: 10),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildOverlay() {
    switch (player.state) {
      case PlayerState.connecting:
      case PlayerState.reconnecting:
        return Container(
          color: Colors.black38,
          child: const Center(
            child: SizedBox(
              width: 20,
              height: 20,
              child: CircularProgressIndicator(
                strokeWidth: 2,
                valueColor: AlwaysStoppedAnimation<Color>(Colors.orangeAccent),
              ),
            ),
          ),
        );
      case PlayerState.idle:
        return Container(
          color: Colors.black26,
          child: Center(
            child: Icon(
              Icons.play_circle_fill,
              size: 30,
              color: Colors.white.withOpacity(0.8),
            ),
          ),
        );
      case PlayerState.error:
        return Container(
          color: Colors.black54,
          child: const Center(
            child: Icon(Icons.error, color: Colors.redAccent, size: 30),
          ),
        );
      case PlayerState.playing:
      default:
        return const SizedBox.shrink();
    }
  }

  Color _getStatusColor(PlayerState state) {
    switch (state) {
      case PlayerState.playing:
        return Colors.greenAccent.withOpacity(0.5);
      case PlayerState.connecting:
      case PlayerState.reconnecting:
        return Colors.orangeAccent.withOpacity(0.5);
      case PlayerState.error:
        return Colors.redAccent.withOpacity(0.5);
      case PlayerState.idle:
      default:
        return Colors.white24;
    }
  }
}