Switch to a pull-based renderer and render from CADisplayLink callback

This commit is contained in:
Cameron Gutman 2022-01-13 22:37:18 -06:00
parent 8391c766c7
commit 512c1479a0
2 changed files with 34 additions and 28 deletions

View File

@ -416,7 +416,6 @@ void ClConnectionStatusUpdate(int status)
LiInitializeVideoCallbacks(&_drCallbacks); LiInitializeVideoCallbacks(&_drCallbacks);
_drCallbacks.setup = DrDecoderSetup; _drCallbacks.setup = DrDecoderSetup;
_drCallbacks.cleanup = DrCleanup; _drCallbacks.cleanup = DrCleanup;
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
// RFI doesn't work properly with HEVC on iOS 11 with an iPhone SE (at least) // RFI doesn't work properly with HEVC on iOS 11 with an iPhone SE (at least)
// It doesnt work on macOS either, tested with Network Link Conditioner. // It doesnt work on macOS either, tested with Network Link Conditioner.
@ -426,7 +425,7 @@ void ClConnectionStatusUpdate(int status)
#if !TARGET_OS_TV #if !TARGET_OS_TV
CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC | CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC |
#endif #endif
CAPABILITY_DIRECT_SUBMIT; CAPABILITY_PULL_RENDERER;
LiInitializeAudioCallbacks(&_arCallbacks); LiInitializeAudioCallbacks(&_arCallbacks);
_arCallbacks.init = ArInit; _arCallbacks.init = ArInit;

View File

@ -78,21 +78,31 @@
{ {
self->videoFormat = videoFormat; self->videoFormat = videoFormat;
if (refreshRate > 60) { _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];
// HACK: We seem to just get 60 Hz screen updates even with a 120 FPS stream if if (@available(iOS 10.0, tvOS 10.0, *)) {
// we don't set preferredFramesPerSecond somewhere. Since we're a UIKit view, we _displayLink.preferredFramesPerSecond = refreshRate;
// have to use CADisplayLink for that. See https://github.com/moonlight-stream/moonlight-ios/issues/372
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];
if (@available(iOS 10.0, tvOS 10.0, *)) {
_displayLink.preferredFramesPerSecond = refreshRate;
}
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
} }
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
} }
int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
- (void)displayLinkCallback:(CADisplayLink *)sender - (void)displayLinkCallback:(CADisplayLink *)sender
{ {
// No-op - rendering done in submitDecodeBuffer VIDEO_FRAME_HANDLE handle;
PDECODE_UNIT du;
while (LiPollNextVideoFrame(&handle, &du)) {
LiCompleteVideoFrame(handle, DrSubmitDecodeUnit(du));
#if 0
// Always keep one pending frame smooth out gaps due to
// network jitter at the cost of 1 frame of latency
if (LiGetPendingVideoFrames() == 1) {
break;
}
#endif
}
} }
- (void)cleanup - (void)cleanup
@ -343,23 +353,20 @@
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DependsOnOthers, kCFBooleanFalse); CFDictionarySetValue(dict, kCMSampleAttachmentKey_DependsOnOthers, kCFBooleanFalse);
} }
// Enqueue video samples on the main thread // Enqueue the next frame
dispatch_async(dispatch_get_main_queue(), ^{ [self->displayLayer enqueueSampleBuffer:sampleBuffer];
// Enqueue the next frame
[self->displayLayer enqueueSampleBuffer:sampleBuffer]; if (frameType == FRAME_TYPE_IDR) {
// Ensure the layer is visible now
self->displayLayer.hidden = NO;
if (frameType == FRAME_TYPE_IDR) { // Tell our parent VC to hide the progress indicator
// Ensure the layer is visible now [self->_callbacks videoContentShown];
self->displayLayer.hidden = NO; }
// Tell our parent VC to hide the progress indicator // Dereference the buffers
[self->_callbacks videoContentShown]; CFRelease(blockBuffer);
} CFRelease(sampleBuffer);
// Dereference the buffers
CFRelease(blockBuffer);
CFRelease(sampleBuffer);
});
return DR_OK; return DR_OK;
} }