Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e322baf1d7 | |||
| 173a07cb59 | |||
| 364afff860 | |||
| 1b59e61b8e | |||
| b1f453f7ba | |||
| 175e842feb |
+2
-2
@@ -7,8 +7,8 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 30
|
||||
|
||||
versionName "9.8"
|
||||
versionCode = 251
|
||||
versionName "9.8.1"
|
||||
versionCode = 252
|
||||
}
|
||||
|
||||
flavorDimensions "root"
|
||||
|
||||
@@ -630,6 +630,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
// On M, we can explicitly set the optimal display mode
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
Display.Mode bestMode = display.getMode();
|
||||
boolean isNativeResolutionStream = PreferenceConfiguration.isNativeResolution(prefConfig.width, prefConfig.height);
|
||||
boolean refreshRateIsGood = isRefreshRateGoodMatch(bestMode.getRefreshRate());
|
||||
for (Display.Mode candidate : display.getSupportedModes()) {
|
||||
boolean refreshRateReduced = candidate.getRefreshRate() < bestMode.getRefreshRate();
|
||||
@@ -641,14 +642,15 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
LimeLog.info("Examining display mode: "+candidate.getPhysicalWidth()+"x"+
|
||||
candidate.getPhysicalHeight()+"x"+candidate.getRefreshRate());
|
||||
|
||||
if (candidate.getPhysicalWidth() > 4096) {
|
||||
if (candidate.getPhysicalWidth() > 4096 && prefConfig.width <= 4096) {
|
||||
// Avoid resolutions options above 4K to be safe
|
||||
continue;
|
||||
}
|
||||
|
||||
// On non-4K streams, we force the resolution to never change unless it's above
|
||||
// 60 FPS, which may require a resolution reduction due to HDMI bandwidth limitations.
|
||||
if (prefConfig.width < 3840 && prefConfig.fps <= 60) {
|
||||
// 60 FPS, which may require a resolution reduction due to HDMI bandwidth limitations,
|
||||
// or it's a native resolution stream.
|
||||
if (prefConfig.width < 3840 && prefConfig.fps <= 60 && !isNativeResolutionStream) {
|
||||
if (display.getMode().getPhysicalWidth() != candidate.getPhysicalWidth() ||
|
||||
display.getMode().getPhysicalHeight() != candidate.getPhysicalHeight()) {
|
||||
continue;
|
||||
|
||||
@@ -319,20 +319,23 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
|
||||
// Add a header with PC status details
|
||||
menu.clearHeader();
|
||||
String headerTitle = computer.details.name + " - ";
|
||||
switch (computer.details.state)
|
||||
{
|
||||
case ONLINE:
|
||||
menu.setHeaderTitle(R.string.pcview_menu_header_online);
|
||||
headerTitle += getResources().getString(R.string.pcview_menu_header_online);
|
||||
break;
|
||||
case OFFLINE:
|
||||
menu.setHeaderIcon(R.drawable.ic_pc_offline);
|
||||
menu.setHeaderTitle(R.string.pcview_menu_header_offline);
|
||||
headerTitle += getResources().getString(R.string.pcview_menu_header_offline);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
menu.setHeaderTitle(R.string.pcview_menu_header_unknown);
|
||||
headerTitle += getResources().getString(R.string.pcview_menu_header_unknown);
|
||||
break;
|
||||
}
|
||||
|
||||
menu.setHeaderTitle(headerTitle);
|
||||
|
||||
// Inflate the context menu
|
||||
if (computer.details.state == ComputerDetails.State.OFFLINE ||
|
||||
computer.details.state == ComputerDetails.State.UNKNOWN) {
|
||||
|
||||
@@ -638,7 +638,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public int submitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int decodeUnitType,
|
||||
int frameNumber, long receiveTimeMs) {
|
||||
int frameNumber, long receiveTimeMs, long enqueueTimeMs) {
|
||||
if (stopping) {
|
||||
// Don't bother if we're stopping
|
||||
return MoonBridge.DR_OK;
|
||||
@@ -699,11 +699,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
|
||||
int inputBufferIndex;
|
||||
ByteBuffer buf;
|
||||
|
||||
long timestampUs = System.nanoTime() / 1000;
|
||||
long timestampUs = enqueueTimeMs * 1000;
|
||||
|
||||
if (!FRAME_RENDER_TIME_ONLY) {
|
||||
// Count time from first packet received to decode start
|
||||
activeWindowVideoStats.totalTimeMs += (timestampUs / 1000) - receiveTimeMs;
|
||||
// Count time from first packet received to enqueue time as receive time
|
||||
// We will count DU queue time as part of decoding, because it is directly
|
||||
// caused by a slow decoder.
|
||||
activeWindowVideoStats.totalTimeMs += enqueueTimeMs - receiveTimeMs;
|
||||
}
|
||||
|
||||
if (timestampUs <= lastTimestampUs) {
|
||||
|
||||
@@ -10,7 +10,7 @@ public abstract class VideoDecoderRenderer {
|
||||
// This is called once for each frame-start NALU. This means it will be called several times
|
||||
// for an IDR frame which contains several parameter sets and the I-frame data.
|
||||
public abstract int submitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int decodeUnitType,
|
||||
int frameNumber, long receiveTimeMs);
|
||||
int frameNumber, long receiveTimeMs, long enqueueTimeMs);
|
||||
|
||||
public abstract void cleanup();
|
||||
|
||||
|
||||
@@ -149,11 +149,11 @@ public class MoonBridge {
|
||||
}
|
||||
|
||||
public static int bridgeDrSubmitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength,
|
||||
int decodeUnitType,
|
||||
int frameNumber, long receiveTimeMs) {
|
||||
int decodeUnitType, int frameNumber,
|
||||
long receiveTimeMs, long enqueueTimeMs) {
|
||||
if (videoRenderer != null) {
|
||||
return videoRenderer.submitDecodeUnit(decodeUnitData, decodeUnitLength,
|
||||
decodeUnitType, frameNumber, receiveTimeMs);
|
||||
decodeUnitType, frameNumber, receiveTimeMs, enqueueTimeMs);
|
||||
}
|
||||
else {
|
||||
return DR_OK;
|
||||
|
||||
@@ -109,6 +109,30 @@ public class PreferenceConfiguration {
|
||||
public boolean touchscreenTrackpad;
|
||||
public MoonBridge.AudioConfiguration audioConfiguration;
|
||||
|
||||
public static boolean isNativeResolution(int width, int height) {
|
||||
// It's not a native resolution if it matches an existing resolution option
|
||||
if (width == 640 && height == 360) {
|
||||
return false;
|
||||
}
|
||||
else if (width == 854 && height == 480) {
|
||||
return false;
|
||||
}
|
||||
else if (width == 1280 && height == 720) {
|
||||
return false;
|
||||
}
|
||||
else if (width == 1920 && height == 1080) {
|
||||
return false;
|
||||
}
|
||||
else if (width == 2560 && height == 1440) {
|
||||
return false;
|
||||
}
|
||||
else if (width == 3840 && height == 2160) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String convertFromLegacyResolutionString(String resString) {
|
||||
if (resString.equalsIgnoreCase("360p")) {
|
||||
return RES_360P;
|
||||
|
||||
@@ -68,7 +68,7 @@ public class StreamSettings extends Activity {
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragment {
|
||||
private boolean nativeResolutionOptionPresent = false;
|
||||
private int nativeResolutionStartIndex = Integer.MAX_VALUE;
|
||||
|
||||
private void setValue(String preferenceKey, String value) {
|
||||
ListPreference pref = (ListPreference) findPreference(preferenceKey);
|
||||
@@ -76,36 +76,35 @@ public class StreamSettings extends Activity {
|
||||
pref.setValue(value);
|
||||
}
|
||||
|
||||
private void updateNativeResolutionEntry(int nativeWidth, int nativeHeight) {
|
||||
private void addNativeResolutionEntry(int nativeWidth, int nativeHeight) {
|
||||
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.RESOLUTION_PREF_STRING);
|
||||
|
||||
String nameSuffix = " ("+nativeWidth+"x"+nativeHeight+")";
|
||||
String newName = getResources().getString(R.string.resolution_prefix_native) + " ("+nativeWidth+"x"+nativeHeight+")";
|
||||
String newValue = nativeWidth+"x"+nativeHeight;
|
||||
|
||||
CharSequence[] entries = pref.getEntries();
|
||||
CharSequence[] values = pref.getEntryValues();
|
||||
|
||||
// Check if the native resolution is already present
|
||||
for (CharSequence value : values) {
|
||||
if (newValue.equals(value.toString())) {
|
||||
// It is present in the default list, so remove the native option
|
||||
nativeResolutionOptionPresent = false;
|
||||
|
||||
pref.setEntries(Arrays.copyOf(entries, entries.length - 1));
|
||||
pref.setEntryValues(Arrays.copyOf(values, values.length - 1));
|
||||
|
||||
// It is present in the default list, so don't add it again
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the name suffix to the native option
|
||||
entries[entries.length - 1] = entries[entries.length - 1].toString() + nameSuffix;
|
||||
values[values.length - 1] = newValue;
|
||||
CharSequence[] newEntries = Arrays.copyOf(pref.getEntries(), pref.getEntries().length + 1);
|
||||
CharSequence[] newValues = Arrays.copyOf(values, values.length + 1);
|
||||
|
||||
pref.setEntries(entries);
|
||||
pref.setEntryValues(values);
|
||||
// Add the new native option
|
||||
newEntries[newEntries.length - 1] = newName;
|
||||
newValues[newValues.length - 1] = newValue;
|
||||
|
||||
nativeResolutionOptionPresent = true;
|
||||
pref.setEntries(newEntries);
|
||||
pref.setEntryValues(newValues);
|
||||
|
||||
if (newValues.length - 1 < nativeResolutionStartIndex) {
|
||||
nativeResolutionStartIndex = newValues.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeValue(String preferenceKey, String value, Runnable onMatched) {
|
||||
@@ -226,7 +225,6 @@ public class StreamSettings extends Activity {
|
||||
// HEVC Decoder: OMX.amlogic.hevc.decoder.awesome
|
||||
// AVC supported width range: 64 - 384
|
||||
// HEVC supported width range: 64 - 544
|
||||
int nativeWidth = 0, nativeHeight = 0;
|
||||
for (Display.Mode candidate : display.getSupportedModes()) {
|
||||
// Some devices report their dimensions in the portrait orientation
|
||||
// where height > width. Normalize these to the conventional width > height
|
||||
@@ -235,12 +233,7 @@ public class StreamSettings extends Activity {
|
||||
int width = Math.max(candidate.getPhysicalWidth(), candidate.getPhysicalHeight());
|
||||
int height = Math.min(candidate.getPhysicalWidth(), candidate.getPhysicalHeight());
|
||||
|
||||
if (width > nativeWidth) {
|
||||
nativeWidth = width;
|
||||
}
|
||||
if (height > nativeHeight) {
|
||||
nativeHeight = height;
|
||||
}
|
||||
addNativeResolutionEntry(width, height);
|
||||
|
||||
if ((width >= 3840 || height >= 2160) && maxSupportedResW < 3840) {
|
||||
maxSupportedResW = 3840;
|
||||
@@ -257,8 +250,6 @@ public class StreamSettings extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
updateNativeResolutionEntry(nativeWidth, nativeHeight);
|
||||
|
||||
// This must be called to do runtime initialization before calling functions that evaluate
|
||||
// decoder lists.
|
||||
MediaCodecHelper.initialize(getContext(), GlPreferences.readPreferences(getContext()).glRenderer);
|
||||
@@ -347,7 +338,7 @@ public class StreamSettings extends Activity {
|
||||
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
||||
int width = Math.max(display.getWidth(), display.getHeight());
|
||||
int height = Math.min(display.getWidth(), display.getHeight());
|
||||
updateNativeResolutionEntry(width, height);
|
||||
addNativeResolutionEntry(width, height);
|
||||
}
|
||||
|
||||
if (!PreferenceConfiguration.readPreferences(this.getActivity()).unlockFps) {
|
||||
@@ -458,25 +449,23 @@ public class StreamSettings extends Activity {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsFragment.this.getActivity());
|
||||
String valueStr = (String) newValue;
|
||||
|
||||
if (nativeResolutionOptionPresent) {
|
||||
// Detect if this value is the native resolution option
|
||||
CharSequence[] values = ((ListPreference)preference).getEntryValues();
|
||||
boolean isNativeRes = true;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
// If get a match prior to the end, it's not native res
|
||||
if (valueStr.equals(values[i].toString()) && i < values.length - 1) {
|
||||
isNativeRes = false;
|
||||
break;
|
||||
}
|
||||
// Detect if this value is the native resolution option
|
||||
CharSequence[] values = ((ListPreference)preference).getEntryValues();
|
||||
boolean isNativeRes = true;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
// Look for a match prior to the start of the native resolution entries
|
||||
if (valueStr.equals(values[i].toString()) && i < nativeResolutionStartIndex) {
|
||||
isNativeRes = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is native resolution, show the warning dialog
|
||||
if (isNativeRes) {
|
||||
Dialog.displayDialog(getActivity(),
|
||||
getResources().getString(R.string.title_native_res_dialog),
|
||||
getResources().getString(R.string.text_native_res_dialog),
|
||||
false);
|
||||
}
|
||||
// If this is native resolution, show the warning dialog
|
||||
if (isNativeRes) {
|
||||
Dialog.displayDialog(getActivity(),
|
||||
getResources().getString(R.string.title_native_res_dialog),
|
||||
getResources().getString(R.string.text_native_res_dialog),
|
||||
false);
|
||||
}
|
||||
|
||||
// Write the new bitrate value
|
||||
|
||||
@@ -79,7 +79,7 @@ Java_com_limelight_nvstream_jni_MoonBridge_init(JNIEnv *env, jclass clazz) {
|
||||
BridgeDrStartMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrStart", "()V");
|
||||
BridgeDrStopMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrStop", "()V");
|
||||
BridgeDrCleanupMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrCleanup", "()V");
|
||||
BridgeDrSubmitDecodeUnitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrSubmitDecodeUnit", "([BIIIJ)I");
|
||||
BridgeDrSubmitDecodeUnitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrSubmitDecodeUnit", "([BIIIJJ)I");
|
||||
BridgeArInitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArInit", "(III)I");
|
||||
BridgeArStartMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArStart", "()V");
|
||||
BridgeArStopMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArStop", "()V");
|
||||
@@ -157,7 +157,8 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
|
||||
|
||||
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
|
||||
DecodedFrameBuffer, currentEntry->length, currentEntry->bufferType,
|
||||
decodeUnit->frameNumber, (jlong)decodeUnit->receiveTimeMs);
|
||||
decodeUnit->frameNumber, (jlong)decodeUnit->receiveTimeMs,
|
||||
(jlong)decodeUnit->enqueueTimeMs);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// We will crash here
|
||||
(*JVM)->DetachCurrentThread(JVM);
|
||||
@@ -178,7 +179,7 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
|
||||
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
|
||||
DecodedFrameBuffer, offset, BUFFER_TYPE_PICDATA,
|
||||
decodeUnit->frameNumber,
|
||||
(jlong)decodeUnit->receiveTimeMs);
|
||||
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// We will crash here
|
||||
(*JVM)->DetachCurrentThread(JVM);
|
||||
|
||||
Submodule app/src/main/jni/moonlight-core/moonlight-common-c updated: 3aa2463856...021fe902d9
@@ -7,8 +7,9 @@
|
||||
<item>1080p</item>
|
||||
<item>1440p</item>
|
||||
<item>4K</item>
|
||||
<item>Native</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Keep this in sync with PreferenceConfiguration.isNativeResolution()! -->
|
||||
<string-array name="resolution_values" translatable="false">
|
||||
<item>640x360</item>
|
||||
<item>854x480</item>
|
||||
@@ -16,7 +17,6 @@
|
||||
<item>1920x1080</item>
|
||||
<item>2560x1440</item>
|
||||
<item>3840x2160</item>
|
||||
<item>Native</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="fps_names">
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<string name="help_loading_msg">Loading help page…</string>
|
||||
|
||||
<!-- PC view menu entries -->
|
||||
<string name="pcview_menu_header_online">PC Status: Online</string>
|
||||
<string name="pcview_menu_header_offline">PC Status: Offline</string>
|
||||
<string name="pcview_menu_header_unknown">PC Status: Refreshing</string>
|
||||
<string name="pcview_menu_header_online">Online</string>
|
||||
<string name="pcview_menu_header_offline">Offline</string>
|
||||
<string name="pcview_menu_header_unknown">Refreshing</string>
|
||||
<string name="pcview_menu_app_list">View All Apps</string>
|
||||
<string name="pcview_menu_pair_pc">Pair with PC</string>
|
||||
<string name="pcview_menu_unpair_pc">Unpair</string>
|
||||
@@ -147,6 +147,7 @@
|
||||
<string name="summary_seekbar_bitrate">Increase for better image quality. Decrease to improve performance on slower connections.</string>
|
||||
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
|
||||
<string name="title_checkbox_stretch_video">Stretch video to full-screen</string>
|
||||
<string name="resolution_prefix_native">Native</string>
|
||||
|
||||
<string name="category_audio_settings">Audio Settings</string>
|
||||
<string name="title_audio_config_list">Surround sound configuration</string>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
- Added support for multiple native resolution options
|
||||
- Improve accuracy of decoder latency reports for very slow decoders
|
||||
- Minor UI improvements
|
||||
Reference in New Issue
Block a user