diff --git a/Limelight/Stream/Connection.m b/Limelight/Stream/Connection.m index 5c2153b..31653f9 100644 --- a/Limelight/Stream/Connection.m +++ b/Limelight/Stream/Connection.m @@ -416,7 +416,6 @@ void ClConnectionStatusUpdate(int status) LiInitializeVideoCallbacks(&_drCallbacks); _drCallbacks.setup = DrDecoderSetup; _drCallbacks.cleanup = DrCleanup; - _drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit; // 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. @@ -426,7 +425,7 @@ void ClConnectionStatusUpdate(int status) #if !TARGET_OS_TV CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC | #endif - CAPABILITY_DIRECT_SUBMIT; + CAPABILITY_PULL_RENDERER; LiInitializeAudioCallbacks(&_arCallbacks); _arCallbacks.init = ArInit; diff --git a/Limelight/Stream/VideoDecoderRenderer.m b/Limelight/Stream/VideoDecoderRenderer.m index 24149c8..1c8355c 100644 --- a/Limelight/Stream/VideoDecoderRenderer.m +++ b/Limelight/Stream/VideoDecoderRenderer.m @@ -78,21 +78,31 @@ { self->videoFormat = videoFormat; - if (refreshRate > 60) { - // HACK: We seem to just get 60 Hz screen updates even with a 120 FPS stream if - // we don't set preferredFramesPerSecond somewhere. Since we're a UIKit view, we - // 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 = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)]; + if (@available(iOS 10.0, tvOS 10.0, *)) { + _displayLink.preferredFramesPerSecond = refreshRate; } + [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; } +int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit); + - (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 @@ -343,23 +353,20 @@ CFDictionarySetValue(dict, kCMSampleAttachmentKey_DependsOnOthers, kCFBooleanFalse); } - // Enqueue video samples on the main thread - dispatch_async(dispatch_get_main_queue(), ^{ - // Enqueue the next frame - [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) { - // Ensure the layer is visible now - self->displayLayer.hidden = NO; - - // Tell our parent VC to hide the progress indicator - [self->_callbacks videoContentShown]; - } - - // Dereference the buffers - CFRelease(blockBuffer); - CFRelease(sampleBuffer); - }); + // Tell our parent VC to hide the progress indicator + [self->_callbacks videoContentShown]; + } + + // Dereference the buffers + CFRelease(blockBuffer); + CFRelease(sampleBuffer); return DR_OK; }