diff --git a/electron/native/ScreenCaptureKitRecorder.swift b/electron/native/ScreenCaptureKitRecorder.swift index 0d039dfb..29253a75 100644 --- a/electron/native/ScreenCaptureKitRecorder.swift +++ b/electron/native/ScreenCaptureKitRecorder.swift @@ -94,7 +94,9 @@ final class ScreenCaptureRecorder: NSObject, SCStreamOutput, SCStreamDelegate { let requestedFPS = max(targetCaptureFPS, config.fps ?? targetCaptureFPS) streamConfig.minimumFrameInterval = CMTime(value: 1, timescale: CMTimeScale(requestedFPS)) streamConfig.queueDepth = 6 - streamConfig.pixelFormat = kCVPixelFormatType_32BGRA + streamConfig.pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange + streamConfig.colorSpaceName = CGColorSpace.sRGB + streamConfig.colorMatrix = CGDisplayStream.yCbCrMatrix_ITU_R_709_2 streamConfig.showsCursor = false streamConfig.capturesAudio = capturesSystemAudio || capturesMicrophone streamConfig.sampleRate = 48000 @@ -168,11 +170,14 @@ final class ScreenCaptureRecorder: NSObject, SCStreamOutput, SCStreamDelegate { throw NSError(domain: "RecordlyCapture", code: 5, userInfo: [NSLocalizedDescriptionKey: "Unable to create output settings assistant"]) } - assistant.sourceVideoFormat = try CMVideoFormatDescription( - videoCodecType: .h264, + let sourceVideoFormat = try CMVideoFormatDescription( + videoCodecType: CMFormatDescription.MediaSubType( + rawValue: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange + ), width: outputWidth, height: outputHeight ) + assistant.sourceVideoFormat = sourceVideoFormat guard var outputSettings = assistant.videoSettings else { throw NSError(domain: "RecordlyCapture", code: 6, userInfo: [NSLocalizedDescriptionKey: "Output settings unavailable"]) @@ -186,7 +191,11 @@ final class ScreenCaptureRecorder: NSObject, SCStreamOutput, SCStreamDelegate { AVVideoYCbCrMatrixKey: AVVideoYCbCrMatrix_ITU_R_709_2, ] - let videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: outputSettings) + let videoInput = AVAssetWriterInput( + mediaType: .video, + outputSettings: outputSettings, + sourceFormatHint: sourceVideoFormat + ) videoInput.expectsMediaDataInRealTime = true guard let assetWriter = assetWriter, assetWriter.canAdd(videoInput) else { diff --git a/electron/native/ScreenCaptureKitRecorder.test.ts b/electron/native/ScreenCaptureKitRecorder.test.ts index b2de7e59..0956bf6f 100644 --- a/electron/native/ScreenCaptureKitRecorder.test.ts +++ b/electron/native/ScreenCaptureKitRecorder.test.ts @@ -42,6 +42,21 @@ describe("ScreenCaptureKitRecorder resume timing", () => { }); describe("ScreenCaptureKitRecorder colour metadata", () => { + it("asks ScreenCaptureKit for BT.709-compatible video-range frames", () => { + expect(recorderSource).toContain( + "streamConfig.pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange", + ); + expect(recorderSource).toContain("streamConfig.colorSpaceName = CGColorSpace.sRGB"); + expect(recorderSource).toContain( + "streamConfig.colorMatrix = CGDisplayStream.yCbCrMatrix_ITU_R_709_2", + ); + expect(recorderSource).toContain( + "rawValue: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange", + ); + expect(recorderSource).toContain("sourceFormatHint: sourceVideoFormat"); + expect(recorderSource).not.toContain("videoCodecType: .h264"); + }); + it("tags recordings as BT.709", () => { expect(recorderSource).toContain("AVVideoColorPropertiesKey"); expect(recorderSource).toContain("AVVideoColorPrimaries_ITU_R_709_2"); diff --git a/electron/native/bin/darwin-arm64/recordly-screencapturekit-helper b/electron/native/bin/darwin-arm64/recordly-screencapturekit-helper index f5dd25b4..233cfd17 100755 Binary files a/electron/native/bin/darwin-arm64/recordly-screencapturekit-helper and b/electron/native/bin/darwin-arm64/recordly-screencapturekit-helper differ diff --git a/electron/native/bin/darwin-x64/recordly-screencapturekit-helper b/electron/native/bin/darwin-x64/recordly-screencapturekit-helper index 7349cdef..8982873f 100755 Binary files a/electron/native/bin/darwin-x64/recordly-screencapturekit-helper and b/electron/native/bin/darwin-x64/recordly-screencapturekit-helper differ