Levi-Lesches / opencv_ffi

An FFI-based implementation of OpenCV in Dart
https://pub.dev/packages/opencv_ffi
Other
16 stars 1 forks source link

macOS Silicon error: "NSWindow should only be instantiated on the main thread!" #19

Closed TomTom101 closed 6 months ago

TomTom101 commented 6 months ago

Same problem as #17 (at least on an ARM based Mac, the library is named libopencv_ffi.dylib, so the first change needed is this:

String _getPath() {
  if (Platform.isWindows) {
    return "opencv_ffi.dll";
  } else if (Platform.isMacOS) {
    return "libopencv_ffi.dylib";
  } else if (Platform.isLinux) {
    return "libopencv_ffi.so";
  } else {
    throw UnsupportedError("Unsupported platform");
  }
}

Second issue here is that Dart does not seem to care about the LD_LIBRARY_PATH. I have it set, confirmed by echo $LD_LIBRARY_PATH, but it still not found. The given path is not searched for the lib.

I then symlinked the lib to the current directory, where it is found and end up with this error:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow should only be instantiated on the main thread!'
*** First throw call stack:
(
        0   CoreFoundation                      0x0000000186fc2800 __exceptionPreprocess + 176
        1   libobjc.A.dylib                     0x0000000186ab9eb4 objc_exception_throw + 60
        2   CoreFoundation                      0x0000000186fe7b4c _CFBundleGetValueForInfoKey + 0
        3   AppKit                              0x000000018a737538 -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 188
        4   AppKit                              0x000000018a737470 -[NSWindow initWithContentRect:styleMask:backing:defer:] + 48
        5   AppKit                              0x000000018a992b84 -[NSWindow initWithContentRect:styleMask:backing:defer:screen:] + 24
        6   libopencv_highgui.4.8.0.dylib       0x00000001077a1454 cvNamedWindow + 436
        7   libopencv_highgui.4.8.0.dylib       0x00000001077a0eac cvShowImage + 88
        8   libopencv_highgui.4.8.0.dylib       0x000000010779ad58 _ZN2cv6imshowERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKNS_11_InputArrayE + 1376
        9   libopencv_ffi.dylib                 0x0000000106c6839c imshow + 68
        10  ???                                 0x0000000106c87a28 0x0 + 4408769064
        11  ???                                 0x000000010e033134 0x0 + 4530057524
        12  ???                                 0x000000010e032bec 0x0 + 4530056172
        13  ???                                 0x000000010e031fc0 0x0 + 4530053056
        14  ???                                 0x000000010e02e444 0x0 + 4530037828
        15  ???                                 0x000000010e02e27c 0x0 + 4530037372
        16  ???                                 0x000000010e02e158 0x0 + 4530037080
        17  ???                                 0x000000010e02c9a8 0x0 + 4530031016
        18  ???                                 0x000000010e02c600 0x0 + 4530030080
        19  ???                                 0x000000010e02b0e8 0x0 + 4530024680
        20  ???                                 0x0000000106c83404 0x0 + 4408751108
        21  dart                                0x00000001048fd83c dart + 1464380
        22  dart                                0x00000001048ff2f4 dart + 1471220
        23  dart                                0x000000010491cbe4 dart + 1592292
        24  dart                                0x000000010493f830 dart + 1734704
        25  dart                                0x000000010493fe5c dart + 1736284
        26  dart                                0x0000000104a47ef4 dart + 2817780
        27  dart                                0x0000000104a4816c dart + 2818412
        28  dart                                0x00000001049d24a0 dart + 2335904
        29  libsystem_pthread.dylib             0x0000000186e71034 _pthread_start + 136
        30  libsystem_pthread.dylib             0x0000000186e6be3c thread_start + 8
)
libc++abi: terminating due to uncaught exception of type NSException
Levi-Lesches commented 6 months ago

Second issue here is that Dart does not seem to care about the LD_LIBRARY_PATH. I have it set, confirmed by echo $LD_LIBRARY_PATH, but it still not found. The given path is not searched for the lib.

Yep, I found that too. Have not found a proper solution to this but once the Native Assets feature makes it to the stable Dart version, this won't be an issue anymore.

From your stack trace:

libopencv_ffi.dylib                 0x0000000106c6839c imshow + 68

Seems like imshow (or at least, our usage of it) isn't playing nicely with the way Apple expects it to work. Here's the C++ side:

FFI_PLUGIN_EXPORT void imshow(Mat* image) {
  cv::Mat* cvImage = reinterpret_cast<cv::Mat*>(image);
  cv::imshow("Wrapper", *cvImage);
  cv::waitKey(1);
}

and here's the Dart side:

  void showFrame() {
    if (!_read()) throw CameraReadException();
    nativeLib.imshow(_image);
  }

Are you using isolates by any chance? If not, it could be that Dart's FFI mechanisms use threads somehow. I can ask around, but I don't know what's causing the issue nor do I have a Mac to debug it.

If you know your way around C/C++, may I suggest:

Levi-Lesches commented 6 months ago

Just ran this through @mraleph, seems this is an issue with Dart's FFI. Not sure what your next move should be, sorry, but for me, I found it useful to avoid imshow/showFrame altogether and stream the bytes directly to some other I/O, like Flutter's Image widget, or saving them to a file. After all, you can't control much of the OpenCV window, and I mostly just included it as a debug feature.

Here is an issue whose last comment explains the difficulties in this. If you feel imshow() is worth it to you and you understand what they're saying and how to go about it, feel free to try that solution. If not, it doesn't look like this will be fixed anytime soon (although this other issue notes that this should be solved for Flutter soon, it's just native Dart that won't work).

Closing as this is out of scope for this package, but feel free to subscribe or post your use-case to the above issues.