From 7258633994a361a61b93995781e5d0c764dc653b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Mon, 13 Jul 2020 01:08:54 +0200 Subject: [PATCH 1/4] WIP --- Info.plist | 48 +++++++++++++++++ camera/src/camera.cpp | 101 ++++++++++++++++++++++++++++-------- camera/src/camera.mm | 63 ++++++++++++++++++---- camera/src/camera_private.h | 14 ++++- game.project | 1 + main/main.script | 55 +++++++++----------- 6 files changed, 220 insertions(+), 62 deletions(-) create mode 100644 Info.plist diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..685054c --- /dev/null +++ b/Info.plist @@ -0,0 +1,48 @@ + + + + + BuildMachineOSBuild + 11E53 + CFBundleDevelopmentRegion + {{osx.default_language}} + CFBundleDisplayName + {{project.title}} + CFBundleExecutable + {{exe-name}} + CFBundleIconFile + icon.icns + CFBundleIdentifier + {{osx.bundle_identifier}} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + unnamed + CFBundlePackageType + APPL + CFBundleShortVersionString + {{project.version}} + CFBundleSignature + ???? + CFBundleLocalizations + {{#application-localizations}} + {{.}}{{/application-localizations}} + + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.7 + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + NSCameraUsageDescription + App Needs to use camera to take Profile picture + NSPhotoLibraryAddUsageDescription + App Needs to store your photos + {{#display.high_dpi}} + NSHighResolutionCapable + + {{/display.high_dpi}} + + diff --git a/camera/src/camera.cpp b/camera/src/camera.cpp index a4945fd..bc6a948 100644 --- a/camera/src/camera.cpp +++ b/camera/src/camera.cpp @@ -26,26 +26,69 @@ struct DefoldCamera // Information about the currently set camera CameraInfo m_Params; + + dmArray m_MessageQueue; + dmScript::LuaCallbackInfo* m_Callback; + dmMutex::HMutex m_Mutex; }; DefoldCamera g_DefoldCamera; +void Camera_QueueMessage(CameraStatus status) +{ + 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(status); +} + +static void Camera_ProcessQueue() +{ + DM_MUTEX_SCOPED_LOCK(g_DefoldCamera.m_Mutex); + + for (uint32_t i = 0; i != g_DefoldCamera.m_MessageQueue.Size(); ++i) + { + lua_State* L = dmScript::GetCallbackLuaContext(g_DefoldCamera.m_Callback); + if (!dmScript::SetupCallback(g_DefoldCamera.m_Callback)) + { + break; + } + CameraStatus status = g_DefoldCamera.m_MessageQueue[i]; + lua_pushnumber(L, (lua_Number)status); + int ret = lua_pcall(L, 2, 0, 0); + if (ret != 0) + { + lua_pop(L, 1); + } + dmScript::TeardownCallback(g_DefoldCamera.m_Callback); + } + g_DefoldCamera.m_MessageQueue.SetSize(0); +} + +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, 1); + DM_LUA_STACK_CHECK(L, 0); CameraType type = (CameraType) luaL_checkint(L, 1); CaptureQuality quality = (CaptureQuality)luaL_checkint(L, 2); - int status = CameraPlatform_StartCapture(&g_DefoldCamera.m_VideoBuffer, type, quality, g_DefoldCamera.m_Params); + Camera_DestroyCallback(); + g_DefoldCamera.m_Callback = dmScript::CreateCallback(L, 3); - lua_pushboolean(L, status > 0); - if( status == 0 ) - { - dmLogError("capture failed!\n"); - return 1; - } + CameraPlatform_StartCapture(&g_DefoldCamera.m_VideoBuffer, type, quality, g_DefoldCamera.m_Params); // Increase ref count dmScript::LuaHBuffer luabuffer = {g_DefoldCamera.m_VideoBuffer, false}; @@ -59,14 +102,9 @@ static int StopCapture(lua_State* L) { DM_LUA_STACK_CHECK(L, 0); - int status = CameraPlatform_StopCapture(); - if( !status ) - { - return luaL_error(L, "Failed to stop capture. Was it started?"); - } + CameraPlatform_StopCapture(); dmScript::Unref(L, LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef); // We want it destroyed by the GC - return 0; } @@ -94,7 +132,7 @@ static int GetInfo(lua_State* L) static int GetFrame(lua_State* L) { DM_LUA_STACK_CHECK(L, 1); - lua_rawgeti(L,LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef); + lua_rawgeti(L,LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef); return 1; } @@ -113,9 +151,9 @@ 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);\ + #define SETCONSTANT(name) \ + lua_pushnumber(L, (lua_Number) name); \ + lua_setfield(L, -2, #name);\ SETCONSTANT(CAMERA_TYPE_FRONT) SETCONSTANT(CAMERA_TYPE_BACK) @@ -124,7 +162,12 @@ static void LuaInit(lua_State* L) SETCONSTANT(CAPTURE_QUALITY_MEDIUM) SETCONSTANT(CAPTURE_QUALITY_HIGH) -#undef SETCONSTANT + SETCONSTANT(STATUS_STARTED) + SETCONSTANT(STATUS_STOPPED) + SETCONSTANT(STATUS_NOT_PERMITTED) + SETCONSTANT(STATUS_ERROR) + + #undef SETCONSTANT lua_pop(L, 1); assert(top == lua_gettop(L)); @@ -132,12 +175,20 @@ static void LuaInit(lua_State* 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(); + return dmExtension::RESULT_OK; +} + +static dmExtension::Result UpdateCamera(dmExtension::Params* params) +{ + Camera_ProcessQueue(); return dmExtension::RESULT_OK; } @@ -148,6 +199,8 @@ dmExtension::Result AppFinalizeCamera(dmExtension::AppParams* params) dmExtension::Result FinalizeCamera(dmExtension::Params* params) { + dmMutex::Delete(g_DefoldCamera.m_Mutex); + Camera_DestroyCallback(); return dmExtension::RESULT_OK; } @@ -156,7 +209,7 @@ dmExtension::Result FinalizeCamera(dmExtension::Params* params) static dmExtension::Result AppInitializeCamera(dmExtension::AppParams* params) { - dmLogInfo("Registered %s (null) Extension\n", MODULE_NAME); + dmLogInfo("Registered %s (null) Extension", MODULE_NAME); return dmExtension::RESULT_OK; } @@ -165,6 +218,12 @@ static dmExtension::Result InitializeCamera(dmExtension::Params* params) return dmExtension::RESULT_OK; } +static dmExtension::Result UpdateCamera(dmExtension::Params* params) +{ + Camera_ProcessQueue() + return dmExtension::RESULT_OK; +} + static dmExtension::Result AppFinalizeCamera(dmExtension::AppParams* params) { return dmExtension::RESULT_OK; @@ -178,4 +237,4 @@ static dmExtension::Result FinalizeCamera(dmExtension::Params* params) #endif // platforms -DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeCamera, AppFinalizeCamera, InitializeCamera, 0, 0, FinalizeCamera) +DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeCamera, AppFinalizeCamera, InitializeCamera, UpdateCamera, 0, FinalizeCamera) diff --git a/camera/src/camera.mm b/camera/src/camera.mm index 9c466ae..866c2ed 100644 --- a/camera/src/camera.mm +++ b/camera/src/camera.mm @@ -121,11 +121,10 @@ IOSCamera g_Camera; } } -- (void)captureOutput:(AVCaptureOutput *)captureOutput - didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer +- (void)captureOutput:(AVCaptureOutput *)captureOutput + didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { - //NSLog(@"DROPPING FRAME!!!"); } @@ -256,7 +255,7 @@ IOSCamera g_Camera; static CMVideoDimensions FlipCoords(AVCaptureVideoDataOutput* output, const CMVideoDimensions& in) { - CMVideoDimensions out = in; + CMVideoDimensions out = in; #if defined(DM_PLATFORM_IOS) AVCaptureConnection* conn = [output connectionWithMediaType:AVMediaTypeVideo]; switch (conn.videoOrientation) { @@ -274,7 +273,7 @@ static CMVideoDimensions FlipCoords(AVCaptureVideoDataOutput* output, const CMVi - ( BOOL ) startCamera: (AVCaptureDevicePosition) cameraPosition - quality: (CaptureQuality)quality + quality: (CaptureQuality)quality { // 1. Find the back camera if ( ![ self findCamera: cameraPosition ] ) @@ -352,7 +351,7 @@ static CMVideoDimensions FlipCoords(AVCaptureVideoDataOutput* output, const CMVi @end -int CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality, CameraInfo& outparams) +void CameraPlatform_StartCaptureAuthorized(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality, CameraInfo& outparams) { if(g_Camera.m_Delegate == 0) { @@ -381,10 +380,57 @@ int CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, Capt g_Camera.m_VideoBuffer = *buffer; - return started ? 1 : 0; + if (started) + { + Camera_QueueMessage(STATUS_STARTED); + } + else + { + Camera_QueueMessage(STATUS_ERROR); + } } -int CameraPlatform_StopCapture() +void CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality, CameraInfo& outparams) +{ + // Request permission to access the camera. + int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + if (status == AVAuthorizationStatusAuthorized) + { + // The user has previously granted access to the camera. + dmLogInfo("AVAuthorizationStatusAuthorized"); + CameraPlatform_StartCaptureAuthorized(buffer, type, quality, outparams); + } + else if (status == AVAuthorizationStatusNotDetermined) + { + dmLogInfo("AVAuthorizationStatusNotDetermined"); + // The app hasn't yet asked the user for camera access. + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { + if (granted) { + dmLogInfo("AVAuthorizationStatusNotDetermined - granted!"); + CameraPlatform_StartCaptureAuthorized(buffer, type, quality, outparams); + } + else + { + dmLogInfo("AVAuthorizationStatusNotDetermined - not granted!"); + Camera_QueueMessage(STATUS_NOT_PERMITTED); + } + }]; + } + else if (status == AVAuthorizationStatusDenied) + { + // The user has previously denied access. + dmLogInfo("AVAuthorizationStatusDenied"); + Camera_QueueMessage(STATUS_NOT_PERMITTED); + } + else if (status == AVAuthorizationStatusRestricted) + { + // The user can't grant access due to restrictions. + dmLogInfo("AVAuthorizationStatusRestricted"); + Camera_QueueMessage(STATUS_NOT_PERMITTED); + } +} + +void CameraPlatform_StopCapture() { if(g_Camera.m_Delegate != 0) { @@ -395,7 +441,6 @@ int CameraPlatform_StopCapture() dmBuffer::Destroy(g_Camera.m_VideoBuffer); g_Camera.m_VideoBuffer = 0; } - return 1; } #endif // DM_PLATFORM_IOS/DM_PLATFORM_OSX diff --git a/camera/src/camera_private.h b/camera/src/camera_private.h index f0f6131..206a178 100644 --- a/camera/src/camera_private.h +++ b/camera/src/camera_private.h @@ -22,5 +22,15 @@ struct CameraInfo CameraType m_Type; }; -extern int CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality, CameraInfo& outparams); -extern int CameraPlatform_StopCapture(); +enum CameraStatus +{ + STATUS_STARTED, + STATUS_STOPPED, + STATUS_NOT_PERMITTED, + STATUS_ERROR +}; + +extern void CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality, CameraInfo& outparams); +extern void CameraPlatform_StopCapture(); + +void Camera_QueueMessage(CameraStatus message); diff --git a/game.project b/game.project index 421ce8a..db43bea 100644 --- a/game.project +++ b/game.project @@ -26,6 +26,7 @@ package = com.defold.camera [osx] bundle_identifier = com.defold.camera +infoplist = /Info.plist [library] include_dirs = camera diff --git a/main/main.script b/main/main.script index 6bbd636..b1bd207 100644 --- a/main/main.script +++ b/main/main.script @@ -6,44 +6,40 @@ local function stop_capture(self) self.cameraframe = nil camera.stop_capture() - + label.set_text("logo#status", "Capture Status: OFF") end local function start_capture(self) - if self.cameraframe ~= nil then + if not camera then + label.set_text("logo#status", "Capture Status: UNAVAILABLE") return end - - if camera ~= nil then - local sysinfo = sys.get_sys_info() - - local quality = camera.CAPTURE_QUALITY_HIGH - local type = camera.CAMERA_TYPE_FRONT - if sysinfo.system_name == 'iPhone OS' then - type = camera.CAMERA_TYPE_BACK - quality = camera.CAPTURE_QUALITY_MEDIUM - end - - if camera.start_capture(type, quality) then + local sysinfo = sys.get_sys_info() + + local quality = camera.CAPTURE_QUALITY_HIGH + local type = camera.CAMERA_TYPE_FRONT + if sysinfo.system_name == 'iPhone OS' then + type = camera.CAMERA_TYPE_BACK + quality = camera.CAPTURE_QUALITY_MEDIUM + end + + camera.start_capture(type, quality, function(self, status) + if status == camera.STATUS_STARTED then self.cameraframe = camera.get_frame() self.camerainfo = camera.get_info() - print("Initialized camera") - pprint(self.camerainfo) - self.cameratextureheader = {width=self.camerainfo.width, - height=self.camerainfo.height, - type=resource.TEXTURE_TYPE_2D, - format=resource.TEXTURE_FORMAT_RGB, - num_mip_maps=1 } + height=self.camerainfo.height, + type=resource.TEXTURE_TYPE_2D, + format=resource.TEXTURE_FORMAT_RGB, + num_mip_maps=1 } + else + label.set_text("logo#status", "Capture Status: ERROR") end - label.set_text("logo#status", "Capture Status: ON") - else - print("could not start camera capture") - label.set_text("logo#status", "Capture Status: UNAVAILABLE") - end + end) + label.set_text("logo#status", "Capture Status: ON") end function init(self) @@ -54,7 +50,7 @@ function init(self) local screen_height = sys.get_config("display.height", 800) local scale_width = screen_width / logosize local scale_height = screen_height / logosize - + go.set("#sprite", "scale", vmath.vector3(scale_width, scale_height, 1) ) @@ -73,16 +69,15 @@ function update(self, dt) local pathmodelcamera = go.get("#sprite", "texture0") resource.set_texture(pathmodelcamera, self.cameratextureheader, self.cameraframe) end - end function on_input(self, action_id, action) - if (action_id == hash("space") or action_id == hash("touch")) and action.pressed then + --[[if (action_id == hash("space") or action_id == hash("touch")) and action.pressed then if self.cameraframe == nil then start_capture(self) else stop_capture(self) end - end + end--]] end From d5cb318c7de64625dc55d2e5df38f0f6769f656c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Mon, 13 Jul 2020 08:46:26 +0200 Subject: [PATCH 2/4] Only check permission on newer iOS and macOS versions --- LICENSE.md | 2 +- README.md | 94 ++++++++++++++++++++++++++++++-------------- camera/src/camera.mm | 74 ++++++++++++++++++---------------- main/main.script | 6 +-- 4 files changed, 109 insertions(+), 67 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 3e328f1..c03d905 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Defold +Copyright (c) 2019 Defold Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index a496490..3d5c9d5 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,101 @@ # extension-camera -Example of interacting with the camera through native extensions. +Native extension to use device camera to capture frames. -# Disclaimer -Although we aim to provide good example functionality in this example, we cannot guarantee the quality/stability at all times. -Please regard it as just that, an example, and don't rely on this as a dependency for your production code. +# Installation -# Known issues +To use the camera extension in a Defold project this project has to be added as a [Defold library dependency](http://www.defold.com/manuals/libraries/). Open the **game.project** file and in the [Dependencies field in the Project section](https://defold.com/manuals/project-settings/#dependencies) add: + +https://github.com/defold/extension-camera/archive/master.zip + +Or point to the ZIP file of [a specific release](https://github.com/defold/extension-camera/releases). + + +# Supported platforms The currently supported platforms are: OSX + iOS # FAQ -## How do I use this extension? +## How do I reset macOS camera permission? -Add the package link (https://github.com/defold/extension-camera/archive/master.zip) -to the project setting `project.dependencies`, and you should be good to go. +To test macOS camera permission popup multiple times you can reset the permission from the terminal: -See the [manual](http://www.defold.com/manuals/libraries/) for further info. +```bash +tccutil reset Camera +``` # Lua API ## Type constants -Describes what camera should be used +Describes what camera should be used. + +```lua +camera.CAMERA_TYPE_FRONT -- Selfie +camera.CAMERA_TYPE_BACK +``` - camera.CAMERA_TYPE_FRONT -- Selfie - camera.CAMERA_TYPE_BACK ## Quality constants - camera.CAPTURE_QUALITY_HIGH - camera.CAPTURE_QUALITY_MEDIUM - camera.CAPTURE_QUALITY_LOW +```lua +camera.CAPTURE_QUALITY_HIGH +camera.CAPTURE_QUALITY_MEDIUM +camera.CAPTURE_QUALITY_LOW +``` -## camera.start_capture(type, quality) -Returns true if the capture starts well +## Status constants - if camera.start_capture(camera.CAMERA_TYPE_BACK, camera.CAPTURE_QUALITY_HIGH) then +```lua +camera.STATUS_STARTED +camera.STATUS_STOPPED +camera.STATUS_NOT_PERMITTED +camera.STATUS_ERROR +``` + + +## camera.start_capture(type, quality, callback) + +Start camera capture using the specified camera (front/back) and capture quality. This may trigger a camera usage permission popup. When the popup has been dismissed the callback will be invoked with camera start status. + +```lua +camera.start_capture(camera.CAMERA_TYPE_BACK, camera.CAPTURE_QUALITY_HIGH, function(self, status) + if status == camera.STATUS_STARTED then -- do stuff end - +end) +``` + + ## camera.stop_capture() -Stops a previously started capture session +Stops a previously started capture session. + +```lua +camera.stop_capture() +``` + ## camera.get_info() -Gets the info from the current capture session +Gets the info from the current capture session. + +```lua +local info = camera.get_info() +print("width", info.width) +print("height", info.height) +``` + - local info = camera.get_info() - print("width", info.width) - print("height", info.height) - ## camera.get_frame() -Retrieves the camera pixel buffer -This buffer has one stream named "rgb", and is of type buffer.VALUE_TYPE_UINT8 and has the value count of 1 +Retrieves the camera pixel buffer. This buffer has one stream named "rgb", and is of type `buffer.VALUE_TYPE_UINT8` and has the value count of 1. - self.cameraframe = camera.get_frame() - - +```lua +self.cameraframe = camera.get_frame() +``` diff --git a/camera/src/camera.mm b/camera/src/camera.mm index 866c2ed..dfc4065 100644 --- a/camera/src/camera.mm +++ b/camera/src/camera.mm @@ -392,42 +392,50 @@ void CameraPlatform_StartCaptureAuthorized(dmBuffer::HBuffer* buffer, CameraType void CameraPlatform_StartCapture(dmBuffer::HBuffer* buffer, CameraType type, CaptureQuality quality, CameraInfo& outparams) { - // Request permission to access the camera. - int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; - if (status == AVAuthorizationStatusAuthorized) + // Only check for permission on iOS 7+ and macOS 10.14+ + if ([AVCaptureDevice respondsToSelector:@selector(authorizationStatusForMediaType:)]) + { + // Request permission to access the camera. + int status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + if (status == AVAuthorizationStatusAuthorized) + { + // The user has previously granted access to the camera. + dmLogInfo("AVAuthorizationStatusAuthorized"); + CameraPlatform_StartCaptureAuthorized(buffer, type, quality, outparams); + } + else if (status == AVAuthorizationStatusNotDetermined) + { + dmLogInfo("AVAuthorizationStatusNotDetermined"); + // The app hasn't yet asked the user for camera access. + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { + if (granted) { + dmLogInfo("AVAuthorizationStatusNotDetermined - granted!"); + CameraPlatform_StartCaptureAuthorized(buffer, type, quality, outparams); + } + else + { + dmLogInfo("AVAuthorizationStatusNotDetermined - not granted!"); + Camera_QueueMessage(STATUS_NOT_PERMITTED); + } + }]; + } + else if (status == AVAuthorizationStatusDenied) + { + // The user has previously denied access. + dmLogInfo("AVAuthorizationStatusDenied"); + Camera_QueueMessage(STATUS_NOT_PERMITTED); + } + else if (status == AVAuthorizationStatusRestricted) + { + // The user can't grant access due to restrictions. + dmLogInfo("AVAuthorizationStatusRestricted"); + Camera_QueueMessage(STATUS_NOT_PERMITTED); + } + } + else { - // The user has previously granted access to the camera. - dmLogInfo("AVAuthorizationStatusAuthorized"); CameraPlatform_StartCaptureAuthorized(buffer, type, quality, outparams); } - else if (status == AVAuthorizationStatusNotDetermined) - { - dmLogInfo("AVAuthorizationStatusNotDetermined"); - // The app hasn't yet asked the user for camera access. - [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { - if (granted) { - dmLogInfo("AVAuthorizationStatusNotDetermined - granted!"); - CameraPlatform_StartCaptureAuthorized(buffer, type, quality, outparams); - } - else - { - dmLogInfo("AVAuthorizationStatusNotDetermined - not granted!"); - Camera_QueueMessage(STATUS_NOT_PERMITTED); - } - }]; - } - else if (status == AVAuthorizationStatusDenied) - { - // The user has previously denied access. - dmLogInfo("AVAuthorizationStatusDenied"); - Camera_QueueMessage(STATUS_NOT_PERMITTED); - } - else if (status == AVAuthorizationStatusRestricted) - { - // The user can't grant access due to restrictions. - dmLogInfo("AVAuthorizationStatusRestricted"); - Camera_QueueMessage(STATUS_NOT_PERMITTED); - } } void CameraPlatform_StopCapture() diff --git a/main/main.script b/main/main.script index b1bd207..40d2ed1 100644 --- a/main/main.script +++ b/main/main.script @@ -35,11 +35,11 @@ local function start_capture(self) type=resource.TEXTURE_TYPE_2D, format=resource.TEXTURE_FORMAT_RGB, num_mip_maps=1 } + label.set_text("logo#status", "Capture Status: ON") else label.set_text("logo#status", "Capture Status: ERROR") end end) - label.set_text("logo#status", "Capture Status: ON") end function init(self) @@ -73,11 +73,11 @@ end function on_input(self, action_id, action) - --[[if (action_id == hash("space") or action_id == hash("touch")) and action.pressed then + if (action_id == hash("space") or action_id == hash("touch")) and action.pressed then if self.cameraframe == nil then start_capture(self) else stop_capture(self) end - end--]] + end end From 72ecd460d6c787f5a1c968cb7369117844c45119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Tue, 14 Jul 2020 14:53:42 +0200 Subject: [PATCH 3/4] Additional state handling cleanup --- Info.plist | 4 +--- camera/src/camera.cpp | 30 ++++++++++++++++++++++-------- main/main.script | 28 ++++++++++++++-------------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/Info.plist b/Info.plist index 685054c..c5ac1ab 100644 --- a/Info.plist +++ b/Info.plist @@ -37,9 +37,7 @@ NSPrincipalClass NSApplication NSCameraUsageDescription - App Needs to use camera to take Profile picture - NSPhotoLibraryAddUsageDescription - App Needs to store your photos + {{project.title}} needs to use the camera {{#display.high_dpi}} NSHighResolutionCapable diff --git a/camera/src/camera.cpp b/camera/src/camera.cpp index bc6a948..bd1c3b2 100644 --- a/camera/src/camera.cpp +++ b/camera/src/camera.cpp @@ -34,7 +34,6 @@ struct DefoldCamera DefoldCamera g_DefoldCamera; - void Camera_QueueMessage(CameraStatus status) { DM_MUTEX_SCOPED_LOCK(g_DefoldCamera.m_Mutex); @@ -58,6 +57,20 @@ static void Camera_ProcessQueue() break; } CameraStatus status = g_DefoldCamera.m_MessageQueue[i]; + + if (status == STATUS_STARTED) + { + // Increase ref count + dmScript::LuaHBuffer luabuffer = {g_DefoldCamera.m_VideoBuffer, false}; + dmScript::PushBuffer(L, luabuffer); + g_DefoldCamera.m_VideoBufferLuaRef = dmScript::Ref(L, LUA_REGISTRYINDEX); + } + else if (status == STATUS_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)status); int ret = lua_pcall(L, 2, 0, 0); if (ret != 0) @@ -90,11 +103,6 @@ static int StartCapture(lua_State* L) CameraPlatform_StartCapture(&g_DefoldCamera.m_VideoBuffer, type, quality, g_DefoldCamera.m_Params); - // Increase ref count - dmScript::LuaHBuffer luabuffer = {g_DefoldCamera.m_VideoBuffer, false}; - dmScript::PushBuffer(L, luabuffer); - g_DefoldCamera.m_VideoBufferLuaRef = dmScript::Ref(L, LUA_REGISTRYINDEX); - return 1; } @@ -104,7 +112,6 @@ static int StopCapture(lua_State* L) CameraPlatform_StopCapture(); - dmScript::Unref(L, LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef); // We want it destroyed by the GC return 0; } @@ -132,7 +139,14 @@ static int GetInfo(lua_State* L) static int GetFrame(lua_State* L) { DM_LUA_STACK_CHECK(L, 1); - lua_rawgeti(L,LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef); + if (g_DefoldCamera.m_VideoBufferLuaRef != 0) + { + lua_rawgeti(L, LUA_REGISTRYINDEX, g_DefoldCamera.m_VideoBufferLuaRef); + } + else + { + lua_pushnil(L); + } return 1; } diff --git a/main/main.script b/main/main.script index 40d2ed1..51dad22 100644 --- a/main/main.script +++ b/main/main.script @@ -17,11 +17,10 @@ local function start_capture(self) return end - local sysinfo = sys.get_sys_info() - local quality = camera.CAPTURE_QUALITY_HIGH + local type = camera.CAMERA_TYPE_FRONT - if sysinfo.system_name == 'iPhone OS' then + if sys.get_sys_info().system_name == 'iPhone OS' then type = camera.CAMERA_TYPE_BACK quality = camera.CAPTURE_QUALITY_MEDIUM end @@ -30,11 +29,13 @@ local function start_capture(self) if status == camera.STATUS_STARTED then self.cameraframe = camera.get_frame() self.camerainfo = camera.get_info() - self.cameratextureheader = {width=self.camerainfo.width, - height=self.camerainfo.height, - type=resource.TEXTURE_TYPE_2D, - format=resource.TEXTURE_FORMAT_RGB, - num_mip_maps=1 } + self.cameratextureheader = { + width=self.camerainfo.width, + height=self.camerainfo.height, + type=resource.TEXTURE_TYPE_2D, + format=resource.TEXTURE_FORMAT_RGB, + num_mip_maps=1 + } label.set_text("logo#status", "Capture Status: ON") else label.set_text("logo#status", "Capture Status: ERROR") @@ -53,19 +54,18 @@ function init(self) go.set("#sprite", "scale", vmath.vector3(scale_width, scale_height, 1) ) - start_capture(self) end function final(self) - if self.cameraframe ~= nil then + if self.cameraframe then camera.stop_capture() end end function update(self, dt) - if self.cameraframe ~= nil then + if self.cameraframe then local pathmodelcamera = go.get("#sprite", "texture0") resource.set_texture(pathmodelcamera, self.cameratextureheader, self.cameraframe) end @@ -74,10 +74,10 @@ end function on_input(self, action_id, action) if (action_id == hash("space") or action_id == hash("touch")) and action.pressed then - if self.cameraframe == nil then - start_capture(self) - else + if self.cameraframe then stop_capture(self) + else + start_capture(self) end end end From 76a1c7b4f6fa64f1a4c1bda8e27b9afc728ab379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Tue, 14 Jul 2020 15:30:16 +0200 Subject: [PATCH 4/4] Back to manifest merge --- Info.plist | 46 --------------------------------- camera/manifests/osx/Info.plist | 8 ++++++ game.project | 2 -- 3 files changed, 8 insertions(+), 48 deletions(-) delete mode 100644 Info.plist create mode 100644 camera/manifests/osx/Info.plist diff --git a/Info.plist b/Info.plist deleted file mode 100644 index c5ac1ab..0000000 --- a/Info.plist +++ /dev/null @@ -1,46 +0,0 @@ - - - - - BuildMachineOSBuild - 11E53 - CFBundleDevelopmentRegion - {{osx.default_language}} - CFBundleDisplayName - {{project.title}} - CFBundleExecutable - {{exe-name}} - CFBundleIconFile - icon.icns - CFBundleIdentifier - {{osx.bundle_identifier}} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - unnamed - CFBundlePackageType - APPL - CFBundleShortVersionString - {{project.version}} - CFBundleSignature - ???? - CFBundleLocalizations - {{#application-localizations}} - {{.}}{{/application-localizations}} - - CFBundleVersion - 1 - LSMinimumSystemVersion - 10.7 - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - NSCameraUsageDescription - {{project.title}} needs to use the camera - {{#display.high_dpi}} - NSHighResolutionCapable - - {{/display.high_dpi}} - - diff --git a/camera/manifests/osx/Info.plist b/camera/manifests/osx/Info.plist new file mode 100644 index 0000000..4c0af91 --- /dev/null +++ b/camera/manifests/osx/Info.plist @@ -0,0 +1,8 @@ + + + + + NSCameraUsageDescription + {{project.title}} would like to access the camera. + + diff --git a/game.project b/game.project index db43bea..5d6119e 100644 --- a/game.project +++ b/game.project @@ -26,8 +26,6 @@ package = com.defold.camera [osx] bundle_identifier = com.defold.camera -infoplist = /Info.plist [library] include_dirs = camera -