diff --git a/Limelight/Stream/Connection.m b/Limelight/Stream/Connection.m index 763ef4c..8a60127 100644 --- a/Limelight/Stream/Connection.m +++ b/Limelight/Stream/Connection.m @@ -48,10 +48,15 @@ static VideoDecoderRenderer* renderer; int DrDecoderSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) { - [renderer setupWithVideoFormat:videoFormat]; + [renderer setupWithVideoFormat:videoFormat refreshRate:redrawRate]; return 0; } +void DrCleanup(void) +{ + [renderer cleanup]; +} + int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) { int offset = 0; @@ -380,6 +385,7 @@ 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) diff --git a/Limelight/Stream/VideoDecoderRenderer.h b/Limelight/Stream/VideoDecoderRenderer.h index 82c77d4..a8e8295 100644 --- a/Limelight/Stream/VideoDecoderRenderer.h +++ b/Limelight/Stream/VideoDecoderRenderer.h @@ -12,7 +12,9 @@ - (id)initWithView:(OSView*)view; -- (void)setupWithVideoFormat:(int)videoFormat; +- (void)setupWithVideoFormat:(int)videoFormat refreshRate:(int)refreshRate; + +- (void)cleanup; - (void)updateBufferForRange:(CMBlockBufferRef)existingBuffer data:(unsigned char *)data offset:(int)offset length:(int)nalLength; diff --git a/Limelight/Stream/VideoDecoderRenderer.m b/Limelight/Stream/VideoDecoderRenderer.m index ac95e9b..14f561c 100644 --- a/Limelight/Stream/VideoDecoderRenderer.m +++ b/Limelight/Stream/VideoDecoderRenderer.m @@ -20,6 +20,8 @@ NSData *spsData, *ppsData, *vpsData; CMVideoFormatDescriptionRef formatDesc; + + CADisplayLink* _displayLink; } - (void)reinitializeDisplayLayer @@ -70,12 +72,33 @@ return self; } -- (void)setupWithVideoFormat:(int)videoFormat +- (void)setupWithVideoFormat:(int)videoFormat refreshRate:(int)refreshRate { self->videoFormat = videoFormat; #if !TARGET_OS_IPHONE _view.codec = videoFormat; #endif + + 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]; + } +} + +- (void)displayLinkCallback:(CADisplayLink *)sender +{ + // No-op - rendering done in submitDecodeBuffer +} + +- (void)cleanup +{ + [_displayLink invalidate]; } #define FRAME_START_PREFIX_SIZE 4 @@ -356,8 +379,10 @@ // Enqueue the next frame [self->displayLayer enqueueSampleBuffer:sampleBuffer]; - // Ensure the layer is visible now - self->displayLayer.hidden = NO; + if ([self isNalReferencePicture:nalType]) { + // Ensure the layer is visible now + self->displayLayer.hidden = NO; + } // Dereference the buffers CFRelease(blockBuffer);