76 lines
2.7 KiB
Swift
76 lines
2.7 KiB
Swift
//
|
|
// Frame+CV.swift
|
|
// LiveApple
|
|
//
|
|
// Created by Shadowfacts on 9/24/22.
|
|
//
|
|
|
|
import Foundation
|
|
import CoreVideo
|
|
import Accelerate
|
|
|
|
extension Frame {
|
|
init(pixelBuffer buf: CVPixelBuffer) {
|
|
let inputHeight = CVPixelBufferGetHeight(buf)
|
|
let inputWidth = CVPixelBufferGetWidth(buf)
|
|
let width = inputWidth / 8
|
|
let height = inputHeight / 8
|
|
precondition(width <= 64)
|
|
|
|
// something is wonky with the format, sourceBuffer comes out green/white instead of white/black
|
|
// but whatever, we can work with that
|
|
let inputCVImageFormat = vImageCVImageFormat_CreateWithCVPixelBuffer(buf).takeRetainedValue()
|
|
vImageCVImageFormat_SetColorSpace(inputCVImageFormat, CGColorSpaceCreateDeviceRGB())
|
|
|
|
var error = kvImageNoError
|
|
|
|
var sourceFormat = vImage_CGImageFormat(
|
|
bitsPerComponent: 8,
|
|
bitsPerPixel: 32,
|
|
colorSpace: nil,
|
|
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue),
|
|
version: 0,
|
|
decode: nil,
|
|
renderingIntent: .defaultIntent
|
|
)
|
|
var sourceBuffer = vImage_Buffer()
|
|
error = vImageBuffer_InitWithCVPixelBuffer(&sourceBuffer, &sourceFormat, buf, inputCVImageFormat, nil, vImage_Flags(kvImageNoFlags))
|
|
defer { sourceBuffer.free() }
|
|
precondition(error == kvImageNoError)
|
|
|
|
var destBuffer = vImage_Buffer()
|
|
error = vImageBuffer_Init(&destBuffer, vImagePixelCount(height), vImagePixelCount(width), sourceFormat.bitsPerPixel, vImage_Flags(kvImageNoFlags))
|
|
defer { destBuffer.free() }
|
|
precondition(error == kvImageNoError)
|
|
|
|
error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, vImage_Flags(kvImageNoFlags))
|
|
precondition(error == kvImageNoError)
|
|
|
|
let cgImage = vImageCreateCGImageFromBuffer(&destBuffer, &sourceFormat, nil, nil, vImage_Flags(kvImageNoFlags), &error).takeRetainedValue()
|
|
precondition(error == kvImageNoError)
|
|
|
|
let dataRef = cgImage.dataProvider!.data!
|
|
let data = dataRef as Data
|
|
|
|
var enc = [UInt64](repeating: 0, count: height)
|
|
|
|
for row in 0..<height {
|
|
let start = row * cgImage.bytesPerRow
|
|
var rowEnc: UInt64 = 0
|
|
// this could probably be faster with simd
|
|
// note: the individual UInt64s end up being reversed here
|
|
for col in 0..<width {
|
|
// 4 bytes per pixel
|
|
if data[start + (col * 4)] > 127 {
|
|
rowEnc |= (1 << col)
|
|
}
|
|
}
|
|
enc[row] = rowEnc
|
|
}
|
|
|
|
self.width = width
|
|
self.data = enc
|
|
}
|
|
}
|
|
|