From 29ba055024691ee90831300d4643f322bbd4d335 Mon Sep 17 00:00:00 2001 From: hbouhadji Date: Sat, 5 Feb 2022 17:55:32 +0100 Subject: [PATCH] dialog for custom resolution --- .../ViewControllers/SettingsViewController.m | 169 ++++++++++-------- iPad.storyboard | 4 +- iPhone.storyboard | 4 +- 3 files changed, 102 insertions(+), 75 deletions(-) diff --git a/Limelight/ViewControllers/SettingsViewController.m b/Limelight/ViewControllers/SettingsViewController.m index b93ddee..0b81702 100644 --- a/Limelight/ViewControllers/SettingsViewController.m +++ b/Limelight/ViewControllers/SettingsViewController.m @@ -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 { diff --git a/iPad.storyboard b/iPad.storyboard index 2c51427..6e8b54e 100644 --- a/iPad.storyboard +++ b/iPad.storyboard @@ -70,15 +70,15 @@ - + - + diff --git a/iPhone.storyboard b/iPhone.storyboard index 2fb71ff..cf3702c 100644 --- a/iPhone.storyboard +++ b/iPhone.storyboard @@ -92,15 +92,15 @@ - + - +