Duplicate / Copy CVPixelBufferRef with CVPixelBufferCreate
Asked Answered
V

3

11

I need to create a copy of a CVPixelBufferRef in order to be able to manipulate the original pixel buffer in a bit-wise fashion using the values from the copy. I cannot seem to achieve this with CVPixelBufferCreate, or with CVPixelBufferCreateWithBytes.

According to this question, it could possibly also be done with memcpy(). However, there is no explanation on how this would be achieved, and which Core Video library calls would be needed regardless.

Velour answered 24/5, 2016 at 15:58 Comment(5)
Can't you just memcpy the data somewhere else?Jingo
That's actually exactly what I had in mind with the 'easier way', however I didn't find any examples of how to do this, and I'm quite a noob to C programming. Would I just define a new pixel buffer CVPixelBufferRef newPixelBuffer = NULL and then use memcpy()?Velour
No, you'd just want to copy the pixel data rather than copying whatever internal structure the CVPixelBufferRef has. See the documentation for CVPixelBufferGetBaseAddress.Jingo
I understand how to get the base address, but I still don't understand how to use memcpy() Or, to be precise, I don't know how to define the destination addressVelour
Guys, thanks for marking my question as duplicate. However, the previous question provides me with no useful information whatsoever of how to solve my problem. @Jingo if you know how to solve the problem with memcpy() I would greatly appreciate if you could provide an answer to the other question. Otherwise we're basically only wasting each others' time.Velour
V
10

This seems to work:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

    CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

    // Get pixel buffer info
    const int kBytesPerPixel = 4;
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    int bufferWidth = (int)CVPixelBufferGetWidth(pixelBuffer);
    int bufferHeight = (int)CVPixelBufferGetHeight(pixelBuffer);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer); 
    uint8_t *baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);

    // Copy the pixel buffer
    CVPixelBufferRef pixelBufferCopy = NULL;
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, bufferWidth, bufferHeight, kCVPixelFormatType_32BGRA, NULL, &pixelBufferCopy);
    CVPixelBufferLockBaseAddress(pixelBufferCopy, 0);
    uint8_t *copyBaseAddress = CVPixelBufferGetBaseAddress(pixelBufferCopy);
    memcpy(copyBaseAddress, baseAddress, bufferHeight * bytesPerRow);

    // Do what needs to be done with the 2 pixel buffers

}
Velour answered 30/5, 2016 at 9:6 Comment(1)
kBytesPerPixel is unused and unnecessaryOmnibus
I
3

ooOlly's code was not working for me with YUV pixel buffers in all cases (green line at bottom and sig trap in memcpy), so this works in swift for YUV pixel buffers from the camera:

var copyOut: CVPixelBuffer?
let status = CVPixelBufferCreate(kCFAllocatorDefault, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer), CVPixelBufferGetPixelFormatType(pixelBuffer), nil, &copyOut)
let copy = copyOut!

CVPixelBufferLockBaseAddress(copy, [])
CVPixelBufferLockBaseAddress(pixelBuffer, [])

let ydestPlane = CVPixelBufferGetBaseAddressOfPlane(copy, 0)
let ysrcPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)
memcpy(ydestPlane, ysrcPlane, CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0) * CVPixelBufferGetHeightOfPlane(pixelBuffer, 0))

let uvdestPlane = CVPixelBufferGetBaseAddressOfPlane(copy, 1)
let uvsrcPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1)
memcpy(uvdestPlane, uvsrcPlane, CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1) * CVPixelBufferGetHeightOfPlane(pixelBuffer, 1))

CVPixelBufferUnlockBaseAddress(copy, [])
CVPixelBufferUnlockBaseAddress(pixelBuffer, [])

better error handling than the force unwrap is strongly suggested of course.

Ivo answered 8/3, 2019 at 20:8 Comment(1)
So now how to scale it, e.g. by 0.5?Goulet
B
1

Maxi Mus's code only due with RGB/BGR buffer. so for YUV buffer below code should work.

// Copy the pixel buffer
    CVPixelBufferRef pixelBufferCopy = NULL;
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, bufferWidth, bufferHeight, pixelFormat, NULL, &pixelBufferCopy);
    CVPixelBufferLockBaseAddress(pixelBufferCopy, 0);
    //BGR
//    uint8_t *copyBaseAddress = CVPixelBufferGetBaseAddress(pixelBufferCopy);
//    memcpy(copyBaseAddress, baseAddress, bufferHeight * bytesPerRow);
    uint8_t *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBufferCopy, 0);
    //YUV
    uint8_t *yPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
    memcpy(yDestPlane, yPlane, bufferWidth * bufferHeight);
    uint8_t *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBufferCopy, 1);
    uint8_t *uvPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
    memcpy(uvDestPlane, uvPlane, bufferWidth * bufferHeight/2);
    CVPixelBufferUnlockBaseAddress(pixelBufferCopy, 0);
Biddable answered 31/8, 2018 at 12:47 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.