1414static const int32_t XCWTargetRealTimeFrameRate = 60 ;
1515static const int32_t XCWTargetRealtimeHardwareFrameRate = 30 ;
1616static const int32_t XCWTargetSoftwareFrameRate = 60 ;
17+ static const int32_t XCWMinimumLocalStreamFrameRate = 15 ;
18+ static const int32_t XCWMaximumLocalStreamFrameRate = 120 ;
1719static const int32_t XCWTargetLowLatencySoftwareFrameRate = 15 ;
1820static const NSUInteger XCWMaximumInFlightFrames = 2 ;
1921static const int32_t XCWMinimumAverageBitRate = 18000000 ;
@@ -137,6 +139,22 @@ static uint64_t XCWRealtimeMaximumFrameIntervalUs(void) {
137139 return MAX (XCWRealtimeFrameIntervalUs () * 2 , XCWRealtimeFrameIntervalUs ());
138140}
139141
142+ static int32_t XCWLocalStreamTargetFrameRate (void ) {
143+ return XCWIntFromEnvironment (@" SIMDECK_LOCAL_STREAM_FPS" ,
144+ XCWTargetRealTimeFrameRate,
145+ XCWMinimumLocalStreamFrameRate,
146+ XCWMaximumLocalStreamFrameRate);
147+ }
148+
149+ static uint64_t XCWLocalStreamFrameIntervalUs (void ) {
150+ int32_t fps = MAX (1 , XCWLocalStreamTargetFrameRate ());
151+ return (uint64_t )llround (1000000.0 / (double )fps);
152+ }
153+
154+ static uint64_t XCWLocalStreamMaximumFrameIntervalUs (void ) {
155+ return MAX (XCWSoftwareMaximumFrameIntervalUs, XCWLocalStreamFrameIntervalUs ());
156+ }
157+
140158static int64_t XCWRealtimeBitsPerPixelBudgetValue (void ) {
141159 return XCWInt64FromEnvironment (@" SIMDECK_REALTIME_BITS_PER_PIXEL" ,
142160 XCWRealtimeBitsPerPixelBudget,
@@ -490,10 +508,10 @@ @implementation XCWH264Encoder {
490508 uint64_t _lastSoftwareSubmissionUs;
491509 NSUInteger _softwarePacedFrameCount;
492510 NSUInteger _softwareHealthyFrameCount;
493- uint64_t _realtimeHardwareFrameIntervalUs ;
494- uint64_t _lastRealtimeHardwareSubmissionUs ;
495- NSUInteger _realtimeHardwarePacedFrameCount ;
496- NSUInteger _realtimeHardwareHealthyFrameCount ;
511+ uint64_t _hardwareFrameIntervalUs ;
512+ uint64_t _lastHardwareSubmissionUs ;
513+ NSUInteger _hardwarePacedFrameCount ;
514+ NSUInteger _hardwareHealthyFrameCount ;
497515 NSString *_selectedEncoderID;
498516 NSInteger _lastSessionStatus;
499517 NSInteger _lastPrepareStatus;
@@ -518,7 +536,7 @@ - (instancetype)initWithOutputHandler:(XCWH264EncoderOutputHandler)outputHandler
518536 _realtimeStreamMode = XCWRealtimeStreamModeFromEnvironment () || _lowLatencyMode;
519537 _codecType = XCWVideoCodecTypeForMode (_encoderMode);
520538 _softwareFrameIntervalUs = [self initialSoftwareFrameIntervalUsLocked ];
521- _realtimeHardwareFrameIntervalUs = [self initialHardwareFrameIntervalUsLocked ];
539+ _hardwareFrameIntervalUs = [self initialHardwareFrameIntervalUsLocked ];
522540 return self;
523541}
524542
@@ -568,9 +586,9 @@ - (void)reconfigureForStreamQualityChange {
568586 self->_softwareFrameIntervalUs = [self initialSoftwareFrameIntervalUsLocked ];
569587 self->_softwarePacedFrameCount = 0 ;
570588 self->_softwareHealthyFrameCount = 0 ;
571- self->_realtimeHardwareFrameIntervalUs = [self initialHardwareFrameIntervalUsLocked ];
572- self->_realtimeHardwarePacedFrameCount = 0 ;
573- self->_realtimeHardwareHealthyFrameCount = 0 ;
589+ self->_hardwareFrameIntervalUs = [self initialHardwareFrameIntervalUsLocked ];
590+ self->_hardwarePacedFrameCount = 0 ;
591+ self->_hardwareHealthyFrameCount = 0 ;
574592 });
575593}
576594
@@ -597,9 +615,13 @@ - (NSDictionary *)statsRepresentation {
597615 @" softwareFrameIntervalUs" : @(self->_softwareFrameIntervalUs ),
598616 @" softwareTargetFps" : @(self->_softwareFrameIntervalUs > 0 ? (1000000.0 / (double )self->_softwareFrameIntervalUs ) : 0.0 ),
599617 @" softwarePacedFrames" : @(self->_softwarePacedFrameCount ),
600- @" realtimeHardwareFrameIntervalUs" : @(self->_realtimeHardwareFrameIntervalUs ),
601- @" realtimeHardwareTargetFps" : @(self->_realtimeHardwareFrameIntervalUs > 0 ? (1000000.0 / (double )self->_realtimeHardwareFrameIntervalUs ) : 0.0 ),
602- @" realtimeHardwarePacedFrames" : @(self->_realtimeHardwarePacedFrameCount ),
618+ @" localStreamTargetFps" : @(XCWLocalStreamTargetFrameRate ()),
619+ @" hardwareFrameIntervalUs" : @(self->_hardwareFrameIntervalUs ),
620+ @" hardwareTargetFps" : @(self->_hardwareFrameIntervalUs > 0 ? (1000000.0 / (double )self->_hardwareFrameIntervalUs ) : 0.0 ),
621+ @" hardwarePacedFrames" : @(self->_hardwarePacedFrameCount ),
622+ @" realtimeHardwareFrameIntervalUs" : @(self->_hardwareFrameIntervalUs ),
623+ @" realtimeHardwareTargetFps" : @(self->_hardwareFrameIntervalUs > 0 ? (1000000.0 / (double )self->_hardwareFrameIntervalUs ) : 0.0 ),
624+ @" realtimeHardwarePacedFrames" : @(self->_hardwarePacedFrameCount ),
603625 @" transportCodec" : XCWCodecName (self->_codecType ),
604626 @" encoderMode" : XCWVideoEncoderModeName (self->_encoderMode ),
605627 @" lowLatencyMode" : @(self->_lowLatencyMode ),
@@ -665,15 +687,15 @@ - (NSUInteger)softwareHealthyFrameWindowLocked {
665687}
666688
667689- (uint64_t )minimumHardwareFrameIntervalUsLocked {
668- return _realtimeStreamMode ? XCWRealtimeFrameIntervalUs () : XCWSoftwareMinimumFrameIntervalUs ;
690+ return _realtimeStreamMode ? XCWRealtimeFrameIntervalUs () : XCWLocalStreamFrameIntervalUs () ;
669691}
670692
671693- (uint64_t )initialHardwareFrameIntervalUsLocked {
672- return _realtimeStreamMode ? XCWRealtimeFrameIntervalUs () : XCWSoftwareInitialFrameIntervalUs ;
694+ return _realtimeStreamMode ? XCWRealtimeFrameIntervalUs () : XCWLocalStreamFrameIntervalUs () ;
673695}
674696
675697- (uint64_t )maximumHardwareFrameIntervalUsLocked {
676- return _realtimeStreamMode ? XCWRealtimeMaximumFrameIntervalUs () : XCWSoftwareMaximumFrameIntervalUs ;
698+ return _realtimeStreamMode ? XCWRealtimeMaximumFrameIntervalUs () : XCWLocalStreamMaximumFrameIntervalUs () ;
677699}
678700
679701- (int32_t )expectedFrameRateLocked {
@@ -686,24 +708,24 @@ - (int32_t)expectedFrameRateLocked {
686708 if (_realtimeStreamMode) {
687709 return XCWRealtimeTargetFrameRate ();
688710 }
689- return XCWTargetRealTimeFrameRate ;
711+ return XCWLocalStreamTargetFrameRate () ;
690712}
691713
692- - (BOOL )shouldPaceRealtimeHardwareFrameAtTimeUs : (uint64_t )nowUs {
693- if ((_encoderMode != XCWVideoEncoderModeAuto && _encoderMode != XCWVideoEncoderModeH264Hardware) || !_realtimeStreamMode || _needsKeyFrame) {
714+ - (BOOL )shouldPaceHardwareFrameAtTimeUs : (uint64_t )nowUs {
715+ if ((_encoderMode != XCWVideoEncoderModeAuto && _encoderMode != XCWVideoEncoderModeH264Hardware) || _needsKeyFrame) {
694716 return NO ;
695717 }
696- if (_realtimeHardwareFrameIntervalUs == 0 ) {
697- _realtimeHardwareFrameIntervalUs = [self initialHardwareFrameIntervalUsLocked ];
718+ if (_hardwareFrameIntervalUs == 0 ) {
719+ _hardwareFrameIntervalUs = [self initialHardwareFrameIntervalUsLocked ];
698720 }
699- if (_lastRealtimeHardwareSubmissionUs == 0 ) {
721+ if (_lastHardwareSubmissionUs == 0 ) {
700722 return NO ;
701723 }
702- uint64_t elapsedUs = nowUs >= _lastRealtimeHardwareSubmissionUs ? nowUs - _lastRealtimeHardwareSubmissionUs : 0 ;
703- if (elapsedUs >= _realtimeHardwareFrameIntervalUs ) {
724+ uint64_t elapsedUs = nowUs >= _lastHardwareSubmissionUs ? nowUs - _lastHardwareSubmissionUs : 0 ;
725+ if (elapsedUs >= _hardwareFrameIntervalUs ) {
704726 return NO ;
705727 }
706- _realtimeHardwarePacedFrameCount += 1 ;
728+ _hardwarePacedFrameCount += 1 ;
707729 return YES ;
708730}
709731
@@ -764,41 +786,41 @@ - (void)adaptSoftwarePacingForLatencyUs:(uint64_t)latencyUs {
764786 _softwareHealthyFrameCount = 0 ;
765787}
766788
767- - (void )adaptRealtimeHardwarePacingForLatencyUs : (uint64_t )latencyUs {
768- if ((_encoderMode != XCWVideoEncoderModeAuto && _encoderMode != XCWVideoEncoderModeH264Hardware) || !_realtimeStreamMode || latencyUs == 0 ) {
789+ - (void )adaptHardwarePacingForLatencyUs : (uint64_t )latencyUs {
790+ if ((_encoderMode != XCWVideoEncoderModeAuto && _encoderMode != XCWVideoEncoderModeH264Hardware) || latencyUs == 0 ) {
769791 return ;
770792 }
771- if (_realtimeHardwareFrameIntervalUs == 0 ) {
772- _realtimeHardwareFrameIntervalUs = [self initialHardwareFrameIntervalUsLocked ];
793+ if (_hardwareFrameIntervalUs == 0 ) {
794+ _hardwareFrameIntervalUs = [self initialHardwareFrameIntervalUsLocked ];
773795 }
774796
775797 uint64_t minimumIntervalUs = [self minimumHardwareFrameIntervalUsLocked ];
776798 uint64_t maximumIntervalUs = [self maximumHardwareFrameIntervalUsLocked ];
777- if (latencyUs > _realtimeHardwareFrameIntervalUs ) {
778- uint64_t nextIntervalUs = _realtimeHardwareFrameIntervalUs + XCWRealtimeHardwareFrameIntervalStepUs;
799+ if (latencyUs > _hardwareFrameIntervalUs ) {
800+ uint64_t nextIntervalUs = _hardwareFrameIntervalUs + XCWRealtimeHardwareFrameIntervalStepUs;
779801 uint64_t latencyBoundIntervalUs = latencyUs + XCWRealtimeHardwareFrameIntervalStepUs;
780802 if (nextIntervalUs < latencyBoundIntervalUs) {
781803 nextIntervalUs = latencyBoundIntervalUs;
782804 }
783- _realtimeHardwareFrameIntervalUs = MIN (nextIntervalUs, maximumIntervalUs);
784- _realtimeHardwareHealthyFrameCount = 0 ;
805+ _hardwareFrameIntervalUs = MIN (nextIntervalUs, maximumIntervalUs);
806+ _hardwareHealthyFrameCount = 0 ;
785807 return ;
786808 }
787809
788- if (latencyUs < _realtimeHardwareFrameIntervalUs &&
789- _realtimeHardwareFrameIntervalUs > minimumIntervalUs) {
790- _realtimeHardwareHealthyFrameCount += 1 ;
791- if (_realtimeHardwareHealthyFrameCount >= XCWRealtimeHardwareHealthyFrameWindow) {
792- uint64_t nextIntervalUs = _realtimeHardwareFrameIntervalUs > XCWRealtimeHardwareFrameIntervalStepUs
793- ? _realtimeHardwareFrameIntervalUs - XCWRealtimeHardwareFrameIntervalStepUs
810+ if (latencyUs < _hardwareFrameIntervalUs &&
811+ _hardwareFrameIntervalUs > minimumIntervalUs) {
812+ _hardwareHealthyFrameCount += 1 ;
813+ if (_hardwareHealthyFrameCount >= XCWRealtimeHardwareHealthyFrameWindow) {
814+ uint64_t nextIntervalUs = _hardwareFrameIntervalUs > XCWRealtimeHardwareFrameIntervalStepUs
815+ ? _hardwareFrameIntervalUs - XCWRealtimeHardwareFrameIntervalStepUs
794816 : minimumIntervalUs;
795- _realtimeHardwareFrameIntervalUs = MAX (nextIntervalUs, minimumIntervalUs);
796- _realtimeHardwareHealthyFrameCount = 0 ;
817+ _hardwareFrameIntervalUs = MAX (nextIntervalUs, minimumIntervalUs);
818+ _hardwareHealthyFrameCount = 0 ;
797819 }
798820 return ;
799821 }
800822
801- _realtimeHardwareHealthyFrameCount = 0 ;
823+ _hardwareHealthyFrameCount = 0 ;
802824}
803825
804826- (void )drainPendingFramesLocked {
@@ -839,7 +861,7 @@ - (BOOL)encodePixelBufferLocked:(CVPixelBufferRef)pixelBuffer {
839861 }
840862
841863 uint64_t nowUs = (uint64_t )(CACurrentMediaTime () * 1000000.0 );
842- if ([self shouldPaceSoftwareFrameAtTimeUs: nowUs] || [self shouldPaceRealtimeHardwareFrameAtTimeUs : nowUs]) {
864+ if ([self shouldPaceSoftwareFrameAtTimeUs: nowUs] || [self shouldPaceHardwareFrameAtTimeUs : nowUs]) {
843865 return YES ;
844866 }
845867
@@ -885,8 +907,8 @@ - (BOOL)encodePixelBufferLocked:(CVPixelBufferRef)pixelBuffer {
885907 _submittedFrameCount += 1 ;
886908 if (_encoderMode == XCWVideoEncoderModeH264Software) {
887909 _lastSoftwareSubmissionUs = nowUs;
888- } else if (( _encoderMode == XCWVideoEncoderModeAuto || _encoderMode == XCWVideoEncoderModeH264Hardware) && _realtimeStreamMode ) {
889- _lastRealtimeHardwareSubmissionUs = nowUs;
910+ } else if (_encoderMode == XCWVideoEncoderModeAuto || _encoderMode == XCWVideoEncoderModeH264Hardware) {
911+ _lastHardwareSubmissionUs = nowUs;
890912 }
891913 _maxInFlightFrameCount = MAX (_maxInFlightFrameCount, _inFlightFrameCount);
892914 if (_encoderMode == XCWVideoEncoderModeH264Software || !_realtimeStreamMode) {
@@ -1013,7 +1035,7 @@ - (void)invalidateCompressionSessionLocked {
10131035 _timestampOriginUs = 0 ;
10141036 _inFlightFrameCount = 0 ;
10151037 _lastSoftwareSubmissionUs = 0 ;
1016- _lastRealtimeHardwareSubmissionUs = 0 ;
1038+ _lastHardwareSubmissionUs = 0 ;
10171039 _hardwareAccelerated = NO ;
10181040 _selectedEncoderID = nil ;
10191041 [self invalidateScalingResourcesLocked ];
@@ -1203,7 +1225,7 @@ - (void)handleEncodedSampleBuffer:(CMSampleBufferRef)sampleBuffer
12031225 uint64_t nowUs = (uint64_t )(CACurrentMediaTime () * 1000000.0 );
12041226 _latestEncodeLatencyUs = nowUs >= submittedAtUs ? nowUs - submittedAtUs : 0 ;
12051227 [self adaptSoftwarePacingForLatencyUs: _latestEncodeLatencyUs];
1206- [self adaptRealtimeHardwarePacingForLatencyUs : _latestEncodeLatencyUs];
1228+ [self adaptHardwarePacingForLatencyUs : _latestEncodeLatencyUs];
12071229 }
12081230 NSString *codec = nil ;
12091231 NSData *decoderConfig = nil ;
0 commit comments