Skip to content

Commit 2612d03

Browse files
committed
Avoid VideoToolbox scaler for software H264
1 parent f305903 commit 2612d03

2 files changed

Lines changed: 101 additions & 0 deletions

File tree

cli/XCWH264Encoder.m

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#import "XCWH264Encoder.h"
22

3+
#import <Accelerate/Accelerate.h>
34
#import <CoreMedia/CoreMedia.h>
45
#import <os/lock.h>
56
#import <QuartzCore/QuartzCore.h>
@@ -307,6 +308,18 @@ static BOOL XCWCompressionSessionUsesHardwareEncoder(VTCompressionSessionRef ses
307308
return isHardware;
308309
}
309310

311+
static BOOL XCWPixelFormatSupportsSoftwareScaling(OSType pixelFormat) {
312+
switch (pixelFormat) {
313+
case kCVPixelFormatType_32ARGB:
314+
case kCVPixelFormatType_32BGRA:
315+
case kCVPixelFormatType_32ABGR:
316+
case kCVPixelFormatType_32RGBA:
317+
return YES;
318+
default:
319+
return NO;
320+
}
321+
}
322+
310323
static void XCWH264EncoderOutputCallback(void *outputCallbackRefCon,
311324
void *sourceFrameRefCon,
312325
OSStatus status,
@@ -317,6 +330,10 @@ @interface XCWH264Encoder ()
317330

318331
@property (nonatomic, copy, readonly) XCWH264EncoderOutputHandler outputHandler;
319332

333+
- (nullable CVPixelBufferRef)copySoftwareScaledPixelBuffer:(CVPixelBufferRef)pixelBuffer
334+
targetWidth:(int32_t)targetWidth
335+
targetHeight:(int32_t)targetHeight;
336+
320337
@end
321338

322339
@implementation XCWH264Encoder {
@@ -772,6 +789,12 @@ - (nullable CVPixelBufferRef)copyScaledPixelBufferIfNeeded:(CVPixelBufferRef)pix
772789
return pixelBuffer;
773790
}
774791

792+
if (_encoderMode == XCWVideoEncoderModeH264Software) {
793+
return [self copySoftwareScaledPixelBuffer:pixelBuffer
794+
targetWidth:targetWidth
795+
targetHeight:targetHeight];
796+
}
797+
775798
if (_pixelTransferSession == NULL) {
776799
OSStatus sessionStatus = VTPixelTransferSessionCreate(kCFAllocatorDefault, &_pixelTransferSession);
777800
if (sessionStatus != noErr || _pixelTransferSession == NULL) {
@@ -829,6 +852,83 @@ - (nullable CVPixelBufferRef)copyScaledPixelBufferIfNeeded:(CVPixelBufferRef)pix
829852
return _scaledPixelBuffer;
830853
}
831854

855+
- (nullable CVPixelBufferRef)copySoftwareScaledPixelBuffer:(CVPixelBufferRef)pixelBuffer
856+
targetWidth:(int32_t)targetWidth
857+
targetHeight:(int32_t)targetHeight {
858+
OSType sourcePixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer);
859+
if (!XCWPixelFormatSupportsSoftwareScaling(sourcePixelFormat)) {
860+
_lastScaleStatus = -1;
861+
return NULL;
862+
}
863+
864+
BOOL needsNewBuffer = (_scaledPixelBuffer == NULL)
865+
|| ((int32_t)CVPixelBufferGetWidth(_scaledPixelBuffer) != targetWidth)
866+
|| ((int32_t)CVPixelBufferGetHeight(_scaledPixelBuffer) != targetHeight)
867+
|| (_scaledPixelFormat != sourcePixelFormat);
868+
if (needsNewBuffer) {
869+
if (_scaledPixelBuffer != NULL) {
870+
CVPixelBufferRelease(_scaledPixelBuffer);
871+
_scaledPixelBuffer = NULL;
872+
}
873+
874+
NSDictionary *attributes = @{
875+
(__bridge NSString *)kCVPixelBufferIOSurfacePropertiesKey: @{},
876+
};
877+
CVPixelBufferRef scaledPixelBuffer = NULL;
878+
OSStatus bufferStatus = CVPixelBufferCreate(kCFAllocatorDefault,
879+
targetWidth,
880+
targetHeight,
881+
sourcePixelFormat,
882+
(__bridge CFDictionaryRef)attributes,
883+
&scaledPixelBuffer);
884+
if (bufferStatus != noErr || scaledPixelBuffer == NULL) {
885+
_lastScaleStatus = bufferStatus;
886+
return NULL;
887+
}
888+
_scaledPixelBuffer = scaledPixelBuffer;
889+
_scaledPixelFormat = sourcePixelFormat;
890+
}
891+
892+
CVReturn sourceLockStatus = CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
893+
if (sourceLockStatus != kCVReturnSuccess) {
894+
_lastScaleStatus = sourceLockStatus;
895+
return NULL;
896+
}
897+
898+
CVReturn targetLockStatus = CVPixelBufferLockBaseAddress(_scaledPixelBuffer, 0);
899+
if (targetLockStatus != kCVReturnSuccess) {
900+
CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
901+
_lastScaleStatus = targetLockStatus;
902+
return NULL;
903+
}
904+
905+
vImage_Buffer sourceBuffer = {
906+
.data = CVPixelBufferGetBaseAddress(pixelBuffer),
907+
.height = (vImagePixelCount)CVPixelBufferGetHeight(pixelBuffer),
908+
.width = (vImagePixelCount)CVPixelBufferGetWidth(pixelBuffer),
909+
.rowBytes = CVPixelBufferGetBytesPerRow(pixelBuffer),
910+
};
911+
vImage_Buffer targetBuffer = {
912+
.data = CVPixelBufferGetBaseAddress(_scaledPixelBuffer),
913+
.height = (vImagePixelCount)CVPixelBufferGetHeight(_scaledPixelBuffer),
914+
.width = (vImagePixelCount)CVPixelBufferGetWidth(_scaledPixelBuffer),
915+
.rowBytes = CVPixelBufferGetBytesPerRow(_scaledPixelBuffer),
916+
};
917+
vImage_Error scaleStatus = vImageScale_ARGB8888(&sourceBuffer,
918+
&targetBuffer,
919+
NULL,
920+
kvImageHighQualityResampling);
921+
CVPixelBufferUnlockBaseAddress(_scaledPixelBuffer, 0);
922+
CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
923+
_lastScaleStatus = scaleStatus;
924+
if (scaleStatus != kvImageNoError) {
925+
return NULL;
926+
}
927+
928+
CVPixelBufferRetain(_scaledPixelBuffer);
929+
return _scaledPixelBuffer;
930+
}
931+
832932
- (void)invalidateScalingResourcesLocked {
833933
if (_scaledPixelBuffer != NULL) {
834934
CVPixelBufferRelease(_scaledPixelBuffer);

server/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ fn main() {
7575

7676
for framework in [
7777
"Foundation",
78+
"Accelerate",
7879
"AppKit",
7980
"CoreImage",
8081
"CoreGraphics",

0 commit comments

Comments
 (0)