Skip to content

Instantly share code, notes, and snippets.

@kientux
Created February 7, 2023 08:52
Show Gist options
  • Save kientux/92ffd82e05e2a86a70a33bb89815d5ba to your computer and use it in GitHub Desktop.
Save kientux/92ffd82e05e2a86a70a33bb89815d5ba to your computer and use it in GitHub Desktop.
Cropping CMSampleBuffer from AVCaptureVideoDataOutputSampleBufferDelegate
import Accelerate
func cropSampleBuffer(_ sampleBuffer: CMSampleBuffer) -> CMSampleBuffer? {
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return nil
}
CVPixelBufferLockBaseAddress(imageBuffer, .readOnly)
defer { CVPixelBufferUnlockBaseAddress(imageBuffer, .readOnly) }
guard let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer) else {
return nil
}
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
let imageWidth = CGFloat(CVPixelBufferGetWidth(imageBuffer))
let imageHeight = CGFloat(CVPixelBufferGetHeight(imageBuffer))
let cropRect = CGRect(x: metadataRectOfInterest.origin.x * imageWidth,
y: metadataRectOfInterest.origin.y * imageHeight,
width: metadataRectOfInterest.size.width * imageWidth,
height: metadataRectOfInterest.size.height * imageHeight)
let outWidth = Int(cropRect.width)
let outHeight = Int(cropRect.height)
var inBuff = vImage_Buffer()
inBuff.height = UInt(cropRect.height)
inBuff.width = UInt(cropRect.width)
inBuff.rowBytes = bytesPerRow
let startpos = Int(cropRect.origin.y) * bytesPerRow + 4 * Int(cropRect.origin.x)
inBuff.data = baseAddress + startpos
guard let outImg = malloc(4 * outWidth * outHeight) else {
return nil
}
var outBuff = vImage_Buffer(data: outImg,
height: vImagePixelCount(outHeight),
width: vImagePixelCount(outWidth),
rowBytes: 4 * outWidth)
vImageScale_ARGB8888(&inBuff, &outBuff, nil, 0)
let pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer)
let releaseCallback: CVPixelBufferReleaseBytesCallback = { _, ptr in
if let ptr = ptr {
free(UnsafeMutableRawPointer(mutating: ptr))
}
}
var dstPixelBuffer: CVPixelBuffer?
CVPixelBufferCreateWithBytes(nil,
outWidth,
outHeight,
pixelFormat,
outImg,
4 * outWidth,
releaseCallback,
nil,
nil,
&dstPixelBuffer)
guard let dstPixelBuffer = dstPixelBuffer else {
return nil
}
var sampleBuffer2: CMSampleBuffer?
var timingInfo = CMSampleTimingInfo()
var formatDescription: CMFormatDescription? = nil
CMVideoFormatDescriptionCreateForImageBuffer(allocator: kCFAllocatorDefault,
imageBuffer: dstPixelBuffer,
formatDescriptionOut: &formatDescription)
guard let formatDescription = formatDescription else {
return nil
}
let osStatus = CMSampleBufferCreateReadyWithImageBuffer(
allocator: kCFAllocatorDefault,
imageBuffer: dstPixelBuffer,
formatDescription: formatDescription,
sampleTiming: &timingInfo,
sampleBufferOut: &sampleBuffer2
)
// Print out errors
if osStatus == kCMSampleBufferError_AllocationFailed {
print("osStatus == kCMSampleBufferError_AllocationFailed")
}
if osStatus == kCMSampleBufferError_RequiredParameterMissing {
print("osStatus == kCMSampleBufferError_RequiredParameterMissing")
}
if osStatus == kCMSampleBufferError_AlreadyHasDataBuffer {
print("osStatus == kCMSampleBufferError_AlreadyHasDataBuffer")
}
if osStatus == kCMSampleBufferError_BufferNotReady {
print("osStatus == kCMSampleBufferError_BufferNotReady")
}
if osStatus == kCMSampleBufferError_SampleIndexOutOfRange {
print("osStatus == kCMSampleBufferError_SampleIndexOutOfRange")
}
if osStatus == kCMSampleBufferError_BufferHasNoSampleSizes {
print("osStatus == kCMSampleBufferError_BufferHasNoSampleSizes")
}
if osStatus == kCMSampleBufferError_BufferHasNoSampleTimingInfo {
print("osStatus == kCMSampleBufferError_BufferHasNoSampleTimingInfo")
}
if osStatus == kCMSampleBufferError_ArrayTooSmall {
print("osStatus == kCMSampleBufferError_ArrayTooSmall")
}
if osStatus == kCMSampleBufferError_InvalidEntryCount {
print("osStatus == kCMSampleBufferError_InvalidEntryCount")
}
if osStatus == kCMSampleBufferError_CannotSubdivide {
print("osStatus == kCMSampleBufferError_CannotSubdivide")
}
if osStatus == kCMSampleBufferError_SampleTimingInfoInvalid {
print("osStatus == kCMSampleBufferError_SampleTimingInfoInvalid")
}
if osStatus == kCMSampleBufferError_InvalidMediaTypeForOperation {
print("osStatus == kCMSampleBufferError_InvalidMediaTypeForOperation")
}
if osStatus == kCMSampleBufferError_InvalidSampleData {
print("osStatus == kCMSampleBufferError_InvalidSampleData")
}
if osStatus == kCMSampleBufferError_InvalidMediaFormat {
print("osStatus == kCMSampleBufferError_InvalidMediaFormat")
}
if osStatus == kCMSampleBufferError_Invalidated {
print("osStatus == kCMSampleBufferError_Invalidated")
}
if osStatus == kCMSampleBufferError_DataFailed {
print("osStatus == kCMSampleBufferError_DataFailed")
}
if osStatus == kCMSampleBufferError_DataCanceled {
print("osStatus == kCMSampleBufferError_DataCanceled")
}
return sampleBuffer2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment