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+
310323static 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);
0 commit comments