Merge pull request #326 from KryptKode/feat/camera-x

try to handle changing video quality and image resolution
This commit is contained in:
Tibor Kaputa 2022-07-08 22:33:14 +02:00 committed by GitHub
commit 3c16ba8853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 419 additions and 34 deletions

View File

@ -0,0 +1,104 @@
package com.simplemobiletools.camera.dialogs
import android.app.Activity
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.models.MySize
import com.simplemobiletools.camera.models.VideoQuality
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.models.RadioItem
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_photo
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_photo_holder
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_video
import kotlinx.android.synthetic.main.dialog_change_resolution.view.change_resolution_video_holder
class ChangeResolutionDialogX(
private val activity: Activity,
private val isFrontCamera: Boolean,
private val photoResolutions: List<MySize> = listOf(),
private val videoResolutions: List<VideoQuality>,
private val callback: () -> Unit
) {
private var dialog: AlertDialog
private val config = activity.config
private val TAG = "ChangeResolutionDialogX"
init {
val view = LayoutInflater.from(activity).inflate(R.layout.dialog_change_resolution, null).apply {
setupPhotoResolutionPicker(this)
setupVideoResolutionPicker(this)
}
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.create().apply {
activity.setupDialogStuff(view, this, if (isFrontCamera) R.string.front_camera else R.string.back_camera)
}
}
private fun setupPhotoResolutionPicker(view: View) {
val items = getFormattedResolutions(photoResolutions)
var selectionIndex = if (isFrontCamera) config.frontPhotoResIndex else config.backPhotoResIndex
selectionIndex = Math.max(selectionIndex, 0)
view.change_resolution_photo_holder.setOnClickListener {
RadioGroupDialog(activity, items, selectionIndex) {
selectionIndex = it as Int
Log.w(TAG, "setupPhotoResolutionPicker: selectionIndex=$it")
view.change_resolution_photo.text = items[selectionIndex].title
if (isFrontCamera) {
config.frontPhotoResIndex = it
} else {
config.backPhotoResIndex = it
}
dialog.dismiss()
callback.invoke()
}
}
view.change_resolution_photo.text = items.getOrNull(selectionIndex)?.title
}
private fun setupVideoResolutionPicker(view: View) {
val items = videoResolutions.mapIndexed { index, videoQuality ->
val megapixels = videoQuality.megaPixels
val aspectRatio = videoQuality.getAspectRatio(activity)
RadioItem(index, "${videoQuality.width} x ${videoQuality.height} ($megapixels MP, $aspectRatio)")
}
val videoQuality = if (isFrontCamera) config.frontVideoQuality else config.backVideoQuality
var selectionIndex = videoResolutions.indexOf(videoQuality)
view.change_resolution_video_holder.setOnClickListener {
RadioGroupDialog(activity, ArrayList(items), selectionIndex) {
selectionIndex = it as Int
val selectedItem = items[selectionIndex]
val selectedQuality = videoResolutions[selectionIndex]
view.change_resolution_video.text = selectedItem.title
if (isFrontCamera) {
config.frontVideoQuality = selectedQuality
} else {
config.backVideoQuality = selectedQuality
}
dialog.dismiss()
callback.invoke()
}
}
view.change_resolution_video.text = items.getOrNull(selectionIndex)?.title
}
private fun getFormattedResolutions(resolutions: List<MySize>): ArrayList<RadioItem> {
val items = ArrayList<RadioItem>(resolutions.size)
val sorted = resolutions.sortedByDescending { it.width * it.height }
sorted.forEachIndexed { index, size ->
val megapixels = String.format("%.1f", (size.width * size.height.toFloat()) / 1000000)
val aspectRatio = size.getAspectRatio(activity)
items.add(RadioItem(index, "${size.width} x ${size.height} ($megapixels MP, $aspectRatio)"))
}
return items
}
}

View File

@ -0,0 +1,32 @@
package com.simplemobiletools.camera.extensions
import androidx.camera.core.AspectRatio
import androidx.camera.video.Quality
import com.simplemobiletools.camera.models.VideoQuality
fun Quality.toVideoQuality(): VideoQuality {
return when (this) {
Quality.UHD -> VideoQuality.UHD
Quality.FHD -> VideoQuality.FHD
Quality.HD -> VideoQuality.HD
Quality.SD -> VideoQuality.SD
else -> throw IllegalArgumentException("Unsupported quality: $this")
}
}
fun VideoQuality.toCameraXQuality(): Quality {
return when (this) {
VideoQuality.UHD -> Quality.UHD
VideoQuality.FHD -> Quality.FHD
VideoQuality.HD -> Quality.HD
VideoQuality.SD -> Quality.SD
}
}
fun Quality.getAspectRatio(): Int {
return when(this) {
Quality.UHD, Quality.FHD, Quality.HD -> AspectRatio.RATIO_16_9
Quality.SD -> AspectRatio.RATIO_4_3
else -> throw IllegalArgumentException("Unsupported quality: $this")
}
}

View File

@ -3,6 +3,7 @@ package com.simplemobiletools.camera.helpers
import android.content.Context import android.content.Context
import android.os.Environment import android.os.Environment
import androidx.camera.core.CameraSelector import androidx.camera.core.CameraSelector
import com.simplemobiletools.camera.models.VideoQuality
import com.simplemobiletools.commons.helpers.BaseConfig import com.simplemobiletools.commons.helpers.BaseConfig
import java.io.File import java.io.File
@ -62,6 +63,20 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(FRONT_PHOTO_RESOLUTION_INDEX, 0) get() = prefs.getInt(FRONT_PHOTO_RESOLUTION_INDEX, 0)
set(frontPhotoResIndex) = prefs.edit().putInt(FRONT_PHOTO_RESOLUTION_INDEX, frontPhotoResIndex).apply() set(frontPhotoResIndex) = prefs.edit().putInt(FRONT_PHOTO_RESOLUTION_INDEX, frontPhotoResIndex).apply()
var backVideoQuality: VideoQuality
get() {
val backQuality = prefs.getString(BACK_VIDEO_QUALITY, VideoQuality.UHD.name)
return VideoQuality.values().first { it.name == backQuality }
}
set(backVideoQuality) = prefs.edit().putString(BACK_VIDEO_QUALITY, backVideoQuality.name).apply()
var frontVideoQuality: VideoQuality
get() {
val frontQuality = prefs.getString(FRONT_VIDEO_QUALITY, VideoQuality.UHD.name)
return VideoQuality.values().first { it.name == frontQuality }
}
set(frontVideoQuality) = prefs.edit().putString(FRONT_VIDEO_QUALITY, frontVideoQuality.name).apply()
var frontVideoResIndex: Int var frontVideoResIndex: Int
get() = prefs.getInt(FRONT_VIDEO_RESOLUTION_INDEX, 0) get() = prefs.getInt(FRONT_VIDEO_RESOLUTION_INDEX, 0)
set(frontVideoResIndex) = prefs.edit().putInt(FRONT_VIDEO_RESOLUTION_INDEX, frontVideoResIndex).apply() set(frontVideoResIndex) = prefs.edit().putInt(FRONT_VIDEO_RESOLUTION_INDEX, frontVideoResIndex).apply()

View File

@ -15,6 +15,8 @@ const val FLASHLIGHT_STATE = "flashlight_state"
const val INIT_PHOTO_MODE = "init_photo_mode" const val INIT_PHOTO_MODE = "init_photo_mode"
const val BACK_PHOTO_RESOLUTION_INDEX = "back_photo_resolution_index_2" const val BACK_PHOTO_RESOLUTION_INDEX = "back_photo_resolution_index_2"
const val BACK_VIDEO_RESOLUTION_INDEX = "back_video_resolution_index_2" const val BACK_VIDEO_RESOLUTION_INDEX = "back_video_resolution_index_2"
const val BACK_VIDEO_QUALITY = "back_video_quality_2"
const val FRONT_VIDEO_QUALITY = "front_video_quality_2"
const val FRONT_PHOTO_RESOLUTION_INDEX = "front_photo_resolution_index_2" const val FRONT_PHOTO_RESOLUTION_INDEX = "front_photo_resolution_index_2"
const val FRONT_VIDEO_RESOLUTION_INDEX = "front_video_resolution_index_2" const val FRONT_VIDEO_RESOLUTION_INDEX = "front_video_resolution_index_2"
const val KEEP_SETTINGS_VISIBLE = "keep_settings_visible" const val KEEP_SETTINGS_VISIBLE = "keep_settings_visible"

View File

@ -0,0 +1,89 @@
package com.simplemobiletools.camera.helpers
import android.content.Context
import android.graphics.ImageFormat
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.hardware.camera2.params.StreamConfigurationMap
import android.media.MediaRecorder
import android.util.Log
import android.util.Size
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.video.Quality
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.extensions.toCameraXQuality
import com.simplemobiletools.camera.models.CameraSelectorImageQualities
import com.simplemobiletools.camera.models.CameraSelectorVideoQualities
import com.simplemobiletools.camera.models.MySize
class ImageQualityManager(
activity: AppCompatActivity,
) {
companion object {
private const val TAG = "ImageQualityManager"
private const val MAX_VIDEO_WIDTH = 4096
private const val MAX_VIDEO_HEIGHT = 2160
private val CAMERA_LENS = arrayOf(CameraCharacteristics.LENS_FACING_FRONT, CameraCharacteristics.LENS_FACING_BACK)
}
private val cameraManager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
private val config = activity.config
private val imageQualities = mutableListOf<CameraSelectorImageQualities>()
fun initSupportedQualities() {
for (cameraId in cameraManager.cameraIdList) {
try {
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
for (lens in CAMERA_LENS) {
if (characteristics.get(CameraCharacteristics.LENS_FACING) == lens) {
val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
val imageSizes = configMap.getOutputSizes(ImageFormat.JPEG).map { MySize(it.width, it.height) }
val cameraSelector = lens.toCameraSelector()
imageQualities.add(CameraSelectorImageQualities(cameraSelector, imageSizes))
Log.i(TAG, "initQualities: imageSizes=$imageSizes")
}
}
} catch (e: Exception) {
Log.e(TAG, "Camera ID=$cameraId is not supported", e)
}
}
}
private fun getAvailableVideoSizes(configMap: StreamConfigurationMap): List<Size> {
return configMap.getOutputSizes(MediaRecorder::class.java).filter {
it.width <= MAX_VIDEO_WIDTH && it.height <= MAX_VIDEO_HEIGHT
}
}
private fun Int.toCameraSelector(): CameraSelector {
return if (this == CameraCharacteristics.LENS_FACING_FRONT) {
CameraSelector.DEFAULT_FRONT_CAMERA
} else {
CameraSelector.DEFAULT_BACK_CAMERA
}
}
fun getUserSelectedResolution(cameraSelector: CameraSelector): Size? {
val index = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontPhotoResIndex else config.backPhotoResIndex
return imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedByDescending { it.pixels}
.distinctBy { it.pixels }
.map { Size(it.width, it.height) }
.also {
Log.i(TAG, "Resolutions: $it, index=$index")
}
.getOrNull(index).also {
Log.i(TAG, "getUserSelectedResolution: $it, index=$index")
}
}
fun getSupportedResolutions(cameraSelector: CameraSelector): List<MySize> {
return imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedByDescending { it.pixels }
.distinctBy { it.pixels }
}
}

View File

@ -0,0 +1,60 @@
package com.simplemobiletools.camera.helpers
import android.util.Log
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.Quality
import androidx.camera.video.QualitySelector
import com.simplemobiletools.camera.extensions.toCameraXQuality
import com.simplemobiletools.camera.extensions.toVideoQuality
import com.simplemobiletools.camera.models.CameraSelectorVideoQualities
import com.simplemobiletools.camera.models.VideoQuality
class VideoQualityManager(private val config: Config) {
companion object {
private const val TAG = "VideoQualityHelper"
private val QUALITIES = listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD)
private val CAMERA_SELECTORS = arrayOf(CameraSelector.DEFAULT_BACK_CAMERA, CameraSelector.DEFAULT_FRONT_CAMERA)
}
private val videoQualities = mutableListOf<CameraSelectorVideoQualities>()
fun initSupportedQualities(
cameraProvider: ProcessCameraProvider,
camera: Camera,
) {
if (videoQualities.isEmpty()) {
for (camSelector in CAMERA_SELECTORS) {
try {
if (cameraProvider.hasCamera(camSelector)) {
QualitySelector.getSupportedQualities(camera.cameraInfo)
.filter(QUALITIES::contains)
.also { allQualities ->
val qualities = allQualities.map { it.toVideoQuality() }
videoQualities.add(CameraSelectorVideoQualities(camSelector, qualities))
}
Log.i(TAG, "bindCameraUseCases: videoQualities=$videoQualities")
}
} catch (e: Exception) {
Log.e(TAG, "Camera Face $camSelector is not supported", e)
}
}
}
}
fun getUserSelectedQuality(cameraSelector: CameraSelector): Quality {
return if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) {
config.frontVideoQuality.toCameraXQuality()
} else {
config.backVideoQuality.toCameraXQuality()
}
}
fun getSupportedQualities(cameraSelector: CameraSelector): List<VideoQuality> {
return videoQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedByDescending { it.pixels }
}
}

View File

@ -1,13 +1,9 @@
package com.simplemobiletools.camera.implementations package com.simplemobiletools.camera.implementations
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Context import android.content.Context
import android.hardware.SensorManager import android.hardware.SensorManager
import android.hardware.display.DisplayManager import android.hardware.display.DisplayManager
import android.net.Uri
import android.os.Environment
import android.provider.MediaStore
import android.util.Log import android.util.Log
import android.view.Display import android.view.Display
import android.view.GestureDetector import android.view.GestureDetector
@ -36,14 +32,7 @@ import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview import androidx.camera.core.Preview
import androidx.camera.core.UseCase import androidx.camera.core.UseCase
import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.FileDescriptorOutputOptions import androidx.camera.video.*
import androidx.camera.video.MediaStoreOutputOptions
import androidx.camera.video.Quality
import androidx.camera.video.QualitySelector
import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture
import androidx.camera.video.VideoRecordEvent
import androidx.camera.view.PreviewView import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.doOnLayout import androidx.core.view.doOnLayout
@ -52,23 +41,12 @@ import androidx.lifecycle.LifecycleOwner
import androidx.window.layout.WindowMetricsCalculator import androidx.window.layout.WindowMetricsCalculator
import com.bumptech.glide.load.ImageHeaderParser.UNKNOWN_ORIENTATION import com.bumptech.glide.load.ImageHeaderParser.UNKNOWN_ORIENTATION
import com.simplemobiletools.camera.R import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.extensions.config import com.simplemobiletools.camera.dialogs.ChangeResolutionDialogX
import com.simplemobiletools.camera.extensions.getRandomMediaName import com.simplemobiletools.camera.extensions.*
import com.simplemobiletools.camera.extensions.toAppFlashMode import com.simplemobiletools.camera.helpers.*
import com.simplemobiletools.camera.extensions.toCameraSelector
import com.simplemobiletools.camera.extensions.toLensFacing
import com.simplemobiletools.camera.helpers.CameraErrorHandler
import com.simplemobiletools.camera.helpers.MediaOutputHelper
import com.simplemobiletools.camera.helpers.MediaSoundHelper
import com.simplemobiletools.camera.helpers.PinchToZoomOnScaleGestureListener
import com.simplemobiletools.camera.interfaces.MyPreview import com.simplemobiletools.camera.interfaces.MyPreview
import com.simplemobiletools.camera.models.MediaOutput import com.simplemobiletools.camera.models.MediaOutput
import com.simplemobiletools.commons.extensions.hasPermission
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.PERMISSION_RECORD_AUDIO
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -98,6 +76,8 @@ class CameraXPreview(
private val displayManager = activity.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager private val displayManager = activity.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
private val mediaSoundHelper = MediaSoundHelper() private val mediaSoundHelper = MediaSoundHelper()
private val windowMetricsCalculator = WindowMetricsCalculator.getOrCreate() private val windowMetricsCalculator = WindowMetricsCalculator.getOrCreate()
private val videoQualityManager = VideoQualityManager(config)
private val imageQualityManager = ImageQualityManager(activity)
private val orientationEventListener = object : OrientationEventListener(activity, SensorManager.SENSOR_DELAY_NORMAL) { private val orientationEventListener = object : OrientationEventListener(activity, SensorManager.SENSOR_DELAY_NORMAL) {
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
@ -146,6 +126,7 @@ class CameraXPreview(
private fun startCamera(switching: Boolean = false) { private fun startCamera(switching: Boolean = false) {
Log.i(TAG, "startCamera: ") Log.i(TAG, "startCamera: ")
imageQualityManager.initSupportedQualities()
val cameraProviderFuture = ProcessCameraProvider.getInstance(activity) val cameraProviderFuture = ProcessCameraProvider.getInstance(activity)
cameraProviderFuture.addListener({ cameraProviderFuture.addListener({
try { try {
@ -163,7 +144,12 @@ class CameraXPreview(
private fun bindCameraUseCases() { private fun bindCameraUseCases() {
val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera initialization failed.") val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera initialization failed.")
val metrics = windowMetricsCalculator.computeCurrentWindowMetrics(activity).bounds val metrics = windowMetricsCalculator.computeCurrentWindowMetrics(activity).bounds
val aspectRatio = aspectRatio(metrics.width(), metrics.height()) val aspectRatio = if (isPhotoCapture) {
aspectRatio(metrics.width(), metrics.height())
} else {
val selectedQuality = videoQualityManager.getUserSelectedQuality(cameraSelector)
selectedQuality.getAspectRatio()
}
val rotation = previewView.display.rotation val rotation = previewView.display.rotation
preview = buildPreview(aspectRatio, rotation) preview = buildPreview(aspectRatio, rotation)
@ -174,7 +160,10 @@ class CameraXPreview(
cameraSelector, cameraSelector,
preview, preview,
captureUseCase, captureUseCase,
) ).also {
videoQualityManager.initSupportedQualities(cameraProvider, it)
}
preview?.setSurfaceProvider(previewView.surfaceProvider) preview?.setSurfaceProvider(previewView.surfaceProvider)
setupZoomAndFocus() setupZoomAndFocus()
} }
@ -220,22 +209,30 @@ class CameraXPreview(
.setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY) .setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY)
.setFlashMode(flashMode) .setFlashMode(flashMode)
.setJpegQuality(config.photoQuality) .setJpegQuality(config.photoQuality)
.setTargetAspectRatio(aspectRatio)
.setTargetRotation(rotation) .setTargetRotation(rotation)
.apply {
imageQualityManager.getUserSelectedResolution(cameraSelector)?.let { resolution ->
Log.i(TAG, "buildImageCapture: resolution=$resolution")
setTargetResolution(resolution)
} ?: setTargetAspectRatio(aspectRatio)
}
.build() .build()
} }
private fun buildPreview(aspectRatio: Int, rotation: Int): Preview { private fun buildPreview(aspectRatio: Int, rotation: Int): Preview {
return Preview.Builder() return Preview.Builder()
.setTargetAspectRatio(aspectRatio)
.setTargetRotation(rotation) .setTargetRotation(rotation)
.setTargetAspectRatio(aspectRatio)
.build() .build()
} }
private fun buildVideoCapture(): VideoCapture<Recorder> { private fun buildVideoCapture(): VideoCapture<Recorder> {
val qualitySelector = QualitySelector.from(
videoQualityManager.getUserSelectedQuality(cameraSelector),
FallbackStrategy.lowerQualityOrHigherThan(Quality.SD),
)
val recorder = Recorder.Builder() val recorder = Recorder.Builder()
//TODO: user control for quality .setQualitySelector(qualitySelector)
.setQualitySelector(QualitySelector.from(Quality.FHD))
.build() .build()
return VideoCapture.withOutput(recorder) return VideoCapture.withOutput(recorder)
} }
@ -305,7 +302,18 @@ class CameraXPreview(
} }
override fun showChangeResolutionDialog() { override fun showChangeResolutionDialog() {
val oldQuality = videoQualityManager.getUserSelectedQuality(cameraSelector)
ChangeResolutionDialogX(
activity,
isFrontCameraInUse(),
imageQualityManager.getSupportedResolutions(cameraSelector),
videoQualityManager.getSupportedQualities(cameraSelector)
) {
if (oldQuality != videoQualityManager.getUserSelectedQuality(cameraSelector)) {
currentRecording?.stop()
}
startCamera()
}
} }
override fun toggleFrontBackCamera() { override fun toggleFrontBackCamera() {
@ -344,7 +352,6 @@ class CameraXPreview(
} }
override fun tryTakePicture() { override fun tryTakePicture() {
Log.i(TAG, "captureImage: ")
val imageCapture = imageCapture ?: throw IllegalStateException("Camera initialization failed.") val imageCapture = imageCapture ?: throw IllegalStateException("Camera initialization failed.")
val metadata = Metadata().apply { val metadata = Metadata().apply {

View File

@ -0,0 +1,8 @@
package com.simplemobiletools.camera.models
import androidx.camera.core.CameraSelector
data class CameraSelectorImageQualities(
val camSelector: CameraSelector,
val qualities: List<MySize>,
)

View File

@ -0,0 +1,8 @@
package com.simplemobiletools.camera.models
import androidx.camera.core.CameraSelector
data class CameraSelectorVideoQualities(
val camSelector: CameraSelector,
val qualities: List<VideoQuality>,
)

View File

@ -6,6 +6,7 @@ import com.simplemobiletools.camera.R
data class MySize(val width: Int, val height: Int) { data class MySize(val width: Int, val height: Int) {
val ratio = width / height.toFloat() val ratio = width / height.toFloat()
val pixels: Int = width * height
fun isSixteenToNine() = ratio == 16 / 9f fun isSixteenToNine() = ratio == 16 / 9f
private fun isFiveToThree() = ratio == 5 / 3f private fun isFiveToThree() = ratio == 5 / 3f

View File

@ -0,0 +1,59 @@
package com.simplemobiletools.camera.models
import android.content.Context
import com.simplemobiletools.camera.R
enum class VideoQuality(val width: Int, val height: Int) {
UHD(3840, 2160),
FHD(1920, 1080),
HD(1280, 720),
SD(720, 480);
val pixels: Int = width * height
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / VideoQuality.ONE_MEGA_PIXELS)
val ratio = width / height.toFloat()
private fun isSixteenToNine() = ratio == 16 / 9f
private fun isFiveToThree() = ratio == 5 / 3f
private fun isFourToThree() = ratio == 4 / 3f
private fun isTwoToOne() = ratio == 2f
private fun isThreeToFour() = ratio == 3 / 4f
private fun isThreeToTwo() = ratio == 3 / 2f
private fun isSixToFive() = ratio == 6 / 5f
private fun isNineteenToNine() = ratio == 19 / 9f
private fun isNineteenToEight() = ratio == 19 / 8f
private fun isOneNineToOne() = ratio == 1.9f
private fun isSquare() = width == height
fun getAspectRatio(context: Context) = when {
isSixteenToNine() -> "16:9"
isFiveToThree() -> "5:3"
isFourToThree() -> "4:3"
isThreeToFour() -> "3:4"
isThreeToTwo() -> "3:2"
isSixToFive() -> "6:5"
isOneNineToOne() -> "1.9:1"
isNineteenToNine() -> "19:9"
isNineteenToEight() -> "19:8"
isSquare() -> "1:1"
isTwoToOne() -> "2:1"
else -> context.resources.getString(R.string.other)
}
companion object {
private const val ONE_MEGA_PIXELS = 1000000
}
}