@@ -10,6 +10,7 @@ import android.os.Handler
1010import android.os.Looper
1111import android.provider.Settings
1212import android.util.Log
13+ import android.util.Range
1314import android.view.MotionEvent
1415import android.view.View
1516import android.view.ViewGroup
@@ -54,8 +55,13 @@ class SettingsDialog(val mActivity: MainActivity) :
5455 private var aRToggle: ToggleButton
5556 var torchToggle: ToggleButton
5657 private var gridToggle: ImageView
58+
5759 var videoQualitySpinner: Spinner
58- private lateinit var vQAdapter: ArrayAdapter <String >
60+ var videoFrameRateSpinner: Spinner
61+
62+ private lateinit var videoQualityAdapter: ArrayAdapter <String >
63+ private lateinit var videoFrameRateAdapter: ArrayAdapter <String >
64+
5965 private var focusTimeoutSpinner: Spinner
6066 private var timerSpinner: Spinner
6167
@@ -77,6 +83,7 @@ class SettingsDialog(val mActivity: MainActivity) :
7783 private var enableEISSetting: View
7884 private var selfIlluminationSetting: View
7985 private var videoQualitySetting: View
86+ private var videoFrameRateSetting: LinearLayout
8087 private var timerSetting: View
8188
8289 var settingsFrame: View
@@ -218,19 +225,35 @@ class SettingsDialog(val mActivity: MainActivity) :
218225 videoQualitySpinner.onItemSelectedListener =
219226 object : AdapterView .OnItemSelectedListener {
220227 override fun onItemSelected (
221- p0 : AdapterView <* >? ,
222- p1 : View ? ,
228+ parent : AdapterView <* >? ,
229+ view : View ? ,
223230 position : Int ,
224- p3 : Long
231+ id : Long
225232 ) {
226-
227- val choice = vQAdapter.getItem(position) as String
233+ val choice = videoQualityAdapter.getItem(position) as String
228234 updateVideoQuality(choice)
229235 }
230236
231- override fun onNothingSelected (p0 : AdapterView <* >? ) {}
237+ override fun onNothingSelected (parent : AdapterView <* >? ) {}
238+ }
239+
240+ videoFrameRateSpinner = binding.videoFrameRateSpinner
241+
242+ videoFrameRateSpinner.onItemSelectedListener = object : AdapterView .OnItemSelectedListener {
243+ override fun onItemSelected (
244+ parent : AdapterView <* >? ,
245+ view : View ? ,
246+ position : Int ,
247+ id : Long
248+ ) {
249+ val choice = videoFrameRateAdapter.getItem(position) as String
250+ updateVideoFrameRate(choice)
232251 }
233252
253+ override fun onNothingSelected (parent : AdapterView <* >? ) {}
254+
255+ }
256+
234257 qRadio = binding.qualityRadio
235258 lRadio = binding.latencyRadio
236259
@@ -320,6 +343,7 @@ class SettingsDialog(val mActivity: MainActivity) :
320343 enableEISSetting = binding.enableEisSetting
321344 selfIlluminationSetting = binding.selfIlluminationSetting
322345 videoQualitySetting = binding.videoQualitySetting
346+ videoFrameRateSetting = binding.videoFrameRateSetting
323347 timerSetting = binding.timerSetting
324348
325349 includeAudioToggle = binding.includeAudioSwitch
@@ -369,19 +393,22 @@ class SettingsDialog(val mActivity: MainActivity) :
369393 fun showOnlyRelevantSettings () {
370394 @androidx.camera.camera2.interop.ExperimentalCamera2Interop
371395 if (camConfig.isVideoMode) {
372- includeAudioSetting.visibility = View .VISIBLE
373396 enableEISSetting.visibility = View .GONE
374397 for (mode in Camera2CameraInfo .from(camConfig.camera!! .cameraInfo)
375398 .getCameraCharacteristic(CameraCharacteristics
376399 .CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES )!! ){
377400 if (mode == CameraMetadata .CONTROL_VIDEO_STABILIZATION_MODE_ON )
378401 enableEISSetting.visibility = View .VISIBLE
379402 }
403+ includeAudioSetting.visibility = View .VISIBLE
380404 videoQualitySetting.visibility = View .VISIBLE
405+ videoFrameRateSpinner.visibility = View .VISIBLE
406+ videoFrameRateSetting.visibility = View .VISIBLE
381407 } else {
382408 includeAudioSetting.visibility = View .GONE
383409 enableEISSetting.visibility = View .GONE
384410 videoQualitySetting.visibility = View .GONE
411+ videoFrameRateSetting.visibility = View .GONE
385412 }
386413
387414 selfIlluminationSetting.visibility =
@@ -434,21 +461,23 @@ class SettingsDialog(val mActivity: MainActivity) :
434461 if (resCam) {
435462 camConfig.startCamera(true )
436463 } else {
437- videoQualitySpinner.setSelection(getAvailableQTitles ().indexOf(choice))
464+ videoQualitySpinner.setSelection(getAvailableQualityTitles ().indexOf(choice))
438465
439466 }
440467 }
441468
442- fun titleToQuality (title : String ): Quality {
443- return when (title) {
444- " 2160p (UHD)" -> Quality .UHD
445- " 1080p (FHD)" -> Quality .FHD
446- " 720p (HD)" -> Quality .HD
447- " 480p (SD)" -> Quality .SD
448- else -> {
449- Log .e(" TAG" , " Unknown quality: $title " )
450- Quality .SD
451- }
469+ fun updateVideoFrameRate (choice : String , restartCamera : Boolean = true) {
470+
471+ val videoFrameRate = titleToFrameRateRange(choice)
472+
473+ if (videoFrameRate == camConfig.videoFrameRate) return
474+
475+ camConfig.videoFrameRate = videoFrameRate
476+
477+ if (restartCamera) {
478+ camConfig.startCamera(true )
479+ } else {
480+ videoFrameRateSpinner.setSelection(videoFrameRateAdapter.getPosition(choice))
452481 }
453482 }
454483
@@ -620,27 +649,31 @@ class SettingsDialog(val mActivity: MainActivity) :
620649 return Recorder .getVideoCapabilities(cameraInfo).getSupportedQualities(DynamicRange .SDR )
621650 }
622651
623- private fun getAvailableQTitles (): List <String > {
652+ private fun getAvailableVideoFrameRates (): List <Range <Int >> {
653+ val resSet = camConfig.camera?.cameraInfo?.supportedFrameRateRanges ? : Collections .emptySet()
654+ // Individual fps -> Ranged fps (sorted by lower value of range and then upper for each lower value)
655+ val resList = resSet.sortedWith(compareBy<Range <Int >> { it.lower != it.upper }.thenBy { it.lower }.thenBy { it.upper })
656+ return resList
657+ }
658+
659+ private fun getAvailableQualityTitles (): List <String > {
624660 val titles = arrayListOf<String >()
625661
626662 getAvailableQualities().forEach {
627- titles.add(getTitleFor (it))
663+ titles.add(getTitleForQuality (it))
628664 }
629665
630666 return titles
631667 }
632668
633- private fun getTitleFor (quality : Quality ): String {
634- return when (quality) {
635- Quality .UHD -> " 2160p (UHD)"
636- Quality .FHD -> " 1080p (FHD)"
637- Quality .HD -> " 720p (HD)"
638- Quality .SD -> " 480p (SD)"
639- else -> {
640- Log .i(" TAG" , " Unknown constant: $quality " )
641- " Unknown"
642- }
669+ private fun getAvailableFRTitles (): List <String > {
670+ val titles = arrayListOf<String >()
671+
672+ getAvailableVideoFrameRates().forEach {
673+ titles.add(getTitleForFrameRateRange(it))
643674 }
675+
676+ return titles
644677 }
645678
646679 fun updateGridToggleUI () {
@@ -691,24 +724,91 @@ class SettingsDialog(val mActivity: MainActivity) :
691724 slideDialogDown()
692725 }
693726
694- fun reloadQualities () {
727+ fun reloadVideoSettings () {
695728
696- val titles = getAvailableQTitles()
729+ val qualityTitles = getAvailableQualityTitles()
730+ val frameRateTitles = getAvailableFRTitles()
697731
698- vQAdapter = ArrayAdapter <String >(
732+ videoQualityAdapter = ArrayAdapter <String >(
699733 mActivity,
700734 android.R .layout.simple_spinner_item,
701- titles
735+ qualityTitles
702736 )
703737
704- vQAdapter .setDropDownViewResource(
738+ videoQualityAdapter .setDropDownViewResource(
705739 android.R .layout.simple_spinner_dropdown_item
706740 )
707741
708- videoQualitySpinner.adapter = vQAdapter
742+ videoQualitySpinner.adapter = videoQualityAdapter
709743
710- if (camConfig.videoQuality != Quality .HIGHEST ) {
711- videoQualitySpinner.setSelection(titles.indexOf(getTitleFor(camConfig.videoQuality)))
744+ videoFrameRateAdapter = ArrayAdapter <String >(
745+ mActivity,
746+ android.R .layout.simple_spinner_item,
747+ frameRateTitles
748+ )
749+
750+ videoFrameRateAdapter.setDropDownViewResource(
751+ android.R .layout.simple_spinner_dropdown_item
752+ )
753+
754+ videoFrameRateSpinner.adapter = videoFrameRateAdapter
755+
756+ videoFrameRateSpinner.setSelection(videoFrameRateAdapter.getPosition(getTitleForFrameRateRange(camConfig.videoFrameRate)))
757+
758+ if (camConfig.videoQuality != CamConfig .SettingValues .Default .VIDEO_QUALITY ) {
759+ videoQualitySpinner.setSelection(videoQualityAdapter.getPosition(getTitleForQuality(camConfig.videoQuality)))
760+ }
761+ }
762+
763+ companion object {
764+ fun titleToQuality (title : String ): Quality {
765+ return when (title) {
766+ " 2160p (UHD)" -> Quality .UHD
767+ " 1080p (FHD)" -> Quality .FHD
768+ " 720p (HD)" -> Quality .HD
769+ " 480p (SD)" -> Quality .SD
770+ else -> {
771+ Log .e(" TAG" , " Unknown quality: $title " )
772+ Quality .SD
773+ }
774+ }
775+ }
776+
777+ fun titleToFrameRateRange (title : String ): Range <Int > {
778+ val titleWithoutFps = title.dropLast(4 )
779+
780+ if (titleWithoutFps.contains(" -" )) {
781+ val lUArr = titleWithoutFps.split(" -" )
782+
783+ val lower = lUArr[0 ].dropLast(1 ).toInt()
784+ val upper = lUArr[1 ].drop(1 ).toInt()
785+
786+ return Range (lower, upper)
787+ } else {
788+ val fps = titleWithoutFps.toInt()
789+ return Range (fps, fps)
790+ }
791+ }
792+ }
793+
794+ fun getTitleForFrameRateRange (range : Range <Int >) : String {
795+ if (range.lower == range.upper) {
796+ return " ${range.lower} fps"
797+ } else {
798+ return " ${range.lower} - ${range.upper} fps"
799+ }
800+ }
801+
802+ private fun getTitleForQuality (quality : Quality ): String {
803+ return when (quality) {
804+ Quality .UHD -> " 2160p (UHD)"
805+ Quality .FHD -> " 1080p (FHD)"
806+ Quality .HD -> " 720p (HD)"
807+ Quality .SD -> " 480p (SD)"
808+ else -> {
809+ Log .i(" TAG" , " Unknown constant: $quality " )
810+ " Unknown"
811+ }
712812 }
713813 }
714814}
0 commit comments