Browse Source

mac-virtualcam: Fix incorrect PTS on Apple Silicon

The `fillFrame` method of the mac-virtualcam plugin is creating samples
directly using the value from `mach_absolute_time()` as `hostTime`.
This assumes this value is in nanoseconds, while it is in fact in mach
tick units. On Intel Macs mach tick units will be exactly 1 nanosecond
resulting in valid values, but on Apple Silicon macs this is no longer
the case.

This results in sample buffers with the placeholder image that have
much lower presentation time stamps than the samples containing content
produced by OBS. In previews/live streams this shows due to the last
content sample being shown frozen until the whole buffer is filled with
samples containing the placeholder image. Applications recording the
video stream are even more confused and crash or record videos with
wildly incorrect lengths.

In this PR `clock_gettime_nsec_np` is used to convert from mach tick units
to nanoseconds. This will make sure the `hostTime` value is correct on
both Apple Silicon and Intel macs. Making sure we produce stable
presentation time stamps from the virtual camera plugin at all times.
Mathijs Kadijk 2 years ago
parent
commit
ecaa5466cb

+ 1 - 1
plugins/mac-virtualcam/src/dal-plugin/CMSampleBufferUtils.mm

@@ -13,7 +13,7 @@ CMSampleTimingInfo CMSampleTimingInfoForTimestamp(uint64_t timestampNanos,
 {
 	// The timing here is quite important. For frames to be delivered correctly and successfully be recorded by apps
 	// like QuickTime Player, we need to be accurate in both our timestamps _and_ have a sensible scale. Using large
-	// timestamps and scales like mach_absolute_time() and NSEC_PER_SEC will work for display, but will error out
+	// timestamps and scales like clock_gettime_nsec_np() and NSEC_PER_SEC will work for display, but will error out
 	// when trying to record.
 	//
 	// 600 is a common default in Apple's docs https://developer.apple.com/documentation/avfoundation/avmutablemovie/1390622-timescale

+ 4 - 4
plugins/mac-virtualcam/src/dal-plugin/OBSDALStream.mm

@@ -316,7 +316,7 @@
 	CVPixelBufferRef pixelBuffer =
 		[self createPixelBufferWithTestAnimation];
 
-	uint64_t hostTime = mach_absolute_time();
+	uint64_t hostTime = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
 	CMSampleTimingInfo timingInfo =
 		CMSampleTimingInfoForTimestamp(hostTime, (uint32_t)self.fps, 1);
 
@@ -365,9 +365,9 @@
 	CMSampleTimingInfo timingInfo = CMSampleTimingInfoForTimestamp(
 		timestamp, fpsNumerator, fpsDenominator);
 
-	err = CMIOStreamClockPostTimingEvent(timingInfo.presentationTimeStamp,
-					     mach_absolute_time(), true,
-					     self.clock);
+	err = CMIOStreamClockPostTimingEvent(
+		timingInfo.presentationTimeStamp,
+		clock_gettime_nsec_np(CLOCK_UPTIME_RAW), true, self.clock);
 	if (err != noErr) {
 		DLog(@"CMIOStreamClockPostTimingEvent err %d", err);
 	}