node-mac-recorder 2.12.4 → 2.12.5
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/screen_capture_kit.mm +58 -15
package/package.json
CHANGED
|
@@ -9,6 +9,8 @@ static AVAssetWriter *g_assetWriter = nil;
|
|
|
9
9
|
static AVAssetWriterInput *g_videoWriterInput = nil;
|
|
10
10
|
static AVAssetWriterInput *g_audioWriterInput = nil;
|
|
11
11
|
static NSString *g_outputPath = nil;
|
|
12
|
+
static BOOL g_sessionStarted = NO;
|
|
13
|
+
static AVAssetWriterInputPixelBufferAdaptor *g_pixelBufferAdaptor = nil;
|
|
12
14
|
|
|
13
15
|
@interface ScreenCaptureKitRecorderDelegate : NSObject <SCStreamDelegate>
|
|
14
16
|
@property (nonatomic, copy) void (^completionHandler)(NSURL *outputURL, NSError *error);
|
|
@@ -36,25 +38,51 @@ static NSString *g_outputPath = nil;
|
|
|
36
38
|
|
|
37
39
|
@implementation ScreenCaptureKitStreamOutput
|
|
38
40
|
- (void)stream:(SCStream *)stream didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer ofType:(SCStreamOutputType)type {
|
|
39
|
-
if (!g_assetWriter
|
|
41
|
+
if (!g_assetWriter) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Start session on first sample
|
|
46
|
+
if (!g_sessionStarted && g_assetWriter.status == AVAssetWriterStatusWriting) {
|
|
47
|
+
CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
|
|
48
|
+
[g_assetWriter startSessionAtSourceTime:presentationTime];
|
|
49
|
+
g_sessionStarted = YES;
|
|
50
|
+
NSLog(@"📽️ ScreenCaptureKit video session started at time: %lld/%d", presentationTime.value, presentationTime.timescale);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (g_assetWriter.status != AVAssetWriterStatusWriting) {
|
|
40
54
|
return;
|
|
41
55
|
}
|
|
42
56
|
|
|
43
57
|
switch (type) {
|
|
44
58
|
case SCStreamOutputTypeScreen:
|
|
45
|
-
if (
|
|
46
|
-
|
|
59
|
+
if (g_pixelBufferAdaptor && g_pixelBufferAdaptor.assetWriterInput.isReadyForMoreMediaData) {
|
|
60
|
+
// Convert sample buffer to pixel buffer
|
|
61
|
+
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
|
62
|
+
if (pixelBuffer) {
|
|
63
|
+
CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
|
|
64
|
+
BOOL success = [g_pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:presentationTime];
|
|
65
|
+
if (!success) {
|
|
66
|
+
NSLog(@"❌ Failed to append pixel buffer: %@", g_assetWriter.error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
47
69
|
}
|
|
48
70
|
break;
|
|
49
71
|
case SCStreamOutputTypeAudio:
|
|
50
72
|
if (g_audioWriterInput && g_audioWriterInput.isReadyForMoreMediaData) {
|
|
51
|
-
[g_audioWriterInput appendSampleBuffer:sampleBuffer];
|
|
73
|
+
BOOL success = [g_audioWriterInput appendSampleBuffer:sampleBuffer];
|
|
74
|
+
if (!success) {
|
|
75
|
+
NSLog(@"❌ Failed to append audio sample: %@", g_assetWriter.error);
|
|
76
|
+
}
|
|
52
77
|
}
|
|
53
78
|
break;
|
|
54
79
|
case SCStreamOutputTypeMicrophone:
|
|
55
80
|
// Handle microphone input (if needed in future)
|
|
56
81
|
if (g_audioWriterInput && g_audioWriterInput.isReadyForMoreMediaData) {
|
|
57
|
-
[g_audioWriterInput appendSampleBuffer:sampleBuffer];
|
|
82
|
+
BOOL success = [g_audioWriterInput appendSampleBuffer:sampleBuffer];
|
|
83
|
+
if (!success) {
|
|
84
|
+
NSLog(@"❌ Failed to append microphone sample: %@", g_assetWriter.error);
|
|
85
|
+
}
|
|
58
86
|
}
|
|
59
87
|
break;
|
|
60
88
|
}
|
|
@@ -322,7 +350,9 @@ static NSString *g_outputPath = nil;
|
|
|
322
350
|
g_assetWriter = nil;
|
|
323
351
|
g_videoWriterInput = nil;
|
|
324
352
|
g_audioWriterInput = nil;
|
|
353
|
+
g_pixelBufferAdaptor = nil;
|
|
325
354
|
g_outputPath = nil;
|
|
355
|
+
g_sessionStarted = NO;
|
|
326
356
|
}];
|
|
327
357
|
}
|
|
328
358
|
|
|
@@ -344,25 +374,21 @@ static NSString *g_outputPath = nil;
|
|
|
344
374
|
outputPath:(NSString *)outputPath
|
|
345
375
|
includeAudio:(BOOL)includeAudio {
|
|
346
376
|
|
|
347
|
-
// Create asset writer
|
|
377
|
+
// Create asset writer with MP4 format for better compatibility
|
|
348
378
|
NSURL *outputURL = [NSURL fileURLWithPath:outputPath];
|
|
349
379
|
NSError *error = nil;
|
|
350
|
-
g_assetWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:
|
|
380
|
+
g_assetWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeMPEG4 error:&error];
|
|
351
381
|
|
|
352
382
|
if (error || !g_assetWriter) {
|
|
353
383
|
NSLog(@"❌ Failed to create asset writer: %@", error);
|
|
354
384
|
return NO;
|
|
355
385
|
}
|
|
356
386
|
|
|
357
|
-
// Video writer input
|
|
387
|
+
// Video writer input - basic settings for maximum compatibility
|
|
358
388
|
NSDictionary *videoSettings = @{
|
|
359
389
|
AVVideoCodecKey: AVVideoCodecTypeH264,
|
|
360
390
|
AVVideoWidthKey: @(width),
|
|
361
|
-
AVVideoHeightKey: @(height)
|
|
362
|
-
AVVideoCompressionPropertiesKey: @{
|
|
363
|
-
AVVideoAverageBitRateKey: @(width * height * 8), // 8 bits per pixel
|
|
364
|
-
AVVideoExpectedSourceFrameRateKey: @(60)
|
|
365
|
-
}
|
|
391
|
+
AVVideoHeightKey: @(height)
|
|
366
392
|
};
|
|
367
393
|
|
|
368
394
|
g_videoWriterInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
|
|
@@ -374,6 +400,23 @@ static NSString *g_outputPath = nil;
|
|
|
374
400
|
}
|
|
375
401
|
[g_assetWriter addInput:g_videoWriterInput];
|
|
376
402
|
|
|
403
|
+
// Create pixel buffer adaptor for ScreenCaptureKit compatibility
|
|
404
|
+
NSDictionary *pixelBufferAttributes = @{
|
|
405
|
+
(NSString *)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
|
|
406
|
+
(NSString *)kCVPixelBufferWidthKey: @(width),
|
|
407
|
+
(NSString *)kCVPixelBufferHeightKey: @(height),
|
|
408
|
+
(NSString *)kCVPixelBufferIOSurfacePropertiesKey: @{}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
g_pixelBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc]
|
|
412
|
+
initWithAssetWriterInput:g_videoWriterInput
|
|
413
|
+
sourcePixelBufferAttributes:pixelBufferAttributes];
|
|
414
|
+
|
|
415
|
+
if (!g_pixelBufferAdaptor) {
|
|
416
|
+
NSLog(@"❌ Cannot create pixel buffer adaptor");
|
|
417
|
+
return NO;
|
|
418
|
+
}
|
|
419
|
+
|
|
377
420
|
// Audio writer input (if needed)
|
|
378
421
|
if (includeAudio) {
|
|
379
422
|
NSDictionary *audioSettings = @{
|
|
@@ -391,13 +434,13 @@ static NSString *g_outputPath = nil;
|
|
|
391
434
|
}
|
|
392
435
|
}
|
|
393
436
|
|
|
394
|
-
// Start writing
|
|
437
|
+
// Start writing (session will be started when first sample arrives)
|
|
395
438
|
if (![g_assetWriter startWriting]) {
|
|
396
439
|
NSLog(@"❌ Failed to start writing: %@", g_assetWriter.error);
|
|
397
440
|
return NO;
|
|
398
441
|
}
|
|
399
442
|
|
|
400
|
-
|
|
443
|
+
g_sessionStarted = NO; // Reset session flag
|
|
401
444
|
NSLog(@"✅ ScreenCaptureKit video writer setup complete: %@", outputPath);
|
|
402
445
|
|
|
403
446
|
return YES;
|