0

I am trying to make an app that captures image (and doesnt display the camera stream) using dart:ffi (.c file is not included in code below). (I used this page) I use allocate() and free() methods, but I get an error: "The method 'free' ('allocate') isn't defined for the type '_MyHomePageState'. How do i fix this?

calloc.allocate(), calloc.free(), malloc.allocate() and malloc.free() work and then ffi library is used. Without this, errors appear again.

I have ffi: ^2.0.1 in my dependencies and i ran flutter pub get, flutter clean, flutter outdated, flutter upgrade and restarted my computer.

import 'dart:io';
import 'dart:typed_data';
import 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:image/image.dart' as imglib;

typedef convert_func = Pointer<Uint32> Function(Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>, Int32, Int32, Int32, Int32);
typedef Convert = Pointer<Uint32> Function(Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>, int, int, int, int);

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Camera App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const MyHomePage(title: 'Camera App'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late CameraController _camera;
  bool _cameraInitialized = false;
  late CameraImage _savedImage;


  final DynamicLibrary convertImageLib = Platform.isAndroid
      ? DynamicLibrary.open("lib-convertImage.so")
      : DynamicLibrary.process();
  late Convert conv;


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

    // Load the convertImage() function from the library
    conv = convertImageLib.lookup<NativeFunction<convert_func>>('convertImage').asFunction<Convert>();
  }

  void _initializeCamera() async {
    // Get list of cameras of the device
    List<CameraDescription> cameras = await availableCameras();

    // Create the CameraController
    _camera = CameraController(cameras[0], ResolutionPreset.veryHigh);
    _camera.initialize().then((_) async{
      // Start ImageStream
      await _camera.startImageStream((CameraImage image) => _processCameraImage(image));
      setState(() {
        _cameraInitialized = true;
      });
    });
  }

  void _processCameraImage(CameraImage image) async {
    setState(() {
      _savedImage = image;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: const Center(),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          // Allocate memory for the 3 planes of the image
          Pointer<Uint8> p = allocate(count: _savedImage.planes[0].bytes.length);
          Pointer<Uint8> p1 = allocate(count: _savedImage.planes[1].bytes.length);
          Pointer<Uint8> p2 = allocate(count: _savedImage.planes[2].bytes.length);

          // Assign the planes data to the pointers of the image
          Uint8List pointerList = p.asTypedList(_savedImage.planes[0].bytes.length);
          Uint8List pointerList1 = p1.asTypedList(_savedImage.planes[1].bytes.length);
          Uint8List pointerList2 = p2.asTypedList(_savedImage.planes[2].bytes.length);
          pointerList.setRange(0, _savedImage.planes[0].bytes.length, _savedImage.planes[0].bytes);
          pointerList1.setRange(0, _savedImage.planes[1].bytes.length, _savedImage.planes[1].bytes);
          pointerList2.setRange(0, _savedImage.planes[2].bytes.length, _savedImage.planes[2].bytes);

          // Call the convertImage function and convert the YUV to RGB
          Pointer<Uint32> imgP = conv(p, p1, p2, _savedImage.planes[1].bytesPerRow,
              _savedImage.planes[1].bytesPerPixel, _savedImage.width, _savedImage.height);
          // Get the pointer of the data returned from the function to a List
          List imgData = imgP.asTypedList((_savedImage.width * _savedImage.height));

          // Generate image from the converted data
          imglib.Image img = imglib.Image.fromBytes(_savedImage.height, _savedImage.width, imgData);

          // Free the memory space allocated
          // from the planes and the converted data
          free(p);
          free(p1);
          free(p2);
          free(imgP);

        },
        tooltip: 'Increment',
        child: const Icon(Icons.camera_alt),
      ), // This trailing comma makes auto-formatting nicer for build methods.
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}
Ozdek
  • 3
  • 3
  • You may need to add an `import` for the file that actually defines the alloc and free functions. – Ber Nov 28 '22 at 16:59
  • c'mon man, he just said that he imported ffi. Im facing the same problem actually. – Hamdan Feb 22 '23 at 17:50

2 Answers2

0

Make sure to add ffi to both dependencies and dev_dependencies, like this:

dependencies:
  ffi: ^2.0.1
  flutter:
    sdk: flutter
  plugin_platform_interface: ^2.0.2

dev_dependencies:
  ffi: ^2.0.1
  ffigen: ^8.0.2
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0
blade
  • 804
  • 1
  • 9
  • 18
0

alongside the previous answers i also had to add calloc (or malloc depending on your need). not sure why there's no clear answers that free and allocate were moved to calloc (probably just renamed as in the pic below) which is part of ffi but it works calloc.free(p);

enter image description here

Kream
  • 131
  • 1
  • 3
  • 12