OC CVPixelBuffer不同图像格式间转换

1.YUV转RGB,调用libYUV

- (BOOL)NV12ToRgbaPixelBuffer:(CVPixelBufferRef)pixelBufferNV12 pixelBufferRGBA:(CVPixelBufferRef)pixelBufferRGBA
{
    CVPixelBufferLockBaseAddress(pixelBufferNV12, 0);
    unsigned char* y = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(pixelBufferNV12,0);
    unsigned char* uv = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(pixelBufferNV12,1);
    CVPixelBufferLockBaseAddress(pixelBufferRGBA, 0);
    uint8_t* data = (uint8_t*)CVPixelBufferGetBaseAddress(pixelBufferRGBA);
    
    int32_t width  = (int32_t)CVPixelBufferGetWidth(pixelBufferNV12);
    int32_t height = (int32_t)CVPixelBufferGetHeight(pixelBufferNV12);
    
    size_t bgraStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferRGBA,0);
    size_t y_stride = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferNV12,0);
    size_t uv_stride  = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferNV12, 1);
    libyuv::NV12ToARGB(y,
                       int(y_stride),
                       uv,
                       int(uv_stride),
                       data,
                       int(bgraStride),
                       width,
                       height);
    
    CVPixelBufferUnlockBaseAddress(pixelBufferRGBA, 0);
    CVPixelBufferUnlockBaseAddress(pixelBufferNV12, 0);
    return true;
}

2.RGB转YUV

- (BOOL)RgbaToNV12PixelBuffer:(CVPixelBufferRef)pixelBufferRGBA pixelBufferYUV:(CVPixelBufferRef)pixelBufferNV12
{
    CVPixelBufferLockBaseAddress(pixelBufferNV12, 0);
    unsigned char* y = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(pixelBufferNV12,0);
    unsigned char* u = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(pixelBufferNV12,1);
    CVPixelBufferLockBaseAddress(pixelBufferRGBA, 0);
    uint8_t* data = (uint8_t*)CVPixelBufferGetBaseAddress(pixelBufferRGBA);
    
    int32_t width  = (int32_t)CVPixelBufferGetWidth(pixelBufferNV12);
    int32_t height = (int32_t)CVPixelBufferGetHeight(pixelBufferNV12);
    unsigned char* v = u + width*height/4;
    
    size_t bgraStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferRGBA,0);
//    size_t y_stride = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferNV12,0);
//    size_t uv_stride  = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferNV12, 1);
    libyuv::ARGBToI420(data,
               (int)bgraStride,
               y,
               width,
               u,
               width/2,
               v,
               width/2,
               width,
               height);
    
    CVPixelBufferUnlockBaseAddress(pixelBufferRGBA, 0);
    CVPixelBufferUnlockBaseAddress(pixelBufferNV12, 0);
    return true;
}

3.YUV保存本地

-(BOOL) savePixelBufferYUV:(CVPixelBufferRef)CVPixelBufferYUV
{
    int32_t width  = (int32_t)CVPixelBufferGetWidth(CVPixelBufferYUV);
    int32_t height = (int32_t)CVPixelBufferGetHeight(CVPixelBufferYUV);
    
    CVPixelBufferLockBaseAddress(CVPixelBufferYUV, 0);
    unsigned char* y = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(CVPixelBufferYUV,0);
    unsigned char* uv = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(CVPixelBufferYUV,1);
    FILE *VTcaptureFile = NULL;
    if (!VTcaptureFile)
    {
        NSString *path_document = NSHomeDirectory();
        NSString *imagePath = [path_document stringByAppendingFormat:@"%@",@"/Documents/previewYUV.yuv"];
        //   VTcaptureFile = fopen(captureTestName, "aw");
        const char * captureTestName = [imagePath UTF8String];
        VTcaptureFile = fopen(captureTestName, "aw");
        if (!VTcaptureFile)
        {
            NSLog(@"fopen file  error!! \n");
            return NO ;
        }
        fwrite(y, 1, width*height, VTcaptureFile);
        fflush(VTcaptureFile);
        fwrite(uv, 1, width*height/2, VTcaptureFile);
        fflush(VTcaptureFile);
    }
    CVPixelBufferUnlockBaseAddress(CVPixelBufferYUV, 0);
    return YES;
}

4.Creat YUV PixelBuffer

    CVPixelBufferRef _pixelBufferYUV = NULL;
    const void *keys[] = {
        kCVPixelBufferOpenGLCompatibilityKey,
        kCVPixelBufferIOSurfacePropertiesKey,
    };
    const void *values[] = {
        (__bridge const void *)([NSNumber numberWithBool:YES]),
        (__bridge const void *)([NSDictionary dictionary])
    };

    OSType bufferPixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;

    CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 2, NULL, NULL);
    CVReturn err __unused = CVPixelBufferCreate(kCFAllocatorDefault,
                                       encodedWidth,
                                       encodedHeight,
                                       bufferPixelFormat,
                                       optionsDictionary,
                                       &_pixelBufferYUV);

5.NSImage转BGRA CVPixelBuffer

- (CVPixelBufferRef)venusFastImageFromNSImage:(NSImage *)image
{
    
    CVPixelBufferRef buffer = NULL;
    size_t width = [image size].width;
    size_t height = [image size].height;
    size_t bitsPerComponent = 8; // *not* CGImageGetBitsPerComponent(image);
    CGColorSpaceRef cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    CGBitmapInfo bitmap = kCGImageAlphaNoneSkipFirst;
    NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
    
    // create pixel buffer
    CVPixelBufferCreate(kCFAllocatorDefault, width, height, k32ARGBPixelFormat, (__bridge CFDictionaryRef)dic, &buffer);
    CVPixelBufferLockBaseAddress(buffer, 0);
    void *rasterData = CVPixelBufferGetBaseAddress(buffer);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(buffer);
    
    // context to draw in, set to pixel buffer's address pls 4 align just for venus
    CGContextRef ctxt = CGBitmapContextCreate(rasterData, width, height, bitsPerComponent, bytesPerRow, cs, bitmap);
    if(ctxt == NULL){
        NSLog(@"could not create context");
        return NULL;
    }
    
    // draw image -> pixelbuffer
    NSGraphicsContext *nsctxt = [NSGraphicsContext graphicsContextWithGraphicsPort:ctxt flipped:NO];
    [NSGraphicsContext saveGraphicsState];
    [NSGraphicsContext setCurrentContext:nsctxt];
    [image compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeCopy];
    [NSGraphicsContext restoreGraphicsState];
    
    //reset pixelbuffer -> image
    
    CVPixelBufferUnlockBaseAddress(buffer, 0);
    CFRelease(ctxt);
    
    return buffer;
}

6. CVPixelBuffer转NSImage

//后面有空再研究,参考下面链接
// https://gist.github.com/AllanChen/d1478f6794075b82e9458c13b3539006

7.CVPixelBuffer(NV12)保存本地,YUV420和NV12

- (void)SavePixelBufferNV12:(CVPixelBufferRef)pixelBuf{
    int yStride = (int)CVPixelBufferGetBytesPerRowOfPlane(pixelBuf,0);
    int h = (int)CVPixelBufferGetHeight(pixelBuf);
    auto buffer = (unsigned char*) malloc(yStride * h * 1.5);

    CVPixelBufferLockBaseAddress(pixelBuf, 0);

    if (CVPixelBufferIsPlanar(pixelBuf)) {
        unsigned char* src = (unsigned char*) CVPixelBufferGetBaseAddressOfPlane(pixelBuf, 0);
        unsigned char* uvsrc = (unsigned char*) CVPixelBufferGetBaseAddressOfPlane(pixelBuf, 1);
        unsigned char* dst = buffer;
         
        memcpy(dst, src, yStride * h);
         
        auto d1 = dst + yStride * h;
        auto d2 = dst + yStride * h * 5 / 4;
        
        auto len = yStride * h / 4;
        for(int i = 0; i < len; i++){
            //nv12 --> YUV420
            //nv12,uv分量交替存储;YUV420,uv分量分层存储
            *d1++ = *uvsrc++;
            *d2++ = *uvsrc++;
        }
        
        // 420 yuv
        {
            std::string path = [[NSHomeDirectory() stringByAppendingString:@"/Downloads"] UTF8String];
            path += "/";
            std::string str = path;
            str += "_";
            str += std::to_string(h);
            str += "x";
            str += std::to_string(yStride);
            str += "_420.yuv";
            FILE* fp = fopen(str.c_str(), "ab+");
            if (fp) {
                fwrite(buffer, 1, yStride * h * 1.5, fp);
                fclose(fp);
            }
        }
        
        // nv12
        {
            std::string path = [[NSHomeDirectory() stringByAppendingString:@"/Downloads"] UTF8String];
            path += "/";
            std::string str = path;
            str += "_";
            str += std::to_string(h);
            str += "x";
            str += std::to_string(yStride);
            str += "_nv12.yuv";
            FILE* fp = fopen(str.c_str(), "ab+");
            if (fp) {
                fwrite((unsigned char*) CVPixelBufferGetBaseAddressOfPlane(pixelBuf, 0), 1, yStride * h , fp);
                fwrite((unsigned char*) CVPixelBufferGetBaseAddressOfPlane(pixelBuf, 1), 1, yStride * h /2, fp);
                fclose(fp);
            }
        }
    }
    CVPixelBufferUnlockBaseAddress(pixelBuf, 0);
}

 

你可能感兴趣的:(图像处理,OC)