diff --git a/Limelight/Base.lproj/iPad.storyboard b/Limelight/Base.lproj/iPad.storyboard index c887646f..ed5bb49f 100644 --- a/Limelight/Base.lproj/iPad.storyboard +++ b/Limelight/Base.lproj/iPad.storyboard @@ -1,9 +1,9 @@ - + - + @@ -12,7 +12,7 @@ - + @@ -370,101 +370,15 @@ ICAgICAgICAgICAgICA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -548,22 +462,125 @@ ICAgICAgICAgICAgICA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -574,7 +591,7 @@ ICAgICAgICAgICAgICA - + @@ -631,6 +648,7 @@ ICAgICAgICAgICAgICA + @@ -646,7 +664,7 @@ ICAgICAgICAgICAgICA - + @@ -686,7 +704,7 @@ ICAgICAgICAgICAgICA - + @@ -708,7 +726,7 @@ ICAgICAgICAgICAgICA - + @@ -735,7 +753,7 @@ ICAgICAgICAgICAgICA - + @@ -953,11 +971,11 @@ ICAgICAgICAgICAgICA - + - + diff --git a/Limelight/Base.lproj/iPhone.storyboard b/Limelight/Base.lproj/iPhone.storyboard index ab2a8ffd..0ab12fe1 100644 --- a/Limelight/Base.lproj/iPhone.storyboard +++ b/Limelight/Base.lproj/iPhone.storyboard @@ -1,9 +1,9 @@ - + - + @@ -349,14 +349,14 @@ ICAgICAgICAgICAgIA - + @@ -366,14 +366,14 @@ ICAgICAgICAgICAgIA - + @@ -383,14 +383,14 @@ ICAgICAgICAgICAgIA - + @@ -400,14 +400,14 @@ ICAgICAgICAgICAgIA - + @@ -531,14 +531,14 @@ ICAgICAgICAgICAgIA - + @@ -548,14 +548,14 @@ ICAgICAgICAgICAgIA - + @@ -565,14 +565,14 @@ ICAgICAgICAgICAgIA - + @@ -583,14 +583,14 @@ ICAgICAgICAgICAgIA - + @@ -600,6 +600,23 @@ ICAgICAgICAgICAgIA + + + + + + + + + + + @@ -647,6 +664,7 @@ ICAgICAgICAgICAgIA + diff --git a/Limelight/Crypto/mkcert.h b/Limelight/Crypto/mkcert.h index f3c62f8b..106f2f6c 100644 --- a/Limelight/Crypto/mkcert.h +++ b/Limelight/Crypto/mkcert.h @@ -9,6 +9,7 @@ #ifndef Limelight_mkcert_h #define Limelight_mkcert_h +#include #include #include diff --git a/Limelight/Database/DataManager.h b/Limelight/Database/DataManager.h index d250fa94..c0797e21 100644 --- a/Limelight/Database/DataManager.h +++ b/Limelight/Database/DataManager.h @@ -36,6 +36,7 @@ swapABXYButtons:(BOOL)swapABXYButtons audioOnPC:(BOOL)audioOnPC preferredCodec:(uint32_t)preferredCodec + enableYUV444:(BOOL)enableYUV444 useFramePacing:(BOOL)useFramePacing enableHdr:(BOOL)enableHdr btMouseSupport:(BOOL)btMouseSupport diff --git a/Limelight/Database/DataManager.m b/Limelight/Database/DataManager.m index 7e2975f9..3cebfb84 100644 --- a/Limelight/Database/DataManager.m +++ b/Limelight/Database/DataManager.m @@ -75,6 +75,7 @@ swapABXYButtons:(BOOL)swapABXYButtons audioOnPC:(BOOL)audioOnPC preferredCodec:(uint32_t)preferredCodec + enableYUV444:(BOOL)enableYUV444 useFramePacing:(BOOL)useFramePacing enableHdr:(BOOL)enableHdr btMouseSupport:(BOOL)btMouseSupport @@ -112,6 +113,7 @@ settingsToSave.swapABXYButtons = swapABXYButtons; settingsToSave.playAudioOnPC = audioOnPC; settingsToSave.preferredCodec = preferredCodec; + settingsToSave.enableYUV444 = enableYUV444; settingsToSave.useFramePacing = useFramePacing; settingsToSave.enableHdr = enableHdr; settingsToSave.btMouseSupport = btMouseSupport; diff --git a/Limelight/Database/TemporarySettings.h b/Limelight/Database/TemporarySettings.h index 5dbe9e65..35bffde0 100644 --- a/Limelight/Database/TemporarySettings.h +++ b/Limelight/Database/TemporarySettings.h @@ -42,6 +42,7 @@ CODEC_PREF_HEVC, CODEC_PREF_AV1, } preferredCodec; +@property (nonatomic) BOOL enableYUV444; @property (nonatomic) BOOL reverseMouseWheelDirection; @property (nonatomic) BOOL largerStickLR1; @property (nonatomic) BOOL useFramePacing; diff --git a/Limelight/Database/TemporarySettings.m b/Limelight/Database/TemporarySettings.m index dbc78d7c..c910b49d 100644 --- a/Limelight/Database/TemporarySettings.m +++ b/Limelight/Database/TemporarySettings.m @@ -37,6 +37,7 @@ self.audioConfig = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"audioConfig"]]; assert([self.audioConfig intValue] != 0); self.preferredCodec = (typeof(self.preferredCodec))[[NSUserDefaults standardUserDefaults] integerForKey:@"preferredCodec"]; + self.enableYUV444 = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableYUV444"]; self.useFramePacing = [[NSUserDefaults standardUserDefaults] integerForKey:@"useFramePacing"] != 0; self.playAudioOnPC = [[NSUserDefaults standardUserDefaults] boolForKey:@"audioOnPC"]; self.enableHdr = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableHdr"]; @@ -75,6 +76,7 @@ self.width = settings.width; self.audioConfig = settings.audioConfig; self.preferredCodec = settings.preferredCodec; + self.enableYUV444 = settings.enableYUV444; self.useFramePacing = settings.useFramePacing; self.playAudioOnPC = settings.playAudioOnPC; self.enableHdr = settings.enableHdr; diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents index e716f972..5178e199 100644 --- a/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents +++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -26,6 +26,7 @@ + @@ -57,4 +58,4 @@ - \ No newline at end of file + diff --git a/Limelight/Stream/Connection.m b/Limelight/Stream/Connection.m index 846add93..60d52880 100644 --- a/Limelight/Stream/Connection.m +++ b/Limelight/Stream/Connection.m @@ -86,8 +86,12 @@ void DrStop(void) { case VIDEO_FORMAT_H264: return @"H.264"; + case VIDEO_FORMAT_H264_HIGH8_444: + return @"H.264 YUV444"; case VIDEO_FORMAT_H265: return @"HEVC"; + case VIDEO_FORMAT_H265_REXT8_444: + return @"HEVC YUV444"; case VIDEO_FORMAT_H265_MAIN10: if (LiGetCurrentHostDisplayHdrMode()) { return @"HEVC Main 10 HDR"; @@ -95,8 +99,17 @@ void DrStop(void) else { return @"HEVC Main 10 SDR"; } + case VIDEO_FORMAT_H265_REXT10_444: + if (LiGetCurrentHostDisplayHdrMode()) { + return @"HEVC Main 10 YUV444 HDR"; + } + else { + return @"HEVC Main 10 YUV444 SDR"; + } case VIDEO_FORMAT_AV1_MAIN8: return @"AV1"; + case VIDEO_FORMAT_AV1_HIGH8_444: + return @"AV1 YUV444"; case VIDEO_FORMAT_AV1_MAIN10: if (LiGetCurrentHostDisplayHdrMode()) { return @"AV1 10-bit HDR"; @@ -104,6 +117,13 @@ void DrStop(void) else { return @"AV1 10-bit SDR"; } + case VIDEO_FORMAT_AV1_HIGH10_444: + if (LiGetCurrentHostDisplayHdrMode()) { + return @"AV1 10-bit YUV444 HDR"; + } + else { + return @"AV1 10-bit YUV444 SDR"; + } default: return @"UNKNOWN"; } diff --git a/Limelight/Stream/StreamConfiguration.h b/Limelight/Stream/StreamConfiguration.h index 05d9fc13..559cde62 100644 --- a/Limelight/Stream/StreamConfiguration.h +++ b/Limelight/Stream/StreamConfiguration.h @@ -16,6 +16,7 @@ @property NSString* appName; @property NSString* rtspSessionUrl; @property int serverCodecModeSupport; +@property BOOL enableYUV444; @property int width; @property int height; @property int frameRate; diff --git a/Limelight/Stream/StreamConfiguration.m b/Limelight/Stream/StreamConfiguration.m index 4d308cd8..306f9ced 100644 --- a/Limelight/Stream/StreamConfiguration.m +++ b/Limelight/Stream/StreamConfiguration.m @@ -9,5 +9,5 @@ #import "StreamConfiguration.h" @implementation StreamConfiguration -@synthesize host, httpsPort, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, appName, optimizeGameSettings, playAudioOnPC, swapABXYButtons, audioConfiguration, supportedVideoFormats, multiController, serverCert, rtspSessionUrl, serverCodecModeSupport; +@synthesize host, httpsPort, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, appName, optimizeGameSettings, playAudioOnPC, swapABXYButtons, audioConfiguration, supportedVideoFormats, multiController, serverCert, rtspSessionUrl, serverCodecModeSupport, enableYUV444; @end diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index dd43e32d..16d47eba 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -693,7 +693,12 @@ static NSMutableSet* hostList; case CODEC_PREF_AV1: #if defined(__IPHONE_16_0) || defined(__TVOS_16_0) if (VTIsHardwareDecodeSupported(kCMVideoCodecType_AV1)) { - _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_AV1_MAIN8; + if (streamSettings.enableYUV444) { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_AV1_HIGH8_444; + } + else { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_AV1_MAIN8; + } } #endif // Fall-through @@ -701,12 +706,21 @@ static NSMutableSet* hostList; case CODEC_PREF_AUTO: case CODEC_PREF_HEVC: if (VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { - _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265; + if (streamSettings.enableYUV444) { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265_REXT8_444; + } + else { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265; + } } // Fall-through case CODEC_PREF_H264: - _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H264; + if (streamSettings.enableYUV444) { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H264_HIGH8_444; + } else { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H264; + } break; } @@ -716,7 +730,12 @@ static NSMutableSet* hostList; // HEVC Main10 is supported if the user wants it and the display supports it if (streamSettings.enableHdr && (AVPlayer.availableHDRModes & AVPlayerHDRModeHDR10) != 0) { - _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265_MAIN10; + if (streamSettings.enableYUV444) { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265_REXT10_444; + } + else { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_H265_MAIN10; + } } } @@ -724,7 +743,11 @@ static NSMutableSet* hostList; // 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; + if (streamSettings.enableYUV444) { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_AV1_HIGH10_444; + } else { + _streamConfig.supportedVideoFormats |= VIDEO_FORMAT_AV1_MAIN10; + } } #endif } @@ -947,6 +970,7 @@ static NSMutableSet* hostList; [settingsViewController.optimizeSettingsSelector setEnabled:!self.settingsExpandedInStreamView]; [settingsViewController.audioOnPCSelector setEnabled:!self.settingsExpandedInStreamView]; [settingsViewController.codecSelector setEnabled:!self.settingsExpandedInStreamView]; + [settingsViewController.yuv444Selector setEnabled:!self.settingsExpandedInStreamView]; [settingsViewController.hdrSelector setEnabled:!self.settingsExpandedInStreamView]; [settingsViewController.framePacingSelector setEnabled:!self.settingsExpandedInStreamView]; [settingsViewController.btMouseSelector setEnabled:!self.settingsExpandedInStreamView]; diff --git a/Limelight/ViewControllers/SettingsViewController.h b/Limelight/ViewControllers/SettingsViewController.h index 6f9affbf..6ead3cae 100644 --- a/Limelight/ViewControllers/SettingsViewController.h +++ b/Limelight/ViewControllers/SettingsViewController.h @@ -28,6 +28,7 @@ @property (strong, nonatomic) IBOutlet UISegmentedControl *swapABXYButtonsSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *audioOnPCSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *codecSelector; +@property (strong, nonatomic) IBOutlet UISegmentedControl *yuv444Selector; @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 b7151623..76171858 100644 --- a/Limelight/ViewControllers/SettingsViewController.m +++ b/Limelight/ViewControllers/SettingsViewController.m @@ -452,6 +452,7 @@ BOOL isCustomResolution(CGSize res) { [self.hdrSelector setSelectedSegmentIndex:currentSettings.enableHdr ? 1 : 0]; } + [self.yuv444Selector setSelectedSegmentIndex:currentSettings.enableYUV444 ? 1 : 0]; [self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlayLevel.intValue]; [self.btMouseSelector setSelectedSegmentIndex:currentSettings.btMouseSupport ? 1 : 0]; [self.optimizeSettingsSelector setSelectedSegmentIndex:currentSettings.optimizeGames ? 1 : 0]; @@ -1062,6 +1063,7 @@ BOOL isCustomResolution(CGSize res) { BOOL swapABXYButtons = [self.swapABXYButtonsSelector selectedSegmentIndex] == 1; BOOL audioOnPC = [self.audioOnPCSelector selectedSegmentIndex] == 1; uint32_t preferredCodec = [self getChosenCodecPreference]; + BOOL enableYUV444 = [self.yuv444Selector selectedSegmentIndex] == 1; BOOL btMouseSupport = [self.btMouseSelector selectedSegmentIndex] == 1; BOOL useFramePacing = [self.framePacingSelector selectedSegmentIndex] == 1; // BOOL absoluteTouchMode = [self.touchModeSelector selectedSegmentIndex] == 1; @@ -1096,6 +1098,7 @@ BOOL isCustomResolution(CGSize res) { swapABXYButtons:swapABXYButtons audioOnPC:audioOnPC preferredCodec:preferredCodec + enableYUV444:enableYUV444 useFramePacing:useFramePacing enableHdr:enableHdr btMouseSupport:btMouseSupport diff --git a/Limelight/mul.lproj/iPad.xcstrings b/Limelight/mul.lproj/iPad.xcstrings index 00cff39c..fad3bc76 100644 --- a/Limelight/mul.lproj/iPad.xcstrings +++ b/Limelight/mul.lproj/iPad.xcstrings @@ -577,6 +577,66 @@ } } }, + "bw9-4S-s2V.segmentTitles[0]" : { + "comment" : "Class = \"UISegmentedControl\"; bw9-4S-s2V.segmentTitles[0] = \"No\"; ObjectID = \"bw9-4S-s2V\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "关闭" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "关闭" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "关闭" + } + } + } + }, + "bw9-4S-s2V.segmentTitles[1]" : { + "comment" : "Class = \"UISegmentedControl\"; bw9-4S-s2V.segmentTitles[1] = \"Yes\"; ObjectID = \"bw9-4S-s2V\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Yes" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "启用" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "启用" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "启用" + } + } + } + }, "byH-Qz-Nbw.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; byH-Qz-Nbw.segmentTitles[0] = \"No\"; ObjectID = \"byH-Qz-Nbw\";", "extractionState" : "extracted_with_value", @@ -1867,6 +1927,36 @@ } } }, + "OHY-2z-Tm7.text" : { + "comment" : "Class = \"UILabel\"; text = \"Enable YUV 4:4:4 (Beta)\"; ObjectID = \"OHY-2z-Tm7\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Enable YUV 4:4:4 (Beta)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "YUV 4:4:4 (测试功能)" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "YUV 4:4:4 (测试功能)" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "YUV 4:4:4 (测试功能)" + } + } + } + }, "oPM-G6-u5O.text" : { "comment" : "Class = \"UILabel\"; text = \"Mouse Pointer Velocity: 100% \"; ObjectID = \"oPM-G6-u5O\";", "extractionState" : "extracted_with_value", @@ -2733,4 +2823,4 @@ } }, "version" : "1.0" -} \ No newline at end of file +} diff --git a/Limelight/mul.lproj/iPhone.xcstrings b/Limelight/mul.lproj/iPhone.xcstrings index 28cdd79b..658bca90 100644 --- a/Limelight/mul.lproj/iPhone.xcstrings +++ b/Limelight/mul.lproj/iPhone.xcstrings @@ -1819,6 +1819,36 @@ } } }, + "Pew-kf-bSM.text" : { + "comment" : "Class = \"UILabel\"; text = \"Enable YUV 4:4:4 (Beta)\"; ObjectID = \"Pew-kf-bSM\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Enable YUV 4:4:4 (Beta)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "YUV 4:4:4 (测试功能)" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "YUV 4:4:4 (测试功能)" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "YUV 4:4:4 (测试功能)" + } + } + } + }, "pQE-vU-Nr7.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; pQE-vU-Nr7.segmentTitles[0] = \"No\"; ObjectID = \"pQE-vU-Nr7\";", "extractionState" : "extracted_with_value", @@ -2281,6 +2311,30 @@ } } }, + "vwT-tg-RfT.segmentTitles[0]" : { + "comment" : "Class = \"UISegmentedControl\"; vwT-tg-RfT.segmentTitles[0] = \"No\"; ObjectID = \"vwT-tg-RfT\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No" + } + } + } + }, + "vwT-tg-RfT.segmentTitles[1]" : { + "comment" : "Class = \"UISegmentedControl\"; vwT-tg-RfT.segmentTitles[1] = \"Yes\"; ObjectID = \"vwT-tg-RfT\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Yes" + } + } + } + }, "WGf-9d-eAm.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; WGf-9d-eAm.segmentTitles[0] = \"Off\"; ObjectID = \"WGf-9d-eAm\";", "extractionState" : "extracted_with_value", @@ -2703,4 +2757,4 @@ } }, "version" : "1.0" -} \ No newline at end of file +}