node-mac-recorder 2.13.2 → 2.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/mac_recorder.mm +3 -3
- package/src/screen_capture_kit.mm +63 -23
package/package.json
CHANGED
package/src/mac_recorder.mm
CHANGED
|
@@ -168,9 +168,9 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
@try {
|
|
171
|
-
//
|
|
172
|
-
NSLog(@"🔍
|
|
173
|
-
if (
|
|
171
|
+
// Phase 4: Pure ScreenCaptureKit with memory-optimized implementation
|
|
172
|
+
NSLog(@"🔍 Phase 4: Pure ScreenCaptureKit with Electron-safe memory optimization");
|
|
173
|
+
if (@available(macOS 12.3, *)) {
|
|
174
174
|
NSLog(@"✅ macOS 12.3+ detected - ScreenCaptureKit should be available");
|
|
175
175
|
if ([ScreenCaptureKitRecorder isScreenCaptureKitAvailable]) {
|
|
176
176
|
NSLog(@"✅ ScreenCaptureKit availability check passed");
|
|
@@ -26,11 +26,13 @@ static BOOL g_writerStarted = NO;
|
|
|
26
26
|
if (error) {
|
|
27
27
|
NSLog(@"❌ Stream stopped with error: %@", error);
|
|
28
28
|
} else {
|
|
29
|
-
NSLog(@"✅ ScreenCaptureKit stream stopped successfully");
|
|
29
|
+
NSLog(@"✅ ScreenCaptureKit stream stopped successfully in delegate");
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// Finalize video writer
|
|
33
|
+
NSLog(@"🎬 Delegate calling finalizeVideoWriter...");
|
|
33
34
|
[ScreenCaptureKitRecorder finalizeVideoWriter];
|
|
35
|
+
NSLog(@"🎬 Delegate finished calling finalizeVideoWriter");
|
|
34
36
|
}
|
|
35
37
|
@end
|
|
36
38
|
|
|
@@ -55,18 +57,45 @@ static BOOL g_writerStarted = NO;
|
|
|
55
57
|
NSLog(@"✅ Electron-safe video writer started");
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
// Ultra-conservative Electron-safe sample buffer processing
|
|
61
|
+
@autoreleasepool {
|
|
62
|
+
if (!g_writerStarted || !g_assetWriterInput || !g_pixelBufferAdaptor) {
|
|
63
|
+
return; // Skip if not ready
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Rate limiting for Electron stability
|
|
67
|
+
static NSTimeInterval lastProcessTime = 0;
|
|
68
|
+
NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
|
|
69
|
+
if (currentTime - lastProcessTime < 0.1) { // Max 10 FPS for stability
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
lastProcessTime = currentTime;
|
|
73
|
+
|
|
74
|
+
if (g_assetWriterInput.isReadyForMoreMediaData) {
|
|
75
|
+
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
|
64
76
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
if (pixelBuffer && g_pixelBufferAdaptor) {
|
|
78
|
+
// Ultra-conservative validation
|
|
79
|
+
size_t width = CVPixelBufferGetWidth(pixelBuffer);
|
|
80
|
+
size_t height = CVPixelBufferGetHeight(pixelBuffer);
|
|
81
|
+
|
|
82
|
+
if (width == 1280 && height == 720) { // Exact match only
|
|
83
|
+
CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
|
|
84
|
+
CMTime relativeTime = CMTimeSubtract(presentationTime, g_startTime);
|
|
85
|
+
|
|
86
|
+
// Conservative time validation
|
|
87
|
+
if (CMTimeGetSeconds(relativeTime) >= 0 && CMTimeGetSeconds(relativeTime) < 30) {
|
|
88
|
+
BOOL success = [g_pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:relativeTime];
|
|
89
|
+
if (success) {
|
|
90
|
+
g_currentTime = relativeTime;
|
|
91
|
+
static int safeFrameCount = 0;
|
|
92
|
+
safeFrameCount++;
|
|
93
|
+
if (safeFrameCount % 10 == 0) {
|
|
94
|
+
NSLog(@"✅ Electron-safe: %d frames", safeFrameCount);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
70
99
|
}
|
|
71
100
|
}
|
|
72
101
|
}
|
|
@@ -108,12 +137,14 @@ static BOOL g_writerStarted = NO;
|
|
|
108
137
|
// Simple content filter - no exclusions for now
|
|
109
138
|
SCContentFilter *filter = [[SCContentFilter alloc] initWithDisplay:targetDisplay excludingWindows:@[]];
|
|
110
139
|
|
|
111
|
-
//
|
|
140
|
+
// Electron-optimized stream configuration (lower resource usage)
|
|
112
141
|
SCStreamConfiguration *streamConfig = [[SCStreamConfiguration alloc] init];
|
|
113
142
|
streamConfig.width = 1280;
|
|
114
143
|
streamConfig.height = 720;
|
|
115
|
-
streamConfig.minimumFrameInterval = CMTimeMake(1,
|
|
144
|
+
streamConfig.minimumFrameInterval = CMTimeMake(1, 10); // 10 FPS for stability
|
|
116
145
|
streamConfig.pixelFormat = kCVPixelFormatType_32BGRA;
|
|
146
|
+
streamConfig.capturesAudio = NO; // Disable audio for simplicity
|
|
147
|
+
streamConfig.excludesCurrentProcessAudio = YES;
|
|
117
148
|
|
|
118
149
|
// Create Electron-safe delegates
|
|
119
150
|
g_streamDelegate = [[ElectronSafeDelegate alloc] init];
|
|
@@ -153,7 +184,11 @@ static BOOL g_writerStarted = NO;
|
|
|
153
184
|
} else {
|
|
154
185
|
NSLog(@"✅ ScreenCaptureKit stream stopped in completion handler");
|
|
155
186
|
}
|
|
156
|
-
|
|
187
|
+
|
|
188
|
+
// Finalize video since delegate might not be called
|
|
189
|
+
NSLog(@"🎬 Completion handler calling finalizeVideoWriter...");
|
|
190
|
+
[ScreenCaptureKitRecorder finalizeVideoWriter];
|
|
191
|
+
NSLog(@"🎬 Completion handler finished calling finalizeVideoWriter");
|
|
157
192
|
}];
|
|
158
193
|
}
|
|
159
194
|
|
|
@@ -178,19 +213,20 @@ static BOOL g_writerStarted = NO;
|
|
|
178
213
|
return;
|
|
179
214
|
}
|
|
180
215
|
|
|
181
|
-
//
|
|
216
|
+
// Ultra-conservative Electron video settings
|
|
182
217
|
NSDictionary *videoSettings = @{
|
|
183
218
|
AVVideoCodecKey: AVVideoCodecTypeH264,
|
|
184
219
|
AVVideoWidthKey: @1280,
|
|
185
220
|
AVVideoHeightKey: @720,
|
|
186
221
|
AVVideoCompressionPropertiesKey: @{
|
|
187
|
-
AVVideoAverageBitRateKey: @(1280 * 720 *
|
|
188
|
-
AVVideoMaxKeyFrameIntervalKey: @
|
|
222
|
+
AVVideoAverageBitRateKey: @(1280 * 720 * 1), // Lower bitrate
|
|
223
|
+
AVVideoMaxKeyFrameIntervalKey: @10,
|
|
224
|
+
AVVideoProfileLevelKey: AVVideoProfileLevelH264BaselineAutoLevel
|
|
189
225
|
}
|
|
190
226
|
};
|
|
191
227
|
|
|
192
228
|
g_assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
|
|
193
|
-
g_assetWriterInput.expectsMediaDataInRealTime =
|
|
229
|
+
g_assetWriterInput.expectsMediaDataInRealTime = NO; // Safer for Electron
|
|
194
230
|
|
|
195
231
|
// Pixel buffer attributes matching ScreenCaptureKit format
|
|
196
232
|
NSDictionary *pixelBufferAttributes = @{
|
|
@@ -210,25 +246,29 @@ static BOOL g_writerStarted = NO;
|
|
|
210
246
|
}
|
|
211
247
|
|
|
212
248
|
+ (void)finalizeVideoWriter {
|
|
213
|
-
NSLog(@"🎬 Finalizing
|
|
249
|
+
NSLog(@"🎬 Finalizing video writer - writer: %p, started: %d", g_assetWriter, g_writerStarted);
|
|
214
250
|
|
|
215
251
|
if (!g_assetWriter || !g_writerStarted) {
|
|
216
|
-
NSLog(@"⚠️ Video writer not started,
|
|
252
|
+
NSLog(@"⚠️ Video writer not started properly - writer: %p, started: %d", g_assetWriter, g_writerStarted);
|
|
217
253
|
[ScreenCaptureKitRecorder cleanupVideoWriter];
|
|
218
254
|
return;
|
|
219
255
|
}
|
|
220
256
|
|
|
257
|
+
NSLog(@"🎬 Marking input as finished and finalizing...");
|
|
221
258
|
[g_assetWriterInput markAsFinished];
|
|
222
259
|
|
|
223
260
|
[g_assetWriter finishWritingWithCompletionHandler:^{
|
|
261
|
+
NSLog(@"🎬 Finalization completion handler called");
|
|
224
262
|
if (g_assetWriter.status == AVAssetWriterStatusCompleted) {
|
|
225
|
-
NSLog(@"✅
|
|
263
|
+
NSLog(@"✅ Video finalization successful: %@", g_outputPath);
|
|
226
264
|
} else {
|
|
227
|
-
NSLog(@"❌ Video
|
|
265
|
+
NSLog(@"❌ Video finalization failed - status: %ld, error: %@", (long)g_assetWriter.status, g_assetWriter.error);
|
|
228
266
|
}
|
|
229
267
|
|
|
230
268
|
[ScreenCaptureKitRecorder cleanupVideoWriter];
|
|
231
269
|
}];
|
|
270
|
+
|
|
271
|
+
NSLog(@"🎬 Finalization request submitted, waiting for completion...");
|
|
232
272
|
}
|
|
233
273
|
|
|
234
274
|
+ (void)cleanupVideoWriter {
|