@@ -311,11 +311,9 @@ static CGSize XCWScaledDimensionsForSourceSize(int32_t width, int32_t height, XC
311311
312312 int32_t maximumDimension = realtimeStreamMode
313313 ? XCWRealtimeMaximumEncodedDimension ()
314- : XCWMaximumEncodedDimension ;
314+ : XCWMaximumSoftwareEncodedDimension ;
315315 if (mode == XCWVideoEncoderModeH264Software && lowLatencyMode) {
316316 maximumDimension = MIN (maximumDimension, XCWMaximumLowLatencySoftwareEncodedDimension);
317- } else if (mode == XCWVideoEncoderModeH264Software && !realtimeStreamMode) {
318- maximumDimension = XCWMaximumSoftwareEncodedDimension;
319317 }
320318 int32_t longestEdge = MAX (width, height);
321319 if (longestEdge <= maximumDimension) {
@@ -333,7 +331,7 @@ static int32_t XCWAverageBitRateForDimensions(int32_t width, int32_t height, XCW
333331 if (realtimeStreamMode && !lowLatencyMode) {
334332 bitsPerPixelBudget = XCWRealtimeBitsPerPixelBudgetValue ();
335333 minimumAverageBitRate = XCWRealtimeMinimumAverageBitRate ();
336- } else if (mode == XCWVideoEncoderModeH264Software) {
334+ } else if (mode == XCWVideoEncoderModeH264Software || !realtimeStreamMode ) {
337335 bitsPerPixelBudget = lowLatencyMode
338336 ? XCWLowLatencySoftwareBitsPerPixelBudget
339337 : XCWSoftwareBitsPerPixelBudget;
@@ -411,6 +409,28 @@ static BOOL XCWCompressionSessionUsesHardwareEncoder(VTCompressionSessionRef ses
411409 return isHardware;
412410}
413411
412+ static NSString *XCWCompressionSessionEncoderID (VTCompressionSessionRef session) {
413+ if (session == NULL ) {
414+ return nil ;
415+ }
416+
417+ CFTypeRef value = NULL ;
418+ OSStatus status = VTSessionCopyProperty (session,
419+ kVTCompressionPropertyKey_EncoderID ,
420+ kCFAllocatorDefault ,
421+ &value);
422+ if (status != noErr || value == NULL ) {
423+ return nil ;
424+ }
425+
426+ NSString *encoderID = nil ;
427+ if (CFGetTypeID (value) == CFStringGetTypeID ()) {
428+ encoderID = [(__bridge NSString *)value copy ];
429+ }
430+ CFRelease (value);
431+ return encoderID;
432+ }
433+
414434static BOOL XCWPixelFormatSupportsSoftwareScaling (OSType pixelFormat) {
415435 switch (pixelFormat) {
416436 case kCVPixelFormatType_32ARGB :
@@ -474,6 +494,7 @@ @implementation XCWH264Encoder {
474494 uint64_t _lastRealtimeHardwareSubmissionUs;
475495 NSUInteger _realtimeHardwarePacedFrameCount;
476496 NSUInteger _realtimeHardwareHealthyFrameCount;
497+ NSString *_selectedEncoderID;
477498 NSInteger _lastSessionStatus;
478499 NSInteger _lastPrepareStatus;
479500 NSInteger _lastScaleStatus;
@@ -497,7 +518,7 @@ - (instancetype)initWithOutputHandler:(XCWH264EncoderOutputHandler)outputHandler
497518 _realtimeStreamMode = XCWRealtimeStreamModeFromEnvironment () || _lowLatencyMode;
498519 _codecType = XCWVideoCodecTypeForMode (_encoderMode);
499520 _softwareFrameIntervalUs = [self initialSoftwareFrameIntervalUsLocked ];
500- _realtimeHardwareFrameIntervalUs = XCWRealtimeFrameIntervalUs () ;
521+ _realtimeHardwareFrameIntervalUs = [ self initialHardwareFrameIntervalUsLocked ] ;
501522 return self;
502523}
503524
@@ -547,7 +568,7 @@ - (void)reconfigureForStreamQualityChange {
547568 self->_softwareFrameIntervalUs = [self initialSoftwareFrameIntervalUsLocked ];
548569 self->_softwarePacedFrameCount = 0 ;
549570 self->_softwareHealthyFrameCount = 0 ;
550- self->_realtimeHardwareFrameIntervalUs = XCWRealtimeFrameIntervalUs () ;
571+ self->_realtimeHardwareFrameIntervalUs = [ self initialHardwareFrameIntervalUsLocked ] ;
551572 self->_realtimeHardwarePacedFrameCount = 0 ;
552573 self->_realtimeHardwareHealthyFrameCount = 0 ;
553574 });
@@ -584,6 +605,7 @@ - (NSDictionary *)statsRepresentation {
584605 @" lowLatencyMode" : @(self->_lowLatencyMode ),
585606 @" realtimeStreamMode" : @(self->_realtimeStreamMode ),
586607 @" encoderId" : XCWVideoEncoderIDForMode (self->_encoderMode ) ?: @" automatic" ,
608+ @" selectedEncoderId" : self->_selectedEncoderID ?: NSNull .null ,
587609 @" hardwareAccelerated" : @(self->_hardwareAccelerated ),
588610 @" lastSessionStatus" : @(self->_lastSessionStatus ),
589611 @" lastPrepareStatus" : @(self->_lastPrepareStatus ),
@@ -642,6 +664,18 @@ - (NSUInteger)softwareHealthyFrameWindowLocked {
642664 return _lowLatencyMode ? XCWLowLatencySoftwareHealthyFrameWindow : XCWSoftwareHealthyFrameWindow;
643665}
644666
667+ - (uint64_t )minimumHardwareFrameIntervalUsLocked {
668+ return _realtimeStreamMode ? XCWRealtimeFrameIntervalUs () : XCWSoftwareMinimumFrameIntervalUs;
669+ }
670+
671+ - (uint64_t )initialHardwareFrameIntervalUsLocked {
672+ return _realtimeStreamMode ? XCWRealtimeFrameIntervalUs () : XCWSoftwareInitialFrameIntervalUs;
673+ }
674+
675+ - (uint64_t )maximumHardwareFrameIntervalUsLocked {
676+ return _realtimeStreamMode ? XCWRealtimeMaximumFrameIntervalUs () : XCWSoftwareMaximumFrameIntervalUs;
677+ }
678+
645679- (int32_t )expectedFrameRateLocked {
646680 if (_encoderMode == XCWVideoEncoderModeH264Software) {
647681 if (_lowLatencyMode) {
@@ -660,7 +694,7 @@ - (BOOL)shouldPaceRealtimeHardwareFrameAtTimeUs:(uint64_t)nowUs {
660694 return NO ;
661695 }
662696 if (_realtimeHardwareFrameIntervalUs == 0 ) {
663- _realtimeHardwareFrameIntervalUs = XCWRealtimeFrameIntervalUs () ;
697+ _realtimeHardwareFrameIntervalUs = [ self initialHardwareFrameIntervalUsLocked ] ;
664698 }
665699 if (_lastRealtimeHardwareSubmissionUs == 0 ) {
666700 return NO ;
@@ -735,11 +769,11 @@ - (void)adaptRealtimeHardwarePacingForLatencyUs:(uint64_t)latencyUs {
735769 return ;
736770 }
737771 if (_realtimeHardwareFrameIntervalUs == 0 ) {
738- _realtimeHardwareFrameIntervalUs = XCWRealtimeFrameIntervalUs () ;
772+ _realtimeHardwareFrameIntervalUs = [ self initialHardwareFrameIntervalUsLocked ] ;
739773 }
740774
741- uint64_t minimumIntervalUs = XCWRealtimeFrameIntervalUs () ;
742- uint64_t maximumIntervalUs = XCWRealtimeMaximumFrameIntervalUs () ;
775+ uint64_t minimumIntervalUs = [ self minimumHardwareFrameIntervalUsLocked ] ;
776+ uint64_t maximumIntervalUs = [ self maximumHardwareFrameIntervalUsLocked ] ;
743777 if (latencyUs > _realtimeHardwareFrameIntervalUs) {
744778 uint64_t nextIntervalUs = _realtimeHardwareFrameIntervalUs + XCWRealtimeHardwareFrameIntervalStepUs;
745779 uint64_t latencyBoundIntervalUs = latencyUs + XCWRealtimeHardwareFrameIntervalStepUs;
@@ -855,7 +889,7 @@ - (BOOL)encodePixelBufferLocked:(CVPixelBufferRef)pixelBuffer {
855889 _lastRealtimeHardwareSubmissionUs = nowUs;
856890 }
857891 _maxInFlightFrameCount = MAX (_maxInFlightFrameCount, _inFlightFrameCount);
858- if (_encoderMode == XCWVideoEncoderModeH264Software) {
892+ if (_encoderMode == XCWVideoEncoderModeH264Software || !_realtimeStreamMode ) {
859893 VTCompressionSessionCompleteFrames (_compressionSession, presentationTime);
860894 }
861895 return YES ;
@@ -873,7 +907,7 @@ - (BOOL)ensureCompressionSessionWithWidth:(int32_t)width height:(int32_t)height
873907 if (encoderID.length > 0 ) {
874908 encoderSpecification[(__bridge NSString *)kVTVideoEncoderSpecification_EncoderID ] = encoderID;
875909 }
876- if (_encoderMode != XCWVideoEncoderModeH264Software) {
910+ if (_encoderMode != XCWVideoEncoderModeH264Software && _realtimeStreamMode ) {
877911 if (@available (macOS 11.3 , *)) {
878912 encoderSpecification[(__bridge NSString *)kVTVideoEncoderSpecification_EnableLowLatencyRateControl ] = @YES ;
879913 }
@@ -919,18 +953,14 @@ - (BOOL)ensureCompressionSessionWithWidth:(int32_t)width height:(int32_t)height
919953 if (@available (macOS 10.14 , *)) {
920954 VTSessionSetProperty (session, kVTCompressionPropertyKey_AllowOpenGOP , kCFBooleanFalse );
921955 }
922- if (_encoderMode == XCWVideoEncoderModeH264Software || _realtimeStreamMode) {
923- if (@available (macOS 12.0 , *)) {
924- VTSessionSetProperty (session,
925- kVTCompressionPropertyKey_ProfileLevel ,
926- kVTProfileLevel_H264_ConstrainedBaseline_AutoLevel );
927- } else {
928- VTSessionSetProperty (session, kVTCompressionPropertyKey_ProfileLevel , kVTProfileLevel_H264_Baseline_AutoLevel );
929- }
930- VTSessionSetProperty (session, kVTCompressionPropertyKey_H264EntropyMode , kVTH264EntropyMode_CAVLC );
956+ if (@available (macOS 12.0 , *)) {
957+ VTSessionSetProperty (session,
958+ kVTCompressionPropertyKey_ProfileLevel ,
959+ kVTProfileLevel_H264_ConstrainedBaseline_AutoLevel );
931960 } else {
932- VTSessionSetProperty (session, kVTCompressionPropertyKey_ProfileLevel , kVTProfileLevel_H264_High_AutoLevel );
961+ VTSessionSetProperty (session, kVTCompressionPropertyKey_ProfileLevel , kVTProfileLevel_H264_Baseline_AutoLevel );
933962 }
963+ VTSessionSetProperty (session, kVTCompressionPropertyKey_H264EntropyMode , kVTH264EntropyMode_CAVLC );
934964 VTSessionSetProperty (session, kVTCompressionPropertyKey_ExpectedFrameRate , (__bridge CFTypeRef)@(expectedFrameRate));
935965 BOOL shortKeyframeInterval = _lowLatencyMode || _realtimeStreamMode;
936966 VTSessionSetProperty (session, kVTCompressionPropertyKey_MaxKeyFrameInterval , (__bridge CFTypeRef)@(shortKeyframeInterval ? MAX (1 , expectedFrameRate / 2 ) : expectedFrameRate * 2 ));
@@ -964,6 +994,7 @@ - (BOOL)ensureCompressionSessionWithWidth:(int32_t)width height:(int32_t)height
964994 return NO ;
965995 }
966996 _hardwareAccelerated = XCWCompressionSessionUsesHardwareEncoder (session);
997+ _selectedEncoderID = XCWCompressionSessionEncoderID (session);
967998
968999 return YES ;
9691000}
@@ -984,6 +1015,7 @@ - (void)invalidateCompressionSessionLocked {
9841015 _lastSoftwareSubmissionUs = 0 ;
9851016 _lastRealtimeHardwareSubmissionUs = 0 ;
9861017 _hardwareAccelerated = NO ;
1018+ _selectedEncoderID = nil ;
9871019 [self invalidateScalingResourcesLocked ];
9881020}
9891021
0 commit comments