- restore asyncDequeue switch
- tweak frame buffering
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
</entity>
|
||||
<entity name="Settings" representedClassName="Settings" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="appTheme" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="asyncFrameDequeue" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="asyncFrameDequeue" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="asyncNativeTouchPriority" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="audioConfig" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="audioEngine" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
- (id) initWithConfig:(StreamConfiguration*)config renderView:(UIView*)view connectionCallbacks:(id<ConnectionCallbacks>)callback;
|
||||
|
||||
- (void) stopStream;
|
||||
- (void) setNeedRequeuing:(bool)needRequeuing;
|
||||
|
||||
- (NSString*) getStatsOverlayText: (uint16_t) overlayLevel;
|
||||
|
||||
|
||||
@@ -114,6 +114,11 @@
|
||||
});
|
||||
}
|
||||
|
||||
- (void) setNeedRequeuing:(bool)needRequeuing{
|
||||
[_videoRenderer.frameQueue clear];
|
||||
_videoRenderer.needRequeuing = needRequeuing;
|
||||
}
|
||||
|
||||
- (void) stopStream
|
||||
{
|
||||
[_connection terminate];
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
@property (atomic, readonly) PlotMetrics decodeMetrics;
|
||||
@property (atomic, readonly) PlotMetrics frameQueueMetrics;
|
||||
@property (atomic, assign) bool needRequeuing;
|
||||
@property (nonatomic, strong) FrameQueue* frameQueue;
|
||||
|
||||
@property (nonatomic, strong, readonly) AVSampleBufferDisplayLayer *displayLayer;
|
||||
|
||||
|
||||
@@ -52,9 +52,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
VTDecompressionSessionRef _decompressionSession;
|
||||
|
||||
CADisplayLink *_displayLink;
|
||||
FrameQueue *_frameQueue;
|
||||
uint8_t queueSize;
|
||||
bool isFirstFrame;
|
||||
NSInteger _maxRefreshRate;
|
||||
RenderingBackend _renderingBackend;
|
||||
|
||||
@@ -145,9 +143,10 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
|
||||
_framePacingMode = tempSettings.framePacingMode.integerValue;
|
||||
_asyncFrameDequeue = tempSettings.asyncFrameDequeue;
|
||||
NSLog(@"_asyncFrameDequeue %d", _asyncFrameDequeue);
|
||||
_enableTimebase = false;
|
||||
queueSize = tempSettings.frameQueueSize.intValue;
|
||||
isFirstFrame = true;
|
||||
_needRequeuing = true;
|
||||
isIPhone = [Utils isIPhone];
|
||||
|
||||
_frameQueue = [FrameQueue sharedInstance];
|
||||
@@ -155,7 +154,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
[_frameQueue setHighWaterMark:(int)[tempSettings.frameQueueSize integerValue]];
|
||||
|
||||
[self reinitializeDisplayLayer];
|
||||
NSTimeInterval interval = 1.0/tempSettings.framerate.intValue;
|
||||
// NSTimeInterval interval = 1.0/tempSettings.framerate.intValue;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(reinitializeDisplayLayer)
|
||||
@@ -261,7 +260,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
||||
// Check for issues with the SampleBuffer, this should be much less likely since
|
||||
// AVSB is not actually decoding the frames anymore
|
||||
if (self->_displayLayer.status == AVQueuedSampleBufferRenderingStatusFailed) {
|
||||
Log(LOG_E, @"Display layer rendering failed: %@", _displayLayer.error);
|
||||
// Log(LOG_E, @"Display layer rendering failed: %@", _displayLayer.error);
|
||||
|
||||
// Recreate the display layer. We are already on the main thread,
|
||||
// so this is safe to do right here.
|
||||
@@ -277,10 +276,11 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
||||
|
||||
#pragma mark DisplayLink - Frame Pacing - Vsync with FrameQueue
|
||||
|
||||
/*
|
||||
// This frame pacing method was inspired by the behavior of moonlight-qt's Pacer class, although it has evolved
|
||||
// a few additional features. Incoming frames from Sunshine are asynchronously processed into a queue by the VideoRecv thread.
|
||||
// DisplayLink calls us every vsync we we try to present the most recent frame. We try to maintain a user-configurable buffer
|
||||
// of 1-5 frames. If the buffer is full, every other frame is dropped which just appears to the user as a lower framerate stream.
|
||||
// of 1-5 frames. If the buffer is full, every other frame is dropped which just appears to the user as a lower framerate stream. */
|
||||
- (void)renderModeAVSB:(CADisplayLink *)link {
|
||||
// NSTimeInterval current = link.targetTimestamp;
|
||||
// NSLog(@"link %f", link.duration);
|
||||
@@ -303,13 +303,17 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
||||
|
||||
CFTimeInterval waitFor = targetTime - dl0;
|
||||
|
||||
/*
|
||||
if (waitFor < 0.001f) {
|
||||
waitFor = isIPhone ? waitFor : 0.0f;
|
||||
NSLog(@"waitFor %f", waitFor);
|
||||
// waitFor = isIPhone ? waitFor : 0.0f;
|
||||
waitFor = 0.0f;
|
||||
}
|
||||
*/
|
||||
|
||||
if(isFirstFrame ? _frameQueue.count>0 : true){
|
||||
if(_needRequeuing ? _frameQueue.count>queueSize-1 : true){
|
||||
// if(true){
|
||||
if(isFirstFrame) isFirstFrame = false;
|
||||
_needRequeuing = false;
|
||||
if(_asyncFrameDequeue){
|
||||
[_frameQueue dequeueWithTimeout:waitFor completion:^(Frame *frame) {
|
||||
if (frame) {
|
||||
|
||||
@@ -1168,6 +1168,15 @@ static NSMutableSet* hostList;
|
||||
_settingsViewExpanded = position != FrontViewPositionLeft;
|
||||
if (position == FrontViewPositionLeft) {
|
||||
self.navigationItem.leftBarButtonItems = @[_settingsButton];
|
||||
|
||||
if(streamFrameViewController.streamMan){
|
||||
NSLog(@"setNeedRequeuing %f", CACurrentMediaTime());
|
||||
double delayInSeconds = 0.1;
|
||||
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
|
||||
dispatch_after(popTime, dispatch_get_main_queue(), ^{
|
||||
[self->streamFrameViewController.streamMan setNeedRequeuing:true];
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
self.navigationItem.leftBarButtonItems = @[];
|
||||
@@ -1227,10 +1236,10 @@ static NSMutableSet* hostList;
|
||||
[settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.appThemeStack];
|
||||
[settingsViewController.renderingBackendSelector setEnabled:!_settingsExpandedInStreamView];
|
||||
// Enable frame pacing mode selector only if not in stream view AND not in performance mode
|
||||
BOOL shouldEnableFramePacing = !_settingsExpandedInStreamView && (settingsViewController.renderingBackendSelector.selectedSegmentIndex != RENDER_METAL);
|
||||
[settingsViewController.framePacingModeSelector setEnabled:shouldEnableFramePacing];
|
||||
BOOL shouldEnableFramePacingSelector = !_settingsExpandedInStreamView && (settingsViewController.renderingBackendSelector.selectedSegmentIndex != RENDER_METAL);
|
||||
[settingsViewController.framePacingModeSelector setEnabled:shouldEnableFramePacingSelector];
|
||||
// [settingsViewController.frameTimebaseSwitch setEnabled:shouldEnableFramePacing];
|
||||
// [settingsViewController.asyncFrameDequeueSwitch setEnabled:shouldEnableFramePacing];
|
||||
[settingsViewController.asyncFrameDequeueSwitch setEnabled:shouldEnableFramePacingSelector && settingsViewController.framePacingModeSelector.selectedSegmentIndex == FramePacingModeQueue];
|
||||
[settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.frameQueueSizeStack];
|
||||
|
||||
// Disable mic switch if sunshine does not support mic redirection
|
||||
|
||||
@@ -982,7 +982,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
[self addSetting:self.leftClickDelayStack ofId:@"leftClickDelayStack" withInfoTag:NO withDynamicLabel:YES to:experimentalSection];
|
||||
[self addSetting:self.renderingBackendStack ofId:@"renderingBackendStack" withInfoTag:YES withDynamicLabel:NO to:experimentalSection];
|
||||
// [self addSetting:self.frameTimebaseStack ofId:@"frameTimebaseStack" withInfoTag:NO withDynamicLabel:NO to:videoSection];
|
||||
// [self addSetting:self.asyncFrameDequeueStack ofId:@"asyncFrameDequeueStack" withInfoTag:NO withDynamicLabel:NO to:experimentalSection];
|
||||
[self addSetting:self.asyncFrameDequeueStack ofId:@"asyncFrameDequeueStack" withInfoTag:NO withDynamicLabel:NO to:experimentalSection];
|
||||
[self addSetting:self.performanceGraphStack ofId:@"performanceGraphStack" withInfoTag:YES withDynamicLabel:NO to:experimentalSection];
|
||||
[self addDynamicLabelForStack:self.graphOpacityStack];
|
||||
|
||||
@@ -2292,6 +2292,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
// Set pacing method to Queue and disable selector
|
||||
[self.framePacingModeSelector setSelectedSegmentIndex:FramePacingModeQueue];
|
||||
[self.framePacingModeSelector setEnabled:NO];
|
||||
[self setHidden:true forStack:self.asyncFrameDequeueStack];
|
||||
} else {
|
||||
// Balanced mode (AVSB renderer) - enable PiP toggle if iOS 15+
|
||||
if (@available(iOS 15.0, *)) {
|
||||
@@ -2301,6 +2302,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
[self.pipSwitch setEnabled:NO];
|
||||
}
|
||||
[self.framePacingModeSelector setEnabled:YES];
|
||||
[self setHidden:false forStack:self.asyncFrameDequeueStack];
|
||||
}
|
||||
|
||||
// Get the current settings to compare with the new selection
|
||||
@@ -2331,6 +2333,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction * _Nonnull action) {
|
||||
self.renderingBackendSelector.selectedSegmentIndex = 0;
|
||||
[self renderingBackendChanged:self.renderingBackendSelector];
|
||||
NSURL *url = [NSURL URLWithString:[LocalizationHelper localizedStringForKey:@"betterPerformanceLink"]];
|
||||
if ([[UIApplication sharedApplication] canOpenURL:url]) {
|
||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
||||
@@ -2347,7 +2350,8 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
// Hide frame queue size for Off and Legacy modes
|
||||
[self setHidden:(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy) forStack:self.frameQueueSizeStack];
|
||||
// [self setHidden:(sender.selectedSegmentIndex != FramePacingModeQueue) forStack:self.frameTimebaseStack];
|
||||
// [self setHidden:(sender.selectedSegmentIndex != FramePacingModeQueue) forStack:self.asyncFrameDequeueStack];
|
||||
[self setHidden:(sender.selectedSegmentIndex != FramePacingModeQueue
|
||||
|| self.renderingBackendSelector.selectedSegmentIndex != 0) forStack:self.asyncFrameDequeueStack];
|
||||
|
||||
if(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy){
|
||||
[self.enableGraphsSwitch setOn:NO];
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
@interface StreamFrameViewController : UIViewController <ConnectionCallbacks, ControllerSupportDelegate, UserInteractionDelegate, UIScrollViewDelegate, ToolboxSpecialEntryDelegate, AVPictureInPictureControllerDelegate, OnScreenFunctionalButtonDelegate>
|
||||
|
||||
#endif
|
||||
@property (nonatomic) StreamManager* streamMan;
|
||||
@property (nonatomic, strong) StreamManager* streamMan;
|
||||
@property (nonatomic) StreamConfiguration* streamConfig;
|
||||
@property (nonatomic, strong) AVPictureInPictureController *pipController API_AVAILABLE(ios(9.0));
|
||||
@property (nonatomic, strong) AVPictureInPictureControllerContentSource *pipContentSource API_AVAILABLE(ios(15.0)); // Needed for iOS 15+ layer-based PiP
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
|
||||
@implementation StreamFrameViewController {
|
||||
ControllerSupport *_controllerSupport;
|
||||
StreamManager *_streamMan;
|
||||
TemporarySettings *_settings;
|
||||
OSCProfile* _oscProfile;
|
||||
NSTimer *_inactivityTimer;
|
||||
@@ -1092,6 +1091,7 @@
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||
appDidEnterBackgroundWithoutPip = false;
|
||||
[_streamMan setNeedRequeuing:true];
|
||||
// Stop the background timer, since we're foregrounded again
|
||||
if (_inactivityTimer != nil) {
|
||||
Log(LOG_I, @"Stopping inactivity timer after becoming active again");
|
||||
@@ -1338,11 +1338,15 @@
|
||||
&& _settings.sdrPerformanceWorkaround
|
||||
&& [Utils hdrSupported]
|
||||
){
|
||||
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC));
|
||||
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC));
|
||||
dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
if(LiGetCurrentHostDisplayHdrMode()){
|
||||
NSArray* hdrCommand = [CommandManager.shared extractAutoReleaseButtonStringsFrom:@"WIN+ALT+B"];
|
||||
[CommandManager.shared sendAutoReleaseComboCommandWithCmdStrings:hdrCommand delay:0.15 index:0 pressOnly:false releaseOnly:false];
|
||||
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
|
||||
dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self->_streamMan setNeedRequeuing:true];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1711,6 +1715,11 @@
|
||||
|
||||
Log(LOG_I, @"View size changed, terminating stream");
|
||||
|
||||
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
|
||||
dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self->_streamMan setNeedRequeuing:true];
|
||||
});
|
||||
|
||||
double delayInSeconds = 0.2;
|
||||
if (_delayedRemoveExtScreen) {
|
||||
dispatch_block_cancel(_delayedRemoveExtScreen);
|
||||
|
||||
Reference in New Issue
Block a user