From 74e26568310cfcbfeba0b2ef8e83e1386f9394cf Mon Sep 17 00:00:00 2001 From: darthpaul Date: Fri, 8 Jul 2022 00:12:03 +0100 Subject: [PATCH] try to handle changing video quality and image resolution - CameraX video allowed predefined buckets of qualities UHD, FHD, HD, SD (defined in VideoQuality enum), the CameraXPreview is configured to use the highest quality and CameraX will select the closest corresponding resolution supported by the device. - tentatively add ChangeResolutionDialogX (which would be renamed back to ChangeResolutionDialog) to give user option to select photo resolution and video qualities - add ImageQualityManager which performs the same operation for getting all resolutions supported by a device using the Camera2 API, as defined in the legacy CameraPreview - add VideoQualityManager to manage saving/ getting user selected quality. --- .../camera/dialogs/ChangeResolutionDialogX.kt | 104 ++++++++++++++++++ .../camera/extensions/Quality.kt | 32 ++++++ .../camera/helpers/Config.kt | 15 +++ .../camera/helpers/Constants.kt | 2 + .../camera/helpers/ImageQualityManager.kt | 89 +++++++++++++++ .../camera/helpers/VideoQualityManager.kt | 60 ++++++++++ .../camera/implementations/CameraXPreview.kt | 75 +++++++------ .../models/CameraSelectorImageQualities.kt | 8 ++ .../models/CameraSelectorVideoQualities.kt | 8 ++ .../simplemobiletools/camera/models/MySize.kt | 1 + .../camera/models/VideoQuality.kt | 59 ++++++++++ 11 files changed, 419 insertions(+), 34 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/camera/dialogs/ChangeResolutionDialogX.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/camera/extensions/Quality.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/camera/helpers/ImageQualityManager.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/camera/helpers/VideoQualityManager.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/camera/models/CameraSelectorImageQualities.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/camera/models/CameraSelectorVideoQualities.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/camera/models/VideoQuality.kt diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/dialogs/ChangeResolutionDialogX.kt b/app/src/main/kotlin/com/simplemobiletools/camera/dialogs/ChangeResolutionDialogX.kt new file mode 100644 index 00000000..1b5c69a7 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/camera/dialogs/ChangeResolutionDialogX.kt @@ -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 = listOf(), + private val videoResolutions: List, + 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): ArrayList { + val items = ArrayList(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 + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/extensions/Quality.kt b/app/src/main/kotlin/com/simplemobiletools/camera/extensions/Quality.kt new file mode 100644 index 00000000..017f6c01 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/camera/extensions/Quality.kt @@ -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") + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/camera/helpers/Config.kt index 5ede2c12..6ae1a3ed 100644 --- a/app/src/main/kotlin/com/simplemobiletools/camera/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/camera/helpers/Config.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.camera.helpers import android.content.Context import android.os.Environment import androidx.camera.core.CameraSelector +import com.simplemobiletools.camera.models.VideoQuality import com.simplemobiletools.commons.helpers.BaseConfig import java.io.File @@ -62,6 +63,20 @@ class Config(context: Context) : BaseConfig(context) { get() = prefs.getInt(FRONT_PHOTO_RESOLUTION_INDEX, 0) 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 get() = prefs.getInt(FRONT_VIDEO_RESOLUTION_INDEX, 0) set(frontVideoResIndex) = prefs.edit().putInt(FRONT_VIDEO_RESOLUTION_INDEX, frontVideoResIndex).apply() diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/camera/helpers/Constants.kt index 0b543b7c..b36a6ba2 100644 --- a/app/src/main/kotlin/com/simplemobiletools/camera/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/camera/helpers/Constants.kt @@ -15,6 +15,8 @@ const val FLASHLIGHT_STATE = "flashlight_state" const val INIT_PHOTO_MODE = "init_photo_mode" 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_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_VIDEO_RESOLUTION_INDEX = "front_video_resolution_index_2" const val KEEP_SETTINGS_VISIBLE = "keep_settings_visible" diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/helpers/ImageQualityManager.kt b/app/src/main/kotlin/com/simplemobiletools/camera/helpers/ImageQualityManager.kt new file mode 100644 index 00000000..bad6f719 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/camera/helpers/ImageQualityManager.kt @@ -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() + + 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 { + 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 { + return imageQualities.filter { it.camSelector == cameraSelector } + .flatMap { it.qualities } + .sortedByDescending { it.pixels } + .distinctBy { it.pixels } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/helpers/VideoQualityManager.kt b/app/src/main/kotlin/com/simplemobiletools/camera/helpers/VideoQualityManager.kt new file mode 100644 index 00000000..26f3dc3b --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/camera/helpers/VideoQualityManager.kt @@ -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() + + 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 { + return videoQualities.filter { it.camSelector == cameraSelector } + .flatMap { it.qualities } + .sortedByDescending { it.pixels } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/implementations/CameraXPreview.kt b/app/src/main/kotlin/com/simplemobiletools/camera/implementations/CameraXPreview.kt index 5207a8f6..89bfe1ba 100644 --- a/app/src/main/kotlin/com/simplemobiletools/camera/implementations/CameraXPreview.kt +++ b/app/src/main/kotlin/com/simplemobiletools/camera/implementations/CameraXPreview.kt @@ -1,13 +1,9 @@ package com.simplemobiletools.camera.implementations import android.annotation.SuppressLint -import android.content.ContentValues import android.content.Context import android.hardware.SensorManager import android.hardware.display.DisplayManager -import android.net.Uri -import android.os.Environment -import android.provider.MediaStore import android.util.Log import android.view.Display import android.view.GestureDetector @@ -36,14 +32,7 @@ import androidx.camera.core.ImageCaptureException import androidx.camera.core.Preview import androidx.camera.core.UseCase import androidx.camera.lifecycle.ProcessCameraProvider -import androidx.camera.video.FileDescriptorOutputOptions -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.video.* import androidx.camera.view.PreviewView import androidx.core.content.ContextCompat import androidx.core.view.doOnLayout @@ -52,23 +41,12 @@ import androidx.lifecycle.LifecycleOwner import androidx.window.layout.WindowMetricsCalculator import com.bumptech.glide.load.ImageHeaderParser.UNKNOWN_ORIENTATION import com.simplemobiletools.camera.R -import com.simplemobiletools.camera.extensions.config -import com.simplemobiletools.camera.extensions.getRandomMediaName -import com.simplemobiletools.camera.extensions.toAppFlashMode -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.dialogs.ChangeResolutionDialogX +import com.simplemobiletools.camera.extensions.* +import com.simplemobiletools.camera.helpers.* import com.simplemobiletools.camera.interfaces.MyPreview import com.simplemobiletools.camera.models.MediaOutput -import com.simplemobiletools.commons.extensions.hasPermission 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.max import kotlin.math.min @@ -98,6 +76,8 @@ class CameraXPreview( private val displayManager = activity.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager private val mediaSoundHelper = MediaSoundHelper() 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) { @SuppressLint("RestrictedApi") @@ -146,6 +126,7 @@ class CameraXPreview( private fun startCamera(switching: Boolean = false) { Log.i(TAG, "startCamera: ") + imageQualityManager.initSupportedQualities() val cameraProviderFuture = ProcessCameraProvider.getInstance(activity) cameraProviderFuture.addListener({ try { @@ -163,7 +144,12 @@ class CameraXPreview( private fun bindCameraUseCases() { val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera initialization failed.") 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 preview = buildPreview(aspectRatio, rotation) @@ -174,7 +160,10 @@ class CameraXPreview( cameraSelector, preview, captureUseCase, - ) + ).also { + videoQualityManager.initSupportedQualities(cameraProvider, it) + } + preview?.setSurfaceProvider(previewView.surfaceProvider) setupZoomAndFocus() } @@ -220,22 +209,30 @@ class CameraXPreview( .setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY) .setFlashMode(flashMode) .setJpegQuality(config.photoQuality) - .setTargetAspectRatio(aspectRatio) .setTargetRotation(rotation) + .apply { + imageQualityManager.getUserSelectedResolution(cameraSelector)?.let { resolution -> + Log.i(TAG, "buildImageCapture: resolution=$resolution") + setTargetResolution(resolution) + } ?: setTargetAspectRatio(aspectRatio) + } .build() } private fun buildPreview(aspectRatio: Int, rotation: Int): Preview { return Preview.Builder() - .setTargetAspectRatio(aspectRatio) .setTargetRotation(rotation) + .setTargetAspectRatio(aspectRatio) .build() } private fun buildVideoCapture(): VideoCapture { + val qualitySelector = QualitySelector.from( + videoQualityManager.getUserSelectedQuality(cameraSelector), + FallbackStrategy.lowerQualityOrHigherThan(Quality.SD), + ) val recorder = Recorder.Builder() - //TODO: user control for quality - .setQualitySelector(QualitySelector.from(Quality.FHD)) + .setQualitySelector(qualitySelector) .build() return VideoCapture.withOutput(recorder) } @@ -305,7 +302,18 @@ class CameraXPreview( } 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() { @@ -344,7 +352,6 @@ class CameraXPreview( } override fun tryTakePicture() { - Log.i(TAG, "captureImage: ") val imageCapture = imageCapture ?: throw IllegalStateException("Camera initialization failed.") val metadata = Metadata().apply { diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/models/CameraSelectorImageQualities.kt b/app/src/main/kotlin/com/simplemobiletools/camera/models/CameraSelectorImageQualities.kt new file mode 100644 index 00000000..b354f453 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/camera/models/CameraSelectorImageQualities.kt @@ -0,0 +1,8 @@ +package com.simplemobiletools.camera.models + +import androidx.camera.core.CameraSelector + +data class CameraSelectorImageQualities( + val camSelector: CameraSelector, + val qualities: List, +) diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/models/CameraSelectorVideoQualities.kt b/app/src/main/kotlin/com/simplemobiletools/camera/models/CameraSelectorVideoQualities.kt new file mode 100644 index 00000000..cca1c2ed --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/camera/models/CameraSelectorVideoQualities.kt @@ -0,0 +1,8 @@ +package com.simplemobiletools.camera.models + +import androidx.camera.core.CameraSelector + +data class CameraSelectorVideoQualities( + val camSelector: CameraSelector, + val qualities: List, +) diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/models/MySize.kt b/app/src/main/kotlin/com/simplemobiletools/camera/models/MySize.kt index 96b7b65d..d1a77804 100644 --- a/app/src/main/kotlin/com/simplemobiletools/camera/models/MySize.kt +++ b/app/src/main/kotlin/com/simplemobiletools/camera/models/MySize.kt @@ -6,6 +6,7 @@ import com.simplemobiletools.camera.R data class MySize(val width: Int, val height: Int) { val ratio = width / height.toFloat() + val pixels: Int = width * height fun isSixteenToNine() = ratio == 16 / 9f private fun isFiveToThree() = ratio == 5 / 3f diff --git a/app/src/main/kotlin/com/simplemobiletools/camera/models/VideoQuality.kt b/app/src/main/kotlin/com/simplemobiletools/camera/models/VideoQuality.kt new file mode 100644 index 00000000..9fce732f --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/camera/models/VideoQuality.kt @@ -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 + } +}