node-mac-recorder 2.16.13 โ 2.16.15
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"permissions": {
|
|
3
3
|
"allow": [
|
|
4
|
-
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing
|
|
4
|
+
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing area recording with scaling...'');\nconst MacRecorder = require(''./index.js'');\nconst recorder = new MacRecorder();\n\nconst options = {\n captureArea: {\n x: 200,\n y: 200, \n width: 800,\n height: 600\n }\n};\n\nrecorder.startRecording(''/tmp/area-scaling-test.mov'', options)\n .then(success => {\n console.log(''Area recording:'', success ? ''โ
SUCCESS'' : ''โ FAILED'');\n if (success) {\n setTimeout(() => {\n recorder.stopRecording().then(() => {\n console.log(''โ
Area scaling test complete'');\n const fs = require(''fs'');\n if (fs.existsSync(''/tmp/area-scaling-test.mov'')) {\n const size = Math.round(fs.statSync(''/tmp/area-scaling-test.mov'').size/1024);\n console.log(''๐น File size:'', size + ''KB'');\n }\n });\n }, 2000);\n }\n })\n .catch(console.error);\n\")"
|
|
5
5
|
],
|
|
6
6
|
"deny": [],
|
|
7
7
|
"ask": []
|
package/package.json
CHANGED
|
@@ -53,9 +53,33 @@ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
|
|
|
53
53
|
return false;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
// Get display dimensions
|
|
56
|
+
// Get display dimensions with proper scaling for macOS 14/13 compatibility
|
|
57
57
|
CGRect displayBounds = CGDisplayBounds(displayID);
|
|
58
|
-
|
|
58
|
+
|
|
59
|
+
// Get both logical (bounds) and physical (pixels) dimensions
|
|
60
|
+
CGSize logicalSize = displayBounds.size;
|
|
61
|
+
CGSize physicalSize = CGSizeMake(CGDisplayPixelsWide(displayID), CGDisplayPixelsHigh(displayID));
|
|
62
|
+
|
|
63
|
+
// Calculate scale factor
|
|
64
|
+
CGFloat scaleX = physicalSize.width / logicalSize.width;
|
|
65
|
+
CGFloat scaleY = physicalSize.height / logicalSize.height;
|
|
66
|
+
CGFloat scaleFactor = MAX(scaleX, scaleY); // Use max to handle non-uniform scaling
|
|
67
|
+
|
|
68
|
+
// For AVFoundation, use logical size (what CGDisplayCreateImage actually captures)
|
|
69
|
+
CGSize recordingSize = captureRect.size.width > 0 ? captureRect.size : logicalSize;
|
|
70
|
+
|
|
71
|
+
NSLog(@"๐ฅ๏ธ Display bounds (logical): %.0fx%.0f", logicalSize.width, logicalSize.height);
|
|
72
|
+
NSLog(@"๐ฅ๏ธ Display pixels (physical): %.0fx%.0f", physicalSize.width, physicalSize.height);
|
|
73
|
+
|
|
74
|
+
if (scaleFactor > 1.5) {
|
|
75
|
+
NSLog(@"๐ Scale factor: %.1fx โ Retina display detected (macOS 14/13 scaling fix applied)", scaleFactor);
|
|
76
|
+
} else if (scaleFactor > 1.1) {
|
|
77
|
+
NSLog(@"๐ Scale factor: %.1fx โ Non-standard scaling detected", scaleFactor);
|
|
78
|
+
} else {
|
|
79
|
+
NSLog(@"๐ Scale factor: %.1fx โ Standard display", scaleFactor);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
NSLog(@"๐ฏ Recording size: %.0fx%.0f (using logical dimensions for AVFoundation)", recordingSize.width, recordingSize.height);
|
|
59
83
|
|
|
60
84
|
// Video settings with macOS compatibility
|
|
61
85
|
NSString *codecKey;
|
|
@@ -118,9 +142,20 @@ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
|
|
|
118
142
|
g_avStartTime = CMTimeMakeWithSeconds(CACurrentMediaTime(), 600);
|
|
119
143
|
[g_avWriter startSessionAtSourceTime:g_avStartTime];
|
|
120
144
|
|
|
121
|
-
// Store recording parameters
|
|
145
|
+
// Store recording parameters with scaling correction
|
|
122
146
|
g_avDisplayID = displayID;
|
|
123
|
-
|
|
147
|
+
|
|
148
|
+
// Apply scaling to capture rect if provided (for macOS 14/13 compatibility)
|
|
149
|
+
if (!CGRectIsEmpty(captureRect)) {
|
|
150
|
+
// Note: captureRect comes in logical coordinates, keep as-is for CGDisplayCreateImage
|
|
151
|
+
g_avCaptureRect = captureRect;
|
|
152
|
+
NSLog(@"๐ฒ Capture area (logical): %.0f,%.0f %.0fx%.0f",
|
|
153
|
+
captureRect.origin.x, captureRect.origin.y, captureRect.size.width, captureRect.size.height);
|
|
154
|
+
} else {
|
|
155
|
+
g_avCaptureRect = CGRectZero; // Full screen
|
|
156
|
+
NSLog(@"๐ฅ๏ธ Full screen capture (logical bounds)");
|
|
157
|
+
}
|
|
158
|
+
|
|
124
159
|
g_avFrameNumber = 0;
|
|
125
160
|
|
|
126
161
|
// Start capture timer (10 FPS for Electron compatibility)
|
|
@@ -173,6 +208,16 @@ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
|
|
|
173
208
|
CVReturn cvRet = CVPixelBufferPoolCreatePixelBuffer(NULL, localPixelBufferAdaptor.pixelBufferPool, &pixelBuffer);
|
|
174
209
|
|
|
175
210
|
if (cvRet == kCVReturnSuccess && pixelBuffer) {
|
|
211
|
+
// Check pixel buffer dimensions match screen image
|
|
212
|
+
size_t bufferWidth = CVPixelBufferGetWidth(pixelBuffer);
|
|
213
|
+
size_t bufferHeight = CVPixelBufferGetHeight(pixelBuffer);
|
|
214
|
+
size_t imageWidth = CGImageGetWidth(screenImage);
|
|
215
|
+
size_t imageHeight = CGImageGetHeight(screenImage);
|
|
216
|
+
|
|
217
|
+
if (bufferWidth != imageWidth || bufferHeight != imageHeight) {
|
|
218
|
+
NSLog(@"โ ๏ธ Size mismatch! Buffer %zux%zu vs Image %zux%zu", bufferWidth, bufferHeight, imageWidth, imageHeight);
|
|
219
|
+
}
|
|
220
|
+
|
|
176
221
|
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
|
|
177
222
|
|
|
178
223
|
void *pixelData = CVPixelBufferGetBaseAddress(pixelBuffer);
|
package/src/window_selector.mm
CHANGED
|
@@ -875,25 +875,32 @@ void updateOverlay() {
|
|
|
875
875
|
}
|
|
876
876
|
|
|
877
877
|
// Determine if this is a primary display window
|
|
878
|
-
|
|
878
|
+
NSArray *allScreens = [NSScreen screens];
|
|
879
|
+
NSScreen *primaryScreen = [allScreens objectAtIndex:0]; // Primary screen
|
|
880
|
+
NSRect primaryFrame = [primaryScreen frame];
|
|
881
|
+
BOOL isPrimaryDisplayWindow = (x >= primaryFrame.origin.x &&
|
|
882
|
+
x <= primaryFrame.origin.x + primaryFrame.size.width &&
|
|
883
|
+
y >= primaryFrame.origin.y &&
|
|
884
|
+
y <= primaryFrame.origin.y + primaryFrame.size.height);
|
|
879
885
|
|
|
880
886
|
CGFloat localX, localY;
|
|
881
887
|
if (isPrimaryDisplayWindow) {
|
|
882
|
-
// Primary display windows:
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
888
|
+
// Primary display windows: Calculate dynamic offset from combined frame
|
|
889
|
+
NSRect combinedFrame = [g_overlayWindow frame];
|
|
890
|
+
|
|
891
|
+
// Calculate primary screen offset within combined frame
|
|
892
|
+
CGFloat primaryOffsetX = primaryFrame.origin.x - combinedFrame.origin.x;
|
|
893
|
+
CGFloat primaryOffsetY = primaryFrame.origin.y - combinedFrame.origin.y;
|
|
894
|
+
|
|
895
|
+
localX = x + primaryOffsetX;
|
|
896
|
+
localY = ([g_overlayView frame].size.height - (y + primaryOffsetY)) - height;
|
|
897
|
+
|
|
886
898
|
} else {
|
|
887
899
|
// Secondary display windows: Apply standard coordinate transformation
|
|
888
900
|
localX = x - globalOffset.x;
|
|
889
901
|
localY = ([g_overlayView frame].size.height - (y - globalOffset.y)) - height;
|
|
890
902
|
}
|
|
891
903
|
|
|
892
|
-
NSLog(@"๐ง COORDINATE DEBUG: Window (%d, %d) %dx%d [%@]", (int)x, (int)y, (int)width, (int)height, isPrimaryDisplayWindow ? @"PRIMARY" : @"SECONDARY");
|
|
893
|
-
NSLog(@" GlobalOffset: (%.0f, %.0f)", globalOffset.x, globalOffset.y);
|
|
894
|
-
NSLog(@" LocalCoords: (%.0f, %.0f)", localX, localY);
|
|
895
|
-
NSLog(@" ViewFrame: %.0fx%.0f", [g_overlayView frame].size.width, [g_overlayView frame].size.height);
|
|
896
|
-
|
|
897
904
|
// Update overlay view window info for highlighting
|
|
898
905
|
[overlayView setWindowInfo:targetWindow];
|
|
899
906
|
[overlayView setHighlightFrame:NSMakeRect(localX, localY, width, height)];
|