mirror of
https://github.com/defold/extension-camera
synced 2025-06-27 10:27:45 +02:00
265 lines
6.3 KiB
C++
265 lines
6.3 KiB
C++
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#define EXTENSION_NAME Camera
|
|
#define LIB_NAME "Camera"
|
|
#define MODULE_NAME "camera"
|
|
|
|
// Defold SDK
|
|
#include <dmsdk/sdk.h>
|
|
|
|
#if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_OSX) || defined(DM_PLATFORM_ANDROID)
|
|
|
|
#include <unistd.h>
|
|
#include "camera_private.h"
|
|
|
|
struct DefoldCamera
|
|
{
|
|
// The buffer that receives the pixel data
|
|
dmBuffer::HBuffer m_VideoBuffer;
|
|
|
|
// We create the buffer once, and keep a reference to it throughout
|
|
// the capture.
|
|
int m_VideoBufferLuaRef;
|
|
|
|
// Information about the currently set camera
|
|
CameraInfo m_Params;
|
|
|
|
dmArray<CameraMessage> m_MessageQueue;
|
|
dmScript::LuaCallbackInfo* m_Callback;
|
|
dmMutex::HMutex m_Mutex;
|
|
};
|
|
|
|
DefoldCamera g_DefoldCamera;
|
|
|
|
void Camera_QueueMessage(CameraMessage message)
|
|
{
|
|
dmLogInfo("Camera_QueueMessage %d", message);
|
|
DM_MUTEX_SCOPED_LOCK(g_DefoldCamera.m_Mutex);
|
|
|
|
if (g_DefoldCamera.m_MessageQueue.Full())
|
|
{
|
|
g_DefoldCamera.m_MessageQueue.OffsetCapacity(1);
|
|
}
|
|
g_DefoldCamera.m_MessageQueue.Push(message);
|
|
}
|
|
|
|
static void Camera_ProcessQueue()
|
|
{
|
|
if (g_DefoldCamera.m_MessageQueue.Empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
dmArray<CameraMessage> tmp;
|
|
{
|
|
DM_MUTEX_SCOPED_LOCK(g_DefoldCamera.m_Mutex);
|
|
tmp.Swap(g_DefoldCamera.m_MessageQueue);
|
|
}
|
|
|
|
for (uint32_t i = 0; i != tmp.Size(); ++i)
|
|
{
|
|
lua_State* L = dmScript::GetCallbackLuaContext(g_DefoldCamera.m_Callback);
|
|
if (!dmScript::SetupCallback(g_DefoldCamera.m_Callback))
|
|
{
|
|
break;
|
|
}
|
|
CameraMessage message = tmp[i];
|
|
|
|
if (message == CAMERA_STARTED)
|
|
{
|
|
// Increase ref count
|
|
dmScript::LuaHBuffer luabuffer(g_DefoldCamera.m_VideoBuffer, dmScript::OWNER_C);
|
|
dmScript::PushBuffer(L, luabuffer);
|
|
g_DefoldCamera.m_VideoBufferLuaRef = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
|
}
|
|
else if (message == CAMERA_STOPPED)
|
|
{
|
|
dmScript::Unref(L, LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef); // We want it destroyed by the GC
|
|
g_DefoldCamera.m_VideoBufferLuaRef = 0;
|
|
}
|
|
|
|
lua_pushnumber(L, (lua_Number)message);
|
|
int ret = lua_pcall(L, 2, 0, 0);
|
|
if (ret != 0)
|
|
{
|
|
lua_pop(L, 1);
|
|
}
|
|
dmScript::TeardownCallback(g_DefoldCamera.m_Callback);
|
|
}
|
|
}
|
|
|
|
static void Camera_DestroyCallback()
|
|
{
|
|
if (g_DefoldCamera.m_Callback != 0)
|
|
{
|
|
dmScript::DestroyCallback(g_DefoldCamera.m_Callback);
|
|
g_DefoldCamera.m_Callback = 0;
|
|
}
|
|
}
|
|
|
|
static int StartCapture(lua_State* L)
|
|
{
|
|
DM_LUA_STACK_CHECK(L, 0);
|
|
|
|
CameraType type = (CameraType) luaL_checkint(L, 1);
|
|
CaptureQuality quality = (CaptureQuality)luaL_checkint(L, 2);
|
|
|
|
Camera_DestroyCallback();
|
|
g_DefoldCamera.m_Callback = dmScript::CreateCallback(L, 3);
|
|
|
|
CameraPlatform_StartCapture(&g_DefoldCamera.m_VideoBuffer, type, quality);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int StopCapture(lua_State* L)
|
|
{
|
|
DM_LUA_STACK_CHECK(L, 0);
|
|
|
|
CameraPlatform_StopCapture();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int GetInfo(lua_State* L)
|
|
{
|
|
DM_LUA_STACK_CHECK(L, 1);
|
|
|
|
CameraPlatform_GetCameraInfo(g_DefoldCamera.m_Params);
|
|
lua_newtable(L);
|
|
lua_pushstring(L, "width");
|
|
lua_pushnumber(L, g_DefoldCamera.m_Params.m_Width);
|
|
lua_rawset(L, -3);
|
|
lua_pushstring(L, "height");
|
|
lua_pushnumber(L, g_DefoldCamera.m_Params.m_Height);
|
|
lua_rawset(L, -3);
|
|
lua_pushstring(L, "bytes_per_pixel");
|
|
lua_pushnumber(L, 3);
|
|
lua_rawset(L, -3);
|
|
lua_pushstring(L, "type");
|
|
lua_pushinteger(L, g_DefoldCamera.m_Params.m_Type);
|
|
lua_rawset(L, -3);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int GetFrame(lua_State* L)
|
|
{
|
|
DM_LUA_STACK_CHECK(L, 1);
|
|
if (g_DefoldCamera.m_VideoBufferLuaRef != 0)
|
|
{
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef);
|
|
}
|
|
else
|
|
{
|
|
lua_pushnil(L);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static const luaL_reg Module_methods[] =
|
|
{
|
|
{"start_capture", StartCapture},
|
|
{"stop_capture", StopCapture},
|
|
{"get_frame", GetFrame},
|
|
{"get_info", GetInfo},
|
|
{0, 0}
|
|
};
|
|
|
|
static void LuaInit(lua_State* L)
|
|
{
|
|
int top = lua_gettop(L);
|
|
luaL_register(L, MODULE_NAME, Module_methods);
|
|
|
|
#define SETCONSTANT(name) \
|
|
lua_pushnumber(L, (lua_Number) name); \
|
|
lua_setfield(L, -2, #name);\
|
|
|
|
SETCONSTANT(CAMERA_TYPE_FRONT)
|
|
SETCONSTANT(CAMERA_TYPE_BACK)
|
|
|
|
SETCONSTANT(CAPTURE_QUALITY_LOW)
|
|
SETCONSTANT(CAPTURE_QUALITY_MEDIUM)
|
|
SETCONSTANT(CAPTURE_QUALITY_HIGH)
|
|
|
|
SETCONSTANT(CAMERA_STARTED)
|
|
SETCONSTANT(CAMERA_STOPPED)
|
|
SETCONSTANT(CAMERA_NOT_PERMITTED)
|
|
SETCONSTANT(CAMERA_ERROR)
|
|
|
|
#undef SETCONSTANT
|
|
|
|
lua_pop(L, 1);
|
|
assert(top == lua_gettop(L));
|
|
}
|
|
|
|
dmExtension::Result AppInitializeCamera(dmExtension::AppParams* params)
|
|
{
|
|
dmLogInfo("Registered %s Extension", MODULE_NAME);
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
dmExtension::Result InitializeCamera(dmExtension::Params* params)
|
|
{
|
|
LuaInit(params->m_L);
|
|
g_DefoldCamera.m_Mutex = dmMutex::New();
|
|
CameraPlatform_Initialize();
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
static dmExtension::Result UpdateCamera(dmExtension::Params* params)
|
|
{
|
|
CameraPlatform_UpdateCapture();
|
|
Camera_ProcessQueue();
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
dmExtension::Result AppFinalizeCamera(dmExtension::AppParams* params)
|
|
{
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
dmExtension::Result FinalizeCamera(dmExtension::Params* params)
|
|
{
|
|
dmMutex::Delete(g_DefoldCamera.m_Mutex);
|
|
Camera_DestroyCallback();
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
#else // unsupported platforms
|
|
|
|
|
|
static dmExtension::Result AppInitializeCamera(dmExtension::AppParams* params)
|
|
{
|
|
dmLogInfo("Registered %s (null) Extension", MODULE_NAME);
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
static dmExtension::Result InitializeCamera(dmExtension::Params* params)
|
|
{
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
static dmExtension::Result UpdateCamera(dmExtension::Params* params)
|
|
{
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
static dmExtension::Result AppFinalizeCamera(dmExtension::AppParams* params)
|
|
{
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
static dmExtension::Result FinalizeCamera(dmExtension::Params* params)
|
|
{
|
|
return dmExtension::RESULT_OK;
|
|
}
|
|
|
|
#endif // platforms
|
|
|
|
|
|
DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeCamera, AppFinalizeCamera, InitializeCamera, UpdateCamera, 0, FinalizeCamera)
|