diff --git a/src/camera/SDL_camera.c b/src/camera/SDL_camera.c index 10320613a..7a9172643 100644 --- a/src/camera/SDL_camera.c +++ b/src/camera/SDL_camera.c @@ -229,10 +229,15 @@ static void ZombieReleaseFrame(SDL_Camera *device, SDL_Surface *frame) // Reclai // we just leave zombie_pixels alone, as we'll reuse it for every new frame until the camera is closed. } + +static void ObtainPhysicalCameraObj(SDL_Camera *device); +static void ReleaseCamera(SDL_Camera *device); + + static void ClosePhysicalCamera(SDL_Camera *device) { - if (!device) { - return; + if (!device || (device->hidden == NULL)) { + return; // device is not open. } SDL_SetAtomicInt(&device->shutdown, 1); @@ -244,6 +249,8 @@ static void ClosePhysicalCamera(SDL_Camera *device) device->thread = NULL; } + ObtainPhysicalCameraObj(device); + // release frames that are queued up somewhere... if (!device->needs_conversion && !device->needs_scaling) { for (SurfaceList *i = device->filled_output_surfaces.next; i != NULL; i = i->next) { @@ -255,6 +262,7 @@ static void ClosePhysicalCamera(SDL_Camera *device) } camera_driver.impl.CloseDevice(device); + device->hidden = NULL; // just in case backend didn't reset this. SDL_DestroyProperties(device->props); @@ -280,13 +288,16 @@ static void ClosePhysicalCamera(SDL_Camera *device) device->adjust_timestamp = 0; SDL_zero(device->spec); + UnrefPhysicalCamera(device); // we're closed, release a reference. + + ReleaseCamera(device); } // Don't hold the device lock when calling this, as we may destroy the device! void UnrefPhysicalCamera(SDL_Camera *device) { if (SDL_AtomicDecRef(&device->refcount)) { - // take it out of the device list. + // take it out of the device list. This will call DestroyCameraHashItem to clean up the object. SDL_LockRWLockForWriting(camera_driver.device_hash_lock); if (SDL_RemoveFromHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id)) { SDL_AddAtomicInt(&camera_driver.device_count, -1); @@ -555,6 +566,8 @@ void SDL_CameraDisconnected(SDL_Camera *device) pending_tail->next = p; pending_tail = p; } + + UnrefPhysicalCamera(device); // camera is disconnected, drop its reference } ReleaseCamera(device); @@ -941,6 +954,8 @@ static int SDLCALL CameraThread(void *devicep) SDL_Log("CAMERA: dev[%p] Start thread 'CameraThread'", devicep); #endif + RefPhysicalCamera(device); // this thread holds a reference. + SDL_assert(device != NULL); SDL_CameraThreadSetup(device); @@ -952,6 +967,8 @@ static int SDLCALL CameraThread(void *devicep) SDL_CameraThreadShutdown(device); + UnrefPhysicalCamera(device); // this thread no longer holds a reference. + #if DEBUG_CAMERA SDL_Log("CAMERA: dev[%p] End thread 'CameraThread'", devicep); #endif @@ -1245,6 +1262,8 @@ SDL_Camera *SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec) } } + RefPhysicalCamera(device); // we're open, hold a reference. + ReleaseCamera(device); // unlock, we're good to go! return device; // currently there's no separation between physical and logical device. @@ -1443,6 +1462,11 @@ void SDL_QuitCamera(void) static void SDLCALL DestroyCameraHashItem(void *userdata, const void *key, const void *value) { SDL_Camera *device = (SDL_Camera *) value; + + #if DEBUG_CAMERA + SDL_Log("DESTROYING CAMERA '%s'", device->name); + #endif + ClosePhysicalCamera(device); camera_driver.impl.FreeDeviceHandle(device); SDL_DestroyMutex(device->lock);