ios - 将 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 缓冲区转换为 RGB 缓冲区会创建蓝色图片

标签 ios objective-c graphics rgb yuv

我正在尝试将 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 转换为 RGB,以便我可以将图像保存在 JPG 文件中,这是我正在使用的代码:

#define clamp(a) (a>255?255:(a<0?0:a));

- (UIImage *)makeUIImage:(uint8_t *)inBaseAddress bufferInfo:(CVPlanarPixelBufferInfo_YCbCrBiPlanar *)inBufferInfo width:(size_t)inWidth height:(size_t)inHeight bytesPerRow:(size_t)inBytesPerRow
{
    NSUInteger yOffset = EndianU32_BtoN(inBufferInfo->componentInfoY.offset);
    NSUInteger yPitch = EndianU32_BtoN(inBufferInfo->componentInfoY.rowBytes);

    NSUInteger cbCrOffset = EndianU32_BtoN(inBufferInfo->componentInfoCbCr.offset);
    NSUInteger cbCrPitch = EndianU32_BtoN(inBufferInfo->componentInfoCbCr.rowBytes);

    uint8_t *rgbBuffer = malloc(inWidth * inHeight * 4);
    uint8_t *yBuffer = inBaseAddress + yOffset;
    uint8_t *cbCrBuffer = inBaseAddress + cbCrOffset;

    for(int y = 0; y < inHeight; y++)
    {
        uint8_t *rgbBufferLine = &rgbBuffer[y * inWidth * 4];
        uint8_t *yBufferLine = &yBuffer[y * yPitch];
        uint8_t *cbCrBufferLine = &cbCrBuffer[(y >> 1) * cbCrPitch];

        for(int x = 0; x < inWidth; x++)
        {
            uint8_t y = yBufferLine[x];
            uint8_t cb = cbCrBufferLine[x & ~1];
            uint8_t cr = cbCrBufferLine[x | 1];

            uint8_t *rgbOutput = &rgbBufferLine[x*4];

            int r = (int)round( (y - 16) * 1.164 + (cr - 128) *  1.596 );
            int g = (int)round( (y - 16) * 1.164 + (cb - 128) * -0.391 + (cr - 128) * -0.813 );
            int b = (int)round( (y - 16) * 1.164 + (cb - 128) *  2.018 );

            rgbOutput[0] = 0xff;
            rgbOutput[1] = clamp(r);
            rgbOutput[2] = clamp(g);
            rgbOutput[3] = clamp(b);

        }
    }

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(rgbBuffer, yPitch, inHeight, 8,
                                                 yPitch*4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);

    CGImageRef quartzImage = CGBitmapContextCreateImage(context);

    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    UIImage *image = [UIImage imageWithCGImage:quartzImage];

    CGImageRelease(quartzImage);
    free(rgbBuffer);
    return  image;
}

-(void)createImg:(CMSampleBufferRef) sampleBuffer index:(int)index
{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

    //Lock the imagebuffer
    CVPixelBufferLockBaseAddress(imageBuffer,0);

    // Get information about the image
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);

    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);

    CVPlanarPixelBufferInfo_YCbCrBiPlanar *bufferInfo = (CVPlanarPixelBufferInfo_YCbCrBiPlanar *)baseAddress;

    baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);


    // convert the image
    UIImage *img = [self makeUIImage:baseAddress bufferInfo:bufferInfo width:width height:height bytesPerRow:bytesPerRow];
    NSString *videoThumbPath = [NSString
                                stringWithFormat:@"%@/img%02d.jpg",
                                burstFolderPath,
                                index];

    NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(img,0.8f)];
    [imageData writeToFile:videoThumbPath atomically:YES];
}

图像已生成,但颜色错误,图片偏蓝,而且图片右侧似乎有断点: enter image description here

我做错了什么?

最佳答案

// Hope it can help someone!

int bytesPerPixel = 4;

uint8_t *rgbBuffer = (uint8_t *)malloc(width * height * bytesPerPixel);

for(int y = 0; y < height; y++)
{
    uint8_t *rgbBufferLine = &rgbBuffer[y * width * bytesPerPixel];
    uint8_t *yBufferLine = &yBuffer[y * yPitch];
    uint8_t *cbCrBufferLine = &cbCrBuffer[(y >> 1) * cbCrPitch];

    for(int x = 0; x < width; x++)
    {
        int16_t y = yBufferLine[x];
        int16_t cb = cbCrBufferLine[x & ~1] - 128;
        int16_t cr = cbCrBufferLine[x | 1] - 128;

        uint8_t *rgbOutput = &rgbBufferLine[x*bytesPerPixel];

        int16_t r = (int16_t)roundf( y + cr *  1.4 );
        int16_t g = (int16_t)roundf( y + cb * -0.343 + cr * -0.711 );
        int16_t b = (int16_t)roundf( y + cb *  1.765);

        //ABGR
        rgbOutput[0] = 0xff;
        rgbOutput[1] = clamp(b);
        rgbOutput[2] = clamp(g);
        rgbOutput[3] = clamp(r);
    }
}

关于ios - 将 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 缓冲区转换为 RGB 缓冲区会创建蓝色图片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24090122/

相关文章:

colors - 为什么片段着色器根据片段坐标将图像着色为饱和色?

c++ - 如何创建优化的图形多色记录器?

c# - 如何在 .NET 中访问桌面缓冲区的图像?

ios - 当 NSDictionary 添加到数组中时,它会替换之前的字典

ios - 如何修复 "Command/usr/bin/codesign failed with exit code 1"错误

ios - 对象符合 Swift 协议(protocol)

objective-c - 使用 contentScaleFactor 属性缩放 UITextView

iphone - iOS 7 UITextView 高度调整大小怪癖

python - PyAPNs 抛出设备不支持的 IOError 操作

iphone - Pago 支付网关集成