Merge pull request #326 from KryptKode/feat/camera-x
try to handle changing video quality and image resolution
This commit is contained in:
commit
3c16ba8853
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
|
@ -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 }
|
||||
}
|
||||
}
|
|
@ -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<Recorder> {
|
||||
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 {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package com.simplemobiletools.camera.models
|
||||
|
||||
import androidx.camera.core.CameraSelector
|
||||
|
||||
data class CameraSelectorImageQualities(
|
||||
val camSelector: CameraSelector,
|
||||
val qualities: List<MySize>,
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
package com.simplemobiletools.camera.models
|
||||
|
||||
import androidx.camera.core.CameraSelector
|
||||
|
||||
data class CameraSelectorVideoQualities(
|
||||
val camSelector: CameraSelector,
|
||||
val qualities: List<VideoQuality>,
|
||||
)
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue