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
|
||
|
}
|
||
|
}
|
||
|
|