mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-29 21:10:20 +02:00
feat(camera): custom frame rate
- experimental disable cameras
This commit is contained in:
parent
1f4eb18aa8
commit
2905fe6e2d
@ -532,9 +532,9 @@
|
|||||||
"name": "Camera",
|
"name": "Camera",
|
||||||
"description": "Adjust the right settings for the perfect snap",
|
"description": "Adjust the right settings for the perfect snap",
|
||||||
"properties": {
|
"properties": {
|
||||||
"disable_camera": {
|
"disable_cameras": {
|
||||||
"name": "Disable Camera",
|
"name": "Disable Cameras",
|
||||||
"description": "Prevents Snapchat from using the cameras available on your device"
|
"description": "Prevents Snapchat from using the selected cameras"
|
||||||
},
|
},
|
||||||
"black_photos": {
|
"black_photos": {
|
||||||
"name": "Black Photos",
|
"name": "Black Photos",
|
||||||
@ -556,9 +556,13 @@
|
|||||||
"name": "Custom Resolution",
|
"name": "Custom Resolution",
|
||||||
"description": "Sets a custom camera resolution, width x height (e.g. 1920x1080).\nThe custom resolution must be supported by your device"
|
"description": "Sets a custom camera resolution, width x height (e.g. 1920x1080).\nThe custom resolution must be supported by your device"
|
||||||
},
|
},
|
||||||
"custom_frame_rate": {
|
"front_custom_frame_rate": {
|
||||||
"name": "Custom Frame Rate",
|
"name": "Front Custom Frame Rate",
|
||||||
"description": "Overrides the camera frame rate"
|
"description": "Overrides the front camera frame rate"
|
||||||
|
},
|
||||||
|
"back_custom_frame_rate": {
|
||||||
|
"name": "Back Custom Frame Rate",
|
||||||
|
"description": "Overrides the back camera frame rate"
|
||||||
},
|
},
|
||||||
"force_camera_source_encoding": {
|
"force_camera_source_encoding": {
|
||||||
"name": "Force Camera Source Encoding",
|
"name": "Force Camera Source Encoding",
|
||||||
@ -866,6 +870,10 @@
|
|||||||
"friends": "Friends",
|
"friends": "Friends",
|
||||||
"following": "Following",
|
"following": "Following",
|
||||||
"discover": "Discover"
|
"discover": "Discover"
|
||||||
|
},
|
||||||
|
"disable_cameras":{
|
||||||
|
"front": "Front Camera",
|
||||||
|
"back": "Back Camera"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -13,6 +13,7 @@ import me.rhunk.snapenhance.common.logger.AbstractLogger
|
|||||||
class Camera : ConfigContainer() {
|
class Camera : ConfigContainer() {
|
||||||
companion object {
|
companion object {
|
||||||
private val defaultResolutions = listOf("3264x2448", "3264x1840", "3264x1504", "2688x1512", "2560x1920", "2448x2448", "2340x1080", "2160x1080", "1920x1440", "1920x1080", "1600x1200", "1600x960", "1600x900", "1600x736", "1600x720", "1560x720", "1520x720", "1440x1080", "1440x720", "1280x720", "1080x1080", "1080x720", "960x720", "720x720", "720x480", "640x480", "352x288", "320x240", "176x144").toTypedArray()
|
private val defaultResolutions = listOf("3264x2448", "3264x1840", "3264x1504", "2688x1512", "2560x1920", "2448x2448", "2340x1080", "2160x1080", "1920x1440", "1920x1080", "1600x1200", "1600x960", "1600x900", "1600x736", "1600x720", "1560x720", "1520x720", "1440x1080", "1440x720", "1280x720", "1080x1080", "1080x720", "960x720", "720x720", "720x480", "640x480", "352x288", "320x240", "176x144").toTypedArray()
|
||||||
|
private val customFrameRates = arrayOf("5", "10", "20", "25", "30", "48", "60", "90", "120")
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var _overrideFrontResolution: PropertyValue<String>
|
private lateinit var _overrideFrontResolution: PropertyValue<String>
|
||||||
@ -49,13 +50,12 @@ class Camera : ConfigContainer() {
|
|||||||
{ addFlags(ConfigFlag.NO_TRANSLATE) }
|
{ addFlags(ConfigFlag.NO_TRANSLATE) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val disable = boolean("disable_camera")
|
val disableCameras = multiple("disable_cameras", "front", "back") { addNotices(FeatureNotice.INTERNAL_BEHAVIOR); requireRestart() }
|
||||||
val immersiveCameraPreview = boolean("immersive_camera_preview") { addNotices(FeatureNotice.UNSTABLE) }
|
val immersiveCameraPreview = boolean("immersive_camera_preview") { addNotices(FeatureNotice.UNSTABLE) }
|
||||||
val blackPhotos = boolean("black_photos")
|
val blackPhotos = boolean("black_photos")
|
||||||
val customFrameRate = unique("custom_frame_rate",
|
val frontCustomFrameRate = unique("front_custom_frame_rate", *customFrameRates) { requireRestart(); addFlags(ConfigFlag.NO_TRANSLATE) }
|
||||||
"5", "10", "20", "25", "30", "48", "60", "90", "120"
|
val backCustomFrameRate = unique("back_custom_frame_rate", *customFrameRates) { requireRestart(); addFlags(ConfigFlag.NO_TRANSLATE) }
|
||||||
) { addNotices(FeatureNotice.UNSTABLE); addFlags(ConfigFlag.NO_TRANSLATE) }
|
val hevcRecording = boolean("hevc_recording") { requireRestart() }
|
||||||
val hevcRecording = boolean("hevc_recording") { requireRestart(); addNotices(FeatureNotice.UNSTABLE) }
|
|
||||||
val forceCameraSourceEncoding = boolean("force_camera_source_encoding")
|
val forceCameraSourceEncoding = boolean("force_camera_source_encoding")
|
||||||
val overrideFrontResolution get() = _overrideFrontResolution
|
val overrideFrontResolution get() = _overrideFrontResolution
|
||||||
val overrideBackResolution get() = _overrideBackResolution
|
val overrideBackResolution get() = _overrideBackResolution
|
||||||
|
@ -28,25 +28,41 @@ class CameraTweaks : Feature("Camera Tweaks", loadParams = FeatureLoadParams.ACT
|
|||||||
@SuppressLint("MissingPermission", "DiscouragedApi")
|
@SuppressLint("MissingPermission", "DiscouragedApi")
|
||||||
override fun onActivityCreate() {
|
override fun onActivityCreate() {
|
||||||
val config = context.config.camera
|
val config = context.config.camera
|
||||||
if (config.disable.get()) {
|
|
||||||
|
val frontCameraId = runCatching { context.androidContext.getSystemService(CameraManager::class.java).run {
|
||||||
|
cameraIdList.firstOrNull { getCameraCharacteristics(it).get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT }
|
||||||
|
} }.getOrNull()
|
||||||
|
|
||||||
|
if (config.disableCameras.get().isNotEmpty() && frontCameraId != null) {
|
||||||
ContextWrapper::class.java.hook("checkPermission", HookStage.BEFORE) { param ->
|
ContextWrapper::class.java.hook("checkPermission", HookStage.BEFORE) { param ->
|
||||||
val permission = param.arg<String>(0)
|
val permission = param.arg<String>(0)
|
||||||
if (permission == Manifest.permission.CAMERA) {
|
if (permission == Manifest.permission.CAMERA) {
|
||||||
param.setResult(PackageManager.PERMISSION_GRANTED)
|
param.setResult(PackageManager.PERMISSION_GRANTED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var isLastCameraFront = false
|
var isLastCameraFront = false
|
||||||
|
|
||||||
CameraManager::class.java.hook("openCamera", HookStage.BEFORE) { param ->
|
CameraManager::class.java.hook("openCamera", HookStage.BEFORE) { param ->
|
||||||
if (config.disable.get()) {
|
val cameraManager = param.thisObject() as? CameraManager ?: return@hook
|
||||||
|
val cameraId = param.arg<String>(0)
|
||||||
|
val disabledCameras = config.disableCameras.get()
|
||||||
|
|
||||||
|
if (disabledCameras.size >= 2) {
|
||||||
param.setResult(null)
|
param.setResult(null)
|
||||||
return@hook
|
return@hook
|
||||||
}
|
}
|
||||||
val cameraManager = param.thisObject() as? CameraManager ?: return@hook
|
|
||||||
isLastCameraFront = cameraManager.getCameraCharacteristics(param.arg(0)).get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT
|
isLastCameraFront = cameraId == frontCameraId
|
||||||
|
|
||||||
|
if (disabledCameras.size != 1) return@hook
|
||||||
|
|
||||||
|
// trick to replace unwanted camera with another one
|
||||||
|
if ((disabledCameras.contains("front") && isLastCameraFront) || (disabledCameras.contains("back") && !isLastCameraFront)) {
|
||||||
|
param.setArg(0, cameraManager.cameraIdList.filterNot { it == cameraId }.firstOrNull() ?: return@hook)
|
||||||
|
isLastCameraFront = !isLastCameraFront
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageReader::class.java.hook("newInstance", HookStage.BEFORE) { param ->
|
ImageReader::class.java.hook("newInstance", HookStage.BEFORE) { param ->
|
||||||
@ -56,19 +72,33 @@ class CameraTweaks : Feature("Camera Tweaks", loadParams = FeatureLoadParams.ACT
|
|||||||
param.setArg(1, captureResolutionConfig[1])
|
param.setArg(1, captureResolutionConfig[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
config.customFrameRate.getNullable()?.also { value ->
|
CameraCharacteristics::class.java.hook("get", HookStage.AFTER) { param ->
|
||||||
val customFrameRate = value.toInt()
|
val key = param.argNullable<Key<*>>(0) ?: return@hook
|
||||||
CameraCharacteristics::class.java.hook("get", HookStage.AFTER) { param ->
|
|
||||||
val key = param.arg<Key<*>>(0)
|
if (key == CameraCharacteristics.LENS_FACING) {
|
||||||
if (key == CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES) {
|
val disabledCameras = config.disableCameras.get()
|
||||||
val fpsRanges = param.getResult() as? Array<*> ?: return@hook
|
//FIXME: unexpected behavior when app is resumed
|
||||||
fpsRanges.forEach {
|
if (disabledCameras.size == 1) {
|
||||||
val range = it as? Range<*> ?: return@forEach
|
val isFrontCamera = param.getResult() as? Int == CameraCharacteristics.LENS_FACING_FRONT
|
||||||
range.setObjectField("mUpper", customFrameRate)
|
if ((disabledCameras.contains("front") && isFrontCamera) || (disabledCameras.contains("back") && !isFrontCamera)) {
|
||||||
range.setObjectField("mLower", customFrameRate)
|
param.setResult(if (isFrontCamera) CameraCharacteristics.LENS_FACING_BACK else CameraCharacteristics.LENS_FACING_FRONT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key == CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES) {
|
||||||
|
val isFrontCamera = param.invokeOriginal(
|
||||||
|
arrayOf(CameraCharacteristics.LENS_FACING)
|
||||||
|
) == CameraCharacteristics.LENS_FACING_FRONT
|
||||||
|
val customFrameRate = (if (isFrontCamera) config.frontCustomFrameRate.getNullable() else config.backCustomFrameRate.getNullable())?.toIntOrNull() ?: return@hook
|
||||||
|
val fpsRanges = param.getResult() as? Array<*> ?: return@hook
|
||||||
|
|
||||||
|
fpsRanges.forEach {
|
||||||
|
val range = it as? Range<*> ?: return@forEach
|
||||||
|
range.setObjectField("mUpper", customFrameRate)
|
||||||
|
range.setObjectField("mLower", customFrameRate)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.blackPhotos.get()) {
|
if (config.blackPhotos.get()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user