diff --git a/Limelight/Database/DataManager.h b/Limelight/Database/DataManager.h index d7d4d5e..5717a79 100644 --- a/Limelight/Database/DataManager.h +++ b/Limelight/Database/DataManager.h @@ -23,7 +23,7 @@ multiController:(BOOL)multiController swapABXYButtons:(BOOL)swapABXYButtons audioOnPC:(BOOL)audioOnPC - useHevc:(BOOL)useHevc + preferredCodec:(uint32_t)preferredCodec useFramePacing:(BOOL)useFramePacing enableHdr:(BOOL)enableHdr btMouseSupport:(BOOL)btMouseSupport diff --git a/Limelight/Database/DataManager.m b/Limelight/Database/DataManager.m index 1c3144a..0f5edeb 100644 --- a/Limelight/Database/DataManager.m +++ b/Limelight/Database/DataManager.m @@ -62,7 +62,7 @@ multiController:(BOOL)multiController swapABXYButtons:(BOOL)swapABXYButtons audioOnPC:(BOOL)audioOnPC - useHevc:(BOOL)useHevc + preferredCodec:(uint32_t)preferredCodec useFramePacing:(BOOL)useFramePacing enableHdr:(BOOL)enableHdr btMouseSupport:(BOOL)btMouseSupport @@ -81,7 +81,7 @@ settingsToSave.multiController = multiController; settingsToSave.swapABXYButtons = swapABXYButtons; settingsToSave.playAudioOnPC = audioOnPC; - settingsToSave.useHevc2 = useHevc; + settingsToSave.preferredCodec = preferredCodec; settingsToSave.useFramePacing = useFramePacing; settingsToSave.enableHdr = enableHdr; settingsToSave.btMouseSupport = btMouseSupport; diff --git a/Limelight/Database/TemporarySettings.h b/Limelight/Database/TemporarySettings.h index 196c689..da35b30 100644 --- a/Limelight/Database/TemporarySettings.h +++ b/Limelight/Database/TemporarySettings.h @@ -19,7 +19,12 @@ @property (nonatomic, retain) NSNumber * audioConfig; @property (nonatomic, retain) NSNumber * onscreenControls; @property (nonatomic, retain) NSString * uniqueId; -@property (nonatomic) BOOL useHevc; +@property (nonatomic) enum { + CODEC_PREF_AUTO, + CODEC_PREF_H264, + CODEC_PREF_HEVC, + CODEC_PREF_AV1, +} preferredCodec; @property (nonatomic) BOOL useFramePacing; @property (nonatomic) BOOL multiController; @property (nonatomic) BOOL swapABXYButtons; diff --git a/Limelight/Database/TemporarySettings.m b/Limelight/Database/TemporarySettings.m index 16aaa77..93e01b5 100644 --- a/Limelight/Database/TemporarySettings.m +++ b/Limelight/Database/TemporarySettings.m @@ -36,7 +36,7 @@ assert([self.framerate intValue] != 0); self.audioConfig = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"audioConfig"]]; assert([self.audioConfig intValue] != 0); - self.useHevc = [[NSUserDefaults standardUserDefaults] boolForKey:@"useHevc2"]; + self.preferredCodec = [[NSUserDefaults standardUserDefaults] integerForKey:@"preferredCodec"]; self.useFramePacing = [[NSUserDefaults standardUserDefaults] integerForKey:@"useFramePacing"] != 0; self.playAudioOnPC = [[NSUserDefaults standardUserDefaults] boolForKey:@"audioOnPC"]; self.enableHdr = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableHdr"]; @@ -74,7 +74,7 @@ self.height = settings.height; self.width = settings.width; self.audioConfig = settings.audioConfig; - self.useHevc = settings.useHevc2; + self.preferredCodec = settings.preferredCodec; self.useFramePacing = settings.useFramePacing; self.playAudioOnPC = settings.playAudioOnPC; self.enableHdr = settings.enableHdr; diff --git a/Limelight/Limelight.xcdatamodeld/.xccurrentversion b/Limelight/Limelight.xcdatamodeld/.xccurrentversion index 4e7ed17..b202eb9 100644 --- a/Limelight/Limelight.xcdatamodeld/.xccurrentversion +++ b/Limelight/Limelight.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - Moonlight v1.9.xcdatamodel + Moonlight v1.10.xcdatamodel diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents new file mode 100644 index 0000000..a2cc61c --- /dev/null +++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index fbef7cb..b900df0 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -662,11 +662,27 @@ static NSMutableSet* hostList; _streamConfig.serverCodecModeSupport = app.host.serverCodecModeSupport; - // H.264 is always supported - _streamConfig.supportedVideoFormats = VIDEO_FORMAT_H264; + switch (streamSettings.preferredCodec) { + case CODEC_PREF_AV1: + if (VTIsHardwareDecodeSupported(kCMVideoCodecType_AV1)) { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_AV1_MAIN8; + } + // Fall-through + + case CODEC_PREF_AUTO: + case CODEC_PREF_HEVC: + if (VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265; + } + // Fall-through + + case CODEC_PREF_H264: + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H264; + break; + } // HEVC is supported if the user wants it (or it's required by the chosen resolution) and the SoC supports it - if ((_streamConfig.width > 4096 || _streamConfig.height > 4096 || streamSettings.useHevc || streamSettings.enableHdr) && VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { + if ((_streamConfig.width > 4096 || _streamConfig.height > 4096 || streamSettings.enableHdr) && VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265; // HEVC Main10 is supported if the user wants it and the display supports it @@ -674,6 +690,12 @@ static NSMutableSet* hostList; _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265_MAIN10; } } + + // Add the AV1 Main10 format if AV1 and HDR are both enabled and supported + if ((_streamConfig.supportedVideoFormats & VIDEO_FORMAT_MASK_AV1) && streamSettings.enableHdr && + VTIsHardwareDecodeSupported(kCMVideoCodecType_AV1) && (AVPlayer.availableHDRModes & AVPlayerHDRModeHDR10) != 0) { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_AV1_MAIN10; + } } - (void)appLongClicked:(TemporaryApp *)app view:(UIView *)view { diff --git a/Limelight/ViewControllers/SettingsViewController.h b/Limelight/ViewControllers/SettingsViewController.h index 9bdcf21..1a79162 100644 --- a/Limelight/ViewControllers/SettingsViewController.h +++ b/Limelight/ViewControllers/SettingsViewController.h @@ -21,7 +21,7 @@ @property (strong, nonatomic) IBOutlet UISegmentedControl *multiControllerSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *swapABXYButtonsSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *audioOnPCSelector; -@property (strong, nonatomic) IBOutlet UISegmentedControl *hevcSelector; +@property (strong, nonatomic) IBOutlet UISegmentedControl *codecSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *hdrSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *framePacingSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *btMouseSelector; diff --git a/Limelight/ViewControllers/SettingsViewController.m b/Limelight/ViewControllers/SettingsViewController.m index 0b83ba5..8e105c8 100644 --- a/Limelight/ViewControllers/SettingsViewController.m +++ b/Limelight/ViewControllers/SettingsViewController.m @@ -198,53 +198,43 @@ BOOL isCustomResolution(CGSize res) { if (!enable120Fps) { [self.framerateSelector removeSegmentAtIndex:2 animated:NO]; } - - // Only show the 4K option for "recent" devices. We'll judge that by whether - // they support HEVC decoding (A9 or later). - if (@available(iOS 11.0, tvOS 11.0, *)) { - if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { - [self.resolutionSelector setEnabled:NO forSegmentAtIndex:3]; - } + + // Disable codec selector segments for unsupported codecs + if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_AV1)) { + [self.codecSelector setEnabled:NO forSegmentAtIndex:2]; } - else { + if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { + [self.codecSelector setEnabled:NO forSegmentAtIndex:1]; + + // Only enable the 4K option for "recent" devices. We'll judge that by whether + // they support HEVC decoding (A9 or later). [self.resolutionSelector setEnabled:NO forSegmentAtIndex:3]; } - - // 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. - if (@available(iOS 11.3, tvOS 11.3, *)) { - if (VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { - [self.hevcSelector setSelectedSegmentIndex:currentSettings.useHevc ? 1 : 0]; - } - else { - [self.hevcSelector removeAllSegments]; - [self.hevcSelector insertSegmentWithTitle:@"Unsupported on this device" atIndex:0 animated:NO]; - [self.hevcSelector setEnabled:NO]; - } - - // Disable HDR selector if HDR is not supported by the display - if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC) || !(AVPlayer.availableHDRModes & AVPlayerHDRModeHDR10)) { - [self.hdrSelector removeAllSegments]; - [self.hdrSelector insertSegmentWithTitle:@"Unsupported on this device" atIndex:0 animated:NO]; - [self.hdrSelector setEnabled:NO]; - } - else { - [self.hdrSelector setSelectedSegmentIndex:currentSettings.enableHdr ? 1 : 0]; - [self.hdrSelector addTarget:self action:@selector(hdrStateChanged) forControlEvents:UIControlEventValueChanged]; + switch (currentSettings.preferredCodec) { + case CODEC_PREF_AUTO: + [self.codecSelector setSelectedSegmentIndex:self.codecSelector.numberOfSegments - 1]; + break; - // Manually trigger the hdrStateChanged callback to set the HEVC selector appropriately - [self hdrStateChanged]; - } + case CODEC_PREF_AV1: + [self.codecSelector setSelectedSegmentIndex:2]; + break; + + case CODEC_PREF_HEVC: + [self.codecSelector setSelectedSegmentIndex:1]; + break; + + case CODEC_PREF_H264: + [self.codecSelector setSelectedSegmentIndex:0]; + break; + } + + if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC) || !(AVPlayer.availableHDRModes & AVPlayerHDRModeHDR10)) { + [self.hdrSelector removeAllSegments]; + [self.hdrSelector insertSegmentWithTitle:@"Unsupported on this device" atIndex:0 animated:NO]; + [self.hdrSelector setEnabled:NO]; } else { - [self.hevcSelector removeAllSegments]; - [self.hevcSelector insertSegmentWithTitle:@"Requires iOS 11.3 or later" atIndex:0 animated:NO]; - [self.hevcSelector setEnabled:NO]; - - [self.hdrSelector removeAllSegments]; - [self.hdrSelector insertSegmentWithTitle:@"Requires iOS 11.3 or later" atIndex:0 animated:NO]; - [self.hdrSelector setEnabled:NO]; + [self.hdrSelector setSelectedSegmentIndex:currentSettings.enableHdr ? 1 : 0]; } [self.touchModeSelector setSelectedSegmentIndex:currentSettings.absoluteTouchMode ? 1 : 0]; @@ -351,16 +341,6 @@ BOOL isCustomResolution(CGSize res) { } } -- (void) hdrStateChanged { - if ([self.hdrSelector selectedSegmentIndex] == 1) { - [self.hevcSelector setSelectedSegmentIndex:1]; - [self.hevcSelector setEnabled:NO]; - } - else { - [self.hevcSelector setEnabled:YES]; - } -} - - (void) promptCustomResolutionDialog { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Enter Custom Resolution" message:nil preferredStyle:UIAlertControllerStyleAlert]; @@ -497,6 +477,28 @@ BOOL isCustomResolution(CGSize res) { } } +- (uint32_t) getChosenCodecPreference { + // Auto is always the last segment + if (self.codecSelector.selectedSegmentIndex == self.codecSelector.numberOfSegments - 1) { + return CODEC_PREF_AUTO; + } + else { + switch (self.codecSelector.selectedSegmentIndex) { + case 0: + return CODEC_PREF_H264; + + case 1: + return CODEC_PREF_HEVC; + + case 2: + return CODEC_PREF_AV1; + + default: + abort(); + } + } +} + - (NSInteger) getChosenStreamHeight { // because the 4k resolution can be removed BOOL lastSegmentSelected = [self.resolutionSelector selectedSegmentIndex] + 1 == [self.resolutionSelector numberOfSegments]; @@ -527,7 +529,7 @@ BOOL isCustomResolution(CGSize res) { BOOL multiController = [self.multiControllerSelector selectedSegmentIndex] == 1; BOOL swapABXYButtons = [self.swapABXYButtonsSelector selectedSegmentIndex] == 1; BOOL audioOnPC = [self.audioOnPCSelector selectedSegmentIndex] == 1; - BOOL useHevc = [self.hevcSelector selectedSegmentIndex] == 1; + uint32_t preferredCodec = [self getChosenCodecPreference]; BOOL btMouseSupport = [self.btMouseSelector selectedSegmentIndex] == 1; BOOL useFramePacing = [self.framePacingSelector selectedSegmentIndex] == 1; BOOL absoluteTouchMode = [self.touchModeSelector selectedSegmentIndex] == 1; @@ -543,8 +545,8 @@ BOOL isCustomResolution(CGSize res) { multiController:multiController swapABXYButtons:swapABXYButtons audioOnPC:audioOnPC - useHevc:useHevc - useFramePacing:useFramePacing + preferredCodec:preferredCodec + useFramePacing:useFramePacing enableHdr:enableHdr btMouseSupport:btMouseSupport absoluteTouchMode:absoluteTouchMode diff --git a/Moonlight TV/Settings.bundle/Root.plist b/Moonlight TV/Settings.bundle/Root.plist index 36193c7..8088188 100644 --- a/Moonlight TV/Settings.bundle/Root.plist +++ b/Moonlight TV/Settings.bundle/Root.plist @@ -188,13 +188,25 @@ Type - PSToggleSwitchSpecifier + PSMultiValueSpecifier Title - Use HEVC Codec + Preferred Codec Key - useHevc2 + preferredCodec DefaultValue - + 0 + Values + + 0 + 1 + 2 + + Titles + + Auto + H.264 + HEVC + Type diff --git a/Moonlight.xcodeproj/project.pbxproj b/Moonlight.xcodeproj/project.pbxproj index 2968af5..d5a3658 100644 --- a/Moonlight.xcodeproj/project.pbxproj +++ b/Moonlight.xcodeproj/project.pbxproj @@ -186,6 +186,7 @@ 9865DC3B2132922E0005B9B9 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS11.4.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; }; 986CCE6C2133E45300168291 /* Moonlight v1.2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.2.xcdatamodel"; sourceTree = ""; }; 986E28A528EA989100758361 /* Moonlight v1.9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.9.xcdatamodel"; sourceTree = ""; }; + 9874E8962AE95E1D00130A3C /* Moonlight v1.10.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.10.xcdatamodel"; sourceTree = ""; }; 98783FEA242EAC5D00F00EF4 /* Moonlight v1.5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.5.xcdatamodel"; sourceTree = ""; }; 988FCD3F293B091B003050E2 /* KeyboardInputField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyboardInputField.h; sourceTree = ""; }; 988FCD40293B091B003050E2 /* KeyboardInputField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeyboardInputField.m; sourceTree = ""; }; @@ -1448,6 +1449,7 @@ FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 9874E8962AE95E1D00130A3C /* Moonlight v1.10.xcdatamodel */, 986E28A528EA989100758361 /* Moonlight v1.9.xcdatamodel */, 984CD023288A310D0097D2D4 /* Moonlight v1.8.xcdatamodel */, 566E9D2B2770B23A00EF7BFE /* Moonlight v1.7.xcdatamodel */, @@ -1463,7 +1465,7 @@ FB4678F21A51BDCB00377732 /* Limelight 0.3.0.xcdatamodel */, FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */, ); - currentVersion = 986E28A528EA989100758361 /* Moonlight v1.9.xcdatamodel */; + currentVersion = 9874E8962AE95E1D00130A3C /* Moonlight v1.10.xcdatamodel */; path = Limelight.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/iPad.storyboard b/iPad.storyboard index 1898f86..9017b15 100644 --- a/iPad.storyboard +++ b/iPad.storyboard @@ -1,9 +1,9 @@ - + - + @@ -217,19 +217,21 @@ - diff --git a/iPhone.storyboard b/iPhone.storyboard index 65880f3..03aa007 100644 --- a/iPhone.storyboard +++ b/iPhone.storyboard @@ -1,9 +1,9 @@ - + - + @@ -247,19 +247,21 @@ -