Example of IOSurfaceCreateMachPort and IOSurfaceLookupFromMachPort

The IOSurface framework lets you pass a reference to an IOSurface — a kind of pixel buffer — from one process to another. Here’s an example of how to pass an IOSurface through a mach port using the functions IOSurfaceCreateMachPort and IOSurfaceLookupFromMachPort. IOSurfaceCreateMachPort returns a mach port, and IOSurfaceLookupFromMachPort takes a mach port. You can pass the mach port returned by IOSurfaceCreateMachPort through another mach port created by you. This effectively passes a reference to the IOSurface from the caller of IOSurfaceCreateMachPort to the caller of IOSurfaceLookupFromMachPort.

From the Apple mailing lists:

The mach port stuff was created so that an application can pull a CVPixelBufferRef out of a pool, render into it, create a send right, post it to a message port and then drop all of their own references to the buffer.  The send right basically behind the scene also ensures that the underlying IOSurface is marked as “in use” as long as the send right exists.   If the mach port is deleted due to app death, then things get cleaned up correctly.   Otherwise the receiving app can then pull the send right out from the mach port, do the IOSurface lookup on it, recreate a CVPixelBufferRef and the latter will also ensure the IOSurface is still marked as “in use”.   At that point the send right can go away.

According to the documentation for CVPixelBufferCreateWithIOSurface, the above does not work if, instead of passing the IOSurface with IOSurfaceCreateMachPort and IOSurfaceLookupFromMachPort, you pass the IOSurfaceID — like in this example.

Establish inter-process communication

Create a mach port, framePortPort, that the sending process can send to and the receiving process can receive from. See my previous post.

Send the mach port

Create a CVPixelBuffer backed by an IOSurface.

CVPixelBufferRef frame = NULL; 
NSDictionary *pbAttr = [NSDictionary dictionaryWithObject:[NSDictionary dictionary]
                        forKey:kCVPixelBufferIOSurfacePropertiesKey]; 
CVPixelBufferCreate(NULL, width, height, pixelFormat, pbAttr, &frame); 

Put the image data you want to send into the CVPixelBuffer.

Send the mach port returned by IOSurfaceCreateMachPort through framePortPort.

mach_port_t framePort = IOSurfaceCreateMachPort(CVPixelBufferGetIOSurface(frame));     
if (send_port(framePortPort, framePort) != 0)
{
    // send failed
}

You can use the function send_port from this example, or CFMachPort or NSMachPort.

When finished, destroy the mach ports and release frame.

Receive the mach port

Receive framePort through framePortPort.

if (recv_port(framePortPort, &framePort) != 0)
{
    // receive failed
}
IOSurfaceRef surface = IOSurfaceLookupFromMachPort(framePort); 

You can use recv_port, or CFMachPort or NSMachPort.

Create another pixel buffer backed by the IOSurface.

CVPixelBufferRef frame = NULL; 
CVPixelBufferCreateWithIOSurface(NULL, surface, NULL, &frame); 

When finished, destroy the mach ports and release frame and surface. (Release an IOSurfaceRef with CFRelease.)


Jaymie Strecker is a software developer at Kosada, Inc. and one of the creators of Vuo.