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

