diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
index b9a9df67..f4926e93 100644
--- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
+++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
@@ -5,7 +5,9 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
public class PreferenceConfiguration {
- static final String RES_FPS_PREF_STRING = "list_resolution_fps";
+ static final String RESX_PREF_STRING = "resolution_x";
+ static final String RESY_PREF_STRING = "resolution_y";
+ private static final String FPS_PREF_STRING = "fps";
private static final String DECODER_PREF_STRING = "list_decoders";
static final String BITRATE_PREF_STRING = "seekbar_bitrate";
private static final String STRETCH_PREF_STRING = "checkbox_stretch_video";
@@ -21,10 +23,12 @@ public class PreferenceConfiguration {
private static final int BITRATE_DEFAULT_720_60 = 10;
private static final int BITRATE_DEFAULT_1080_30 = 10;
private static final int BITRATE_DEFAULT_1080_60 = 20;
+ private static final int BITRATE_DEFAULT_MAX = 35;
- private static final String DEFAULT_RES_FPS = "720p60";
+ private static final int DEFAULT_RESX = 1280;
+ private static final int DEFAULT_RESY = 720;
+ private static final String DEFAULT_FPS = "60";
private static final String DEFAULT_DECODER = "auto";
- private static final int DEFAULT_BITRATE = BITRATE_DEFAULT_720_60;
private static final boolean DEFAULT_STRETCH = false;
private static final boolean DEFAULT_SOPS = true;
private static final boolean DEFAULT_DISABLE_TOASTS = false;
@@ -45,49 +49,40 @@ public class PreferenceConfiguration {
public String language;
public boolean listMode, smallIconMode;
- public static int getDefaultBitrate(String resFpsString) {
- if (resFpsString.equals("720p30")) {
- return BITRATE_DEFAULT_720_30;
- }
- else if (resFpsString.equals("720p60")) {
- return BITRATE_DEFAULT_720_60;
- }
- else if (resFpsString.equals("1080p30")) {
- return BITRATE_DEFAULT_1080_30;
- }
- else if (resFpsString.equals("1080p60")) {
- return BITRATE_DEFAULT_1080_60;
- }
- else {
- // Should never get here
- return DEFAULT_BITRATE;
- }
- }
-
public static boolean getDefaultSmallMode(Context context) {
// Use small mode on anything smaller than a 7" tablet
return context.getResources().getConfiguration().smallestScreenWidthDp < 600;
}
+ private static int getFpsInt(SharedPreferences prefs) {
+ try {
+ return Integer.parseInt(prefs.getString(FPS_PREF_STRING, DEFAULT_FPS));
+ } catch (NumberFormatException e) {
+ return Integer.parseInt(DEFAULT_FPS);
+ }
+ }
+
public static int getDefaultBitrate(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- String str = prefs.getString(RES_FPS_PREF_STRING, DEFAULT_RES_FPS);
- if (str.equals("720p30")) {
+ long width = prefs.getInt(RESX_PREF_STRING, DEFAULT_RESX);
+ long height = prefs.getInt(RESY_PREF_STRING, DEFAULT_RESY);
+
+ long product = width * height * getFpsInt(prefs);
+ if (product <= 1280 * 720 * 30) {
return BITRATE_DEFAULT_720_30;
}
- else if (str.equals("720p60")) {
+ else if (product <= 1280 * 720 * 60) {
return BITRATE_DEFAULT_720_60;
}
- else if (str.equals("1080p30")) {
+ else if (product <= 1920 * 1080 * 30) {
return BITRATE_DEFAULT_1080_30;
}
- else if (str.equals("1080p60")) {
+ else if (product <= 1920 * 1080 * 60) {
return BITRATE_DEFAULT_1080_60;
}
else {
- // Should never get here
- return DEFAULT_BITRATE;
+ return BITRATE_DEFAULT_MAX;
}
}
@@ -115,33 +110,9 @@ public class PreferenceConfiguration {
PreferenceConfiguration config = new PreferenceConfiguration();
config.bitrate = prefs.getInt(BITRATE_PREF_STRING, getDefaultBitrate(context));
- String str = prefs.getString(RES_FPS_PREF_STRING, DEFAULT_RES_FPS);
- if (str.equals("720p30")) {
- config.width = 1280;
- config.height = 720;
- config.fps = 30;
- }
- else if (str.equals("720p60")) {
- config.width = 1280;
- config.height = 720;
- config.fps = 60;
- }
- else if (str.equals("1080p30")) {
- config.width = 1920;
- config.height = 1080;
- config.fps = 30;
- }
- else if (str.equals("1080p60")) {
- config.width = 1920;
- config.height = 1080;
- config.fps = 60;
- }
- else {
- // Should never get here
- config.width = 1280;
- config.height = 720;
- config.fps = 60;
- }
+ config.width = prefs.getInt(RESX_PREF_STRING, DEFAULT_RESX);
+ config.height = prefs.getInt(RESY_PREF_STRING, DEFAULT_RESY);
+ config.fps = getFpsInt(prefs);
config.decoder = getDecoderValue(context);
diff --git a/app/src/main/java/com/limelight/preferences/ResolutionPreference.java b/app/src/main/java/com/limelight/preferences/ResolutionPreference.java
new file mode 100644
index 00000000..3016f5de
--- /dev/null
+++ b/app/src/main/java/com/limelight/preferences/ResolutionPreference.java
@@ -0,0 +1,208 @@
+package com.limelight.preferences;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.DialogPreference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.RadioButton;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import com.limelight.R;
+
+public class ResolutionPreference extends DialogPreference {
+ private RadioButton a4_3;
+ private RadioButton a16_9;
+ private RadioButton a16_10;
+ private SeekBar resolutionSeekBar;
+ private TextView resolutionText;
+
+ private int resolutionX;
+ private int resolutionY;
+
+ public ResolutionPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ setDialogLayoutResource(R.layout.dialog_resolution);
+ setPositiveButtonText(android.R.string.ok);
+ setNegativeButtonText(android.R.string.cancel);
+
+ setDialogIcon(null);
+ }
+
+ private int getPreferenceState() {
+ int checkboxState;
+ int sliderState;
+
+ if (a4_3.isChecked()) {
+ checkboxState = 1;
+ }
+ else if (a16_10.isChecked()) {
+ checkboxState = 2;
+ }
+ else {
+ checkboxState = 0;
+ }
+
+ sliderState = resolutionSeekBar.getProgress();
+
+ return checkboxState << 24 | sliderState;
+ }
+
+ private void setPreferenceState(int state) {
+ int checkboxState;
+ int sliderState;
+
+ checkboxState = state >> 24;
+ sliderState = state & 0x00FFFFFF;
+
+ a4_3.setChecked(false);
+ a16_10.setChecked(false);
+ a16_9.setChecked(false);
+
+ if (checkboxState == 1) {
+ a4_3.setChecked(true);
+ }
+ else if (checkboxState == 2) {
+ a16_10.setChecked(true);
+ }
+ else {
+ a16_9.setChecked(true);
+ }
+
+ resolutionSeekBar.setProgress(sliderState);
+ }
+
+ private void updateResolution() {
+ double aspectFactor;
+ int step = resolutionSeekBar.getProgress() + 1;
+
+ if (a4_3.isChecked()) {
+ aspectFactor = 4.0/3.0;
+
+ switch (step) {
+ case 1:
+ // 640x480
+ resolutionY = 480;
+ break;
+ case 2:
+ // 800x600
+ resolutionY = 600;
+ break;
+ case 3:
+ // 1024x768
+ resolutionY = 768;
+ break;
+ case 4:
+ // 1600x1200
+ resolutionY = 1200;
+ break;
+ }
+ }
+ else if (a16_9.isChecked()) {
+ aspectFactor = 16.0/9.0;
+
+ switch (step) {
+ case 1:
+ // 1280x720
+ resolutionY = 720;
+ break;
+ case 2:
+ // 1920x1080
+ resolutionY = 1080;
+ break;
+ case 3:
+ // 2560x1440
+ resolutionY = 1440;
+ break;
+ case 4:
+ // 3840x2160
+ resolutionY = 2160;
+ break;
+ }
+ }
+ else /* if (a16_10.isChecked() */ {
+ aspectFactor = 16.0/10.0;
+
+ switch (step) {
+ case 1:
+ // 1280x800
+ resolutionY = 800;
+ break;
+ case 2:
+ // 1920x1200
+ resolutionY = 1200;
+ break;
+ case 3:
+ // 2560x1600
+ resolutionY = 1600;
+ break;
+ case 4:
+ // 3840x2400
+ resolutionY = 2400;
+ break;
+ }
+ }
+
+ resolutionX = (int)(resolutionY * aspectFactor);
+
+ resolutionText.setText(resolutionX+"x"+resolutionY);
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ if (positiveResult) {
+ SharedPreferences.Editor e = getPreferenceManager().getSharedPreferences().edit();
+ e.putInt(PreferenceConfiguration.RESX_PREF_STRING, resolutionX);
+ e.putInt(PreferenceConfiguration.RESY_PREF_STRING, resolutionY);
+ persistInt(getPreferenceState());
+ e.commit();
+ }
+ }
+
+ @Override
+ protected View onCreateDialogView() {
+ View v = super.onCreateDialogView();
+
+ a4_3 = (RadioButton) v.findViewById(R.id.aspect_4_3);
+ a16_9 = (RadioButton) v.findViewById(R.id.aspect_16_9);
+ a16_10 = (RadioButton) v.findViewById(R.id.aspect_16_10);
+ resolutionText = (TextView) v.findViewById(R.id.resolutionText);
+ resolutionSeekBar = (SeekBar) v.findViewById(R.id.resolutionSeekbar);
+
+ CompoundButton.OnCheckedChangeListener ccListener = new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ updateResolution();
+ }
+ };
+ a4_3.setOnCheckedChangeListener(ccListener);
+ a16_9.setOnCheckedChangeListener(ccListener);
+ a16_10.setOnCheckedChangeListener(ccListener);
+
+ resolutionSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ updateResolution();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+
+ // Check the correct checkbox
+ setPreferenceState(getPersistedInt(0));
+
+ // Set initial resolution value
+ updateResolution();
+
+ return v;
+ }
+}
diff --git a/app/src/main/java/com/limelight/preferences/StreamSettings.java b/app/src/main/java/com/limelight/preferences/StreamSettings.java
index 47982480..983e486f 100644
--- a/app/src/main/java/com/limelight/preferences/StreamSettings.java
+++ b/app/src/main/java/com/limelight/preferences/StreamSettings.java
@@ -51,26 +51,6 @@ public class StreamSettings extends Activity {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
-
- // Add a listener to the FPS and resolution preference
- // so the bitrate can be auto-adjusted
- Preference pref = findPreference(PreferenceConfiguration.RES_FPS_PREF_STRING);
- pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsFragment.this.getActivity());
- String valueStr = (String) newValue;
-
- // Write the new bitrate value
- prefs.edit()
- .putInt(PreferenceConfiguration.BITRATE_PREF_STRING,
- PreferenceConfiguration.getDefaultBitrate(valueStr))
- .apply();
-
- // Allow the original preference change to take place
- return true;
- }
- });
}
}
}
diff --git a/app/src/main/res/layout/dialog_resolution.xml b/app/src/main/res/layout/dialog_resolution.xml
new file mode 100644
index 00000000..d259596d
--- /dev/null
+++ b/app/src/main/res/layout/dialog_resolution.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 44a32405..415c09e1 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -1,16 +1,12 @@
-
- - 720p 30 FPS
- - 720p 60 FPS
- - 1080p 30 FPS
- - 1080p 60 FPS
+
+ - 30 FPS
+ - 60 FPS
-
- - 720p30
- - 720p60
- - 1080p30
- - 1080p60
+
+ - 30
+ - 60
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d5258ef4..76aa5c8b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -85,8 +85,10 @@
Basic Settings
- Select resolution and FPS target
- Setting values too high for your device may cause lag or crashing
+ Select stream resolution
+ Some resolutions may not be supported on your device
+ Select target FPS
+ Some FPS values may not be supported with high resolutions on your device
Select target video bitrate
Lower bitrate to reduce stuttering. Raise bitrate to increase image quality.
Mbps
@@ -115,4 +117,9 @@
Advanced Settings
Change decoder
Software decoding may improve video latency at lower streaming settings
+
+
+ 4:3
+ 16:9
+ 16:10
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index b56f0d15..83ade8ba 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -2,13 +2,17 @@
+
+ android:title="@string/title_fps_list"
+ android:summary="@string/summary_fps_list"
+ android:entries="@array/fps_names"
+ android:entryValues="@array/fps_values"
+ android:defaultValue="60" />