简体   繁体   中英

Web Camera plugin not working in flutter ( only in iOS)

Im using the 'camera.dart' package to access the web cam. It works perfectly fine on the machine browser, yet the issue arise once it comes to the mobile. Even on android it works. But on iOS after asking the permission the camera stream is not loading. Any help would much appreciate to spot the part I'm missing. My code as follows in the Camera class.

String getRandString() {
  var random = Random.secure();
  var values = List<int>.generate(8, (i) =>  random.nextInt(255));
  return base64UrlEncode(values);
}

Class implementation

 class _WebcamPageState extends State<WebcamPage> {
  // VideoElement
  late final VideoElement _webcamVideoElement;

  final String videoTag = getRandString();
@override
  void initState() {
  super.initState();

     // Create an video element which will be provided with stream source
     _webcamVideoElement = VideoElement();

    // Register an webcam
    ui.platformViewRegistry.registerViewFactory(
    videoTag, (int viewId) => _webcamVideoElement);
 
    loadCameraStream();

  }

 // I suppose the issue is here
  void loadCameraStream() { 

   var constraints = {
      "audio": false,
      "video": {
              'mandatory':
                  { 'minAspectRatio': 1.333, 'maxAspectRatio': 1.334 },
              'optional':
              [{ 'minFrameRate': 60 },
              { 'maxWidth': 400 }]
      }
  };
  window.navigator.mediaDevices?.getUserMedia(constraints).then((MediaStream stream) {
   _webcamVideoElement.srcObject = stream;
   _webcamVideoElement.play();
  });
  }


@override
  Widget build(BuildContext context) =>
     Scaffold(
         body: SingleChildScrollView(
         child: Container(
                          height: 500.0,
                          child: HtmlElementView(key: UniqueKey(),
                          viewType:videoTag),
                        )
          )//SingleChildScrollView
      );//Scaffold

 }

I have my dispose method separately

@override
  void dispose() {

   if (_webcamVideoElement.srcObject != null &&
    (_webcamVideoElement.srcObject!.active ?? false)) {
    _webcamVideoElement.pause();
    var tracks = _webcamVideoElement.srcObject?.getTracks();
    _webcamVideoElement.srcObject = null;

  tracks?.forEach((track) {
    track.stop();
  });
  }
   super.dispose();
 }

For those who are stuck as me, here a simple demo app code that works on any browser any device.

import 'package:flutter/material.dart';
import 'dart:html' as html;
import 'dart:ui' as ui;

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

class MyApp extends StatelessWidget {
  @override
 Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Container(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await showDialog(
              context: context,
              builder: (BuildContext context) {
                return FractionallySizedBox(
                  heightFactor: 0.5,
                  widthFactor: 0.5,
                  child: WebCam(),
                );
              });
        },
        // tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class WebCam extends StatefulWidget {
  @override
  _WebCamState createState() => _WebCamState();
}

class _WebCamState extends State<WebCam> {
  static html.VideoElement _webcamVideoElement = html.VideoElement();

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

  // Register a webcam
  // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory('webcamVideoElement',
        (int viewId) {
      getMedia();
      return _webcamVideoElement;
    });
  }

  getMedia() {
    html.window.navigator.mediaDevices
        .getUserMedia({"video": true}).then((streamHandle) {
      _webcamVideoElement
        ..srcObject = streamHandle
        ..autoplay = true;
    }).catchError((onError) {
      print(onError);
    });
  }

  switchCameraOff() {
    if (_webcamVideoElement.srcObject != null &&
        _webcamVideoElement.srcObject.active) {
      var tracks = _webcamVideoElement.srcObject.getTracks();

      //stopping tracks and setting srcObject to null to switch camera off
      _webcamVideoElement.srcObject = null;

      tracks.forEach((track) {
        track.stop();
      });
    }
  }

  @override
  void dispose() {
    switchCameraOff();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Container(
              child: new HtmlElementView(
            key: UniqueKey(),
            viewType: 'webcamVideoElement',
          )),
          Container(
            child: Column(
              children: [
                RaisedButton(
                  child: Text('Play/Pause'),
                  onPressed: () async {
                    if (_webcamVideoElement.paused) {
                      _webcamVideoElement.play();
                    } else {
                       _webcamVideoElement.pause();
                    }
                   },
                ),
                RaisedButton(
                  child: Text('Switch off'),
                  onPressed: () {
                    switchCameraOff();
                  },
                ),
                 RaisedButton(
                  child: Text('Switch on'),
                  onPressed: () {
                    if (_webcamVideoElement.srcObject == null) getMedia();
                  },
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

following is the the demo app code from @danu's answer, with updates to work with null safety.

import 'package:flutter/material.dart';
import 'dart:html' as html;
import 'dart:ui' as ui;

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

class MyApp extends StatelessWidget {
  @override
 Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Container(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await showDialog(
              context: context,
              builder: (BuildContext context) {
                return FractionallySizedBox(
                  heightFactor: 0.5,
                  widthFactor: 0.5,
                  child: WebCam(),
                );
              });
        },
        // tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

class WebCam extends StatefulWidget {
  @override
  _WebCamState createState() => _WebCamState();
}

class _WebCamState extends State<WebCam> {
  static html.VideoElement _webcamVideoElement = html.VideoElement();

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

  // Register a webcam
  // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory('webcamVideoElement',
        (int viewId) {
      getMedia();
      return _webcamVideoElement;
    });
  }

  getMedia() {
    html.window.navigator.mediaDevices!
        .getUserMedia({"video": true}).then((streamHandle) {
      _webcamVideoElement
        ..srcObject = streamHandle
        ..autoplay = true;
    }).catchError((onError) {
      print(onError);
    });
  }

  switchCameraOff() {
    if (_webcamVideoElement.srcObject != null &&
        _webcamVideoElement.srcObject!.active!) {
      var tracks = _webcamVideoElement.srcObject!.getTracks();

      //stopping tracks and setting srcObject to null to switch camera off
      _webcamVideoElement.srcObject = null;

      tracks.forEach((track) {
        track.stop();
      });
    }
  }

  @override
  void dispose() {
    switchCameraOff();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Container(
              child: new HtmlElementView(
            key: UniqueKey(),
            viewType: 'webcamVideoElement',
          )),
          Container(
            child: Column(
              children: [
                RaisedButton(
                  child: const Text('Play/Pause'),
                  onPressed: () async {
                    if (_webcamVideoElement.paused) {
                      _webcamVideoElement.play();
                    } else {
                       _webcamVideoElement.pause();
                    }
                   },
                ),
                RaisedButton(
                  child: const Text('Switch off'),
                  onPressed: () {
                    switchCameraOff();
                  },
                ),
                 RaisedButton(
                  child: const Text('Switch on'),
                  onPressed: () {
                    if (_webcamVideoElement.srcObject == null) getMedia();
                  },
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM