kCVPixelFormatType_420YpCbCr8BiPlanarFullRange frame to UIImage conversion

后端 未结 3 516
猫巷女王i
猫巷女王i 2020-12-01 05:39

I have an app that capture live video in kCVPixelFormatType_420YpCbCr8BiPlanarFullRange format to process Y channel. According to Apple\'s documentation:

3条回答
  •  渐次进展
    2020-12-01 06:33

    I'm not aware of any accessible built-in way to convert a biplanar Y / CbCr image to RGB in iOS. However you should be able to perform the conversion yourself in software, e.g.

    uint8_t clamp(int16_t input)
    {
        // clamp negative numbers to 0; assumes signed shifts
        // (a valid assumption on iOS)
        input &= ~(num >> 16);
    
        // clamp numbers greater than 255 to 255; the accumulation
        // of the mask looks odd but is an attempt to avoid
        // pipeline stalls
        uint8_t saturationMask = num >> 8;
        saturationMask |= saturationMask << 4;
        saturationMask |= saturationMask << 2;
        saturationMask |= saturationMask << 1;
        num |= saturationMask;
    
        return num&0xff;
    }
    
    ...
    
    CVPixelBufferLockBaseAddress(imageBuffer, 0);
    
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    
    uint8_t *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
    CVPlanarPixelBufferInfo_YCbCrBiPlanar *bufferInfo = (CVPlanarPixelBufferInfo_YCbCrBiPlanar *)baseAddress;
    
    NSUInteger yOffset = EndianU32_BtoN(bufferInfo->componentInfoY.offset);
    NSUInteger yPitch = EndianU32_BtoN(bufferInfo->componentInfoY.rowBytes);
    
    NSUInteger cbCrOffset = EndianU32_BtoN(bufferInfo->componentInfoCbCr.offset);
    NSUInteger cbCrPitch = EndianU32_BtoN(bufferInfo->componentInfoCbCr.rowBytes);
    
    uint8_t *rgbBuffer = malloc(width * height * 3);
    uint8_t *yBuffer = baseAddress + yOffset;
    uint8_t *cbCrBuffer = baseAddress + cbCrOffset;
    
    for(int y = 0; y < height; y++)
    {
        uint8_t *rgbBufferLine = &rgbBuffer[y * width * 3];
        uint8_t *yBufferLine = &yBuffer[y * yPitch];
        uint8_t *cbCrBufferLine = &cbCrBuffer[(y >> 1) * cbCrPitch];
    
        for(int x = 0; x < width; x++)
        {
            // from ITU-R BT.601, rounded to integers
            uint8_t y = yBufferLine[x] - 16;
            uint8_t cb = cbCrBufferLine[x & ~1] - 128;
            uint8_t cr = cbCrBufferLine[x | 1] - 128;
    
            uint8_t *rgbOutput = &rgbBufferLine[x*3];
    
            rgbOutput[0] = clamp(((298 * y + 409 * cr - 223) >> 8) - 223);
            rgbOutput[1] = clamp(((298 * y - 100 * cb - 208 * cr + 136) >> 8) + 136);
            rgbOutput[2] = clamp(((298 * y + 516 * cb - 277) >> 8) - 277);
        }
    
    }
    

    Just written directly into this box and untested, I think I've got the cb/cr extraction correct. You'd then use CGBitmapContextCreate with rgbBuffer to create a CGImage and hence a UIImage.

提交回复
热议问题