frameInterpolation beta ready
This commit is contained in:
@@ -411,6 +411,42 @@
|
||||
<constraint firstAttribute="height" constant="56.5" id="IFC-Wo-Eu0"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="FIp-Lv-StK" userLabel="interpolationLevel Stack">
|
||||
<rect key="frame" x="440" y="1350" width="380" height="56.5"/>
|
||||
<subviews>
|
||||
<label verifyAmbiguity="off" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Interpolation Resolution" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FIp-Lv-Lbl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="380" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="FIp-Lv-Sel" userLabel="Interpolation Level Slider">
|
||||
<rect key="frame" x="0.0" y="25.5" width="380" height="31"/>
|
||||
</slider>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="380" id="FIp-Lv-Wid"/>
|
||||
<constraint firstAttribute="height" constant="56.5" id="FIp-Lv-Hgt"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="FIp-Sc-StK" userLabel="streamDimensionScale Stack">
|
||||
<rect key="frame" x="440" y="1411" width="380" height="56.5"/>
|
||||
<subviews>
|
||||
<label verifyAmbiguity="off" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Scaled Stream Resolution" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FIp-Sc-Lbl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="380" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="FIp-Sc-Sld" userLabel="Stream Dimension Scale Slider">
|
||||
<rect key="frame" x="0.0" y="25.5" width="380" height="31"/>
|
||||
</slider>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="380" id="FIp-Sc-Wid"/>
|
||||
<constraint firstAttribute="height" constant="56.5" id="FIp-Sc-Hgt"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="hcl-DT-peO" userLabel="redirectMicStack">
|
||||
<rect key="frame" x="432" y="2215" width="245.5" height="31"/>
|
||||
<subviews>
|
||||
@@ -2302,6 +2338,10 @@
|
||||
<outlet property="fpsStack" destination="TuR-H8-e2H" id="zGQ-gR-P1i"/>
|
||||
<outlet property="framePacingModeSelector" destination="2Dp-Qg-chi" id="h8A-YF-SZP"/>
|
||||
<outlet property="framePacingStack" destination="oZG-5Y-pw5" id="vGd-hD-zTr"/>
|
||||
<outlet property="interpolationLevelSlider" destination="FIp-Lv-Sel" id="FIp-Out-Sel"/>
|
||||
<outlet property="interpolationLevelStack" destination="FIp-Lv-StK" id="FIp-Out-StK"/>
|
||||
<outlet property="streamDimensionScaleSlider" destination="FIp-Sc-Sld" id="FIp-Out-ScS"/>
|
||||
<outlet property="streamDimensionScaleStack" destination="FIp-Sc-StK" id="FIp-Out-ScK"/>
|
||||
<outlet property="frameQueueSizeLabel" destination="Ce3-FM-vIh" id="90D-Tq-OGd"/>
|
||||
<outlet property="frameQueueSizeSlider" destination="oZa-8Y-icz" id="Jo1-Fx-UMw"/>
|
||||
<outlet property="frameQueueSizeStack" destination="MML-c1-D5j" id="82B-r7-Zbh"/>
|
||||
|
||||
@@ -2548,6 +2548,42 @@
|
||||
<constraint firstAttribute="height" constant="56.5" id="Asf-2R-Qoi"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="FIi-Lv-StK" userLabel="interpolationLevel Stack">
|
||||
<rect key="frame" x="456" y="2232" width="380" height="56.5"/>
|
||||
<subviews>
|
||||
<label verifyAmbiguity="off" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Interpolation Resolution" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FIi-Lv-Lbl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="380" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="FIi-Lv-Sel" userLabel="Interpolation Level Slider">
|
||||
<rect key="frame" x="0.0" y="25.5" width="380" height="31"/>
|
||||
</slider>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="380" id="FIi-Lv-Wid"/>
|
||||
<constraint firstAttribute="height" constant="56.5" id="FIi-Lv-Hgt"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="FIi-Sc-StK" userLabel="streamDimensionScale Stack">
|
||||
<rect key="frame" x="456" y="2293" width="380" height="56.5"/>
|
||||
<subviews>
|
||||
<label verifyAmbiguity="off" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Scaled Stream Resolution" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FIi-Sc-Lbl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="380" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="FIi-Sc-Sld" userLabel="Stream Dimension Scale Slider">
|
||||
<rect key="frame" x="0.0" y="25.5" width="380" height="31"/>
|
||||
</slider>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="380" id="FIi-Sc-Wid"/>
|
||||
<constraint firstAttribute="height" constant="56.5" id="FIi-Sc-Hgt"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="CKa-yk-GSi" userLabel="redirectMicStack">
|
||||
<rect key="frame" x="5" y="2157" width="245.5" height="31"/>
|
||||
<subviews>
|
||||
@@ -3569,6 +3605,10 @@
|
||||
<outlet property="fpsStack" destination="aMv-7Q-yYg" id="JxU-wq-2Za"/>
|
||||
<outlet property="framePacingModeSelector" destination="CC6-pu-Uoh" id="HTB-6I-QgB"/>
|
||||
<outlet property="framePacingStack" destination="U0H-kh-QLS" id="M8w-wy-HI8"/>
|
||||
<outlet property="interpolationLevelSlider" destination="FIi-Lv-Sel" id="FIi-Out-Sel"/>
|
||||
<outlet property="interpolationLevelStack" destination="FIi-Lv-StK" id="FIi-Out-StK"/>
|
||||
<outlet property="streamDimensionScaleSlider" destination="FIi-Sc-Sld" id="FIi-Out-ScS"/>
|
||||
<outlet property="streamDimensionScaleStack" destination="FIi-Sc-StK" id="FIi-Out-ScK"/>
|
||||
<outlet property="frameQueueSizeLabel" destination="r8X-jt-JfH" id="Tr9-eb-bIx"/>
|
||||
<outlet property="frameQueueSizeSlider" destination="thv-JE-onX" id="gKD-6c-5tw"/>
|
||||
<outlet property="frameQueueSizeStack" destination="IHx-FO-ctr" id="gob-Ea-Avh"/>
|
||||
|
||||
@@ -130,6 +130,9 @@ typedef NS_ENUM(NSInteger, PencilTickMode) {
|
||||
graphOpacity:(NSInteger)graphOpacity
|
||||
renderingBackend:(NSInteger)renderingBackend
|
||||
framePacingMode:(NSInteger)framePacingMode
|
||||
interpolationMaximumDimension:(NSInteger)interpolationMaximumDimension
|
||||
interpolationMaximumPixelCount:(NSInteger)interpolationMaximumPixelCount
|
||||
streamDimensionScale:(CGFloat)streamDimensionScale
|
||||
sendDummyEvent:(BOOL)sendDummyEvent
|
||||
rememberFoldState:(BOOL)rememberFoldState
|
||||
singleTapSensitivy:(CGFloat)singleTapSensitivy
|
||||
|
||||
@@ -106,6 +106,9 @@
|
||||
graphOpacity:(NSInteger)graphOpacity
|
||||
renderingBackend:(NSInteger)renderingBackend
|
||||
framePacingMode:(NSInteger)framePacingMode
|
||||
interpolationMaximumDimension:(NSInteger)interpolationMaximumDimension
|
||||
interpolationMaximumPixelCount:(NSInteger)interpolationMaximumPixelCount
|
||||
streamDimensionScale:(CGFloat)streamDimensionScale
|
||||
sendDummyEvent:(BOOL)sendDummyEvent
|
||||
rememberFoldState:(BOOL)rememberFoldState
|
||||
singleTapSensitivy:(CGFloat)singleTapSensitivy
|
||||
@@ -193,6 +196,9 @@
|
||||
settingsToSave.graphOpacity = [NSNumber numberWithInteger:graphOpacity];
|
||||
settingsToSave.renderingBackend = [NSNumber numberWithInteger:renderingBackend];
|
||||
settingsToSave.framePacingMode = [NSNumber numberWithInteger:framePacingMode];
|
||||
settingsToSave.interpolationMaximumDimension = [NSNumber numberWithInteger:interpolationMaximumDimension];
|
||||
settingsToSave.interpolationMaximumPixelCount = [NSNumber numberWithInteger:interpolationMaximumPixelCount];
|
||||
settingsToSave.streamDimensionScale = [NSNumber numberWithDouble:streamDimensionScale];
|
||||
settingsToSave.sendDummyEvent = sendDummyEvent;
|
||||
settingsToSave.singleTapSensitivity = [NSNumber numberWithDouble:singleTapSensitivy];
|
||||
settingsToSave.hapticEngine = [NSNumber numberWithInteger:hapticEngine];
|
||||
@@ -370,4 +376,3 @@
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -99,6 +99,9 @@
|
||||
@property (nonatomic) BOOL ctrlDownForPinch;
|
||||
@property (nonatomic) BOOL passthroughGestures;
|
||||
@property (nonatomic, retain) NSNumber * framePacingMode;
|
||||
@property (nonatomic, retain) NSNumber * interpolationMaximumDimension;
|
||||
@property (nonatomic, retain) NSNumber * interpolationMaximumPixelCount;
|
||||
@property (nonatomic, retain) NSNumber * streamDimensionScale;
|
||||
@property (nonatomic, retain) NSNumber * scrollSensitivity;
|
||||
@property (nonatomic, retain) NSNumber * pinchSensitivity;
|
||||
@property (nonatomic, retain) NSNumber * relativeTouchSlideThreshold;
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
self.graphOpacity = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"graphOpacity"]];
|
||||
self.renderingBackend = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"renderingBackend"]];
|
||||
self.framePacingMode = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"framePacingMode"]];
|
||||
self.interpolationMaximumDimension = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"interpolationMaximumDimension"]];
|
||||
self.interpolationMaximumPixelCount = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"interpolationMaximumPixelCount"]];
|
||||
self.streamDimensionScale = [NSNumber numberWithDouble:[[NSUserDefaults standardUserDefaults] doubleForKey:@"streamDimensionScale"]];
|
||||
|
||||
NSInteger _screenSize = [[NSUserDefaults standardUserDefaults] integerForKey:@"streamResolution"];
|
||||
switch (_screenSize) {
|
||||
@@ -135,6 +138,9 @@
|
||||
self.graphOpacity = settings.graphOpacity;
|
||||
self.renderingBackend = settings.renderingBackend;
|
||||
self.framePacingMode = settings.framePacingMode;
|
||||
self.interpolationMaximumDimension = settings.interpolationMaximumDimension ?: @(0);
|
||||
self.interpolationMaximumPixelCount = settings.interpolationMaximumPixelCount ?: @(0);
|
||||
self.streamDimensionScale = settings.streamDimensionScale ?: @(1);
|
||||
self.sendDummyEvent = settings.sendDummyEvent;
|
||||
self.rememberFoldState = settings.rememberFoldState;
|
||||
self.gyroBiasX = settings.gyroBiasX;
|
||||
|
||||
@@ -74,6 +74,8 @@
|
||||
<attribute name="gyroSensitivity" optional="YES" attributeType="Float" defaultValueString="1" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hapticEngine" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="height" attributeType="Integer 32" defaultValueString="720" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="interpolationMaximumDimension" optional="YES" attributeType="Integer 32" defaultValueString="1280" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="interpolationMaximumPixelCount" optional="YES" attributeType="Integer 32" defaultValueString="921600" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="keyboardToggleFingers" optional="YES" attributeType="Integer 16" defaultValueString="99" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="leftClickDelayMs" optional="YES" attributeType="Float" defaultValueString="15" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="liftStreamViewForKeyboard" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES" syncable="YES"/>
|
||||
@@ -115,6 +117,7 @@
|
||||
<attribute name="softKeyboardHeight" attributeType="Float" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="statsOverlayEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="statsOverlayLevel" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="streamDimensionScale" optional="YES" attributeType="Double" defaultValueString="1" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="streamingRadialMenuButton" attributeType="Integer 32" defaultValueString="16" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="streamingRadialMenuDelay" optional="YES" attributeType="Float" defaultValueString="0.5" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="swapABXYButtons" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
|
||||
@@ -9304,6 +9304,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Interpolation Resolution" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "插帧分辨率"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "影格插補解析度"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "影格插補解析度"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Most devices currently support frame interpolation only for 8-bit YUV 4:2:0 SDR video. In this case, if HDR or YUV 4:4:4 is enabled, intermediate frames will still be generated in 8-bit YUV 4:2:0 SDR." : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "目前多数设备仅支持 8-bit YUV420 SDR 视频插帧。这种情况下,如果您打开了 HDR 或 YUV444 选项,中间帧将依然按 8-bit YUV420 SDR 格式生成。"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "目前多數裝置僅支援 8-bit YUV420 SDR 影片影格插補。在這種情況下,如果您開啟 HDR 或 YUV444 選項,中間影格仍會以 8-bit YUV420 SDR 格式產生。"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Interpolation failed for an unknown reason." : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -17209,6 +17249,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Scaled Stream Resolution" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "串流分辨率缩放"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "串流解析度縮放"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "串流解析度縮放"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Slow connection to PC, Reduce your bitrate" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,5 +49,7 @@
|
||||
|
||||
- (void)invalidateDecompressionSession;
|
||||
+ (void)setFrameInterpolationEnabled:(bool)enabled;
|
||||
+ (void)startOrRestartFrameInterpolation;
|
||||
+ (void)stopFrameInterpolation;
|
||||
|
||||
@end
|
||||
|
||||
@@ -36,11 +36,19 @@
|
||||
//#define DISPLAYLINK_VERBOSE
|
||||
|
||||
static BOOL kEnableFrameInterpolation = false;
|
||||
static __weak VideoDecoderRenderer *sActiveRenderer = nil;
|
||||
|
||||
// Private libavformat API for writing the AV1 Codec Configuration Box
|
||||
extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
int write_seq_header);
|
||||
|
||||
@interface VideoDecoderRenderer ()
|
||||
- (void)startOrRestartFrameInterpolation;
|
||||
- (void)stopFrameInterpolation;
|
||||
- (NSInteger)displayLinkFrameRateForInterpolationEnabled:(BOOL)enabled;
|
||||
- (void)restartDisplayLinkForInterpolationEnabled:(BOOL)enabled;
|
||||
@end
|
||||
|
||||
@implementation VideoDecoderRenderer {
|
||||
dispatch_queue_t _sq, _vtq;
|
||||
StreamView* _view;
|
||||
@@ -60,6 +68,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
CMVideoFormatDescriptionRef _formatDescImageBuffer;
|
||||
VTDecompressionSessionRef _decompressionSession;
|
||||
FrameInterpolator *_frameInterpolator;
|
||||
BOOL _frameInterpolationPaused;
|
||||
|
||||
CADisplayLink *_displayLink;
|
||||
NSInteger _maxRefreshRate;
|
||||
@@ -77,6 +86,26 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
kEnableFrameInterpolation = enabled;
|
||||
}
|
||||
|
||||
+ (void)startOrRestartFrameInterpolation {
|
||||
kEnableFrameInterpolation = true;
|
||||
|
||||
VideoDecoderRenderer *renderer;
|
||||
@synchronized(self) {
|
||||
renderer = sActiveRenderer;
|
||||
}
|
||||
[renderer startOrRestartFrameInterpolation];
|
||||
}
|
||||
|
||||
+ (void)stopFrameInterpolation {
|
||||
kEnableFrameInterpolation = false;
|
||||
|
||||
VideoDecoderRenderer *renderer;
|
||||
@synchronized(self) {
|
||||
renderer = sActiveRenderer;
|
||||
}
|
||||
[renderer stopFrameInterpolation];
|
||||
}
|
||||
|
||||
- (void)reinitializeDisplayLayer
|
||||
{
|
||||
if (_displayLayer == nil) {
|
||||
@@ -174,7 +203,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
_asyncFrameDequeue = tempSettings.asyncFrameDequeue;
|
||||
NSLog(@"_asyncFrameDequeue %d", _asyncFrameDequeue);
|
||||
_enableTimebase = false;
|
||||
_queueSize = kEnableFrameInterpolation ? 4 : tempSettings.frameQueueSize.intValue;
|
||||
_queueSize = kEnableFrameInterpolation ? 8 : tempSettings.frameQueueSize.intValue;
|
||||
_needRequeuing = _queueSize>0;
|
||||
|
||||
_frameQueue = [FrameQueue sharedInstance];
|
||||
@@ -189,9 +218,115 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
name:@"ScreenChanged"
|
||||
object:nil];
|
||||
|
||||
@synchronized([VideoDecoderRenderer class]) {
|
||||
sActiveRenderer = self;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSInteger)displayLinkFrameRateForInterpolationEnabled:(BOOL)enabled {
|
||||
NSInteger multiplier = enabled ? 2 : 1;
|
||||
return MIN(self->_frameRate * multiplier, self->_maxRefreshRate);
|
||||
}
|
||||
|
||||
- (void)restartDisplayLinkForInterpolationEnabled:(BOOL)enabled {
|
||||
dispatch_block_t restartBlock = ^{
|
||||
if (self->_renderingBackend != RENDER_AVSB || self->_displayLink == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSInteger targetFrameRate = [self displayLinkFrameRateForInterpolationEnabled:enabled];
|
||||
BOOL shouldRemainPaused = appDidEnterBackgroundWithoutPip;
|
||||
self->_displayLink.paused = YES;
|
||||
if (@available(iOS 15.0, tvOS 15.0, *)) {
|
||||
self->_displayLink.preferredFrameRateRange = CAFrameRateRangeMake(targetFrameRate, targetFrameRate, targetFrameRate);
|
||||
}
|
||||
else {
|
||||
self->_displayLink.preferredFramesPerSecond = targetFrameRate;
|
||||
}
|
||||
self->_displayLink.paused = shouldRemainPaused;
|
||||
Log(LOG_I, @"Display link restarted at %ld FPS (interpolation %@)",
|
||||
(long)targetFrameRate, enabled ? @"enabled" : @"disabled");
|
||||
};
|
||||
|
||||
if ([NSThread isMainThread]) {
|
||||
restartBlock();
|
||||
}
|
||||
else {
|
||||
dispatch_async(dispatch_get_main_queue(), restartBlock);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)invalidateDecompressionSession {
|
||||
@synchronized(self) {
|
||||
if (self->_decompressionSession != NULL) {
|
||||
VTDecompressionSessionInvalidate(self->_decompressionSession);
|
||||
CFRelease(self->_decompressionSession);
|
||||
self->_decompressionSession = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)startOrRestartFrameInterpolation {
|
||||
if (self->_displayLink == nil || self->_renderingBackend != RENDER_AVSB) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataManager *dataMan = [[DataManager alloc] init];
|
||||
TemporarySettings *settings = [dataMan getSettings];
|
||||
NSInteger maximumDimension = settings.interpolationMaximumDimension.integerValue;
|
||||
NSInteger maximumPixelCount = settings.interpolationMaximumPixelCount.integerValue;
|
||||
|
||||
dispatch_async(self->_vtq, ^{
|
||||
FrameInterpolator *oldInterpolator = self->_frameInterpolator;
|
||||
self->_frameInterpolator = [[FrameInterpolator alloc]
|
||||
initWithMaximumDimension:maximumDimension
|
||||
maximumPixelCount:maximumPixelCount];
|
||||
self->_frameInterpolator.isEnabled = YES;
|
||||
self->_frameInterpolationPaused = NO;
|
||||
[oldInterpolator reset];
|
||||
|
||||
self->_queueSize = 8;
|
||||
self->_needRequeuing = YES;
|
||||
[self->_frameQueue setHighWaterMark:self->_queueSize];
|
||||
[self->_frameQueue clear];
|
||||
[self invalidateDecompressionSession];
|
||||
[self restartDisplayLinkForInterpolationEnabled:YES];
|
||||
LiRequestIdrFrame();
|
||||
|
||||
Log(LOG_I, @"Frame interpolation started or restarted with limits %ld / %ld pixels",
|
||||
(long)maximumDimension, (long)maximumPixelCount);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)stopFrameInterpolation {
|
||||
if (self->_displayLink == nil || self->_renderingBackend != RENDER_AVSB) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataManager *dataMan = [[DataManager alloc] init];
|
||||
TemporarySettings *settings = [dataMan getSettings];
|
||||
NSInteger normalQueueSize = settings.frameQueueSize.integerValue;
|
||||
|
||||
dispatch_async(self->_vtq, ^{
|
||||
FrameInterpolator *oldInterpolator = self->_frameInterpolator;
|
||||
self->_frameInterpolator = nil;
|
||||
self->_frameInterpolationPaused = NO;
|
||||
[oldInterpolator reset];
|
||||
|
||||
self->_queueSize = (int32_t)normalQueueSize;
|
||||
self->_needRequeuing = self->_queueSize > 0;
|
||||
[self->_frameQueue setHighWaterMark:MAX(1, self->_queueSize)];
|
||||
[self->_frameQueue clear];
|
||||
[self invalidateDecompressionSession];
|
||||
[self restartDisplayLinkForInterpolationEnabled:NO];
|
||||
LiRequestIdrFrame();
|
||||
|
||||
Log(LOG_I, @"Frame interpolation stopped");
|
||||
});
|
||||
}
|
||||
|
||||
# pragma mark DisplayLink vsync callback
|
||||
|
||||
- (void)setupWithVideoFormat:(int)videoFormat width:(int)videoWidth height:(int)videoHeight frameRate:(int)frameRate fullRange:(BOOL)fullRange request10BitCodec:(BOOL)request10BitCodec
|
||||
@@ -210,7 +345,9 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
_renderingBackend = RENDER_AVSB;
|
||||
|
||||
if (kEnableFrameInterpolation) {
|
||||
_frameInterpolator = [[FrameInterpolator alloc] init];
|
||||
_frameInterpolator = [[FrameInterpolator alloc]
|
||||
initWithMaximumDimension:settings.interpolationMaximumDimension.integerValue
|
||||
maximumPixelCount:settings.interpolationMaximumPixelCount.integerValue];
|
||||
_frameInterpolator.isEnabled = YES;
|
||||
}
|
||||
|
||||
@@ -229,10 +366,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:displayLinkSelector];
|
||||
|
||||
NSInteger targetFrameRate = self->_frameRate;
|
||||
if (self->_frameInterpolator != nil) {
|
||||
targetFrameRate = MIN(self->_frameRate * 2, self->_maxRefreshRate);
|
||||
}
|
||||
NSInteger targetFrameRate = [self displayLinkFrameRateForInterpolationEnabled:self->_frameInterpolator != nil];
|
||||
|
||||
if (@available(iOS 15.0, tvOS 15.0, *)) {
|
||||
_displayLink.preferredFrameRateRange = CAFrameRateRangeMake(targetFrameRate, targetFrameRate, targetFrameRate);
|
||||
@@ -289,61 +423,26 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
nativePixelFormat = self->_fullRange ? frFormat : vrFormat;
|
||||
}
|
||||
BOOL interpolationRequested = self->_frameInterpolator != nil;
|
||||
NSNumber *pixelFormat = interpolationRequested ? @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) : nativePixelFormat;
|
||||
OSType interpolationPixelFormat = 0;
|
||||
if (interpolationRequested) {
|
||||
LogOnce(LOG_I, @"Frame interpolation enabled; requesting 420v output from VTDecompressionSession");
|
||||
interpolationPixelFormat = [FrameInterpolator supportedPixelFormatClosestTo:nativePixelFormat.unsignedIntValue];
|
||||
if (interpolationPixelFormat == 0) {
|
||||
LogOnce(LOG_W, @"Frame interpolation disabled because the device reports no supported pixel format");
|
||||
[self->_frameInterpolator reset];
|
||||
self->_frameInterpolator = nil;
|
||||
interpolationRequested = NO;
|
||||
[self restartDisplayLinkForInterpolationEnabled:NO];
|
||||
}
|
||||
}
|
||||
NSNumber *pixelFormat = interpolationRequested ? @(interpolationPixelFormat) : nativePixelFormat;
|
||||
if (interpolationRequested) {
|
||||
LogOnce(LOG_I, @"Frame interpolation enabled; requesting pixel format %@ from VTDecompressionSession", pixelFormat);
|
||||
}
|
||||
NSMutableDictionary *destinationPixelBufferAttributes = [@{
|
||||
(id)kCVPixelBufferPixelFormatTypeKey : pixelFormat
|
||||
} mutableCopy];
|
||||
#endif
|
||||
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
if (interpolationRequested) {
|
||||
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(_formatDesc);
|
||||
NSDictionary *interpolationSourceAttributes =
|
||||
[FrameInterpolator sourcePixelBufferAttributesForDimensions:dimensions];
|
||||
CFDictionaryRef resolvedAttributes = NULL;
|
||||
CVReturn resolveStatus = kCVReturnInvalidArgument;
|
||||
|
||||
if (interpolationSourceAttributes != nil) {
|
||||
NSArray *attributeRequirements = @[
|
||||
destinationPixelBufferAttributes,
|
||||
interpolationSourceAttributes
|
||||
];
|
||||
resolveStatus = CVPixelBufferCreateResolvedAttributesDictionary(
|
||||
kCFAllocatorDefault,
|
||||
(__bridge CFArrayRef)attributeRequirements,
|
||||
&resolvedAttributes);
|
||||
}
|
||||
|
||||
if (resolveStatus == kCVReturnSuccess && resolvedAttributes != NULL) {
|
||||
destinationPixelBufferAttributes =
|
||||
[(__bridge NSDictionary *)resolvedAttributes mutableCopy];
|
||||
CFRelease(resolvedAttributes);
|
||||
} else {
|
||||
if (resolvedAttributes != NULL) {
|
||||
CFRelease(resolvedAttributes);
|
||||
}
|
||||
Log(LOG_W,
|
||||
@"Unable to resolve frame-interpolation source attributes for %dx%d (status %d); using native decode output",
|
||||
dimensions.width,
|
||||
dimensions.height,
|
||||
resolveStatus);
|
||||
[self->_frameInterpolator reset];
|
||||
self->_frameInterpolator = nil;
|
||||
interpolationRequested = NO;
|
||||
destinationPixelBufferAttributes = [@{
|
||||
(id)kCVPixelBufferPixelFormatTypeKey : nativePixelFormat
|
||||
} mutableCopy];
|
||||
|
||||
NSInteger targetFrameRate = MIN(self->_frameRate, self->_maxRefreshRate);
|
||||
if (@available(iOS 15.0, tvOS 15.0, *)) {
|
||||
self->_displayLink.preferredFrameRateRange = CAFrameRateRangeMake(targetFrameRate, targetFrameRate, targetFrameRate);
|
||||
} else {
|
||||
self->_displayLink.preferredFramesPerSecond = targetFrameRate;
|
||||
}
|
||||
}
|
||||
destinationPixelBufferAttributes[(id)kCVPixelBufferIOSurfacePropertiesKey] = @{};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -360,7 +459,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
|
||||
OSStatus status = [self setupDecompressionSessionWithAttributes:destinationPixelBufferAttributes];
|
||||
if (status != noErr) {
|
||||
Log(LOG_W, @"Falling back from 420v frame-interpolation decode output to native pixel format %@", nativePixelFormat);
|
||||
Log(LOG_W, @"Falling back from frame-interpolation decode output %@ to native pixel format %@", pixelFormat, nativePixelFormat);
|
||||
[self->_frameInterpolator reset];
|
||||
self->_frameInterpolator = nil;
|
||||
destinationPixelBufferAttributes = [@{
|
||||
@@ -372,12 +471,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
}
|
||||
[self setupDecompressionSessionWithAttributes:destinationPixelBufferAttributes];
|
||||
|
||||
NSInteger targetFrameRate = MIN(self->_frameRate, self->_maxRefreshRate);
|
||||
if (@available(iOS 15.0, tvOS 15.0, *)) {
|
||||
self->_displayLink.preferredFrameRateRange = CAFrameRateRangeMake(targetFrameRate, targetFrameRate, targetFrameRate);
|
||||
} else {
|
||||
self->_displayLink.preferredFramesPerSecond = targetFrameRate;
|
||||
}
|
||||
[self restartDisplayLinkForInterpolationEnabled:NO];
|
||||
}
|
||||
#else
|
||||
[self setupDecompressionSessionWithAttributes:destinationPixelBufferAttributes];
|
||||
@@ -574,6 +668,12 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
||||
}
|
||||
|
||||
- (void)cleanup{
|
||||
@synchronized([VideoDecoderRenderer class]) {
|
||||
if (sActiveRenderer == self) {
|
||||
sActiveRenderer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self->_frameQueue stop];
|
||||
|
||||
@@ -1187,9 +1287,24 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
||||
[frame setFormatDesc:self->_formatDesc];
|
||||
}
|
||||
|
||||
if (self->_frameInterpolator != nil) {
|
||||
[self->_frameInterpolator processFrame:frame completion:^(NSArray *frames) {
|
||||
FrameInterpolator *interpolator = self->_frameInterpolator;
|
||||
if (interpolator != nil && appDidEnterBackgroundWithoutPip) {
|
||||
if (!self->_frameInterpolationPaused) {
|
||||
self->_frameInterpolationPaused = YES;
|
||||
[interpolator setPaused:YES];
|
||||
}
|
||||
}
|
||||
else if (interpolator != nil) {
|
||||
if (self->_frameInterpolationPaused) {
|
||||
self->_frameInterpolationPaused = NO;
|
||||
[interpolator setPaused:NO];
|
||||
}
|
||||
[interpolator processFrame:frame completion:^(NSArray *frames) {
|
||||
dispatch_async(self->_vtq, ^{
|
||||
if (self->_frameInterpolator != interpolator) {
|
||||
return;
|
||||
}
|
||||
|
||||
int framesDropped = 0;
|
||||
for (Frame *outputFrame in (NSArray<Frame *> *)frames) {
|
||||
framesDropped += [self->_frameQueue enqueue:outputFrame withSlackSize:3];
|
||||
@@ -1403,22 +1518,7 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
||||
- (void)resetFramePacing {
|
||||
// Ensure this only runs for the AVSampleBuffer rendering backend and that the display link exists.
|
||||
if (_renderingBackend == RENDER_AVSB && _displayLink) {
|
||||
Log(LOG_I, @"Frame pacing is being reset to %d FPS...", self->_frameRate);
|
||||
|
||||
// Toggling the paused state can help re-engage the display link with the
|
||||
// run loop correctly after the app resumes from a background state like PiP.
|
||||
_displayLink.paused = YES;
|
||||
|
||||
// Re-apply the desired frame rate range. This is the critical hint for ProMotion
|
||||
// that may have been lost or ignored during the PiP transition.
|
||||
if (@available(iOS 15.0, *)) {
|
||||
_displayLink.preferredFrameRateRange = CAFrameRateRangeMake(self->_frameRate, self->_frameRate, self->_frameRate);
|
||||
} else {
|
||||
_displayLink.preferredFramesPerSecond = self->_frameRate;
|
||||
}
|
||||
|
||||
// Resume the display link immediately.
|
||||
_displayLink.paused = NO;
|
||||
[self restartDisplayLinkForInterpolationEnabled:self->_frameInterpolator.isEnabled];
|
||||
} else if (_renderingBackend == RENDER_METAL) {
|
||||
@synchronized(self) {
|
||||
if (_decompressionSession != nil) {
|
||||
|
||||
@@ -55,6 +55,23 @@ import UIKit
|
||||
completion: {})
|
||||
}
|
||||
}
|
||||
|
||||
@objc public static func handleFrameInterpolationPixelFormatTip(in vc: UIViewController?) {
|
||||
let key = "hasShownFrameInterpolationPixelFormatTip"
|
||||
guard !UserDefaults.standard.bool(forKey: key) else {
|
||||
return
|
||||
}
|
||||
UserDefaults.standard.set(true, forKey: key)
|
||||
|
||||
AlertControllerUtil.showAlert(
|
||||
in: vc,
|
||||
title: LocalizationHelper.localizedString(forKey: "Tips"),
|
||||
message: "\n\(LocalizationHelper.localizedString(forKey: "Most devices currently support frame interpolation only for 8-bit YUV 4:2:0 SDR video. In this case, if HDR or YUV 4:4:4 is enabled, intermediate frames will still be generated in 8-bit YUV 4:2:0 SDR."))",
|
||||
withCancel: false,
|
||||
buttonTitle: LocalizationHelper.localizedString(forKey: "Got it!"),
|
||||
countdown: 5
|
||||
)
|
||||
}
|
||||
|
||||
@objc public static func needUpdateDefaultSettings() -> Bool {
|
||||
// let key = "needUpdateDefaultSettings20260226-1"
|
||||
|
||||
@@ -852,8 +852,8 @@ static NSMutableSet* hostList;
|
||||
}
|
||||
}
|
||||
|
||||
_streamConfig.height = [streamSettings.height intValue];
|
||||
_streamConfig.width = [streamSettings.width intValue];
|
||||
_streamConfig.height = streamSettings.height.intValue;
|
||||
_streamConfig.width = streamSettings.width.intValue;
|
||||
|
||||
NSLog(@"saveSettings.width %d, %d", _streamConfig.width, _streamConfig.height);
|
||||
#if TARGET_OS_TV
|
||||
@@ -1399,11 +1399,16 @@ static NSMutableSet* hostList;
|
||||
[self.settingsViewController setHidden:_settingsExpandedInStreamView forStack:self.settingsViewController.appThemeStack];
|
||||
[self.settingsViewController.renderingBackendSelector setEnabled:!_settingsExpandedInStreamView];
|
||||
// Enable frame pacing mode selector only if not in stream view AND not in performance mode
|
||||
BOOL shouldEnableFramePacingSelector = !_settingsExpandedInStreamView && (self.settingsViewController.renderingBackendSelector.selectedSegmentIndex != RENDER_METAL);
|
||||
[self.settingsViewController.framePacingModeSelector setEnabled:shouldEnableFramePacingSelector];
|
||||
BOOL shouldEnableFrameQueueSettings = !_settingsExpandedInStreamView && (self.settingsViewController.renderingBackendSelector.selectedSegmentIndex != RENDER_METAL);
|
||||
// [self.settingsViewController.framePacingModeSelector setEnabled:shouldEnableFrameQueueSettings];
|
||||
[self.settingsViewController.framePacingModeSelector setEnabled:!_settingsExpandedInStreamView forSegmentAtIndex:0];
|
||||
[self.settingsViewController.framePacingModeSelector setEnabled:!_settingsExpandedInStreamView forSegmentAtIndex:1];
|
||||
|
||||
// [self.settingsViewController.frameTimebaseSwitch setEnabled:shouldEnableFramePacing];
|
||||
[self.settingsViewController.asyncFrameDequeueSwitch setEnabled:shouldEnableFramePacingSelector];
|
||||
[self.settingsViewController setHidden:_settingsExpandedInStreamView || !(shouldEnableFramePacingSelector && self.settingsViewController.framePacingModeSelector.selectedSegmentIndex == FramePacingModeQueue) forStack:self.settingsViewController.frameQueueSizeStack];
|
||||
[self.settingsViewController.asyncFrameDequeueSwitch setEnabled:shouldEnableFrameQueueSettings];
|
||||
[self.settingsViewController setHidden:_settingsExpandedInStreamView || !(shouldEnableFrameQueueSettings && self.settingsViewController.framePacingModeSelector.selectedSegmentIndex == FramePacingModeQueue) forStack:self.settingsViewController.frameQueueSizeStack];
|
||||
[self.settingsViewController setHidden:!(self.settingsViewController.framePacingModeSelector.selectedSegmentIndex == FramePacingModeInterpolation) forStack:self.settingsViewController.interpolationLevelStack];
|
||||
[self.settingsViewController setHidden:_settingsExpandedInStreamView || !(self.settingsViewController.framePacingModeSelector.selectedSegmentIndex == FramePacingModeInterpolation) forStack:self.settingsViewController.streamDimensionScaleStack];
|
||||
|
||||
// Disable mic switch if sunshine does not support mic redirection
|
||||
[self.settingsViewController.redirectMicSwitch setEnabled:!_settingsExpandedInStreamView||streamFrameViewController.micStreamInitialized];
|
||||
@@ -2145,24 +2150,19 @@ static NSMutableSet* hostList;
|
||||
.height = (int32_t)currentSettings.height.intValue,
|
||||
};
|
||||
[self fillResolutionTable:tempResolutionTable externalDisplayMode:currentSettings.externalDisplayMode.intValue];
|
||||
|
||||
return;
|
||||
|
||||
/*
|
||||
int selectedIndex = currentSettings.resolutionSelected.intValue;
|
||||
if (selectedIndex >= 0 && selectedIndex < 6) {
|
||||
CMVideoDimensions originalDimensions = tempResolutionTable[selectedIndex];
|
||||
|
||||
CMVideoDimensions targetDimensions;
|
||||
if(currentSettings.framePacingMode.intValue == FramePacingModeInterpolation) {
|
||||
targetDimensions = [FrameInterpolator interpolatableDimensionsBy:originalDimensions];
|
||||
if(!(targetDimensions.width>0 && targetDimensions.height>0)) targetDimensions = [FrameInterpolator interpolatableDimensionsBy720p:originalDimensions];
|
||||
}
|
||||
else targetDimensions = originalDimensions;
|
||||
|
||||
CMVideoDimensions targetDimensions = originalDimensions;
|
||||
currentSettings.width = @(targetDimensions.width);
|
||||
currentSettings.height = @(targetDimensions.height);
|
||||
NSLog(@"Updated resolution to: %@ x %@", currentSettings.width, currentSettings.height);
|
||||
}
|
||||
|
||||
[dataMan saveData];
|
||||
*/
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV
|
||||
|
||||
@@ -128,6 +128,10 @@
|
||||
@property (strong, nonatomic) IBOutlet UIStackView *graphOpacityStack;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *renderingBackendSelector;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *framePacingModeSelector;
|
||||
@property (strong, nonatomic) IBOutlet UIStackView *interpolationLevelStack;
|
||||
@property (strong, nonatomic) IBOutlet UISlider *interpolationLevelSlider;
|
||||
@property (strong, nonatomic) IBOutlet UIStackView *streamDimensionScaleStack;
|
||||
@property (strong, nonatomic) IBOutlet UISlider *streamDimensionScaleSlider;
|
||||
|
||||
@property (strong, nonatomic) IBOutlet UIStackView *backgroundSessionTimerStack;
|
||||
@property (strong, nonatomic) IBOutlet UISlider *backgroundSessionTimerSlider;
|
||||
|
||||
@@ -633,6 +633,12 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
|
||||
if(!settingsViewAlreadyAppeared) {
|
||||
if(![self contentOffsetRestored]) _scrollView.contentOffset = CGPointMake(_scrollView.contentOffset.x, tempSettings.settingsMenuOffset.floatValue);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.view layoutIfNeeded];
|
||||
[self updateResolutionTable];
|
||||
[self updateInterpolationLevelSliderWithMaximumDimension:self->tempSettings.interpolationMaximumDimension.integerValue];
|
||||
[self.streamDimensionScaleSlider sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
});
|
||||
}
|
||||
if(@available(iOS 13.0, *)) if(ControllerUtil.primaryGCController) [self restoreControllerNavigationHighlight];
|
||||
|
||||
@@ -656,6 +662,13 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
bool unlockDisplayOrientationFlipped = tempSettings.unlockDisplayOrientation != (_unlockDisplayOrientationSelector.selectedSegmentIndex == 1);
|
||||
if(unlockDisplayOrientationFlipped) [_mainFrameViewController setNeedsUpdateAllowedOrientation]; // handle allow portratit on & off
|
||||
if (@available(iOS 13.0, *)) if(ControllerNavigator.radialMenuView.superview) [ControllerNavigator updateRadialMenu];
|
||||
|
||||
if(self.framePacingModeSelector.selectedSegmentIndex == FramePacingModeInterpolation) {
|
||||
[VideoDecoderRenderer startOrRestartFrameInterpolation];
|
||||
}
|
||||
else {
|
||||
[VideoDecoderRenderer stopFrameInterpolation];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,6 +897,12 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
[self addSetting:self.framePacingStack ofId:@"framePacingStack" to:videoSection];
|
||||
if(!FrameInterpolator.deviceSupportsInterpolation) [self.framerateSelector setEnabled:false forSegmentAtIndex:FramePacingModeInterpolation];
|
||||
|
||||
self.interpolationLevelStack.hasDynamicLabel = YES;
|
||||
[self addSetting:self.interpolationLevelStack ofId:@"interpolationLevelStack" to:videoSection];
|
||||
|
||||
self.streamDimensionScaleStack.hasDynamicLabel = YES;
|
||||
[self addSetting:self.streamDimensionScaleStack ofId:@"streamDimensionScaleStack" to:videoSection];
|
||||
|
||||
self.frameQueueSizeStack.hasDynamicLabel = YES;
|
||||
[self addSetting:self.frameQueueSizeStack ofId:@"frameQueueSizeStack" to:videoSection];
|
||||
|
||||
@@ -2235,6 +2254,12 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
|
||||
NSInteger framePacingMode = [self->tempSettings.framePacingMode integerValue];
|
||||
self.framePacingModeSelector.selectedSegmentIndex = framePacingMode;
|
||||
((UILabel *)self.interpolationLevelStack.arrangedSubviews.firstObject).text =
|
||||
[LocalizationHelper localizedStringForKey:@"Interpolation Resolution"];
|
||||
[self.interpolationLevelSlider addTarget:self action:@selector(interpolationLevelSliderMoved:) forControlEvents:UIControlEventValueChanged];
|
||||
((UILabel *)self.streamDimensionScaleStack.arrangedSubviews.firstObject).text =
|
||||
[LocalizationHelper localizedStringForKey:@"Scaled Stream Resolution"];
|
||||
[self.streamDimensionScaleSlider addTarget:self action:@selector(streamDimensionScaleSliderMoved:) forControlEvents:UIControlEventValueChanged];
|
||||
[self.framePacingModeSelector addTarget:self action:@selector(framePacingModeChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
[self.framePacingModeSelector sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
|
||||
@@ -2311,6 +2336,11 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
|
||||
self->_lastSelectedResolutionIndex = resolution;
|
||||
self.resolutionSelector.selectedSegmentIndex = resolution;
|
||||
[self updateInterpolationLevelSliderWithMaximumDimension:self->tempSettings.interpolationMaximumDimension.integerValue];
|
||||
self.streamDimensionScaleSlider.minimumValue = 0;
|
||||
self.streamDimensionScaleSlider.maximumValue = 1;
|
||||
self.streamDimensionScaleSlider.value = MIN(1, MAX(0, self->tempSettings.streamDimensionScale.floatValue));
|
||||
[self.streamDimensionScaleSlider sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
[self.resolutionSelector addTarget:self action:@selector(newResolutionChosen) forControlEvents:UIControlEventValueChanged];
|
||||
|
||||
self.framerateSelector.selectedSegmentIndex = framerate;
|
||||
@@ -2690,10 +2720,11 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
- (void)framePacingModeChanged:(UISegmentedControl *)sender {
|
||||
// Hide frame queue size for Off and Legacy modes
|
||||
[GenericUtils handleLegacyFramePacingTipIn:self with:sender passAlert:settingsViewJustExpanded uiAction:^{
|
||||
[self setHidden:(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy) forStack:self.frameQueueSizeStack];
|
||||
// [self setHidden:(sender.selectedSegmentIndex != FramePacingModeQueue) forStack:self.frameTimebaseStack];
|
||||
[self setHidden:(sender.selectedSegmentIndex != FramePacingModeQueue
|
||||
|| sender.selectedSegmentIndex != FramePacingModeInterpolation
|
||||
|| self->_mainFrameViewController.isStreaming) forStack:self.frameQueueSizeStack];
|
||||
// [self setHidden:(sender.selectedSegmentIndex != FramePacingModeQueue) forStack:self.frameTimebaseStack];
|
||||
[self setHidden:((sender.selectedSegmentIndex != FramePacingModeQueue
|
||||
&& sender.selectedSegmentIndex != FramePacingModeInterpolation)
|
||||
|| self.renderingBackendSelector.selectedSegmentIndex != 0) forStack:self.asyncFrameDequeueStack];
|
||||
|
||||
if(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy){
|
||||
@@ -2705,6 +2736,8 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
[self setHidden:(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy) forStack:self.performanceGraphStack];
|
||||
|
||||
bool enableInterpolation = sender.selectedSegmentIndex == FramePacingModeInterpolation;
|
||||
[self setHidden:!enableInterpolation forStack:self.interpolationLevelStack];
|
||||
[self setHidden:!enableInterpolation || self->_mainFrameViewController.isStreaming forStack:self.streamDimensionScaleStack];
|
||||
[self widget:self.frameQueueSizeSlider setEnabled:!enableInterpolation];
|
||||
[self updateResolutionDisplayLabel];
|
||||
if(enableInterpolation){
|
||||
@@ -2712,6 +2745,9 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
if(!FrameInterpolator.dimensionLimitsAreKnown){
|
||||
NSLog(@"FrameInterpolator dimensionLimitsUnknown");
|
||||
}
|
||||
if(!self->settingsViewJustExpanded){
|
||||
[GenericUtils handleFrameInterpolationPixelFormatTipIn:self];
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -3663,7 +3699,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:key];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
if(self.framerateSelector.selectedSegmentIndex == 2
|
||||
if(self.framerateSelector.selectedSegmentIndex == self.framerateSelector.numberOfSegments - 1
|
||||
&& self.framePacingModeSelector.selectedSegmentIndex == FramePacingModeInterpolation) self.framerateSelector.selectedSegmentIndex = self.framerateSelector.previousSelectedSegmentIndex;
|
||||
|
||||
// NSInteger fps = [self getChosenFrameRate];
|
||||
@@ -3735,10 +3771,13 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
}
|
||||
|
||||
- (void) newResolutionChosen {
|
||||
[self updateBitrate];
|
||||
[self updateResolutionDisplayLabel];
|
||||
_lastSelectedResolutionIndex = self.resolutionSelector.selectedSegmentIndex;
|
||||
[self updateResolutionTable];
|
||||
if (self.mainFrameViewController.settingsExpandedInStreamView) {
|
||||
[self updateResolutionDisplayLabel];
|
||||
} else {
|
||||
[self updateResolutionTable];
|
||||
}
|
||||
[self updateBitrate];
|
||||
}
|
||||
|
||||
- (void)customResolutionSwitched:(UISwitch* )sender{
|
||||
@@ -3836,11 +3875,44 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
}
|
||||
|
||||
- (void) updateResolutionDisplayLabel {
|
||||
CMVideoDimensions dimensions = [self getChosenStreamDimensions];
|
||||
CMVideoDimensions dimensions = [self getChosenPresetStreamDimensions];
|
||||
NSInteger width = dimensions.width;
|
||||
NSInteger height = dimensions.height;
|
||||
|
||||
[self findDynamicLabelFromStack:_resolutionSelectorStack].text = [NSString stringWithFormat:@"%ld × %ld", (long)width, (long)height];
|
||||
if (self.interpolationLevelSlider != nil) {
|
||||
[self.interpolationLevelSlider sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateInterpolationLevelSliderWithMaximumDimension:(NSInteger)savedMaximumDimension {
|
||||
self.interpolationLevelSlider.minimumValue = 0;
|
||||
self.interpolationLevelSlider.maximumValue = 1;
|
||||
self.interpolationLevelSlider.value = [FrameInterpolator
|
||||
interpolationLevelForDimensions:[self getChosenPresetStreamDimensions]
|
||||
savedMaximumDimension:savedMaximumDimension];
|
||||
[self.interpolationLevelSlider sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
|
||||
- (void)interpolationLevelSliderMoved:(UISlider *)sender {
|
||||
InterpolationResolutionConfiguration *configuration = [self getCurrentInterpolationResolutionConfiguration];
|
||||
[self findDynamicLabelFromStack:self.interpolationLevelStack].text =
|
||||
[NSString stringWithFormat:@" %d × %d ", configuration.dimensions.width, configuration.dimensions.height];
|
||||
if (self.streamDimensionScaleSlider != nil) {
|
||||
[self.streamDimensionScaleSlider sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
}
|
||||
|
||||
- (InterpolationResolutionConfiguration *)getCurrentInterpolationResolutionConfiguration {
|
||||
return [FrameInterpolator
|
||||
resolutionConfigurationForDimensions:[self getChosenPresetStreamDimensions]
|
||||
level:self.interpolationLevelSlider.value];
|
||||
}
|
||||
|
||||
- (void)streamDimensionScaleSliderMoved:(UISlider *)sender {
|
||||
CMVideoDimensions dimensions = [self getChosenStreamDimensions];
|
||||
[self findDynamicLabelFromStack:self.streamDimensionScaleStack].text =
|
||||
[NSString stringWithFormat:@" %d × %d ", dimensions.width, dimensions.height];
|
||||
}
|
||||
|
||||
- (void) touchMoveEventIntervalSliderMoved:(UISlider* )sender{
|
||||
@@ -3911,7 +3983,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
}
|
||||
}
|
||||
|
||||
- (CMVideoDimensions)getChosenStreamDimensions {
|
||||
- (CMVideoDimensions)getChosenPresetStreamDimensions {
|
||||
// because the 4k resolution can be removed
|
||||
CMVideoDimensions originalDimensions;
|
||||
if (self.customResolutionSwitch.isOn) {
|
||||
@@ -3920,6 +3992,12 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
originalDimensions = resolutionTable[self.resolutionSelector.selectedSegmentIndex];
|
||||
}
|
||||
|
||||
if(originalDimensions.width == 0 || originalDimensions.height == 0) {
|
||||
originalDimensions.width = tempSettings.width.intValue;
|
||||
originalDimensions.height = tempSettings.height.intValue;
|
||||
}
|
||||
|
||||
/*
|
||||
CMVideoDimensions targetDimensions = self.framePacingModeSelector.selectedSegmentIndex == FramePacingModeInterpolation
|
||||
? [FrameInterpolator interpolatableDimensionsBy:originalDimensions]
|
||||
: originalDimensions;
|
||||
@@ -3929,8 +4007,25 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
}
|
||||
|
||||
NSLog(@"dimensions: %d, %d", targetDimensions.width, targetDimensions.height);
|
||||
*/
|
||||
|
||||
return originalDimensions;
|
||||
}
|
||||
|
||||
return targetDimensions;
|
||||
- (CMVideoDimensions)getChosenStreamDimensions {
|
||||
CMVideoDimensions presetDimensions = [self getChosenPresetStreamDimensions];
|
||||
if (self.streamDimensionScaleSlider == nil) {
|
||||
return [FrameInterpolator
|
||||
scaledStreamDimensionsWithPresetDimensions:presetDimensions
|
||||
interpolationDimensions:presetDimensions
|
||||
scale:1];
|
||||
}
|
||||
|
||||
InterpolationResolutionConfiguration *configuration = [self getCurrentInterpolationResolutionConfiguration];
|
||||
return [FrameInterpolator
|
||||
scaledStreamDimensionsWithPresetDimensions:presetDimensions
|
||||
interpolationDimensions:configuration.dimensions
|
||||
scale:self.streamDimensionScaleSlider.value];
|
||||
}
|
||||
|
||||
- (UIStackView *)findFlatStackViewFrom:(UIView *)view {
|
||||
@@ -4299,6 +4394,11 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
|
||||
NSInteger renderingBackend = self.renderingBackendSelector.selectedSegmentIndex;
|
||||
NSInteger framePacingMode = self.framePacingModeSelector.selectedSegmentIndex;
|
||||
InterpolationResolutionConfiguration *interpolationConfiguration =
|
||||
[self getCurrentInterpolationResolutionConfiguration];
|
||||
NSInteger interpolationMaximumDimension = interpolationConfiguration.maximumDimension;
|
||||
NSInteger interpolationMaximumPixelCount = interpolationConfiguration.maximumPixelCount;
|
||||
CGFloat streamDimensionScale = self.streamDimensionScaleSlider.value;
|
||||
NSInteger onscreenControls = self.onScreenWidgetSelector.selectedSegmentIndex;
|
||||
NSInteger keyboardToggleFingers = self.softKeyboardGestureSelector.selectedSegmentIndex == 3 ? 20 : self.softKeyboardGestureSelector.selectedSegmentIndex+3;
|
||||
NSInteger oscLayoutToolFingers = (uint16_t)self->oswLayoutFingers;
|
||||
@@ -4428,6 +4528,9 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
graphOpacity:graphOpacity
|
||||
renderingBackend:renderingBackend
|
||||
framePacingMode:framePacingMode
|
||||
interpolationMaximumDimension:interpolationMaximumDimension
|
||||
interpolationMaximumPixelCount:interpolationMaximumPixelCount
|
||||
streamDimensionScale:streamDimensionScale
|
||||
sendDummyEvent:sendDummyEvent
|
||||
rememberFoldState:rememberFoldState
|
||||
singleTapSensitivy:singleTapSensitivity
|
||||
@@ -4466,7 +4569,6 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
|
||||
@@ -3056,6 +3056,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FIp-Lv-Lbl.text" : {
|
||||
"comment" : "Class = \"UILabel\"; text = \"Interpolation Resolution\"; ObjectID = \"FIp-Lv-Lbl\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Interpolation Resolution"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"FIp-Sc-Lbl.text" : {
|
||||
"comment" : "Class = \"UILabel\"; text = \"Scaled Stream Resolution\"; ObjectID = \"FIp-Sc-Lbl\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Scaled Stream Resolution"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"FJv-HJ-UYJ.text" : {
|
||||
"comment" : "Class = \"UILabel\"; text = \"Touch Move Event Interval\"; ObjectID = \"FJv-HJ-UYJ\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
|
||||
@@ -2557,6 +2557,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FIi-Lv-Lbl.text" : {
|
||||
"comment" : "Class = \"UILabel\"; text = \"Interpolation Resolution\"; ObjectID = \"FIi-Lv-Lbl\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Interpolation Resolution"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"FIi-Sc-Lbl.text" : {
|
||||
"comment" : "Class = \"UILabel\"; text = \"Scaled Stream Resolution\"; ObjectID = \"FIi-Sc-Lbl\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Scaled Stream Resolution"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fRl-Ra-Lbl.text" : {
|
||||
"comment" : "Class = \"UILabel\"; text = \"Full Color Range\"; ObjectID = \"fRl-Ra-Lbl\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
|
||||
Reference in New Issue
Block a user