From b058dcf64e08db11dbd8d83b561d27a040eff74a Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Fri, 22 Nov 2019 08:12:17 -0800 Subject: [PATCH] Catch exceptions generated by OpenCV in cscore JNI (#2118) --- cscore/build.gradle | 3 +- .../main/native/cpp/jni/CameraServerJNI.cpp | 81 +++++++++++++++---- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/cscore/build.gradle b/cscore/build.gradle index 4514b95f9a..9b84031534 100644 --- a/cscore/build.gradle +++ b/cscore/build.gradle @@ -19,7 +19,8 @@ ext { sharedCvConfigs = [cscore : [], cscoreBase: [], cscoreDev : [], - cscoreTest: []] + cscoreTest: [], + cscoreJNIShared: []] staticCvConfigs = [cscoreJNI: []] useJava = true useCpp = true diff --git a/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp b/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp index c50a7dbd37..52a0fea718 100644 --- a/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp +++ b/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp @@ -5,6 +5,9 @@ /* the project. */ /*----------------------------------------------------------------------------*/ +#include + +#include #include #include #include @@ -33,6 +36,7 @@ static JClass rawFrameCls; static JException videoEx; static JException nullPointerEx; static JException unsupportedEx; +static JException exceptionEx; // Thread-attached environment for listener callbacks. static JNIEnv* listenerEnv = nullptr; @@ -45,7 +49,8 @@ static const JClassInit classes[] = { static const JExceptionInit exceptions[] = { {"edu/wpi/cscore/VideoException", &videoEx}, {"java/lang/NullPointerException", &nullPointerEx}, - {"java/lang/UnsupportedOperationException", &unsupportedEx}}; + {"java/lang/UnsupportedOperationException", &unsupportedEx}, + {"java/lang/Exception", &exceptionEx}}; static void ListenerOnStart() { if (!jvm) return; @@ -67,6 +72,30 @@ static void ListenerOnExit() { jvm->DetachCurrentThread(); } +/// throw java exception +static void ThrowJavaException(JNIEnv* env, const std::exception* e) { + wpi::SmallString<128> what; + jclass je = 0; + + if (e) { + const char* exception_type = "std::exception"; + + if (dynamic_cast(e)) { + exception_type = "cv::Exception"; + je = env->FindClass("org/opencv/core/CvException"); + } + + what = exception_type; + what += ": "; + what += e->what(); + } else { + what = "unknown exception"; + } + + if (!je) je = exceptionEx; + env->ThrowNew(je, what.c_str()); +} + extern "C" { JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { @@ -1096,10 +1125,16 @@ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerCvJNI_putSourceFrame (JNIEnv* env, jclass, jint source, jlong imageNativeObj) { - cv::Mat& image = *((cv::Mat*)imageNativeObj); - CS_Status status = 0; - cs::PutSourceFrame(source, image, &status); - CheckStatus(env, status); + try { + cv::Mat& image = *((cv::Mat*)imageNativeObj); + CS_Status status = 0; + cs::PutSourceFrame(source, image, &status); + CheckStatus(env, status); + } catch (const std::exception& e) { + ThrowJavaException(env, &e); + } catch (...) { + ThrowJavaException(env, 0); + } } // int width, int height, int pixelFormat, int totalData @@ -1555,11 +1590,19 @@ JNIEXPORT jlong JNICALL Java_edu_wpi_cscore_CameraServerCvJNI_grabSinkFrame (JNIEnv* env, jclass, jint sink, jlong imageNativeObj) { - cv::Mat& image = *((cv::Mat*)imageNativeObj); - CS_Status status = 0; - auto rv = cs::GrabSinkFrame(sink, image, &status); - CheckStatus(env, status); - return rv; + try { + cv::Mat& image = *((cv::Mat*)imageNativeObj); + CS_Status status = 0; + auto rv = cs::GrabSinkFrame(sink, image, &status); + CheckStatus(env, status); + return rv; + } catch (const std::exception& e) { + ThrowJavaException(env, &e); + return 0; + } catch (...) { + ThrowJavaException(env, 0); + return 0; + } } /* @@ -1571,11 +1614,19 @@ JNIEXPORT jlong JNICALL Java_edu_wpi_cscore_CameraServerCvJNI_grabSinkFrameTimeout (JNIEnv* env, jclass, jint sink, jlong imageNativeObj, jdouble timeout) { - cv::Mat& image = *((cv::Mat*)imageNativeObj); - CS_Status status = 0; - auto rv = cs::GrabSinkFrameTimeout(sink, image, timeout, &status); - CheckStatus(env, status); - return rv; + try { + cv::Mat& image = *((cv::Mat*)imageNativeObj); + CS_Status status = 0; + auto rv = cs::GrabSinkFrameTimeout(sink, image, timeout, &status); + CheckStatus(env, status); + return rv; + } catch (const std::exception& e) { + ThrowJavaException(env, &e); + return 0; + } catch (...) { + ThrowJavaException(env, 0); + return 0; + } } static void SetRawFrameData(JNIEnv* env, jobject rawFrameObj,