@@ -26,6 +26,7 @@ import android.hardware.camera2.params.MeteringRectangle
26
26
import android.os.Build
27
27
import android.util.Range
28
28
import android.util.Rational
29
+ import androidx.annotation.RequiresApi
29
30
import io.github.thibaultbee.streampack.internal.sources.camera.CameraController
30
31
import io.github.thibaultbee.streampack.internal.utils.*
31
32
import io.github.thibaultbee.streampack.internal.utils.extensions.clamp
@@ -68,7 +69,7 @@ class CameraSettings(context: Context, cameraController: CameraController) {
68
69
/* *
69
70
* Current camera zoom API.
70
71
*/
71
- val zoom = Zoom (context, cameraController)
72
+ val zoom = Zoom .build (context, cameraController)
72
73
73
74
/* *
74
75
* Current focus API.
@@ -339,104 +340,151 @@ class Exposure(private val context: Context, private val cameraController: Camer
339
340
}
340
341
}
341
342
343
+ sealed class Zoom (
344
+ protected val context : Context ,
345
+ protected val cameraController : CameraController
346
+ ) {
347
+ abstract val availableRatioRange: Range <Float >
348
+ internal abstract val cropSensorRegion: Rect
342
349
343
- class Zoom (private val context : Context , private val cameraController : CameraController ) {
344
- // Keep the zoomRation for Android version < R
345
- private var persistentZoomRatio = 1f
350
+ abstract var zoomRatio: Float
346
351
347
352
/* *
348
- * Get current camera zoom ratio range.
349
- *
350
- * @return zoom ratio range.
353
+ * Sets the zoom on pinch scale gesture.
351
354
*
352
- * @see [zoomRatio]
355
+ * @param scale the scale factor
353
356
*/
354
- val availableRatioRange: Range <Float >
355
- get() = cameraController.cameraId?.let { context.getZoomRatioRange(it) }
356
- ? : DEFAULT_ZOOM_RATIO_RANGE
357
+ fun onPinch (scale : Float ) {
358
+ val scaledRatio: Float = zoomRatio * speedUpZoomByX(scale, 2 )
359
+ // Clamp the ratio with the zoom range.
360
+ zoomRatio = scaledRatio.clamp(availableRatioRange.lower, availableRatioRange.upper)
361
+ }
357
362
358
- /* *
359
- * Set or get the current zoom ratio.
360
- *
361
- * @see [availableRatioRange]
362
- */
363
- var zoomRatio: Float
364
- /* *
365
- * Get the zoom ratio.
366
- *
367
- * @return the current zoom ratio
368
- */
369
- get() = if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
370
- cameraController.getSetting(CaptureRequest .CONTROL_ZOOM_RATIO ) ? : DEFAULT_ZOOM_RATIO
363
+ private fun speedUpZoomByX (scaleFactor : Float , ratio : Int ): Float {
364
+ return if (scaleFactor > 1f ) {
365
+ 1.0f + (scaleFactor - 1.0f ) * ratio
371
366
} else {
372
- synchronized(this ) {
373
- persistentZoomRatio
374
- }
367
+ 1.0f - (1.0f - scaleFactor) * ratio
375
368
}
376
- /* *
377
- * Set the zoom ratio.
378
- *
379
- * @param value zoom ratio
380
- */
381
- set(value) {
382
- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
383
- cameraController.setRepeatingSetting(
384
- CaptureRequest .CONTROL_ZOOM_RATIO ,
385
- value.clamp(availableRatioRange)
369
+ }
370
+
371
+ class CropScalerRegionZoom (context : Context , cameraController : CameraController ) :
372
+ Zoom (context, cameraController) {
373
+ // Keep the zoomRatio
374
+ private var persistentZoomRatio = 1f
375
+ private var currentCropRect: Rect ? = null
376
+
377
+ override val availableRatioRange: Range <Float >
378
+ get() = cameraController.cameraId?.let {
379
+ Range (
380
+ DEFAULT_ZOOM_RATIO ,
381
+ context.getScalerMaxZoom(it)
386
382
)
387
- } else {
383
+ }
384
+ ? : DEFAULT_ZOOM_RATIO_RANGE
385
+
386
+ override var zoomRatio: Float
387
+ get() = synchronized(this ) {
388
+ persistentZoomRatio
389
+ }
390
+ set(value) {
388
391
synchronized(this ) {
389
392
val clampedValue = value.clamp(availableRatioRange)
390
393
cameraController.cameraId?.let { cameraId ->
394
+ currentCropRect = getCropRegion(
395
+ context.getCameraCharacteristics(cameraId),
396
+ clampedValue
397
+ )
391
398
cameraController.setRepeatingSetting(
392
399
CaptureRequest .SCALER_CROP_REGION ,
393
- getCropRegion(
394
- context.getCameraCharacteristics(cameraId),
395
- clampedValue
396
- )
400
+ currentCropRect
397
401
)
398
402
}
399
403
persistentZoomRatio = clampedValue
400
404
}
401
405
}
402
- }
403
406
404
- /* *
405
- * Sets the zoom on pinch scale gesture.
406
- *
407
- * @param scale the scale factor
408
- */
409
- fun onPinch (scale : Float ) {
410
- val scaledRatio: Float = zoomRatio * speedUpZoomByX(scale, 2 )
411
- // Clamp the ratio with the zoom range.
412
- zoomRatio = scaledRatio.clamp(availableRatioRange.lower, availableRatioRange.upper)
413
- }
407
+ override val cropSensorRegion: Rect
408
+ get() {
409
+ synchronized(this ) {
410
+ return if (currentCropRect != null ) {
411
+ currentCropRect!!
412
+ } else {
413
+ val cameraId = cameraController.cameraId
414
+ ? : throw IllegalStateException (" Camera ID is null" )
415
+ return context.getCameraCharacteristics(cameraId)
416
+ .get(CameraCharacteristics .SENSOR_INFO_ACTIVE_ARRAY_SIZE )!!
417
+ }
418
+ }
419
+ }
414
420
415
- private fun speedUpZoomByX (scaleFactor : Float , ratio : Int ): Float {
416
- return if (scaleFactor > 1f ) {
417
- 1.0f + (scaleFactor - 1.0f ) * ratio
418
- } else {
419
- 1.0f - (1.0f - scaleFactor) * ratio
421
+ companion object {
422
+ /* *
423
+ * Calculates sensor crop region for a zoom ratio (zoom >= 1.0).
424
+ *
425
+ * @return the crop region.
426
+ */
427
+ private fun getCropRegion (sensorRect : Rect , zoomRatio : Float ): Rect {
428
+ val xCenter: Int = sensorRect.width() / 2
429
+ val yCenter: Int = sensorRect.height() / 2
430
+ val xDelta = (0.5f * sensorRect.width() / zoomRatio).toInt()
431
+ val yDelta = (0.5f * sensorRect.height() / zoomRatio).toInt()
432
+ return Rect (xCenter - xDelta, yCenter - yDelta, xCenter + xDelta, yCenter + yDelta)
433
+ }
434
+
435
+ /* *
436
+ * Calculates sensor crop region for a zoom ratio (zoom >= 1.0).
437
+ *
438
+ * @return the crop region.
439
+ */
440
+ private fun getCropRegion (
441
+ characteristics : CameraCharacteristics ,
442
+ zoomRatio : Float
443
+ ): Rect {
444
+ val sensorRect =
445
+ characteristics.get(CameraCharacteristics .SENSOR_INFO_ACTIVE_ARRAY_SIZE )
446
+ ? : throw IllegalStateException (" Sensor rect is null" )
447
+ return getCropRegion(sensorRect, zoomRatio)
448
+ }
420
449
}
421
450
}
422
451
452
+ @RequiresApi(Build .VERSION_CODES .R )
453
+ class RZoom (context : Context , cameraController : CameraController ) :
454
+ Zoom (context, cameraController) {
455
+ override val availableRatioRange: Range <Float >
456
+ get() = cameraController.cameraId?.let { context.getZoomRatioRange(it) }
457
+ ? : DEFAULT_ZOOM_RATIO_RANGE
458
+
459
+ override var zoomRatio: Float
460
+ get() = cameraController.getSetting(CaptureRequest .CONTROL_ZOOM_RATIO )
461
+ ? : DEFAULT_ZOOM_RATIO
462
+ set(value) {
463
+ cameraController.setRepeatingSetting(
464
+ CaptureRequest .CONTROL_ZOOM_RATIO ,
465
+ value.clamp(availableRatioRange)
466
+ )
467
+ }
468
+
469
+ override val cropSensorRegion: Rect
470
+ get() {
471
+ val cameraId = cameraController.cameraId
472
+ ? : throw IllegalStateException (" Camera ID is null" )
473
+ return context.getCameraCharacteristics(cameraId)
474
+ .get(CameraCharacteristics .SENSOR_INFO_ACTIVE_ARRAY_SIZE )!!
475
+ }
476
+ }
477
+
423
478
companion object {
424
- val DEFAULT_ZOOM_RATIO = 1f
479
+ const val DEFAULT_ZOOM_RATIO = 1f
425
480
val DEFAULT_ZOOM_RATIO_RANGE = Range (DEFAULT_ZOOM_RATIO , DEFAULT_ZOOM_RATIO )
426
481
427
- /* *
428
- * Calculates sensor crop region for a zoom ratio (zoom >= 1.0).
429
- *
430
- * @return the crop region.
431
- */
432
- internal fun getCropRegion (characteristics : CameraCharacteristics , zoomRatio : Float ): Rect {
433
- val sensorRect =
434
- characteristics.get(CameraCharacteristics .SENSOR_INFO_ACTIVE_ARRAY_SIZE )!!
435
- val xCenter: Int = sensorRect.width() / 2
436
- val yCenter: Int = sensorRect.height() / 2
437
- val xDelta = (0.5f * sensorRect.width() / zoomRatio).toInt()
438
- val yDelta = (0.5f * sensorRect.height() / zoomRatio).toInt()
439
- return Rect (xCenter - xDelta, yCenter - yDelta, xCenter + xDelta, yCenter + yDelta)
482
+ fun build (context : Context , cameraController : CameraController ): Zoom {
483
+ return if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
484
+ RZoom (context, cameraController)
485
+ } else {
486
+ CropScalerRegionZoom (context, cameraController)
487
+ }
440
488
}
441
489
}
442
490
}
@@ -534,10 +582,10 @@ class Focus(private val context: Context, private val cameraController: CameraCo
534
582
}
535
583
536
584
companion object {
537
- val DEFAULT_LENS_DISTANCE = 0f
585
+ const val DEFAULT_LENS_DISTANCE = 0f
538
586
val DEFAULT_LENS_DISTANCE_RANGE = Range (DEFAULT_LENS_DISTANCE , DEFAULT_LENS_DISTANCE )
539
587
540
- val DEFAULT_MAX_NUM_OF_METERING_REGION = 0
588
+ const val DEFAULT_MAX_NUM_OF_METERING_REGION = 0
541
589
}
542
590
}
543
591
@@ -699,7 +747,7 @@ class FocusMetering(
699
747
return
700
748
}
701
749
702
- val cameraId = cameraController.cameraId ? : throw IllegalStateException ( " Camera ID is null " )
750
+ val cropRegion = zoom.cropSensorRegion
703
751
704
752
disableAutoCancel()
705
753
@@ -712,9 +760,6 @@ class FocusMetering(
712
760
return
713
761
}
714
762
715
- val cropRegion =
716
- Zoom .getCropRegion(context.getCameraCharacteristics(cameraId), zoom.zoomRatio)
717
-
718
763
val afRectangles =
719
764
getMeteringRectangles(
720
765
afPoints,
@@ -981,22 +1026,28 @@ class FocusMetering(
981
1026
adjustedPoint : PointF ,
982
1027
cropRegion : Rect
983
1028
): MeteringRectangle {
1029
+ Logger .e(" >>TEST" , " cropRegion: $cropRegion " )
1030
+ Logger .e(" >>TEST" , " adjustedPoint: $adjustedPoint " )
1031
+ Logger .e(" >>TEST" , " size: $size " )
984
1032
val centerX = (cropRegion.left + adjustedPoint.x * cropRegion.width()).toInt()
985
1033
val centerY = (cropRegion.top + adjustedPoint.y * cropRegion.height()).toInt()
986
1034
val width = (size * cropRegion.width())
987
1035
val height = (size * cropRegion.height())
988
1036
1037
+ Logger .e(" >>TEST" , " centerX: $centerX - centerY: $centerY " )
1038
+ Logger .e(" >>TEST" , " width: $width - height: $height " )
1039
+
989
1040
val focusRect = Rect (
990
1041
(centerX - width / 2 ).toInt(), (centerY - height / 2 ).toInt(),
991
1042
(centerX + width / 2 ).toInt(),
992
1043
(centerY + height / 2 ).toInt()
993
1044
)
994
-
1045
+ Logger .e( " >>TEST " , " focusRect1: $focusRect " )
995
1046
focusRect.left = focusRect.left.clamp(cropRegion.right, cropRegion.left)
996
1047
focusRect.right = focusRect.right.clamp(cropRegion.right, cropRegion.left)
997
1048
focusRect.top = focusRect.top.clamp(cropRegion.bottom, cropRegion.top)
998
1049
focusRect.bottom = focusRect.bottom.clamp(cropRegion.bottom, cropRegion.top)
999
-
1050
+ Logger .e( " >>TEST " , " focusRect2: $focusRect " )
1000
1051
return MeteringRectangle (focusRect, DEFAULT_METERING_WEIGHT_MAX )
1001
1052
}
1002
1053
}
0 commit comments