I am trying to resize a pixel buffer with the kCVPixelFormatType_420YpCbCr8BiPlanarFullRange (420f) pixel format to another size with preserving aspect ratio and adding black bars (if needed).
I am using the vImageScale_Planar8 and vImageRotate90_Planar8 functions from the Accelerate framework to scale and rotate the Y plane, and the vImageScale_CbCr8 and vImageRotate90_Planar16U functions to scale and rotate the CbCr plane.
Here is the code:
+ (CVPixelBufferRef)resizeProportionallyBuffer:(CVPixelBufferRef)srcPixelBuffer withOrientation:(CGImagePropertyOrientation)orientation toSize:(CGSize)dstSize {
OSType pixelFormat = CVPixelBufferGetPixelFormatType(srcPixelBuffer);
CVPixelBufferLockFlags srcFlags = kCVPixelBufferLock_ReadOnly;
CVPixelBufferLockBaseAddress(srcPixelBuffer, srcFlags);
void *srcLuminanceData = CVPixelBufferGetBaseAddressOfPlane(srcPixelBuffer, 0);
size_t srcLuminanceWidth = CVPixelBufferGetWidthOfPlane(srcPixelBuffer, 0);//750
size_t srcLuminanceHeight = CVPixelBufferGetHeightOfPlane(srcPixelBuffer, 0);//1334
size_t srcLuminanceBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(srcPixelBuffer, 0);//768
void *srcCbCrData = CVPixelBufferGetBaseAddressOfPlane(srcPixelBuffer, 1);
int srcCbCrWidth = (int)CVPixelBufferGetWidthOfPlane(srcPixelBuffer, 1);//375
int srcCbCrHeight = (int)CVPixelBufferGetHeightOfPlane(srcPixelBuffer, 1);//667
size_t srcCbCrBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(srcPixelBuffer, 1);//768
vImage_Buffer srcLuminanceBuffer = {
.data = srcLuminanceData,
.width = srcLuminanceWidth,
.height = srcLuminanceHeight,
.rowBytes = srcLuminanceBytesPerRow
};
vImage_Buffer srcCbCrBuffer = {
.data = srcCbCrData,
.width = srcCbCrWidth,
.height = srcCbCrHeight,
.rowBytes = srcCbCrBytesPerRow
};
size_t srcWidth = srcLuminanceWidth;
size_t srcHeight = srcLuminanceHeight;
int dstWidth = (int)dstSize.width;
int dstHeight = (int)dstSize.height;
uint8_t rotationConstant = 0;
size_t scaledWidth = srcLuminanceWidth;
size_t scaledHeight = srcLuminanceHeight;
if (orientation == kCGImagePropertyOrientationUp || orientation == kCGImagePropertyOrientationDown) {
BOOL srcIsWider = dstHeight * srcWidth > dstWidth * srcHeight;
scaledWidth = srcIsWider ? dstWidth : (size_t)round((CGFloat)(dstHeight * srcWidth) / (CGFloat)srcHeight);
scaledHeight = srcIsWider ? (size_t)round((CGFloat)(dstWidth * srcHeight) / (CGFloat)srcWidth) : dstHeight;
rotationConstant = (orientation == kCGImagePropertyOrientationUp) ? kRotate0DegreesClockwise : kRotate180DegreesClockwise;
} else if (orientation == kCGImagePropertyOrientationLeft || orientation == kCGImagePropertyOrientationRight) {
BOOL srcIsWider = dstHeight * srcHeight > dstWidth * srcWidth;
scaledHeight = srcIsWider ? dstWidth: (size_t)round((CGFloat)(srcHeight * dstHeight) / (CGFloat)srcWidth);
scaledWidth = srcIsWider ? (size_t)round((CGFloat)(srcWidth * dstWidth) / (CGFloat)srcHeight) : dstHeight;
rotationConstant = (orientation == kCGImagePropertyOrientationLeft) ? kRotate90DegreesClockwise : kRotate90DegreesCounterClockwise;
}
Pixel_8 backColor = 0;
CVPixelBufferRef dstPixelBuffer = NULL;
CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
dstWidth,
dstHeight,
pixelFormat,
nil,
&dstPixelBuffer);
CVPixelBufferLockBaseAddress(dstPixelBuffer, 0);
void *dstLuminanceData = CVPixelBufferGetBaseAddressOfPlane(dstPixelBuffer, 0);
int dstLuminanceWidth = (int)CVPixelBufferGetWidthOfPlane(dstPixelBuffer, 0);//1280
int dstLuminanceHeight = (int)CVPixelBufferGetHeightOfPlane(dstPixelBuffer, 0);//720
size_t dstLuminanceBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(dstPixelBuffer, 0);//1280
void *dstCbCrData = CVPixelBufferGetBaseAddressOfPlane(dstPixelBuffer, 1);
int dstCbCrWidth = (int)CVPixelBufferGetWidthOfPlane(dstPixelBuffer, 1);//640
int dstCbCrHeight = (int)CVPixelBufferGetHeightOfPlane(dstPixelBuffer, 1);//360
size_t dstCbCrBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(dstPixelBuffer, 1);//1280
vImage_Buffer dstLuminanceBuffer = {
.data = dstLuminanceData,
.width = dstLuminanceWidth,
.height = dstLuminanceHeight,
.rowBytes = dstLuminanceBytesPerRow
};
vImage_Buffer dstCbCrBuffer = {
.data = dstCbCrData,
.width = dstCbCrWidth,
.height = dstCbCrHeight,
.rowBytes = dstCbCrBytesPerRow
};
void *dstLuminanceIntermediateBufferData = malloc(scaledWidth*scaledHeight);
vImage_Buffer dstLuminanceIntermediateBuffer = {
.data = dstLuminanceIntermediateBufferData,
.width = scaledWidth,
.height = scaledHeight,
.rowBytes = scaledWidth
};
vImage_Error error = vImageScale_Planar8(&srcLuminanceBuffer, &dstLuminanceIntermediateBuffer, nil, kvImageNoFlags);
error = vImageRotate90_Planar8(&dstLuminanceIntermediateBuffer, &dstLuminanceBuffer, rotationConstant, backColor, kvImageBackgroundColorFill);
free(dstLuminanceIntermediateBufferData);
void *dstCbCrIntermediateBufferData = malloc(scaledWidth*scaledHeight);
vImage_Buffer dstCbCrIntermediateBuffer = {
.data = dstCbCrIntermediateBufferData,
.width = scaledWidth/2,
.height = scaledHeight/2,
.rowBytes = scaledWidth
};
error = vImageScale_CbCr8(&srcCbCrBuffer, &dstCbCrIntermediateBuffer, nil, kvImageNoFlags);
error = vImageRotate90_Planar16U(&dstCbCrIntermediateBuffer, &dstCbCrBuffer, rotationConstant, 127, kvImageBackgroundColorFill);
free(dstCbCrIntermediateBufferData);
CVPixelBufferUnlockBaseAddress(srcPixelBuffer, srcFlags);
CVPixelBufferUnlockBaseAddress(dstPixelBuffer, 0);
return dstPixelBuffer;
}
The code works, but when an image has the kCGImagePropertyOrientationLeft or kCGImagePropertyOrientationRight orientation, green bars are added.
How can I fix this problem?