import 'dart:async'; import 'dart:io'; import 'dart:isolate'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_ffmpeg/stream_information.dart'; import 'package:flutter_opencv_example/native_opencv.dart'; import 'package:path_provider/path_provider.dart'; import 'package:flutter_ffmpeg/flutter_ffmpeg.dart'; const title = 'Native OpenCV Example'; late Directory tempDir; String get dataPath => '${tempDir.path}/data.csv'; void main() { WidgetsFlutterBinding.ensureInitialized(); getTemporaryDirectory().then((dir) => tempDir = dir); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: title, theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { bool _isProcessed = false; bool _isWorking = false; void showVersion() { final scaffoldMessenger = ScaffoldMessenger.of(context); final snackbar = SnackBar( content: Text('OpenCV version: ${opencvVersion()}'), ); scaffoldMessenger ..removeCurrentSnackBar(reason: SnackBarClosedReason.dismiss) ..showSnackBar(snackbar); } Future pickAnImage() async { if (Platform.isIOS || Platform.isAndroid) { return FilePicker.platform .pickFiles( dialogTitle: 'Pick an image', type: FileType.video, allowMultiple: false, ) .then((v) => v?.files.first.path); } else { return FilePicker.platform .pickFiles( dialogTitle: 'Pick an image', type: FileType.image, allowMultiple: false, ) .then((v) => v?.files.first.path); } } Future takeImageAndProcess() async { final imagePath = await pickAnImage(); final FlutterFFprobe _flutterFFmpeg = FlutterFFprobe(); if (imagePath == null) { return; } double? frameRate; var vinfo = await _flutterFFmpeg.getMediaInformation(imagePath); List? streams = vinfo.getStreams(); if (streams!.length > 0) { for (var stream in streams) { if (stream.getAllProperties()['codec_type'] == "video") { frameRate = int.parse( stream.getAllProperties()['avg_frame_rate'].split("/")[0]) / int.parse( stream.getAllProperties()['avg_frame_rate'].split("/")[1]); } } } setState(() { _isWorking = true; }); // Creating a port for communication with isolate and arguments for entry point final port = ReceivePort(); final args = ProcessImageArguments(imagePath, dataPath, frameRate ?? 0.0); // Spawning an isolate Isolate.spawn( processImage, args, onError: port.sendPort, onExit: port.sendPort, ); // Making a variable to store a subscription in late StreamSubscription sub; // Listening for messages on port sub = port.listen((_) async { // Cancel a subscription after message received called await sub.cancel(); setState(() { _isProcessed = true; _isWorking = false; }); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(title)), body: Stack( children: [ Center( child: ListView( shrinkWrap: true, children: [ if (_isProcessed && !_isWorking) ConstrainedBox( constraints: BoxConstraints(maxWidth: 3000, maxHeight: 300), // child: Image.file( // File(tempPath), // alignment: Alignment.center, // ), ), Column( children: [ ElevatedButton( child: Text('Show version'), onPressed: showVersion, ), ElevatedButton( child: Text('Process photo'), onPressed: takeImageAndProcess, ), ], ) ], ), ), if (_isWorking) Positioned.fill( child: Container( color: Colors.black.withOpacity(.7), child: Center( child: CircularProgressIndicator(), ), ), ), ], ), ); } }