Skip to content

Commit

Permalink
Improve camera flash
Browse files Browse the repository at this point in the history
Improves the usage of the camera flash to make it more reliably
be on when it is supposed to be.

Addresses issue #87
  • Loading branch information
cobryan05 committed Jun 1, 2024
1 parent 6e433b4 commit 1e3b94d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 14 deletions.
56 changes: 44 additions & 12 deletions app/app/src/main/java/com/octo4a/camera/CameraService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import kotlin.coroutines.suspendCoroutine
class CameraService : LifecycleService(), MJpegFrameProvider {
private var latestFrame: ByteArray = ByteArray(0)
private var listenerCount = 0
private var flashRefCnt: Int = 0

private val cameraSettings: MainPreferences by inject()
private val logger: LoggerRepository by inject()
Expand Down Expand Up @@ -108,10 +109,16 @@ class CameraService : LifecycleService(), MJpegFrameProvider {
if (!cameraInitialized) {
it.resume(ByteArray(0))
} else {
if (cameraSettings.flashWhenObserved) {
addFlashObserver()
}
imageCapture.takePicture(
captureExecutor,
object : ImageCapture.OnImageCapturedCallback() {
override fun onCaptureSuccess(image: ImageProxy) {
if (cameraSettings.flashWhenObserved) {
removeFlashObserver()
}
val buffer = image.planes[0].buffer
val bytes = ByteArray(buffer.capacity()).also { array -> buffer.get(array) }
val matrix = Matrix().apply { postRotate(rotation.toFloat()) }
Expand All @@ -135,6 +142,9 @@ class CameraService : LifecycleService(), MJpegFrameProvider {
}

override fun onError(exception: ImageCaptureException) {
if (cameraSettings.flashWhenObserved) {
removeFlashObserver()
}
super.onError(exception)
logger.log(this) { "Single capture error: $exception" }
it.resume(ByteArray(0))
Expand All @@ -148,11 +158,8 @@ class CameraService : LifecycleService(), MJpegFrameProvider {
listenerCount++
}
logger.log(this) { "Camera server register listener" }

val turnFlashOn = cameraSettings.flashWhenObserved

if (listenerCount > 0 && turnFlashOn && cameraInitialized) {
currentCamera?.cameraControl?.enableTorch(true)
if (cameraSettings.flashWhenObserved) {
addFlashObserver()
}
}

Expand All @@ -161,16 +168,35 @@ class CameraService : LifecycleService(), MJpegFrameProvider {
listenerCount--
}
logger.log(this) { "Camera server unregister listener" }

if (listenerCount < 1 && cameraInitialized) {
currentCamera?.cameraControl?.enableTorch(false)
if (cameraSettings.flashWhenObserved) {
removeFlashObserver()
}
}

private val mjpegServer by lazy { MJpegServer(5001, this) }

private val callbackExecutorPool = Executors.newCachedThreadPool()

private fun addFlashObserver() {
synchronized(flashRefCnt) {
flashRefCnt++
if (cameraInitialized) {
currentCamera?.cameraControl?.enableTorch(true)
}
}
}

private fun removeFlashObserver() {
synchronized(flashRefCnt) {
if(flashRefCnt > 0) {
flashRefCnt--
}
if(cameraInitialized && flashRefCnt == 0) {
currentCamera?.cameraControl?.enableTorch(false)
}
}
}

override fun onBind(intent: Intent): IBinder {
super.onBind(intent)
return binder
Expand All @@ -184,9 +210,15 @@ class CameraService : LifecycleService(), MJpegFrameProvider {
octoprintHandler.isCameraServerRunning = false
}

fun stopPreview() {
// Doesn't actually unbind the camera
if(cameraSettings.flashWhenObserved) {
removeFlashObserver()
}
}

fun getPreview(): Preview {
cameraInitialized = false
val turnFlashOn = cameraSettings.flashWhenObserved

cameraProcessProvider?.unbindAll()
val camera = cameraProcessProvider?.bindToLifecycle(
Expand All @@ -197,10 +229,10 @@ class CameraService : LifecycleService(), MJpegFrameProvider {
cameraPreview
)

if (turnFlashOn) {
camera?.cameraControl?.enableTorch(true)
}
cameraInitialized = true
if(cameraSettings.flashWhenObserved) {
addFlashObserver()
}
return cameraPreview
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,14 @@ class ServerFragment : Fragment() {
.setTitle(R.string.camera_preview)
.setView(R.layout.dialog_camera_preview)
.setPositiveButton(R.string.action_ok) {dialog, _ -> dialog.dismiss() }
.setOnDismissListener {
if (boundToCameraService) {
cameraService.stopPreview()
}
}
.show()

dialog.findViewById<PreviewView>(R.id.previewView)?.apply {


if (boundToCameraService) {
cameraService.getPreview().setSurfaceProvider(surfaceProvider)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
private val selectedCameraResolution by lazy { findPreference<ListPreference>("selectedResolution") }
private val sshPasswordPref by lazy { findPreference<EditTextPreference>("changeSSHPassword") }
private val fpsLimit by lazy { findPreference<ListPreference>("fpsLimit") }
private val flashWhenObserved by lazy { findPreference<SwitchPreferenceCompat>("flashWhenObserved") }
private val installPluginExtras by lazy { findPreference<Preference>("installPluginExtras") }
private val imageRotation by lazy { findPreference<ListPreference>("imageRotation") }
private val disableAF by lazy { findPreference<SwitchPreferenceCompat>("disableAF") }
Expand Down Expand Up @@ -183,6 +184,12 @@ class SettingsFragment : PreferenceFragmentCompat() {
true
}

flashWhenObserved?.setOnPreferenceChangeListener { _, value ->
stopCameraServer()
startCameraServer()
true
}

enableCameraPref?.setOnPreferenceChangeListener { _, newValue ->
if (cameras.isEmpty()) {
enableCameraPref.isChecked = false
Expand Down

0 comments on commit 1e3b94d

Please sign in to comment.