-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Fix 60 FPS crashing on some Samsungs (#2556)
* fix: Fix 60 FPS crash on Samsung by checking `CamcorderProfile.maxFps` * Log FPS clamp * Update CameraDeviceDetails.kt * Format code
- Loading branch information
Showing
4 changed files
with
120 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 2 additions & 28 deletions
30
...roid/src/main/java/com/mrousavy/camera/extensions/CameraCharacteristics+getOutputSizes.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
package/android/src/main/java/com/mrousavy/camera/utils/CamcorderProfileUtils.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package com.mrousavy.camera.utils | ||
|
||
import android.media.CamcorderProfile | ||
import android.os.Build | ||
import android.util.Size | ||
import kotlin.math.abs | ||
|
||
class CamcorderProfileUtils { | ||
companion object { | ||
private fun getResolutionForCamcorderProfileQuality(camcorderProfile: Int): Int = | ||
when (camcorderProfile) { | ||
CamcorderProfile.QUALITY_QCIF -> 176 * 144 | ||
CamcorderProfile.QUALITY_QVGA -> 320 * 240 | ||
CamcorderProfile.QUALITY_CIF -> 352 * 288 | ||
CamcorderProfile.QUALITY_VGA -> 640 * 480 | ||
CamcorderProfile.QUALITY_480P -> 720 * 480 | ||
CamcorderProfile.QUALITY_720P -> 1280 * 720 | ||
CamcorderProfile.QUALITY_1080P -> 1920 * 1080 | ||
CamcorderProfile.QUALITY_2K -> 2048 * 1080 | ||
CamcorderProfile.QUALITY_QHD -> 2560 * 1440 | ||
CamcorderProfile.QUALITY_2160P -> 3840 * 2160 | ||
CamcorderProfile.QUALITY_4KDCI -> 4096 * 2160 | ||
CamcorderProfile.QUALITY_8KUHD -> 7680 * 4320 | ||
else -> throw Error("Invalid CamcorderProfile \"$camcorderProfile\"!") | ||
} | ||
|
||
fun findClosestCamcorderProfileQuality(cameraId: String, resolution: Size, allowLargerSize: Boolean): Int { | ||
// Iterate through all available CamcorderProfiles and find the one that matches the closest | ||
val targetResolution = resolution.width * resolution.height | ||
val cameraIdInt = cameraId.toIntOrNull() | ||
|
||
var profiles = (CamcorderProfile.QUALITY_QCIF..CamcorderProfile.QUALITY_8KUHD).filter { profile -> | ||
if (cameraIdInt != null) { | ||
return@filter CamcorderProfile.hasProfile(cameraIdInt, profile) | ||
} else { | ||
return@filter CamcorderProfile.hasProfile(profile) | ||
} | ||
} | ||
if (!allowLargerSize) { | ||
profiles = profiles.filter { profile -> | ||
val currentResolution = getResolutionForCamcorderProfileQuality(profile) | ||
return@filter currentResolution <= targetResolution | ||
} | ||
} | ||
val closestProfile = profiles.minBy { profile -> | ||
val currentResolution = getResolutionForCamcorderProfileQuality(profile) | ||
return@minBy abs(currentResolution - targetResolution) | ||
} | ||
return closestProfile | ||
} | ||
|
||
fun getMaximumVideoSize(cameraId: String): Size? { | ||
try { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||
val profiles = CamcorderProfile.getAll(cameraId, CamcorderProfile.QUALITY_HIGH) | ||
if (profiles != null) { | ||
val largestProfile = profiles.videoProfiles.filterNotNull().maxByOrNull { it.width * it.height } | ||
if (largestProfile != null) { | ||
return Size(largestProfile.width, largestProfile.height) | ||
} | ||
} | ||
} | ||
|
||
val cameraIdInt = cameraId.toIntOrNull() | ||
if (cameraIdInt != null) { | ||
val profile = CamcorderProfile.get(cameraIdInt, CamcorderProfile.QUALITY_HIGH) | ||
return Size(profile.videoFrameWidth, profile.videoFrameHeight) | ||
} | ||
|
||
return null | ||
} catch (e: Throwable) { | ||
// some Samsung phones just crash when trying to get the CamcorderProfile. Only god knows why. | ||
return null | ||
} | ||
} | ||
|
||
fun getMaximumFps(cameraId: String, size: Size): Int? { | ||
try { | ||
val quality = findClosestCamcorderProfileQuality(cameraId, size, false) | ||
|
||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||
val profiles = CamcorderProfile.getAll(cameraId, quality) | ||
if (profiles != null) { | ||
return profiles.videoProfiles.maxOf { profile -> profile.frameRate } | ||
} | ||
} | ||
|
||
val cameraIdInt = cameraId.toIntOrNull() | ||
if (cameraIdInt != null) { | ||
val profile = CamcorderProfile.get(cameraIdInt, quality) | ||
return profile.videoFrameRate | ||
} | ||
|
||
return null | ||
} catch (e: Throwable) { | ||
// some Samsung phones just crash when trying to get the CamcorderProfile. Only god knows why. | ||
return null | ||
} | ||
} | ||
} | ||
} |