6

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.

Community
  • 1
  • 1
Maxi Mus
  • 675
  • 5
  • 16
  • Can't you just `memcpy` the data somewhere else? – jtbandes May 24 '16 at 16:00
  • 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()? – Maxi Mus May 24 '16 at 16:25
  • No, you'd just want to copy the pixel data rather than copying whatever internal structure the CVPixelBufferRef has. See the documentation for CVPixelBufferGetBaseAddress. – jtbandes May 24 '16 at 16:27
  • 1
    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 address – Maxi Mus May 24 '16 at 16:30
  • 2
    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. @jtbandes 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. – Maxi Mus May 24 '16 at 17:20

3 Answers3

7

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

}
Maxi Mus
  • 675
  • 5
  • 16
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.

Dennis L
  • 1,448
  • 13
  • 20
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);
ooOlly
  • 1,747
  • 16
  • 29