Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,34 @@ class Camera2ApiManager(context: Context) : CameraDevice.StateCallback() {

@Throws(IllegalStateException::class, Exception::class)
private fun drawSurface(cameraDevice: CameraDevice, surfaces: List<Surface>): CaptureRequest {
val builderInputSurface = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
val builderInputSurface = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
for (surface in surfaces) builderInputSurface.addTarget(surface)
builderInputSurface.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
val validFps = min(60, fps)
builderInputSurface.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(validFps, validFps))
// Find best FPS range instead of forcing strict [30, 30] which causes HAL duplication stutter
var bestRange = Range(validFps, validFps)
try {
val facing = if (cameraId == "1") Facing.FRONT else Facing.BACK
val supportedRanges = getSupportedFps(null, facing)

// Look for a range that maxes out at our target FPS, but allows dipping to save light (e.g. [24, 30] or [15, 30])
for (range in supportedRanges) {
if (range.upper == validFps && range.lower < validFps) {
// Try to avoid dropping too low (e.g. [15, 30] can be too choppy, prefer [24, 30])
if (range.lower >= 24) {
bestRange = range
break
} else if (bestRange.lower == validFps || range.lower > bestRange.lower) {
bestRange = range
}
}
}
Log.i(TAG, "Selected dynamic FPS range: $bestRange for target $validFps")
} catch (e: Exception) {
Log.e(TAG, "Error finding dynamic FPS range", e)
}

builderInputSurface.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, bestRange)
this.builderInputSurface = builderInputSurface
return builderInputSurface.build()
}
Expand Down Expand Up @@ -605,7 +628,12 @@ class Camera2ApiManager(context: Context) : CameraDevice.StateCallback() {
builderInputSurface.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL)
builderInputSurface.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF)
applyRequest(builderInputSurface)
if (supportedFocusModes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)) {
// Prefer CONTINUOUS_VIDEO: same smooth AF as CONTINUOUS_PICTURE but defers
// fine adjustments to not interrupt frame delivery (no dropped frames on focus hunt).
if (supportedFocusModes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)) {
builderInputSurface.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)
isAutoFocusEnabled = true
} else if (supportedFocusModes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)) {
builderInputSurface.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
isAutoFocusEnabled = true
} else if (supportedFocusModes.contains(CaptureRequest.CONTROL_AF_MODE_AUTO)) {
Expand Down
Loading
Loading