/*----------------------------------------------------------------------------*/ /* Copyright (c) FIRST 2016. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ /*----------------------------------------------------------------------------*/ #include "edu_wpi_cscore_CameraServerJNI.h" #include "llvm/raw_ostream.h" #include "llvm/SmallString.h" #include "support/jni_util.h" #include "cscore_cpp.h" using namespace wpi::java; // // Globals and load/unload // // Used for callback. static JavaVM *jvm = nullptr; static jclass usbCameraInfoCls = nullptr; static jclass videoModeCls = nullptr; static jclass videoEventCls = nullptr; static jclass videoExceptionCls = nullptr; // Thread-attached environment for listener callbacks. static JNIEnv *listenerEnv = nullptr; static void ListenerOnStart() { if (!jvm) return; JNIEnv *env; JavaVMAttachArgs args; args.version = JNI_VERSION_1_2; args.name = const_cast("CSListener"); args.group = nullptr; if (jvm->AttachCurrentThreadAsDaemon(reinterpret_cast(&env), &args) != JNI_OK) return; if (!env || !env->functions) return; listenerEnv = env; } static void ListenerOnExit() { listenerEnv = nullptr; if (!jvm) return; jvm->DetachCurrentThread(); } extern "C" { JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { jvm = vm; JNIEnv *env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR; // Cache references to classes jclass local; local = env->FindClass("edu/wpi/cscore/UsbCameraInfo"); if (!local) return JNI_ERR; usbCameraInfoCls = static_cast(env->NewGlobalRef(local)); if (!usbCameraInfoCls) return JNI_ERR; env->DeleteLocalRef(local); local = env->FindClass("edu/wpi/cscore/VideoMode"); if (!local) return JNI_ERR; videoModeCls = static_cast(env->NewGlobalRef(local)); if (!videoModeCls) return JNI_ERR; env->DeleteLocalRef(local); local = env->FindClass("edu/wpi/cscore/VideoEvent"); if (!local) return JNI_ERR; videoEventCls = static_cast(env->NewGlobalRef(local)); if (!videoEventCls) return JNI_ERR; env->DeleteLocalRef(local); local = env->FindClass("edu/wpi/cscore/VideoException"); if (!local) return JNI_ERR; videoExceptionCls = static_cast(env->NewGlobalRef(local)); if (!videoExceptionCls) return JNI_ERR; env->DeleteLocalRef(local); // Initial configuration of listener start/exit cs::SetListenerOnStart(ListenerOnStart); cs::SetListenerOnExit(ListenerOnExit); return JNI_VERSION_1_6; } JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) return; // Delete global references if (usbCameraInfoCls) env->DeleteGlobalRef(usbCameraInfoCls); if (videoModeCls) env->DeleteGlobalRef(videoModeCls); if (videoEventCls) env->DeleteGlobalRef(videoEventCls); if (videoExceptionCls) env->DeleteGlobalRef(videoEventCls); jvm = nullptr; } } // extern "C" // // Helper class to create and clean up a global reference // template class JGlobal { public: JGlobal(JNIEnv *env, T obj) : m_obj(static_cast(env->NewGlobalRef(obj))) {} ~JGlobal() { if (!jvm || cs::NotifierDestroyed()) return; JNIEnv *env; bool attached = false; // don't attach and de-attach if already attached to a thread. if (jvm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) == JNI_EDETACHED) { if (jvm->AttachCurrentThread(reinterpret_cast(&env), nullptr) != JNI_OK) return; attached = true; } if (!env || !env->functions) return; env->DeleteGlobalRef(m_obj); if (attached) jvm->DetachCurrentThread(); } operator T() { return m_obj; } T obj() { return m_obj; } private: T m_obj; }; static void ReportError(JNIEnv *env, CS_Status status) { if (status == CS_OK) return; static jmethodID constructor = nullptr; if (!constructor) constructor = env->GetMethodID(videoExceptionCls, "", "(Ljava/lang/String;)V"); llvm::SmallString<64> msg; switch (status) { case CS_PROPERTY_WRITE_FAILED: msg = "property write failed"; break; case CS_INVALID_HANDLE: msg = "invalid handle"; break; case CS_WRONG_HANDLE_SUBTYPE: msg = "wrong handle subtype"; break; case CS_INVALID_PROPERTY: msg = "invalid property"; break; case CS_WRONG_PROPERTY_TYPE: msg = "wrong property type"; break; case CS_READ_FAILED: msg = "read failed"; break; case CS_SOURCE_IS_DISCONNECTED: msg = "source is disconnected"; break; default: { llvm::raw_svector_ostream oss{msg}; oss << "unknown error code=" << status; break; } } JLocal msg_jstr{env, MakeJString(env, msg)}; jobject exception = env->NewObject(videoExceptionCls, constructor, msg_jstr.obj()); env->Throw(static_cast(exception)); } static inline bool CheckStatus(JNIEnv *env, CS_Status status) { if (status != CS_OK) ReportError(env, status); return status == CS_OK; } static jobject MakeJObject(JNIEnv *env, const cs::UsbCameraInfo &info) { static jmethodID constructor = env->GetMethodID( usbCameraInfoCls, "", "(ILjava/lang/String;Ljava/lang/String;)V"); JLocal path(env, MakeJString(env, info.path)); JLocal name(env, MakeJString(env, info.name)); return env->NewObject(usbCameraInfoCls, constructor, static_cast(info.dev), path.obj(), name.obj()); } static jobject MakeJObject(JNIEnv *env, const cs::VideoMode &videoMode) { static jmethodID constructor = env->GetMethodID(videoModeCls, "", "(IIII)V"); return env->NewObject( videoModeCls, constructor, static_cast(videoMode.pixelFormat), static_cast(videoMode.width), static_cast(videoMode.height), static_cast(videoMode.fps)); } static jobject MakeJObject(JNIEnv *env, const cs::RawEvent &event) { static jmethodID constructor = env->GetMethodID(videoEventCls, "", "(IIILjava/lang/String;IIIIIIILjava/lang/String;)V"); JLocal name(env, MakeJString(env, event.name)); JLocal valueStr(env, MakeJString(env, event.valueStr)); return env->NewObject( videoEventCls, constructor, static_cast(event.kind), static_cast(event.sourceHandle), static_cast(event.sinkHandle), name.obj(), static_cast(event.mode.pixelFormat), static_cast(event.mode.width), static_cast(event.mode.height), static_cast(event.mode.fps), static_cast(event.propertyHandle), static_cast(event.propertyKind), static_cast(event.value), valueStr.obj()); } extern "C" { /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getPropertyKind * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getPropertyKind (JNIEnv *env, jclass, jint property) { CS_Status status = 0; auto val = cs::GetPropertyKind(property, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getPropertyName * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getPropertyName (JNIEnv *env, jclass, jint property) { CS_Status status = 0; llvm::SmallString<128> buf; auto str = cs::GetPropertyName(property, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getProperty * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getProperty (JNIEnv *env, jclass, jint property) { CS_Status status = 0; auto val = cs::GetProperty(property, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setProperty * Signature: (II)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setProperty (JNIEnv *env, jclass, jint property, jint value) { CS_Status status = 0; cs::SetProperty(property, value, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getPropertyMin * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getPropertyMin (JNIEnv *env, jclass, jint property) { CS_Status status = 0; auto val = cs::GetPropertyMin(property, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getPropertyMax * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getPropertyMax (JNIEnv *env, jclass, jint property) { CS_Status status = 0; auto val = cs::GetPropertyMax(property, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getPropertyStep * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getPropertyStep (JNIEnv *env, jclass, jint property) { CS_Status status = 0; auto val = cs::GetPropertyStep(property, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getPropertyDefault * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getPropertyDefault (JNIEnv *env, jclass, jint property) { CS_Status status = 0; auto val = cs::GetPropertyDefault(property, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getStringProperty * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getStringProperty (JNIEnv *env, jclass, jint property) { CS_Status status = 0; llvm::SmallString<128> buf; auto str = cs::GetStringProperty(property, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setStringProperty * Signature: (ILjava/lang/String;)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setStringProperty (JNIEnv *env, jclass, jint property, jstring value) { CS_Status status = 0; cs::SetStringProperty(property, JStringRef{env, value}, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getEnumPropertyChoices * Signature: (I)[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_getEnumPropertyChoices (JNIEnv *env, jclass, jint property) { CS_Status status = 0; auto arr = cs::GetEnumPropertyChoices(property, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJStringArray(env, arr); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: createUsbCameraDev * Signature: (Ljava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraDev (JNIEnv *env, jclass, jstring name, jint dev) { CS_Status status = 0; auto val = cs::CreateUsbCameraDev(JStringRef{env, name}, dev, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: createUsbCameraPath * Signature: (Ljava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraPath (JNIEnv *env, jclass, jstring name, jstring path) { CS_Status status = 0; auto val = cs::CreateUsbCameraPath(JStringRef{env, name}, JStringRef{env, path}, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: createHTTPCamera * Signature: (Ljava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createHttpCamera (JNIEnv *env, jclass, jstring name, jstring url) { CS_Status status = 0; auto val = cs::CreateHttpCamera(JStringRef{env, name}, JStringRef{env, url}, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: createCvSource * Signature: (Ljava/lang/String;IIII)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createCvSource (JNIEnv *env, jclass, jstring name, jint pixelFormat, jint width, jint height, jint fps) { CS_Status status = 0; auto val = cs::CreateCvSource( JStringRef{env, name}, cs::VideoMode{static_cast(pixelFormat), static_cast(width), static_cast(height), static_cast(fps)}, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSourceKind * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSourceKind (JNIEnv *env, jclass, jint source) { CS_Status status = 0; auto val = cs::GetSourceKind(source, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSourceName * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSourceName (JNIEnv *env, jclass, jint source) { CS_Status status = 0; llvm::SmallString<128> buf; auto str = cs::GetSourceName(source, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSourceDescription * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSourceDescription (JNIEnv *env, jclass, jint source) { CS_Status status = 0; llvm::SmallString<128> buf; auto str = cs::GetSourceDescription(source, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSourceLastFrameTime * Signature: (I)J */ JNIEXPORT jlong JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSourceLastFrameTime (JNIEnv *env, jclass, jint source) { CS_Status status = 0; auto val = cs::GetSourceLastFrameTime(source, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: isSourceConnected * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_edu_wpi_cscore_CameraServerJNI_isSourceConnected (JNIEnv *env, jclass, jint source) { CS_Status status = 0; auto val = cs::IsSourceConnected(source, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSourceProperty * Signature: (ILjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSourceProperty (JNIEnv *env, jclass, jint source, jstring name) { CS_Status status = 0; auto val = cs::GetSourceProperty(source, JStringRef{env, name}, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: enumerateSourceProperties * Signature: (I)[I */ JNIEXPORT jintArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_enumerateSourceProperties (JNIEnv *env, jclass, jint source) { CS_Status status = 0; llvm::SmallVector buf; auto arr = cs::EnumerateSourceProperties(source, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJIntArray(env, arr); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSourceVideoMode * Signature: (I)Ledu/wpi/cameraserver/VideoMode; */ JNIEXPORT jobject JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSourceVideoMode (JNIEnv *env, jclass, jint source) { CS_Status status = 0; auto val = cs::GetSourceVideoMode(source, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJObject(env, val); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSourceVideoMode * Signature: (IIIII)Z */ JNIEXPORT jboolean JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSourceVideoMode (JNIEnv *env, jclass, jint source, jint pixelFormat, jint width, jint height, jint fps) { CS_Status status = 0; auto val = cs::SetSourceVideoMode( source, cs::VideoMode(static_cast(pixelFormat), width, height, fps), &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSourcePixelFormat * Signature: (II)Z */ JNIEXPORT jboolean JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSourcePixelFormat (JNIEnv *env, jclass, jint source, jint pixelFormat) { CS_Status status = 0; auto val = cs::SetSourcePixelFormat( source, static_cast(pixelFormat), &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSourceResolution * Signature: (III)Z */ JNIEXPORT jboolean JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSourceResolution (JNIEnv *env, jclass, jint source, jint width, jint height) { CS_Status status = 0; auto val = cs::SetSourceResolution(source, width, height, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSourceFPS * Signature: (II)Z */ JNIEXPORT jboolean JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSourceFPS (JNIEnv *env, jclass, jint source, jint fps) { CS_Status status = 0; auto val = cs::SetSourceFPS(source, fps, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: enumerateSourceVideoModes * Signature: (I)[Ledu/wpi/cameraserver/VideoMode; */ JNIEXPORT jobjectArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_enumerateSourceVideoModes (JNIEnv *env, jclass, jint source) { CS_Status status = 0; auto arr = cs::EnumerateSourceVideoModes(source, &status); if (!CheckStatus(env, status)) return nullptr; jobjectArray jarr = env->NewObjectArray(arr.size(), videoModeCls, nullptr); if (!jarr) return nullptr; for (size_t i = 0; i < arr.size(); ++i) { JLocal jelem{env, MakeJObject(env, arr[i])}; env->SetObjectArrayElement(jarr, i, jelem); } return jarr; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: enumerateSourceSinks * Signature: (I)[I */ JNIEXPORT jintArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_enumerateSourceSinks (JNIEnv *env, jclass, jint source) { CS_Status status = 0; llvm::SmallVector buf; auto arr = cs::EnumerateSourceSinks(source, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJIntArray(env, arr); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: copySource * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_copySource (JNIEnv *env, jclass, jint source) { CS_Status status = 0; auto val = cs::CopySource(source, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: releaseSource * Signature: (I)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_releaseSource (JNIEnv *env, jclass, jint source) { CS_Status status = 0; cs::ReleaseSource(source, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getUsbCameraPath * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getUsbCameraPath (JNIEnv *env, jclass, jint source) { CS_Status status = 0; auto str = cs::GetUsbCameraPath(source, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: putSourceFrame * Signature: (IJ)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_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); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: notifySourceError * Signature: (ILjava/lang/String;)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_notifySourceError (JNIEnv *env, jclass, jint source, jstring msg) { CS_Status status = 0; cs::NotifySourceError(source, JStringRef{env, msg}, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSourceConnected * Signature: (IZ)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSourceConnected (JNIEnv *env, jclass, jint source, jboolean connected) { CS_Status status = 0; cs::SetSourceConnected(source, connected, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSourceDescription * Signature: (ILjava/lang/String;)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSourceDescription (JNIEnv *env, jclass, jint source, jstring description) { CS_Status status = 0; cs::SetSourceDescription(source, JStringRef{env, description}, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: createSourceProperty * Signature: (ILjava/lang/String;IIIIII)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createSourceProperty (JNIEnv *env, jclass, jint source, jstring name, jint kind, jint minimum, jint maximum, jint step, jint defaultValue, jint value) { CS_Status status = 0; auto val = cs::CreateSourceProperty( source, JStringRef{env, name}, static_cast(kind), minimum, maximum, step, defaultValue, value, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSourceEnumPropertyChoices * Signature: (II[Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSourceEnumPropertyChoices (JNIEnv *env, jclass, jint source, jint property, jobjectArray choices) { size_t len = env->GetArrayLength(choices); llvm::SmallVector vec; vec.reserve(len); for (size_t i = 0; i < len; ++i) { JLocal elem{ env, static_cast(env->GetObjectArrayElement(choices, i))}; if (!elem) { // TODO return; } vec.push_back(JStringRef{env, elem}.str()); } CS_Status status = 0; cs::SetSourceEnumPropertyChoices(source, property, vec, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: createMjpegServer * Signature: (Ljava/lang/String;Ljava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createMjpegServer (JNIEnv *env, jclass, jstring name, jstring listenAddress, jint port) { CS_Status status = 0; auto val = cs::CreateMjpegServer( JStringRef{env, name}, JStringRef{env, listenAddress}, port, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: createCvSink * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createCvSink (JNIEnv *env, jclass, jstring name) { CS_Status status = 0; auto val = cs::CreateCvSink(JStringRef{env, name}, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSinkKind * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSinkKind (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; auto val = cs::GetSinkKind(sink, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSinkName * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSinkName (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; llvm::SmallString<128> buf; auto str = cs::GetSinkName(sink, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSinkDescription * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSinkDescription (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; llvm::SmallString<128> buf; auto str = cs::GetSinkDescription(sink, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSinkSource * Signature: (II)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSinkSource (JNIEnv *env, jclass, jint sink, jint source) { CS_Status status = 0; cs::SetSinkSource(sink, source, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSinkSourceProperty * Signature: (ILjava/lang/String;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSinkSourceProperty (JNIEnv *env, jclass, jint sink, jstring name) { CS_Status status = 0; auto val = cs::GetSinkSourceProperty(sink, JStringRef{env, name}, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSinkSource * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSinkSource (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; auto val = cs::GetSinkSource(sink, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: copySink * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_copySink (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; auto val = cs::CopySink(sink, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: releaseSink * Signature: (I)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_releaseSink (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; cs::ReleaseSink(sink, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getMjpegServerListenAddress * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getMjpegServerListenAddress (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; auto str = cs::GetMjpegServerListenAddress(sink, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getMjpegServerPort * Signature: (I)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getMjpegServerPort (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; auto val = cs::GetMjpegServerPort(sink, &status); CheckStatus(env, status); return val; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSinkDescription * Signature: (ILjava/lang/String;)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSinkDescription (JNIEnv *env, jclass, jint sink, jstring description) { CS_Status status = 0; cs::SetSinkDescription(sink, JStringRef{env, description}, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: grabSinkFrame * Signature: (IJ)J */ JNIEXPORT jlong JNICALL Java_edu_wpi_cscore_CameraServerJNI_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; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSinkError * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSinkError (JNIEnv *env, jclass, jint sink) { CS_Status status = 0; llvm::SmallString<128> buf; auto str = cs::GetSinkError(sink, buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJString(env, str); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setSinkEnabled * Signature: (IZ)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setSinkEnabled (JNIEnv *env, jclass, jint sink, jboolean enabled) { CS_Status status = 0; cs::SetSinkEnabled(sink, enabled, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: addListener * Signature: (Ljava/util/function/Consumer;IZ)I */ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_addListener (JNIEnv *envouter, jclass, jobject listener, jint eventMask, jboolean immediateNotify) { // the shared pointer to the weak global will keep it around until the // entry listener is destroyed auto listener_global = std::make_shared>(envouter, listener); // cls is a temporary here; cannot be used within callback functor jclass cls = envouter->GetObjectClass(listener); if (!cls) return 0; // method ids, on the other hand, are safe to retain jmethodID mid = envouter->GetMethodID(cls, "accept", "(Ljava/lang/Object;)V"); if (!mid) return 0; CS_Status status = 0; CS_Listener handle = cs::AddListener( [=](const cs::RawEvent &event) { JNIEnv *env = listenerEnv; if (!env || !env->functions) return; // get the handler auto handler = listener_global->obj(); // convert into the appropriate Java type JLocal jobj{env, MakeJObject(env, event)}; if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); return; } if (!jobj) return; env->CallVoidMethod(handler, mid, jobj.obj()); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } }, eventMask, immediateNotify != JNI_FALSE, &status); CheckStatus(envouter, status); return handle; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: removeListener * Signature: (I)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_removeListener (JNIEnv *env, jclass, jint handle) { CS_Status status = 0; cs::RemoveListener(handle, &status); CheckStatus(env, status); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: enumerateUsbCameras * Signature: ()[Ledu/wpi/cameraserver/UsbCameraInfo; */ JNIEXPORT jobjectArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_enumerateUsbCameras (JNIEnv *env, jclass) { CS_Status status = 0; auto arr = cs::EnumerateUsbCameras(&status); if (!CheckStatus(env, status)) return nullptr; jobjectArray jarr = env->NewObjectArray(arr.size(), usbCameraInfoCls, nullptr); if (!jarr) return nullptr; for (size_t i = 0; i < arr.size(); ++i) { JLocal jelem{env, MakeJObject(env, arr[i])}; env->SetObjectArrayElement(jarr, i, jelem); } return jarr; } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: enumerateSources * Signature: ()[I */ JNIEXPORT jintArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_enumerateSources (JNIEnv *env, jclass) { CS_Status status = 0; llvm::SmallVector buf; auto arr = cs::EnumerateSourceHandles(buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJIntArray(env, arr); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: enumerateSinks * Signature: ()[I */ JNIEXPORT jintArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_enumerateSinks (JNIEnv *env, jclass) { CS_Status status = 0; llvm::SmallVector buf; auto arr = cs::EnumerateSinkHandles(buf, &status); if (!CheckStatus(env, status)) return nullptr; return MakeJIntArray(env, arr); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getHostname * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_edu_wpi_cscore_CameraServerJNI_getHostname (JNIEnv *env, jclass) { return MakeJString(env, cs::GetHostname()); } /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getNetworkInterfaces * Signature: ()[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_getNetworkInterfaces (JNIEnv *env, jclass) { return MakeJStringArray(env, cs::GetNetworkInterfaces()); } } // extern "C" namespace { struct LogMessage { public: LogMessage(unsigned int level, const char *file, unsigned int line, const char *msg) : m_level(level), m_file(file), m_line(line), m_msg(msg) {} void CallJava(JNIEnv* env, jobject func, jmethodID mid) { JLocal file{env, MakeJString(env, m_file)}; JLocal msg{env, MakeJString(env, m_msg)}; env->CallVoidMethod(func, mid, (jint)m_level, file.obj(), (jint)m_line, msg.obj()); } static const char* GetName() { return "NTLogger"; } static JavaVM* GetJVM() { return jvm; } private: unsigned int m_level; const char* m_file; unsigned int m_line; std::string m_msg; }; typedef JSingletonCallbackManager LoggerJNI; } // anonymous namespace ATOMIC_STATIC_INIT(LoggerJNI) extern "C" { /* * Class: edu_wpi_cscore_CameraServerJNI * Method: setLogger * Signature: (Ledu/wpi/cscore/CameraServerJNI/LoggerFunction;I)V */ JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setLogger (JNIEnv *env, jclass, jobject func, jint minLevel) { // cls is a temporary here; cannot be used within callback functor jclass cls = env->GetObjectClass(func); if (!cls) return; // method ids, on the other hand, are safe to retain jmethodID mid = env->GetMethodID( cls, "apply", "(ILjava/lang/String;ILjava/lang/String;)V"); if (!mid) return; auto& logger = LoggerJNI::GetInstance(); logger.Start(); logger.SetFunc(env, func, mid); cs::SetLogger( [](unsigned int level, const char *file, unsigned int line, const char *msg) { LoggerJNI::GetInstance().Send(level, file, line, msg); }, minLevel); } } // extern "C"