4747static const double XCWHardwareFallbackLoadPercent = 500.0 ;
4848static const NSUInteger XCWHardwareFallbackConsecutiveOverBudgetFrameThreshold = 60 ;
4949static const uint64_t XCWAutoHardwareRetryIntervalUs = 10000000 ;
50+ static const NSUInteger XCWMaximumAutoHardwareEncoders = 1 ;
5051static void *XCWH264EncoderQueueSpecificKey = &XCWH264EncoderQueueSpecificKey;
52+ static os_unfair_lock XCWAutoHardwareEncoderLock = OS_UNFAIR_LOCK_INIT;
53+ static NSUInteger XCWActiveAutoHardwareEncoderCount = 0 ;
5154
5255typedef NS_ENUM (NSUInteger , XCWVideoEncoderMode) {
5356 XCWVideoEncoderModeAuto,
@@ -575,6 +578,8 @@ - (void)recordEncodeLatencyLockedWithSubmittedAtUs:(uint64_t)submittedAtUs measu
575578- (void )invalidateX264EncoderLocked ;
576579- (void )handleCompressionOutputSampleBuffer : (CMSampleBufferRef)sampleBuffer
577580 submittedAtUs : (uint64_t )submittedAtUs ;
581+ - (BOOL )acquireAutoHardwareSlotIfNeededLocked ;
582+ - (void )releaseAutoHardwareSlotIfNeededLocked ;
578583- (uint64_t )activeFrameIntervalUsLocked ;
579584- (uint64_t )encoderLatencyBudgetUsLocked ;
580585- (uint64_t )pacingDelayBeforeNextFrameAtTimeUs : (uint64_t )nowUs ;
@@ -603,6 +608,7 @@ @implementation XCWH264Encoder {
603608 BOOL _scalingActive;
604609 XCWVideoEncoderMode _encoderMode;
605610 XCWVideoEncoderMode _activeEncoderMode;
611+ BOOL _holdsAutoHardwareSlot;
606612 BOOL _clientForeground;
607613 BOOL _acceptingFrameInput;
608614 BOOL _lowLatencyMode;
@@ -725,6 +731,7 @@ - (void)requestKeyFrame {
725731
726732- (void )reconfigureForStreamQualityChange {
727733 dispatch_async (_queue, ^{
734+ [self releaseAutoHardwareSlotIfNeededLocked ];
728735 [self invalidateCompressionSessionLocked ];
729736 self->_encoderMode = XCWVideoEncoderModeFromEnvironment ();
730737 self->_activeEncoderMode = self->_encoderMode ;
@@ -761,6 +768,7 @@ - (void)setClientForeground:(BOOL)foreground {
761768 }
762769 os_unfair_lock_unlock (&self->_pendingLock );
763770 if (!foreground) {
771+ [self releaseAutoHardwareSlotIfNeededLocked ];
764772 [self invalidateCompressionSessionLocked ];
765773 self->_needsKeyFrame = YES ;
766774 return ;
@@ -881,6 +889,7 @@ - (NSDictionary *)statsRepresentation {
881889 @" encoderMode" : XCWVideoEncoderModeName (self->_encoderMode ),
882890 @" activeEncoderMode" : XCWVideoEncoderModeName (self->_activeEncoderMode ),
883891 @" clientForeground" : @(self->_clientForeground ),
892+ @" autoHardwareSlot" : @(self->_holdsAutoHardwareSlot ),
884893 @" autoSoftwareFallbackActive" : @(autoSoftwareFallbackActive),
885894 @" autoSoftwareFallbackRemainingUs" : @(autoSoftwareFallbackRemainingUs),
886895 @" autoSoftwareFallbacks" : @(self->_autoSoftwareFallbackCount ),
@@ -902,6 +911,7 @@ - (NSDictionary *)statsRepresentation {
902911- (void )invalidate {
903912 dispatch_sync (_queue, ^{
904913 [self drainPendingFramesLocked ];
914+ [self releaseAutoHardwareSlotIfNeededLocked ];
905915 [self invalidateCompressionSessionLocked ];
906916 });
907917
@@ -976,10 +986,44 @@ - (void)resetAutoFallbackLatencyStateLocked {
976986 _wasOverloaded = NO ;
977987}
978988
989+ - (BOOL )acquireAutoHardwareSlotIfNeededLocked {
990+ if (_encoderMode != XCWVideoEncoderModeAuto || !_clientForeground) {
991+ return NO ;
992+ }
993+ if (_holdsAutoHardwareSlot) {
994+ return YES ;
995+ }
996+
997+ BOOL acquired = NO ;
998+ os_unfair_lock_lock (&XCWAutoHardwareEncoderLock);
999+ if (XCWActiveAutoHardwareEncoderCount < XCWMaximumAutoHardwareEncoders) {
1000+ XCWActiveAutoHardwareEncoderCount += 1 ;
1001+ acquired = YES ;
1002+ }
1003+ os_unfair_lock_unlock (&XCWAutoHardwareEncoderLock);
1004+ _holdsAutoHardwareSlot = acquired;
1005+ return acquired;
1006+ }
1007+
1008+ - (void )releaseAutoHardwareSlotIfNeededLocked {
1009+ if (!_holdsAutoHardwareSlot) {
1010+ return ;
1011+ }
1012+ os_unfair_lock_lock (&XCWAutoHardwareEncoderLock);
1013+ if (XCWActiveAutoHardwareEncoderCount > 0 ) {
1014+ XCWActiveAutoHardwareEncoderCount -= 1 ;
1015+ }
1016+ os_unfair_lock_unlock (&XCWAutoHardwareEncoderLock);
1017+ _holdsAutoHardwareSlot = NO ;
1018+ }
1019+
9791020- (void )switchActiveEncoderModeLocked : (XCWVideoEncoderMode)mode {
9801021 if (_activeEncoderMode == mode) {
9811022 return ;
9821023 }
1024+ if (mode != XCWVideoEncoderModeAuto) {
1025+ [self releaseAutoHardwareSlotIfNeededLocked ];
1026+ }
9831027 _activeEncoderMode = mode;
9841028 _codecType = XCWVideoCodecTypeForMode (_activeEncoderMode);
9851029 if (_activeEncoderMode == XCWVideoEncoderModeH264Software) {
@@ -996,17 +1040,27 @@ - (void)switchActiveEncoderModeLocked:(XCWVideoEncoderMode)mode {
9961040}
9971041
9981042- (void )updateActiveEncoderModeForClientForegroundLockedAtTimeUs : (uint64_t )nowUs {
999- if (_encoderMode == XCWVideoEncoderModeAuto &&
1000- _autoSoftwareFallbackUntilUs != 0 &&
1001- nowUs < _autoSoftwareFallbackUntilUs) {
1043+ if (_encoderMode != XCWVideoEncoderModeAuto) {
1044+ [self switchActiveEncoderModeLocked: _encoderMode];
1045+ return ;
1046+ }
1047+ if (!_clientForeground) {
1048+ [self switchActiveEncoderModeLocked: XCWVideoEncoderModeH264Software];
1049+ return ;
1050+ }
1051+ if (_autoSoftwareFallbackUntilUs != 0 && nowUs < _autoSoftwareFallbackUntilUs) {
10021052 [self switchActiveEncoderModeLocked: XCWVideoEncoderModeH264Software];
10031053 return ;
10041054 }
1005- if (_encoderMode == XCWVideoEncoderModeAuto && _autoSoftwareFallbackUntilUs != 0 ) {
1055+ if (_autoSoftwareFallbackUntilUs != 0 ) {
10061056 _autoSoftwareFallbackUntilUs = 0 ;
10071057 _autoHardwareRetryCount += 1 ;
10081058 }
1009- [self switchActiveEncoderModeLocked: _encoderMode];
1059+ if ([self acquireAutoHardwareSlotIfNeededLocked ]) {
1060+ [self switchActiveEncoderModeLocked: XCWVideoEncoderModeAuto];
1061+ } else {
1062+ [self switchActiveEncoderModeLocked: XCWVideoEncoderModeH264Software];
1063+ }
10101064}
10111065
10121066- (void )enterAutoSoftwareFallbackLockedAtTimeUs : (uint64_t )nowUs {
@@ -1019,18 +1073,6 @@ - (void)enterAutoSoftwareFallbackLockedAtTimeUs:(uint64_t)nowUs {
10191073 [self switchActiveEncoderModeLocked: XCWVideoEncoderModeH264Software];
10201074}
10211075
1022- - (void )retryAutoHardwareIfNeededLockedAtTimeUs : (uint64_t )nowUs {
1023- if (![self isAutoSoftwareFallbackActiveLocked ] ||
1024- !_clientForeground ||
1025- _autoSoftwareFallbackUntilUs == 0 ||
1026- nowUs < _autoSoftwareFallbackUntilUs) {
1027- return ;
1028- }
1029- _autoSoftwareFallbackUntilUs = 0 ;
1030- _autoHardwareRetryCount += 1 ;
1031- [self switchActiveEncoderModeLocked: XCWVideoEncoderModeAuto];
1032- }
1033-
10341076- (uint64_t )activeFrameIntervalUsLocked {
10351077 if (_activeEncoderMode == XCWVideoEncoderModeH264Software) {
10361078 return _softwareFrameIntervalUs > 0 ? _softwareFrameIntervalUs : [self initialSoftwareFrameIntervalUsLocked ];
@@ -1238,7 +1280,7 @@ - (BOOL)encodePixelBufferLocked:(CVPixelBufferRef)pixelBuffer {
12381280 }
12391281
12401282 uint64_t nowUs = (uint64_t )(CACurrentMediaTime () * 1000000.0 );
1241- [self retryAutoHardwareIfNeededLockedAtTimeUs : nowUs];
1283+ [self updateActiveEncoderModeForClientForegroundLockedAtTimeUs : nowUs];
12421284
12431285 CGSize targetSize = XCWScaledDimensionsForSourceSize (sourceWidth, sourceHeight, _activeEncoderMode, _lowLatencyMode, _realtimeStreamMode);
12441286 int32_t targetWidth = (int32_t )targetSize.width ;
0 commit comments