Flutter error: Instance member 'takePicture' can't be accessed using static access - flutter

I am a new developer and have just started using flutter. I was trying to make a camera app and I followed this tutorial:
https://www.youtube.com/watch?v=_nS00ZKnINQ
I am getting an error: Instance member 'takePicture' can't be accessed using static access.
You can view the entire file in this code block. Please don't hesitate to ask if you need the whole project directory.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
class CameraScreen extends StatefulWidget {
#override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<CameraScreen> {
CameraController cameraController;
List cameras;
int selectedCameraIndex;
String imgPath;
Future _initCameraController(CameraDescription cameraDescription) async {
if (cameraController != null) {
await cameraController.dispose();
}
cameraController =
CameraController(cameraDescription, ResolutionPreset.high);
cameraController.addListener(() {
if (mounted) {
setState(() {});
}
});
if (cameraController.value.hasError) {
print('!!!Camera error!!! ${cameraController.value.errorDescription}');
}
try {
await cameraController.initialize();
} on CameraException catch (e) {
_showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
/// Display Camera Preview
Widget _cameraPreviewWidget() {
if (cameraController == null || cameraController.value.isInitialized) {
return const Text(
'Loading...',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w900,
),
);
}
return AspectRatio(
aspectRatio: cameraController.value.aspectRatio,
child: CameraPreview(cameraController),
);
}
/// Display control bar with buttons to take picture
Widget _cameraControlWidget(context) {
return Expanded(
child: Align(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
FloatingActionButton(
child: Icon(
Icons.camera,
color: Colors.black,
),
backgroundColor: Colors.white,
onPressed: () {
_onCapturePressed(context);
})
],
),
));
}
/// Display a row of toggles to select the camera
Widget _cameraToggleRowWidget() {
if (cameras == null || cameras.isEmpty) {
return Spacer();
}
CameraDescription selectedCamera = cameras[selectedCameraIndex];
CameraLensDirection lensDirection = selectedCamera.lensDirection;
return Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: FlatButton.icon(
onPressed: _onSwitchCamera,
icon: Icon(
_getCameraLensIcon(lensDirection),
color: Colors.white,
size: 24,
),
label: Text(
'${lensDirection.toString().substring(lensDirection.toString().indexOf('.') + 1).toUpperCase()}',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
),
)),
));
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return null;
}
void _onSwitchCamera() {
selectedCameraIndex =
selectedCameraIndex < cameras.length - 1 ? selectedCameraIndex + 1 : 0;
CameraDescription selectedCamera = cameras[selectedCameraIndex];
_initCameraController(selectedCamera);
}
IconData _getCameraLensIcon(CameraLensDirection lensDirection) {
switch (lensDirection) {
case CameraLensDirection.back:
return CupertinoIcons.switch_camera;
case CameraLensDirection.front:
return CupertinoIcons.switch_camera_solid;
case CameraLensDirection.external:
return CupertinoIcons.photo_camera;
default:
return Icons.device_unknown;
}
}
}
void _onCapturePressed(context) async {
try {
final path =
join((await getTemporaryDirectory()).path, '${DateTime.now()}.png)');
await CameraController.takePicture(path);
} catch (e) {
_showCameraException(e);
}
}
void _showCameraException(CameraException e) {
String errorText = 'Error: ${e.code} \n Error Message: ${e.description}';
print(errorText);
}
I am using VS Code with Flutter on Windows 10

Do not call takePicture as a static method. You have to use your initialised controller:
cameraController.takePicture(path);
To access it, move your method _onCapturePressed into your class body. The working code from your tutorial can be found here.

Related

Unhandled Exception: setState() called after dispose() - due to modal dissmissed

I have a modalBottomSheet. On it, I am displaying several widgets, especially an audioPlayer.
I have find out that when I press the play button, the audio file is playing, so far so good, but if I tap outside the modalBottomSheet, the modal is dismissed. I am OK to get the modal dismissed. But my problem is that when it is dismissed, the player which is running, is generating an exception.
Unhandled Exception: setState() called after dispose()
I do not want to make the Modal not dissmisible.
Please, can you advise? Many thanks.
import 'package:audioplayers/audioplayers.dart';
import 'package:audioplayers/audioplayers_api.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gtd_official_sharped_focused/Reusable%20Widget/Player_Audio/widgets/play_pause_button.dart';
class AudioPlayerWidget extends StatefulWidget {
final String url;
final bool isAsset;
final Duration currentTime;
final Duration totalTime;
final ValueChanged<Duration> onSeekBarMoved;
const AudioPlayerWidget({
Key key,
this.url,
this.isAsset = false,
this.currentTime,
this.totalTime,
this.onSeekBarMoved,
}) : super(key: key);
#override
_AudioPlayerWidgetState createState() => _AudioPlayerWidgetState();
}
class _AudioPlayerWidgetState extends State<AudioPlayerWidget> {
AudioPlayer _audioPlayer;
AudioCache _audioCache;
//variables for slider
Duration _duration = new Duration();
Duration _position = new Duration();
PlayerState _playerState = PlayerState.STOPPED;
bool get _isPlaying => _playerState == PlayerState.PLAYING;
bool get _isLocal => !widget.url.contains('https');
#override
void initState() {
_audioPlayer = AudioPlayer(mode: PlayerMode.MEDIA_PLAYER);
_audioCache = AudioCache(fixedPlayer: _audioPlayer);
_audioPlayer.onDurationChanged.listen((d) {setState(() {
_duration = d;
});});
_audioPlayer.onAudioPositionChanged.listen((p) {setState((){
_position = p;
});});
_audioPlayer.onPlayerCompletion.listen((event) {
setState(() {
_position = Duration(seconds: 0);
_playerState = PlayerState.STOPPED;
});
});
_audioPlayer.onPlayerError.listen((msg) {
print('audioPlayer error : $msg');
setState(() {
_playerState = PlayerState.STOPPED;
});
});
super.initState();
}
#override
void dispose() {
_audioPlayer.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left:18.0),
child: Text(_position.toString().split('.')[0],style:TextStyle(fontSize: 16)),
),
Padding(
padding: const EdgeInsets.only(right:18.0),
child: Text(_duration.toString().split('.')[0],style:TextStyle(fontSize: 16)),
),
],),
_buildSliderBar(context),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
buttonBackWard10Seconds(),
PlayPauseButton(
isPlaying: _isPlaying,
onPlay: () => _playPause()
),
buttonForward10Seconds(),
//Do not delete iconButton below => for reference
/* IconButton(
onPressed: () => _stop(),
icon: Icon(
Icons.stop,
size: 40,
color: Colors.red,
),
),*/
],
),
],
);
}
//########################################################
_playPause() async {
if (_playerState == PlayerState.PLAYING) {
final playerResult = await _audioPlayer.pause();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PAUSED;
});
}
} else if (_playerState == PlayerState.PAUSED) {
final playerResult = await _audioPlayer.resume();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PLAYING;
});
}
} else {
if (widget.isAsset) {
_audioPlayer = await _audioCache.play(widget.url);
setState(() {
_playerState = PlayerState.PLAYING;
});
} else {
final playerResult = await _audioPlayer.play(widget.url, isLocal: _isLocal);
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PLAYING;
});
}
}
}
}
void changeToSecond(int second){
Duration newDuration = Duration(seconds:second);
_audioPlayer.seek(newDuration);
}
_stop() async {
final playerResult = await _audioPlayer.stop();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.STOPPED;
});
}
}
//###############################################################
Slider _buildSliderBar(BuildContext context) {
return Slider(
value: _position.inSeconds.toDouble(),
min: 0.0,
max: _duration.inSeconds.toDouble(), //_sliderValue,
activeColor: Colors.red,
inactiveColor: Colors.grey,
onChanged: (double value) {
setState(() {
changeToSecond(value.toInt());
value=value;
});
},
);
}
Widget buttonBackWard10Seconds(){
return IconButton( icon: Icon(CupertinoIcons.gobackward_10),
iconSize: 40,
color: Colors.black,
onPressed: (){
_position = _position - Duration(seconds:10);
if (_position < Duration(seconds:0)) {
_audioPlayer.seek(Duration(seconds: 0));
}
else {
_audioPlayer.seek(_position);
}});
}
Widget buttonForward10Seconds(){
return IconButton( icon:Icon( CupertinoIcons.goforward_10),
iconSize: 40,
color: Colors.black,
onPressed: (){
_position = _position + Duration(seconds:10);
if (_duration >_position) {
_audioPlayer.seek(_position);
}
else if (_duration <_position) {
_audioPlayer.seek(_duration);
}
}
);
}
}
import 'package:flutter/material.dart';
import 'package:gtd_official_sharped_focused/Reusable%20Widget/Player_Audio/widgets/audio_player_widget.dart';
import 'package:gtd_official_sharped_focused/Services/extract_file_Name_url/extract_file_name_url.dart';
Widget modalBottomPlayAudio (context,String urlToPlay){
showModalBottomSheet(
context: context,
//background color for modal bottom screen
backgroundColor: Colors.white,
//elevates modal bottom screen
elevation: 10,
// gives rounded corner to modal bottom screen
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
builder: (BuildContext context) {
// UDE : SizedBox instead of Container for whitespaces
return SizedBox(
height: 350,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
/*Padding(
padding: const EdgeInsets.all(28.0),
),*/
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left:18.0),
child: Text(getFileNameFromURL(urlToPlay),
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),),
),
],
),
SizedBox(height: 60,),
AudioPlayerWidget(url:urlToPlay),
],
),
),
);
},
);
}
you could change
setState(()=>{
...
})
to
if(mounted)(
setState(()=>{
...
})
)
Which ensures setState is called only when the widget is mounted on the screen.

unnecessary container but I need this container? flutter/Dart

I am working on a app were I get data from the ESP32 and display it on a simple page. Here is my code for my sensorpage:
import 'dart:async';
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
class sensorpage extends StatefulWidget {
const sensorpage({Key? key, required this.device}) : super(key: key);
final BluetoothDevice device;
#override
_sensorpageState createState() => _sensorpageState();
}
class _sensorpageState extends State<sensorpage> {
final String SERVICE_UUID = "edb91e04-3e19-11ec-9bbc-0242ac130002";
final String CHARACTERISTIC_UUID = "edb920c0-3e19-11ec-9bbc-0242ac130002";
late bool isReady;
//String val1 = "";
//int pot1 = 0;
FlutterBlue flutterBlue = FlutterBlue.instance;
//late StreamSubscription<ScanResult> scanSubScription;
//late BluetoothDevice targetDevice;
late Stream<List<int>> stream;
#override
void initState() {
super.initState();
isReady = false;
connectToDevice();
}
connectToDevice() async {
if (widget.device == null) {
_Pop();
return;
}
Timer(const Duration(seconds: 15), () {
if (!isReady) {
disconnectFromDevice();
_Pop();
}
});
await widget.device.connect();
discoverServices();
}
disconnectFromDevice() {
if (widget.device == null) {
_Pop();
return;
}
widget.device.disconnect();
}
discoverServices() async {
if (widget.device == null) {
_Pop();
return;
}
List<BluetoothService> services = await widget.device.discoverServices();
services.forEach((service) {
if (service.uuid.toString() == SERVICE_UUID) {
service.characteristics.forEach((characteristic) {
if (characteristic.uuid.toString() == CHARACTERISTIC_UUID) {
characteristic.setNotifyValue(!characteristic.isNotifying);
stream = characteristic.value;
setState(() {
isReady = true;
});
}
});
}
});
if (!isReady) {
_Pop();
}
}
Future<bool> _onWillPop() async {
bool shouldPop = false;
await showDialog(
context: context,
builder: (context) =>
AlertDialog(
title: const Text('Are you sure?'),
content: const Text('Do you want to disconnect device and go back?'),
actions: <Widget>[
ElevatedButton(
onPressed: () {
// shouldPop is already false
},
child: const Text('No')),
ElevatedButton(
onPressed: () async {
await disconnectFromDevice();
Navigator.of(context).pop();
shouldPop = true;
},
child: const Text('Yes')),
],
));
return shouldPop;
}
_Pop() {
Navigator.of(context).pop(true);
}
String _dataParser( List<int> dataFromDevice) {
return utf8.decode(dataFromDevice);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: const Text('Test'),
),
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError){
return Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState == ConnectionState.active) {
var currentValue = _dataParser (snapshot.data!);
//val1 = currentValue.split(',')[0];
//pot1 = int.parse(val1);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Current value',
style: TextStyle(fontSize: 14)),
Text('${currentValue} jawool',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24))
])
);
} else {
return const Text('Check the stream');
}
},
)),
)
));
}
}´
My Problem is that my second container where I display my data is shown as unnecessary but I don´t know why.
I assume you mean this piece of code?
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
If isReady is true you return Container(child: Container(child: SteamBuilder));
You should change it to this and it should be fine:
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: StreamBuilder<List<int>>(
The first Container is just wrapping the content based on the boolean and you don't need it. According to the flutter team:
Wrapping a widget in Container with no other parameters set has no effect and makes code needlessly more complex
So instead you can directly do:
body: !isReady ? buildSomething() : Container(....more code);

NoSuchMethodError: The getter 'name' was called on null

I am trying to add an option to take images and pictures and save them to local device. I have managed to add the Camera and video. whenever I click on the take picture or video button I end up getting the error
I/flutter ( 4827): NoSuchMethodError: The getter 'name' was called on
null. Receiver: null.Tried
calling: name . NoSuchMethodError: The getter 'name'
was called on null. Receiver: null Tried calling: name
Am using the flutter camera library. What am I doing wrong? Thank you in advance
my camera code
List<CameraDescription> cameras = [];
void logError(String code, String message) =>
print('Error: $code\nError Message: $message');
Future<void> main() async {
// Fetch the available cameras before initializing the app.
try {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
} on CameraException catch (e) {
logError(e.code, e.description);
}
final camera = cameras.first;
runApp(TakePicturePage(camera: camera));
}
class TakePicturePage extends StatefulWidget {
final CameraDescription camera;
TakePicturePage({#required this.camera});
#override
_TakePicturePageState createState() => _TakePicturePageState();
}
class _TakePicturePageState extends State<TakePicturePage> {
final fileName = DateTime.now().millisecondsSinceEpoch.toString();
var vidPath;
CameraController _cameraController;
Future<void> _initializeCameraControllerFuture;
int _selectedIndex = 0;
bool _start = false;
bool _isRec = false;
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
if (_selectedIndex == 1) {
_start = !_start;
}
});
}
#override
void initState() {
super.initState();
_initApp();
_cameraController =
CameraController(widget.camera, ResolutionPreset.medium);
_initializeCameraControllerFuture = _cameraController.initialize();
_fileInit();
}
_initApp() async {
final cameras = await availableCameras();
final camera = cameras.first;
_cameraController = CameraController(
camera, ResolutionPreset.max,
);
}
void _fileInit() async {
vidPath = join((await getTemporaryDirectory()).path, '${fileName}.mp4');
}
void _takePicture(BuildContext context) async {
try {
await _initializeCameraControllerFuture;
if (_selectedIndex == 0) {
final imgPath =
join((await getTemporaryDirectory()).path, '${fileName}.png');
await _cameraController.takePicture(imgPath);
Navigator.pop(context, imgPath);
} else {
if (_start) {
await _cameraController.startVideoRecording(vidPath);
setState(() {
_start = !_start;
_isRec = !_isRec;
});
} else {
_cameraController.stopVideoRecording();
setState(() {
_isRec = !_isRec;
});
Navigator.pop(context, vidPath);
}
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
FutureBuilder(
future: _initializeCameraControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return CameraPreview(_cameraController);
} else {
return Center(child: CircularProgressIndicator(backgroundColor: Colors.green,));
}
},
),
SafeArea(
child: Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
backgroundColor: Colors.green,
child: _selectedIndex == 1 ? _isRec == true?Icon(Icons.pause, color: Colors.white):Icon(Icons.play_arrow, color: Colors.white) : Icon(Icons.camera, color: Colors.white),
onPressed: () {
_takePicture(context);
},
),
),
),
),
_isRec == true
? SafeArea(
child: Container(
height: 30,
// alignment: Alignment.topLeft,
decoration: BoxDecoration(
color: Color(0xFFEE4400),
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"REC",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Color(0xFFFAFAFA)),
),
),
),
)
: SizedBox(
height: 0,
)
],
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.camera),
title: Text('Picture'),
),
BottomNavigationBarItem(
icon: Icon(Icons.videocam),
title: Text('Video'),
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.green,
onTap: _onItemTapped,
),
);
}
#override
void dispose() {
_cameraController.dispose();
super.dispose();
}
}
the camera is not being opened

Comma separated in AutoCompleteTextField in flutter

I am using a code which is working well and giving suggestion in dropdown menu by send a HTTP GET request.
import 'package:http/http.dart' as http;
import 'user.dart';
import 'dart:convert';
import 'package:autocomplete_textfield/autocomplete_textfield.dart';
class AutoCompleteDemo extends StatefulWidget {
AutoCompleteDemo() : super();
final String title = "AutoComplete Demo";
#override
_AutoCompleteDemoState createState() => _AutoCompleteDemoState();
}
class _AutoCompleteDemoState extends State<AutoCompleteDemo> {
AutoCompleteTextField searchTextField;
GlobalKey<AutoCompleteTextFieldState<User>> key = new GlobalKey();
static List<User> users = new List<User>();
bool loading = true;
void getUsers() async {
try {
final response =
await http.get("https://jsonplaceholder.typicode.com/users");
if (response.statusCode == 200) {
users = loadUsers(response.body);
print('Users: ${users.length}');
setState(() {
loading = false;
});
} else {
print("Error getting users.");
}
} catch (e) {
print("Error getting users.");
}
}
static List<User> loadUsers(String jsonString) {
final parsed = json.decode(jsonString).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
#override
void initState() {
getUsers();
super.initState();
}
Widget row(User user) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
user.name,
style: TextStyle(fontSize: 16.0),
),
SizedBox(
width: 10.0,
),
Text(
user.email,
),
],
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
loading
? CircularProgressIndicator()
: searchTextField = AutoCompleteTextField<User>(
key: key,
clearOnSubmit: false,
suggestions: users,
style: TextStyle(color: Colors.black, fontSize: 16.0),
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(10.0, 30.0, 10.0, 20.0),
hintText: "Search Name",
hintStyle: TextStyle(color: Colors.black),
),
itemFilter: (item, query) {
return item.name
.toLowerCase()
.startsWith(query.toLowerCase());
},
itemSorter: (a, b) {
return a.name.compareTo(b.name);
},
itemSubmitted: (item) {
setState(() {
searchTextField.textField.controller.text = item.name;
});
},
itemBuilder: (context, item) {
// ui for the autocompelete row
return row(item);
},
),
],
),
);
}
}
Requirement:
I want to take the input something like this so that every selected item is separated and the drop-down list shown after an item selected.The user could be able to add its own new item which isn't from the list.

Flutter Camera startImageStream returning images of null

I'm trying to create a realtime poseNet demo app with the help of Flutter and its Camera package.
Displaying the camera preview works very well, but when I try to access the image stream via controller.startImageStream the program crashes. I've succeded in tracking the source of that bug down, and it seems to me that the incoming frames in the 'controller.startImageStream' return values of null. Why is this, and how can I possibly fix it?
The snippet looks like this:
controller.startImageStream((CameraImage img) {
controller.stopImageStream();
if (!isPaused) {
runPoseNetOnFrame(bytesList: img.planes.map((plane) {
return plane.bytes;
}).toList(),
imageHeight: img.height,
imageWidth: img.width,
numResults: 1).then((recognitions) {
setState(() {
photo = img;
_recognitions = recognitions;
imageHeight = img.height;
imageWidth = img.width;
});
});
}
});
And it's the variable, img that's for every iteration composed of nothing but type null when it really should contain a frame of type CameraImage
While the app crashes I get this error in my console:
E/flutter (26077): [ERROR:flutter/shell/common/shell.cc(178)] Dart Error: Unhandled exception:
E/flutter (26077): NoSuchMethodError: The getter 'isActive' was called on null.
E/flutter (26077): Receiver: null
E/flutter (26077): Tried calling: isActive
Here's my code for the entire page:
import 'package:flutter/material.dart';
import 'package:tflite/tflite.dart';
import 'package:flutter/services.dart';
import 'dart:typed_data';
import 'package:camera/camera.dart';
class CoachPage extends StatefulWidget {
#override
_CoachPageState createState() {
return _CoachPageState();
}
}
class _CoachPageState extends State<CoachPage> {
bool isPaused = true;
CameraController controller;
List cameras;
int selectedCameraIdx;
String imagePath;
static const MethodChannel _channel = const MethodChannel('tflite');
String model;
List<dynamic> _recognitions;
int imageHeight;
int imageWidth;
CameraImage photo;
#override
void initState() {
super.initState();
availableCameras().then((availableCameras) {
cameras = availableCameras;
if (cameras.length > 0) {
setState(() {
selectedCameraIdx = 0;
});
_initCameraController(cameras[selectedCameraIdx]);
}
else{
print("No camera available");
}
}).catchError((err) {
print('Error: $err.code\nError Message: $err.message');
});
}
void _initCameraController(CameraDescription cameraDescription) {
controller = CameraController(cameraDescription, ResolutionPreset.medium);
controller.initialize().then((_) {
if (!mounted) {
return;
}
controller.addListener(() {});
controller.startImageStream((CameraImage img) {
controller.stopImageStream();
if (!isPaused) {
runPoseNetOnFrame(bytesList: img.planes.map((plane) {
return plane.bytes;
}).toList(),
imageHeight: img.height,
imageWidth: img.width,
numResults: 1).then((recognitions) {
setState(() {
photo = img;
_recognitions = recognitions;
imageHeight = img.height;
imageWidth = img.width;
});
});
}
});
setState(() {});
});}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 1,
child: isPaused ? _cameraPreviewWidget()
: _renderKeypoints(),
),
SizedBox(height: 10.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
_cameraTogglesRowWidget(),
_captureControlRowWidget(context),
Spacer(),
Text(photo.toString())
],
),
SizedBox(height: 20.0)
],
),
),
),
);
}
/// Display Camera preview.
Widget _cameraPreviewWidget() {
if (controller == null || !controller.value.isInitialized) {
return const Text(
'Loading',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w900,
),
);
}
return AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: CameraPreview(controller),
);
}
/// Display the control bar with buttons to take pictures
Widget _captureControlRowWidget(context) {
return Expanded(
child: Align(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
FloatingActionButton(
child:(isPaused) ? Icon(Icons.play_arrow)
: Icon(Icons.pause),
backgroundColor: Colors.blueGrey,
onPressed: () {
setState(() {
isPaused = !isPaused;
});
})
],
),
),
);
}
/// Display a row of toggle to select the camera (or a message if no camera is available).
Widget _cameraTogglesRowWidget() {
if (cameras == null || cameras.isEmpty) {
return Spacer();
}
CameraDescription selectedCamera = cameras[selectedCameraIdx];
CameraLensDirection lensDirection = selectedCamera.lensDirection;
return Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: FlatButton.icon(
onPressed: _onSwitchCamera,
icon: Icon(_getCameraLensIcon(lensDirection)),
label: Text(
"${lensDirection.toString().substring(lensDirection.toString().indexOf('.') + 1)}")),
),
);
}
IconData _getCameraLensIcon(CameraLensDirection direction) {
switch (direction) {
case CameraLensDirection.back:
return Icons.camera_rear;
case CameraLensDirection.front:
return Icons.camera_front;
case CameraLensDirection.external:
return Icons.camera;
default:
return Icons.device_unknown;
}
}
void _onSwitchCamera() {
selectedCameraIdx =
selectedCameraIdx < cameras.length - 1 ? selectedCameraIdx + 1 : 0;
CameraDescription selectedCamera = cameras[selectedCameraIdx];
_initCameraController(selectedCamera);
}
void _showCameraException(CameraException e) {
String errorText = 'Error: ${e.code}\nError Message: ${e.description}';
print(errorText);
print('Error: ${e.code}\n${e.description}');
}
Future loadModel() async {
Tflite.close();
String res = await Tflite.loadModel(
model: "assets/posenet_mv1_075_float_from_checkpoints.tflite");
model = res;
}
Future<List> runPoseNetOnFrame(
{#required List<Uint8List> bytesList,
int imageHeight = 1280,
int imageWidth = 720,
double imageMean = 127.5,
double imageStd = 127.5,
int rotation: 90, // Android only
int numResults = 1,
double threshold = 0.5,
int nmsRadius = 20,
bool asynch = true}) async {
return await _channel.invokeMethod(
'runPoseNetOnFrame',
{
"bytesList": bytesList,
"imageHeight": imageHeight,
"imageWidth": imageWidth,
"imageMean": imageMean,
"imageStd": imageStd,
"rotation": rotation,
"numResults": numResults,
"threshold": threshold,
"nmsRadius": nmsRadius,
"asynch": asynch,
},
);
}
List<Widget> _renderKeypoints() {
var lists = <Widget>[];
_recognitions.forEach((re) {
var list = re["keypoints"].values.map<Widget>((k) {
var x = k["x"];
var y = k["y"];
return Positioned(
left: x - 6,
top: y - 6,
width: 100,
height: 12,
child: Container(
child: Text(
"● ${k["part"]}",
style: TextStyle(
color: Color.fromRGBO(37, 213, 253, 1.0),
fontSize: 12.0,
),
),
),
);
}).toList();
lists.addAll(list);
});
return lists;
}
}
Thanks in advance! ;)
Checking your code, the issue seems to be caused by calling controller.stopImageStream(); immediately after controller.startImageStream(). You may want to consider closing the Stream only when it's not in use, like in dispose() override method.