420YpCbCr8 Conversion to ARGB , RGBA 변환 방법

2022. 3. 3. 18:03Developer.TokkiSea/Apple

반응형

 

 

개인 메모용 입니다.

 

카메라등에서 들어오는 이미지 버퍼의 420YpCbCr8 포멧을 ARGB 나 RGBA 로 변환하는 방법이예요.

 

(이직 관계로 요즘 일이 너무 많아서 TokkiSea는 신경을 못쓰고 있군요.)

argbBuffer 은 ARGB 포맷이고 RGBA 로는 포인터 +1 를 해주면 되겠지만 맨 끝 포인터가 미할당 영역이라 무슨일이 일어날지 몰라요.

RGBX로 사용하면 문제는 없을듯합니다.

    // YpCbCr Format
    // kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange : Bi-Planar Component Y'CbCr 8-bit 4:2:0, video-range (luma=[16,235] chroma=[16,240]).
    // kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : Bi-Planar Component Y'CbCr 8-bit 4:2:0, full-range (luma=[0,255] chroma=[1,255]).
    // CoreVideo.CVPixelBuffer
    
    private var _conversionInfoYpCbCrToARGB: vImage_YpCbCrToARGB? = {
        var pixelRange = vImage_YpCbCrPixelRange(Yp_bias: 16, CbCr_bias: 128, YpRangeMax: 235, CbCrRangeMax: 240, YpMax: 235, YpMin: 16, CbCrMax: 240, CbCrMin: 16)
        var infoYpCbCrToARGB = vImage_YpCbCrToARGB()
        guard vImageConvert_YpCbCrToARGB_GenerateConversion(kvImage_YpCbCrToARGBMatrix_ITU_R_601_4!, &pixelRange, &infoYpCbCrToARGB, kvImage422CbYpCrYp8, kvImageARGB8888, vImage_Flags(kvImageNoFlags)) == kvImageNoError else {
            return nil
        }
        return infoYpCbCrToARGB
    }()

    /**
     Convert a YpCbCr format pixel buffer into ARGB data.
     - parameter pixelBuffer: Typically captured from the device video camera.
     - parameter argbBuffer: Buffer for ARGB data output. The buffer will be
        resized if needed. Reuse the buffer for best performance.
     */
    public func convertYpCbCr(pixelBuffer: CVPixelBuffer, intoARGBBuffer argbBuffer: inout vImage_Buffer) -> Bool {
        // Adapted from Apple's sample code at:
        // https://developer.apple.com/documentation/accelerate/vimage/converting_luminance_and_chrominance_planes_to_an_argb_image?language=objc
        guard var conversionInfoYpCbCrToARGB = _conversionInfoYpCbCrToARGB else {
            return false
        }

        CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)
        defer {
            CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly)
        }

        guard CVPixelBufferGetPlaneCount(pixelBuffer) == 2 else {
            return false
        }

        let lumaBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)
        let lumaWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0)
        let lumaHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0)
        let lumaRowBytes = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0)
        var sourceLumaBuffer = vImage_Buffer(data: lumaBaseAddress, height: vImagePixelCount(lumaHeight), width: vImagePixelCount(lumaWidth), rowBytes: lumaRowBytes)

        let chromaBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1)
        let chromaWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1)
        let chromaHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1)
        let chromaRowBytes = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1)
        var sourceChromaBuffer = vImage_Buffer(data: chromaBaseAddress, height: vImagePixelCount(chromaHeight), width: vImagePixelCount(chromaWidth), rowBytes: chromaRowBytes)

        if argbBuffer.data == nil || argbBuffer.width != sourceLumaBuffer.width || argbBuffer.height != sourceLumaBuffer.height || argbBuffer.rowBytes != sourceLumaBuffer.width * 4 {
            guard vImageBuffer_Init(&argbBuffer, sourceLumaBuffer.height, sourceLumaBuffer.width, 32, vImage_Flags(kvImageNoFlags)) == kvImageNoError else {
                return false
            }
        }

        guard vImageConvert_420Yp8_CbCr8ToARGB8888(&sourceLumaBuffer, &sourceChromaBuffer, &argbBuffer, &conversionInfoYpCbCrToARGB, nil, 255, vImage_Flags(kvImageNoFlags)) == kvImageNoError else {
            return false
        }
//        vImageConvert_ARGB8888ToRGBA1010102(_ src: UnsafePointer<vImage_Buffer>, _ dest: UnsafePointer<vImage_Buffer>, _ RGB101010RangeMin: Int32, _ RGB101010RangeMax: Int32, _ permuteMap: UnsafePointer<UInt8>!, _ flags: vImage_Flags)
//        for x in 0..<argbBuffer.width {
//            for y in 0..<argbBuffer.height {
//                self.argbValues(at: (x: Int(x), y: Int(y)), in: argbBuffer)
//            }
//        }
//        print(self.argbValues(at: (x: 0, y: 0), in: argbBuffer))
        return true
    }
반응형