mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-08-24 10:14:13 -05:00
mac-virtualcam: Fix memory access issues for shared IOSurfaces
The DAL plugin-based virtualcamera shares data between OBS and the
plugin using an IOSurface. IOSurface locks are necessary to ensure
race conditions between data generation (OBS side) and consumption
(virtual camera side) and also that an IOSurface is not offloaded to
GPU memory when it is indeed needed in CPU memory.
Also moves the invalidation of the NSMachPort for the frames to after
the IOSurface data has been converted into a pixelbuffer and added to
the frame queue of the virtual camera, as an early invalidation will
cut off access to the pixel data shared with the DAL plugin.
(cherry picked from commit 447adfbe38)
This commit is contained in:
@@ -93,6 +93,8 @@
|
||||
|
||||
- (void)handlePortMessage:(NSPortMessage *)message
|
||||
{
|
||||
__strong id<MachClientDelegate> strongDelegate = self.delegate;
|
||||
|
||||
VLogFunc(@"");
|
||||
NSArray *components = message.components;
|
||||
switch (message.msgid) {
|
||||
@@ -113,57 +115,60 @@
|
||||
|
||||
IOSurfaceRef surface = IOSurfaceLookupFromMachPort(
|
||||
[framePort machPort]);
|
||||
|
||||
if (surface) {
|
||||
/*
|
||||
* IOSurfaceLocks are only necessary on non Apple Silicon devices, as those have
|
||||
* unified memory. On Intel machines, the lock ensures that the IOSurface is copied back
|
||||
* from GPU memory to CPU memory so we can process the pixel buffer.
|
||||
*/
|
||||
#ifndef __aarch64__
|
||||
IOSurfaceLock(surface, kIOSurfaceLockReadOnly,
|
||||
NULL);
|
||||
#endif
|
||||
CVPixelBufferRef frame;
|
||||
CVPixelBufferCreateWithIOSurface(
|
||||
kCFAllocatorDefault, surface, NULL,
|
||||
&frame);
|
||||
#ifndef __aarch64__
|
||||
IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly,
|
||||
NULL);
|
||||
#endif
|
||||
CFRelease(surface);
|
||||
|
||||
uint64_t timestamp;
|
||||
[components[1] getBytes:×tamp
|
||||
length:sizeof(timestamp)];
|
||||
|
||||
VLog(@"Received frame data: %zux%zu (%llu)",
|
||||
CVPixelBufferGetWidth(frame),
|
||||
CVPixelBufferGetHeight(frame), timestamp);
|
||||
|
||||
uint32_t fpsNumerator;
|
||||
[components[2] getBytes:&fpsNumerator
|
||||
length:sizeof(fpsNumerator)];
|
||||
uint32_t fpsDenominator;
|
||||
[components[3] getBytes:&fpsDenominator
|
||||
length:sizeof(fpsDenominator)];
|
||||
|
||||
[strongDelegate
|
||||
receivedPixelBuffer:frame
|
||||
timestamp:timestamp
|
||||
fpsNumerator:fpsNumerator
|
||||
fpsDenominator:fpsDenominator];
|
||||
|
||||
CVPixelBufferRelease(frame);
|
||||
} else {
|
||||
ELog(@"Failed to obtain IOSurface from Mach port");
|
||||
}
|
||||
[framePort invalidate];
|
||||
mach_port_deallocate(mach_task_self(),
|
||||
[framePort machPort]);
|
||||
|
||||
if (!surface) {
|
||||
ELog(@"Failed to obtain IOSurface from Mach port");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* IOSurfaceLocks are only necessary on non Apple Silicon devices, as those have
|
||||
* unified memory. On Intel machines, the lock ensures that the IOSurface is copied back
|
||||
* from GPU memory to CPU memory so we can process the pixel buffer.
|
||||
*/
|
||||
#ifndef __aarch64__
|
||||
IOSurfaceLock(surface, kIOSurfaceLockReadOnly, NULL);
|
||||
#endif
|
||||
CVPixelBufferRef frame;
|
||||
CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault,
|
||||
surface, NULL, &frame);
|
||||
#ifndef __aarch64__
|
||||
IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, NULL);
|
||||
#endif
|
||||
CFRelease(surface);
|
||||
|
||||
uint64_t timestamp;
|
||||
[components[1] getBytes:×tamp
|
||||
length:sizeof(timestamp)];
|
||||
|
||||
VLog(@"Received frame data: %zux%zu (%llu)",
|
||||
CVPixelBufferGetWidth(frame),
|
||||
CVPixelBufferGetHeight(frame), timestamp);
|
||||
|
||||
uint32_t fpsNumerator;
|
||||
[components[2] getBytes:&fpsNumerator
|
||||
length:sizeof(fpsNumerator)];
|
||||
uint32_t fpsDenominator;
|
||||
[components[3] getBytes:&fpsDenominator
|
||||
length:sizeof(fpsDenominator)];
|
||||
|
||||
[self.delegate receivedPixelBuffer:frame
|
||||
timestamp:timestamp
|
||||
fpsNumerator:fpsNumerator
|
||||
fpsDenominator:fpsDenominator];
|
||||
|
||||
CVPixelBufferRelease(frame);
|
||||
}
|
||||
break;
|
||||
case MachMsgIdStop:
|
||||
DLog(@"Received stop message");
|
||||
[self.delegate receivedStop];
|
||||
[strongDelegate receivedStop];
|
||||
break;
|
||||
default:
|
||||
ELog(@"Received unexpected response msgid %u",
|
||||
|
||||
@@ -148,6 +148,9 @@
|
||||
length:sizeof(fpsDenominator)];
|
||||
|
||||
IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame);
|
||||
#ifndef __aarch64__
|
||||
IOSurfaceLock(surface, 0, NULL);
|
||||
#endif
|
||||
|
||||
if (!surface) {
|
||||
blog(LOG_ERROR,
|
||||
@@ -174,6 +177,10 @@
|
||||
]];
|
||||
|
||||
mach_port_deallocate(mach_task_self(), framePort);
|
||||
|
||||
#ifndef __aarch64__
|
||||
IOSurfaceUnlock(surface, 0, NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user