mirror of
https://github.com/moonlight-stream/moonlight-ios.git
synced 2026-02-16 02:20:53 +00:00
dialog for custom resolution
This commit is contained in:
committed by
Cameron Gutman
parent
7f7770a42c
commit
29ba055024
@@ -48,6 +48,11 @@ static const int bitrateTable[] = {
|
||||
150000,
|
||||
};
|
||||
|
||||
const int RESOLUTION_TABLE_SIZE = 5;
|
||||
const int RESOLUTION_TABLE_CUSTOM_INDEX = RESOLUTION_TABLE_SIZE - 1;
|
||||
const int RESOLUTION_TABLE_DEFAULT_INDEX = 1;
|
||||
CGSize resolutionTable[RESOLUTION_TABLE_SIZE];
|
||||
|
||||
-(int)getSliderValueForBitrate:(NSInteger)bitrate {
|
||||
int i;
|
||||
|
||||
@@ -119,7 +124,13 @@ static const int bitrateTable[] = {
|
||||
|
||||
// Ensure we pick a bitrate that falls exactly onto a slider notch
|
||||
_bitrate = bitrateTable[[self getSliderValueForBitrate:[currentSettings.bitrate intValue]]];
|
||||
|
||||
|
||||
resolutionTable[0] = CGSizeMake(640, 360);
|
||||
resolutionTable[1] = CGSizeMake(1280, 720);
|
||||
resolutionTable[2] = CGSizeMake(1920, 1080);
|
||||
resolutionTable[3] = CGSizeMake(3840, 2160);
|
||||
resolutionTable[4] = CGSizeMake([currentSettings.width integerValue], [currentSettings.height integerValue]); // custom initial value
|
||||
|
||||
NSInteger framerate;
|
||||
switch ([currentSettings.framerate integerValue]) {
|
||||
case 30:
|
||||
@@ -133,29 +144,15 @@ static const int bitrateTable[] = {
|
||||
framerate = 2;
|
||||
break;
|
||||
}
|
||||
NSInteger resolution;
|
||||
switch ([currentSettings.height integerValue]) {
|
||||
case 360:
|
||||
resolution = 0;
|
||||
break;
|
||||
default:
|
||||
case 720:
|
||||
resolution = 1;
|
||||
break;
|
||||
case 1080:
|
||||
resolution = 2;
|
||||
break;
|
||||
case 2160:
|
||||
resolution = 4;
|
||||
break;
|
||||
}
|
||||
// because switch case doesn't work with "expression"
|
||||
if ([currentSettings.height integerValue] == [self getMainScreenHeight]) {
|
||||
resolution = 3;
|
||||
}
|
||||
|
||||
NSString *newTitle = [NSString stringWithFormat:@"%dx%d", (int) self.getMainScreenWidth, (int) self.getMainScreenHeight];
|
||||
[self.resolutionSelector setTitle:newTitle forSegmentAtIndex:3];
|
||||
NSInteger resolution = RESOLUTION_TABLE_DEFAULT_INDEX;
|
||||
for (int i = 0; i < RESOLUTION_TABLE_SIZE; i++) {
|
||||
if ((int) resolutionTable[i].height == [currentSettings.height intValue]
|
||||
&& (int) resolutionTable[i].width == [currentSettings.width intValue]) {
|
||||
resolution = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only show the 120 FPS option if we have a > 60-ish Hz display
|
||||
bool enable120Fps = false;
|
||||
@@ -172,13 +169,15 @@ static const int bitrateTable[] = {
|
||||
// they support HEVC decoding (A9 or later).
|
||||
if (@available(iOS 11.0, tvOS 11.0, *)) {
|
||||
if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) {
|
||||
[self.resolutionSelector removeSegmentAtIndex:4 animated:NO];
|
||||
[self.resolutionSelector removeSegmentAtIndex:3 animated:NO];
|
||||
if (resolution >= 3) resolution--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
[self.resolutionSelector removeSegmentAtIndex:4 animated:NO];
|
||||
[self.resolutionSelector removeSegmentAtIndex:3 animated:NO];
|
||||
if (resolution >= 3) resolution--;
|
||||
}
|
||||
|
||||
|
||||
// Disable the HEVC selector if HEVC is not supported by the hardware
|
||||
// or the version of iOS. See comment in Connection.m for reasoning behind
|
||||
// the iOS 11.3 check.
|
||||
@@ -208,9 +207,9 @@ static const int bitrateTable[] = {
|
||||
[self.audioOnPCSelector setSelectedSegmentIndex:currentSettings.playAudioOnPC ? 1 : 0];
|
||||
NSInteger onscreenControls = [currentSettings.onscreenControls integerValue];
|
||||
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
||||
[self.resolutionSelector addTarget:self action:@selector(newResolutionFpsChosen) forControlEvents:UIControlEventValueChanged];
|
||||
[self.resolutionSelector addTarget:self action:@selector(newResolutionChosen) forControlEvents:UIControlEventValueChanged];
|
||||
[self.framerateSelector setSelectedSegmentIndex:framerate];
|
||||
[self.framerateSelector addTarget:self action:@selector(newResolutionFpsChosen) forControlEvents:UIControlEventValueChanged];
|
||||
[self.framerateSelector addTarget:self action:@selector(updateBitrate) forControlEvents:UIControlEventValueChanged];
|
||||
[self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls];
|
||||
[self.onscreenControlSelector setEnabled:!currentSettings.absoluteTouchMode];
|
||||
[self.bitrateSlider setMinimumValue:0];
|
||||
@@ -218,6 +217,7 @@ static const int bitrateTable[] = {
|
||||
[self.bitrateSlider setValue:[self getSliderValueForBitrate:_bitrate] animated:YES];
|
||||
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
||||
[self updateBitrateText];
|
||||
[self updateCustomResolutionText];
|
||||
}
|
||||
|
||||
- (void) touchModeChanged {
|
||||
@@ -225,7 +225,7 @@ static const int bitrateTable[] = {
|
||||
[self.onscreenControlSelector setEnabled:[self.touchModeSelector selectedSegmentIndex] == 0];
|
||||
}
|
||||
|
||||
- (void) newResolutionFpsChosen {
|
||||
- (void) updateBitrate {
|
||||
NSInteger fps = [self getChosenFrameRate];
|
||||
NSInteger width = [self getChosenStreamWidth];
|
||||
NSInteger height = [self getChosenStreamHeight];
|
||||
@@ -264,6 +264,63 @@ static const int bitrateTable[] = {
|
||||
[self updateBitrateText];
|
||||
}
|
||||
|
||||
- (void) newResolutionChosen {
|
||||
BOOL lastSegmentSelected = [self.resolutionSelector selectedSegmentIndex] + 1 == [self.resolutionSelector numberOfSegments];
|
||||
if (lastSegmentSelected) {
|
||||
[self promptCustomResolutionDialog];
|
||||
}
|
||||
[self updateBitrate];
|
||||
}
|
||||
|
||||
- (void) promptCustomResolutionDialog {
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle: @"Custom resolution" message: @"Choose a custom width and height" preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||
textField.placeholder = @"width ex: 1920";
|
||||
textField.clearButtonMode = UITextFieldViewModeAlways;
|
||||
textField.borderStyle = UITextBorderStyleRoundedRect;
|
||||
textField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
textField.text = [NSString stringWithFormat:@"%d", (int) resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX].width];
|
||||
}];
|
||||
|
||||
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||
textField.placeholder = @"height ex: 1080";
|
||||
textField.clearButtonMode = UITextFieldViewModeAlways;
|
||||
textField.borderStyle = UITextBorderStyleRoundedRect;
|
||||
textField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
textField.text = [NSString stringWithFormat:@"%d", (int) resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX].height];
|
||||
}];
|
||||
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSArray * textfields = alertController.textFields;
|
||||
UITextField *widthField = textfields[0];
|
||||
UITextField *heightField = textfields[1];
|
||||
|
||||
resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX] = CGSizeMake(
|
||||
[widthField.text integerValue],
|
||||
[heightField.text integerValue]
|
||||
);
|
||||
[self updateBitrate];
|
||||
[self updateCustomResolutionText];
|
||||
}]];
|
||||
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
||||
[self.resolutionSelector setSelectedSegmentIndex:RESOLUTION_TABLE_DEFAULT_INDEX];
|
||||
[self updateBitrate];
|
||||
}]];
|
||||
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void) updateCustomResolutionText {
|
||||
BOOL customResolutionEqualsDefaultResolution = resolutionTable[RESOLUTION_TABLE_DEFAULT_INDEX].width == resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX].width && resolutionTable[RESOLUTION_TABLE_DEFAULT_INDEX].height == resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX].height;
|
||||
|
||||
if (!customResolutionEqualsDefaultResolution) {
|
||||
NSString *newTitle = [NSString stringWithFormat:@"Custom %dx%d", (int) resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX].width, (int) resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX].height];
|
||||
[self.resolutionSelector setTitle:newTitle forSegmentAtIndex:[self.resolutionSelector numberOfSegments] - 1];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) bitrateSliderMoved {
|
||||
assert(self.bitrateSlider.value < (sizeof(bitrateTable) / sizeof(*bitrateTable)));
|
||||
_bitrate = bitrateTable[(int)self.bitrateSlider.value];
|
||||
@@ -288,54 +345,24 @@ static const int bitrateTable[] = {
|
||||
}
|
||||
}
|
||||
|
||||
- (UIEdgeInsets) getSafeAreaInsets {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
return UIApplication.sharedApplication.keyWindow.safeAreaInsets;
|
||||
} else {
|
||||
// todo: find a way to calculate the safe area for previous version
|
||||
return UIEdgeInsetsMake(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger) getMainScreenHeight {
|
||||
CGFloat scale = UIScreen.mainScreen.scale;
|
||||
UIEdgeInsets insets = [self getSafeAreaInsets];
|
||||
CGFloat top = insets.top;
|
||||
CGFloat bottom = insets.bottom;
|
||||
CGFloat height = UIScreen.mainScreen.bounds.size.height;
|
||||
|
||||
return scale * (height - top - bottom);
|
||||
}
|
||||
|
||||
- (NSInteger) getMainScreenWidth {
|
||||
CGFloat scale = UIScreen.mainScreen.scale;
|
||||
UIEdgeInsets insets = [self getSafeAreaInsets];
|
||||
CGFloat left = insets.left;
|
||||
CGFloat right = insets.right;
|
||||
CGFloat width = UIScreen.mainScreen.bounds.size.width;
|
||||
|
||||
return scale * (width - left - right);
|
||||
}
|
||||
|
||||
- (NSInteger) getChosenStreamHeight {
|
||||
const int mainScreenHeight = (int)[self getMainScreenHeight];
|
||||
const int resolutionTable[] = { 360, 720, 1080, mainScreenHeight, 2160 };
|
||||
// because the 4k resolution can be removed
|
||||
BOOL lastSegmentSelected = [self.resolutionSelector selectedSegmentIndex] + 1 == [self.resolutionSelector numberOfSegments];
|
||||
if (lastSegmentSelected) {
|
||||
return resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX].height;
|
||||
}
|
||||
|
||||
return resolutionTable[[self.resolutionSelector selectedSegmentIndex]];
|
||||
return resolutionTable[[self.resolutionSelector selectedSegmentIndex]].height;
|
||||
}
|
||||
|
||||
- (NSInteger) getChosenStreamWidth {
|
||||
const NSInteger choosenHeight = [self getChosenStreamHeight];
|
||||
switch (choosenHeight) {
|
||||
case 360:
|
||||
case 720:
|
||||
case 1080:
|
||||
case 2160:
|
||||
// Assumes fixed 16:9 aspect ratio
|
||||
return choosenHeight * 16 / 9;
|
||||
default:
|
||||
return [self getMainScreenWidth];
|
||||
// because the 4k resolution can be removed
|
||||
BOOL lastSegmentSelected = [self.resolutionSelector selectedSegmentIndex] + 1 == [self.resolutionSelector numberOfSegments];
|
||||
if (lastSegmentSelected) {
|
||||
return resolutionTable[RESOLUTION_TABLE_CUSTOM_INDEX].width;
|
||||
}
|
||||
|
||||
return resolutionTable[[self.resolutionSelector selectedSegmentIndex]].width;
|
||||
}
|
||||
|
||||
- (void) saveSettings {
|
||||
|
||||
@@ -70,15 +70,15 @@
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="ckc-Dm-8ex">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" apportionsSegmentWidthsByContent="YES" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="ckc-Dm-8ex">
|
||||
<rect key="frame" x="16" y="49" width="459" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="360p"/>
|
||||
<segment title="720p"/>
|
||||
<segment title="1080p"/>
|
||||
<segment title="Native"/>
|
||||
<segment title="4K"/>
|
||||
<segment title="Custom"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@@ -92,15 +92,15 @@
|
||||
<color key="textColor" red="0.9513210654258728" green="0.97490358352661133" blue="0.99987185001373291" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="PCM-t4-Sha">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" apportionsSegmentWidthsByContent="YES" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="PCM-t4-Sha">
|
||||
<rect key="frame" x="16" y="49" width="450" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="360p"/>
|
||||
<segment title="720p"/>
|
||||
<segment title="1080p"/>
|
||||
<segment title="Native"/>
|
||||
<segment title="4K"/>
|
||||
<segment title="Custom"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
Reference in New Issue
Block a user