mirror of
https://github.com/defold/extension-camera
synced 2025-06-27 18:37:43 +02:00
217 lines
6.2 KiB
C++
217 lines
6.2 KiB
C++
#include <dmsdk/sdk.h>
|
|
|
|
#if defined(DM_PLATFORM_ANDROID)
|
|
|
|
#include "camera_private.h"
|
|
|
|
static jclass g_CameraClass = 0;
|
|
static jobject g_CameraObject = 0;
|
|
static jmethodID g_GetCameraMethodId = 0;
|
|
static jmethodID g_StartPreviewMethodId = 0;
|
|
static jmethodID g_StopPreviewMethodId = 0;
|
|
|
|
static jint *g_Data = 0;
|
|
static bool g_FrameLock = false;
|
|
|
|
static uint32_t g_Width = 0;
|
|
static uint32_t g_Height = 0;
|
|
static CameraType g_Type;
|
|
static CaptureQuality g_Quality;
|
|
|
|
static dmBuffer::HBuffer* g_Buffer = 0;
|
|
|
|
|
|
static JNIEnv* Attach()
|
|
{
|
|
JNIEnv* env;
|
|
JavaVM* vm = dmGraphics::GetNativeAndroidJavaVM();
|
|
vm->AttachCurrentThread(&env, NULL);
|
|
return env;
|
|
}
|
|
|
|
static bool Detach(JNIEnv* env)
|
|
{
|
|
bool exception = (bool) env->ExceptionCheck();
|
|
env->ExceptionClear();
|
|
JavaVM* vm = dmGraphics::GetNativeAndroidJavaVM();
|
|
vm->DetachCurrentThread();
|
|
return !exception;
|
|
}
|
|
|
|
static jclass GetClass(JNIEnv* env, const char* classname)
|
|
{
|
|
jclass activity_class = env->FindClass("android/app/NativeActivity");
|
|
jmethodID get_class_loader = env->GetMethodID(activity_class,"getClassLoader", "()Ljava/lang/ClassLoader;");
|
|
jobject cls = env->CallObjectMethod(dmGraphics::GetNativeAndroidActivity(), get_class_loader);
|
|
jclass class_loader = env->FindClass("java/lang/ClassLoader");
|
|
jmethodID find_class = env->GetMethodID(class_loader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
|
|
|
jstring str_class_name = env->NewStringUTF(classname);
|
|
jclass outcls = (jclass)env->CallObjectMethod(cls, find_class, str_class_name);
|
|
env->DeleteLocalRef(str_class_name);
|
|
return outcls;
|
|
}
|
|
|
|
|
|
extern "C"
|
|
{
|
|
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_frameUpdate(JNIEnv * env, jobject jobj, jintArray data);
|
|
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_queueMessage(JNIEnv * env, jobject jobj, jint message);
|
|
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_captureStarted(JNIEnv * env, jobject jobj, jint width, jint height);
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_frameUpdate(JNIEnv * env, jobject jobj, jintArray data)
|
|
{
|
|
if(!g_FrameLock)
|
|
{
|
|
env->GetIntArrayRegion(data, 0, g_Width * g_Height, g_Data);
|
|
g_FrameLock = true;
|
|
}
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_queueMessage(JNIEnv * env, jobject jobj, jint message)
|
|
{
|
|
Camera_QueueMessage((CameraMessage)message);
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_defold_android_camera_AndroidCamera_captureStarted(JNIEnv * env, jobject jobj, jint width, jint height)
|
|
{
|
|
g_Width = (uint32_t)width;
|
|
g_Height = (uint32_t)height;
|
|
|
|
uint32_t size = g_Width * g_Height;
|
|
delete g_Data;
|
|
g_Data = new jint[size];
|
|
dmBuffer::StreamDeclaration streams_decl[] = {
|
|
{dmHashString64("rgb"), dmBuffer::VALUE_TYPE_UINT8, 3}
|
|
};
|
|
dmBuffer::Create(size, streams_decl, 1, g_Buffer);
|
|
}
|
|
|
|
|
|
void CameraPlatform_GetCameraInfo(CameraInfo& outparams)
|
|
{
|
|
outparams.m_Width = (g_Width > g_Height) ? g_Height : g_Width;
|
|
outparams.m_Height = (g_Width > g_Height) ? g_Width : g_Height;
|
|
outparams.m_Type = g_Type;
|
|
}
|
|
|
|
int CameraPlatform_Initialize()
|
|
{
|
|
JNIEnv* env = Attach();
|
|
if(!env)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// get the AndroidCamera class
|
|
jclass tmp = GetClass(env, "com.defold.android.camera/AndroidCamera");
|
|
g_CameraClass = (jclass)env->NewGlobalRef(tmp);
|
|
if(!g_CameraClass)
|
|
{
|
|
dmLogError("Could not find class 'com.defold.android.camera/AndroidCamera'.");
|
|
Detach(env);
|
|
return false;
|
|
}
|
|
|
|
// get an instance of the AndroidCamera class using the getCamera() method
|
|
g_GetCameraMethodId = env->GetStaticMethodID(g_CameraClass, "getCamera", "(Landroid/content/Context;)Lcom/defold/android/camera/AndroidCamera;");
|
|
if(!g_GetCameraMethodId)
|
|
{
|
|
dmLogError("Could not get static method 'getCamera'.");
|
|
Detach(env);
|
|
return false;
|
|
}
|
|
|
|
jobject tmp1 = env->CallStaticObjectMethod(g_CameraClass, g_GetCameraMethodId, dmGraphics::GetNativeAndroidActivity());
|
|
g_CameraObject = (jobject)env->NewGlobalRef(tmp1);
|
|
if(!g_CameraObject)
|
|
{
|
|
dmLogError("Could not create instance.");
|
|
Detach(env);
|
|
return false;
|
|
}
|
|
|
|
// get reference to startPreview() and stopPreview() methods
|
|
g_StartPreviewMethodId = env->GetMethodID(g_CameraClass, "startPreview", "(II)V");
|
|
if(!g_StartPreviewMethodId)
|
|
{
|
|
dmLogError("Could not get startPreview() method.");
|
|
Detach(env);
|
|
return false;
|
|
}
|
|
g_StopPreviewMethodId = env->GetMethodID(g_CameraClass, "stopPreview", "()V");
|
|
if(!g_StopPreviewMethodId)
|
|
{
|
|
dmLogError("Could not get stopPreview() method.");
|
|
Detach(env);
|
|
return false;
|
|
}
|
|
|
|
Detach(env);
|
|
return true;
|
|
}
|
|
|
|
void CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality)
|
|
{
|
|
if (!g_CameraObject)
|
|
{
|
|
Camera_QueueMessage(CAMERA_ERROR);
|
|
return;
|
|
}
|
|
|
|
g_Buffer = buffer;
|
|
g_Type = type;
|
|
g_Quality = quality;
|
|
|
|
JNIEnv* env = Attach();
|
|
env->CallVoidMethod(g_CameraObject, g_StartPreviewMethodId);
|
|
Detach(env);
|
|
}
|
|
|
|
void CameraPlatform_StopCapture()
|
|
{
|
|
if (!g_CameraObject)
|
|
{
|
|
Camera_QueueMessage(CAMERA_ERROR);
|
|
return;
|
|
}
|
|
|
|
JNIEnv* env = Attach();
|
|
env->CallVoidMethod(g_CameraObject, g_StopPreviewMethodId);
|
|
Detach(env);
|
|
}
|
|
|
|
void CameraPlatform_UpdateCapture()
|
|
{
|
|
if(g_FrameLock)
|
|
{
|
|
int width = g_Width;
|
|
int height = g_Height;
|
|
int numChannels = 4;
|
|
uint8_t* out;
|
|
uint32_t outsize;
|
|
dmBuffer::GetBytes(*g_Buffer, (void**)&out, &outsize);
|
|
|
|
uint32_t* data = (uint32_t*)g_Data;
|
|
for( int y = 0; y < height; ++y)
|
|
{
|
|
for( int x = 0; x < width; ++x)
|
|
{
|
|
// We get the image in landscape mode, so we flip it to portrait mode
|
|
int index = (width-x-1)*height*3 + (height-y-1)*3;
|
|
|
|
// RGB <- ARGB
|
|
uint32_t argb = data[y*width+x];
|
|
|
|
out[index+0] = (argb>>0)&0xFF; // R
|
|
out[index+1] = (argb>>8)&0xFF; // G
|
|
out[index+2] = (argb>>16)&0xFF; // B
|
|
}
|
|
}
|
|
g_FrameLock = false;
|
|
}
|
|
}
|
|
|
|
#endif // DM_PLATFORM_ANDROID
|