Repository navigation
Expand file tree
/
Copy pathaddon.js
More file actions
121 lines (104 loc) · 3.54 KB
/
Copy pathaddon.js
File metadata and controls
121 lines (104 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
const addon = require("bindings")("addon.node");
const EventEmitter = require("events");
class Camera extends EventEmitter {
constructor() {
super(); // Call EventEmitter constructor
// Create native camera instance
this._nativeCamera = new addon.Camera();
// Bind async methods from native camera
this.enumerateDevices = this._nativeCamera.enumerateDevicesAsync.bind(
this._nativeCamera,
);
this.claimDevice = this._nativeCamera.claimDeviceAsync.bind(
this._nativeCamera,
);
this.releaseDevice = this._nativeCamera.releaseDeviceAsync.bind(
this._nativeCamera,
);
// Bind other native methods
this.getSupportedFormats = this._nativeCamera.getSupportedFormatsAsync.bind(
this._nativeCamera,
);
// Provide a normalized getCameraInfo that returns a single `formats` object
this.getCameraInfo = async () => {
const info = await this._nativeCamera.getCameraInfoAsync();
// If native already provides `formats`, return as-is
if (info && info.formats) return info;
const out = Object.assign({}, info);
try {
// Legacy shapes: supportedResolutionsBySubtype, supportedResolutions, resolutions
if (info && info.supportedResolutionsBySubtype) {
// If it's already grouped, map it to `formats` (keys kept)
out.formats = info.supportedResolutionsBySubtype;
return out;
}
const flat = info && (info.supportedResolutions || info.resolutions);
if (Array.isArray(flat)) {
const formats = {};
for (const r of flat) {
const subtype = r.subtype || "<unknown>";
const key = subtype;
if (!formats[key])
formats[key] = { subtype: subtype, resolutions: [] };
formats[key].resolutions.push({
width: r.width,
height: r.height,
frameRate: r.frameRate,
});
}
out.formats = formats;
}
} catch (e) {
// ignore and return original info
}
return out;
};
// Expose native subtype-aware format setter
this.setFormat = this._nativeCamera.setFormatAsync.bind(this._nativeCamera);
// Output format conversion: set target format for MF conversion, or null to disable
this.setOutputFormat = this._nativeCamera.setOutputFormatAsync.bind(
this._nativeCamera,
);
this.getDimensions = this._nativeCamera.getDimensions.bind(
this._nativeCamera,
);
this._isCapturing = false;
// Frame event emitter used by native code
this._frameEventEmitter = (frameData) => {
// Keep reference alive until event handlers run
this.emit("frame", frameData);
};
}
// Modern async startCapture method with events
async startCapture() {
if (this._isCapturing) {
throw new Error("Capture is already in progress");
}
this._isCapturing = true;
try {
// Pass the frame event emitter to the native method
const result = await this._nativeCamera.startCaptureAsync(
this._frameEventEmitter,
);
return result;
} catch (error) {
this._isCapturing = false;
throw error;
}
}
// Override stopCapture to update internal state
async stopCapture() {
this._isCapturing = false;
try {
const result = await this._nativeCamera.stopCaptureAsync();
return result;
} catch (error) {
throw error;
}
}
// Helper method to check if capturing
isCapturing() {
return this._isCapturing;
}
}
module.exports = Camera;