@camstack/addon-pipeline 0.1.0 → 0.1.1
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/dist/{addon-CwDFZWAb.d.cts → addon-DK7eQ0PN.d.cts} +3 -4
- package/dist/{addon-CwDFZWAb.d.ts → addon-DK7eQ0PN.d.ts} +3 -4
- package/dist/addon.cjs +29 -73
- package/dist/addon.cjs.map +1 -1
- package/dist/addon.d.cts +1 -1
- package/dist/addon.d.ts +1 -1
- package/dist/addon.js +28 -72
- package/dist/addon.js.map +1 -1
- package/dist/index.cjs +31 -3305
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -921
- package/dist/index.d.ts +4 -921
- package/dist/index.js +29 -3271
- package/dist/index.js.map +1 -1
- package/package.json +35 -17
|
@@ -173,6 +173,8 @@ interface RecordingCoordinatorConfig {
|
|
|
173
173
|
readonly storagePath: string;
|
|
174
174
|
readonly globalFfmpegConfig: Partial<FfmpegConfig>;
|
|
175
175
|
readonly detectedFfmpegConfig: Partial<FfmpegConfig>;
|
|
176
|
+
/** Global segment duration from system settings (recording.segmentDurationSeconds). */
|
|
177
|
+
readonly segmentDurationSec?: number;
|
|
176
178
|
}
|
|
177
179
|
declare class RecordingCoordinator$1 {
|
|
178
180
|
private readonly db;
|
|
@@ -185,6 +187,7 @@ declare class RecordingCoordinator$1 {
|
|
|
185
187
|
private readonly storagePath;
|
|
186
188
|
private readonly globalFfmpegConfig;
|
|
187
189
|
private readonly detectedFfmpegConfig;
|
|
190
|
+
private readonly segmentDurationSec;
|
|
188
191
|
private readonly recordings;
|
|
189
192
|
private policyTimer;
|
|
190
193
|
private readonly retentionManager;
|
|
@@ -219,8 +222,6 @@ declare class PipelineAddon implements ICamstackAddon, IConfigurable {
|
|
|
219
222
|
private sqliteDb;
|
|
220
223
|
private recordingDeps;
|
|
221
224
|
private currentRecordingConfig;
|
|
222
|
-
private analysisPipeline;
|
|
223
|
-
private analysisLogger;
|
|
224
225
|
private persistenceFacade;
|
|
225
226
|
setRecordingDependencies(deps: RecordingEngineDependencies): void;
|
|
226
227
|
initialize(context: AddonContext): Promise<void>;
|
|
@@ -228,8 +229,6 @@ declare class PipelineAddon implements ICamstackAddon, IConfigurable {
|
|
|
228
229
|
getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
|
|
229
230
|
getCoordinator(): RecordingCoordinator;
|
|
230
231
|
getRecordingDb(): RecordingDb;
|
|
231
|
-
/** Whether the analysis pipeline package loaded successfully */
|
|
232
|
-
isAnalysisAvailable(): boolean;
|
|
233
232
|
getConfigSchema(): ConfigUISchema;
|
|
234
233
|
getConfig(): Record<string, unknown>;
|
|
235
234
|
onConfigChange(config: Record<string, unknown>): Promise<void>;
|
|
@@ -173,6 +173,8 @@ interface RecordingCoordinatorConfig {
|
|
|
173
173
|
readonly storagePath: string;
|
|
174
174
|
readonly globalFfmpegConfig: Partial<FfmpegConfig>;
|
|
175
175
|
readonly detectedFfmpegConfig: Partial<FfmpegConfig>;
|
|
176
|
+
/** Global segment duration from system settings (recording.segmentDurationSeconds). */
|
|
177
|
+
readonly segmentDurationSec?: number;
|
|
176
178
|
}
|
|
177
179
|
declare class RecordingCoordinator$1 {
|
|
178
180
|
private readonly db;
|
|
@@ -185,6 +187,7 @@ declare class RecordingCoordinator$1 {
|
|
|
185
187
|
private readonly storagePath;
|
|
186
188
|
private readonly globalFfmpegConfig;
|
|
187
189
|
private readonly detectedFfmpegConfig;
|
|
190
|
+
private readonly segmentDurationSec;
|
|
188
191
|
private readonly recordings;
|
|
189
192
|
private policyTimer;
|
|
190
193
|
private readonly retentionManager;
|
|
@@ -219,8 +222,6 @@ declare class PipelineAddon implements ICamstackAddon, IConfigurable {
|
|
|
219
222
|
private sqliteDb;
|
|
220
223
|
private recordingDeps;
|
|
221
224
|
private currentRecordingConfig;
|
|
222
|
-
private analysisPipeline;
|
|
223
|
-
private analysisLogger;
|
|
224
225
|
private persistenceFacade;
|
|
225
226
|
setRecordingDependencies(deps: RecordingEngineDependencies): void;
|
|
226
227
|
initialize(context: AddonContext): Promise<void>;
|
|
@@ -228,8 +229,6 @@ declare class PipelineAddon implements ICamstackAddon, IConfigurable {
|
|
|
228
229
|
getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
|
|
229
230
|
getCoordinator(): RecordingCoordinator;
|
|
230
231
|
getRecordingDb(): RecordingDb;
|
|
231
|
-
/** Whether the analysis pipeline package loaded successfully */
|
|
232
|
-
isAnalysisAvailable(): boolean;
|
|
233
232
|
getConfigSchema(): ConfigUISchema;
|
|
234
233
|
getConfig(): Record<string, unknown>;
|
|
235
234
|
onConfigChange(config: Record<string, unknown>): Promise<void>;
|
package/dist/addon.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(ffmpeg_config_exports, {
|
|
|
36
36
|
buildFfmpegInputArgs: () => buildFfmpegInputArgs,
|
|
37
37
|
buildFfmpegOutputArgs: () => buildFfmpegOutputArgs,
|
|
38
38
|
detectPlatformDefaults: () => detectPlatformDefaults,
|
|
39
|
+
resolveFfmpegBinary: () => resolveFfmpegBinary,
|
|
39
40
|
resolveFfmpegConfig: () => resolveFfmpegConfig
|
|
40
41
|
});
|
|
41
42
|
function detectPlatformDefaults(ffmpegPath = "ffmpeg") {
|
|
@@ -78,12 +79,19 @@ function buildFfmpegOutputArgs(config) {
|
|
|
78
79
|
if (config.outputArgs?.length) args.push(...config.outputArgs);
|
|
79
80
|
return args;
|
|
80
81
|
}
|
|
81
|
-
|
|
82
|
+
async function resolveFfmpegBinary(configPath, dataDir, logger) {
|
|
83
|
+
if (configPath && configPath !== "ffmpeg") {
|
|
84
|
+
return configPath;
|
|
85
|
+
}
|
|
86
|
+
return (0, import_core.ensureFfmpeg)(dataDir, logger);
|
|
87
|
+
}
|
|
88
|
+
var import_node_child_process3, os, import_core;
|
|
82
89
|
var init_ffmpeg_config = __esm({
|
|
83
90
|
"src/recording/ffmpeg-config.ts"() {
|
|
84
91
|
"use strict";
|
|
85
92
|
import_node_child_process3 = require("child_process");
|
|
86
93
|
os = __toESM(require("os"), 1);
|
|
94
|
+
import_core = require("@camstack/core");
|
|
87
95
|
}
|
|
88
96
|
});
|
|
89
97
|
|
|
@@ -1189,7 +1197,7 @@ var recording_coordinator_exports = {};
|
|
|
1189
1197
|
__export(recording_coordinator_exports, {
|
|
1190
1198
|
RecordingCoordinator: () => RecordingCoordinator
|
|
1191
1199
|
});
|
|
1192
|
-
var POLICY_EVAL_INTERVAL_MS, MOTION_FALLBACK_TIMEOUT_MS, RecordingCoordinator;
|
|
1200
|
+
var DEFAULT_SEGMENT_DURATION_SEC, POLICY_EVAL_INTERVAL_MS, MOTION_FALLBACK_TIMEOUT_MS, RecordingCoordinator;
|
|
1193
1201
|
var init_recording_coordinator = __esm({
|
|
1194
1202
|
"src/recording/recording-coordinator.ts"() {
|
|
1195
1203
|
"use strict";
|
|
@@ -1199,6 +1207,7 @@ var init_recording_coordinator = __esm({
|
|
|
1199
1207
|
init_retention_manager();
|
|
1200
1208
|
init_playlist_generator();
|
|
1201
1209
|
init_storage_estimator();
|
|
1210
|
+
DEFAULT_SEGMENT_DURATION_SEC = 4;
|
|
1202
1211
|
POLICY_EVAL_INTERVAL_MS = 1e3;
|
|
1203
1212
|
MOTION_FALLBACK_TIMEOUT_MS = 6e4;
|
|
1204
1213
|
RecordingCoordinator = class _RecordingCoordinator {
|
|
@@ -1212,6 +1221,7 @@ var init_recording_coordinator = __esm({
|
|
|
1212
1221
|
storagePath;
|
|
1213
1222
|
globalFfmpegConfig;
|
|
1214
1223
|
detectedFfmpegConfig;
|
|
1224
|
+
segmentDurationSec;
|
|
1215
1225
|
recordings = /* @__PURE__ */ new Map();
|
|
1216
1226
|
policyTimer = null;
|
|
1217
1227
|
retentionManager;
|
|
@@ -1228,6 +1238,7 @@ var init_recording_coordinator = __esm({
|
|
|
1228
1238
|
this.storagePath = config.storagePath;
|
|
1229
1239
|
this.globalFfmpegConfig = config.globalFfmpegConfig;
|
|
1230
1240
|
this.detectedFfmpegConfig = config.detectedFfmpegConfig;
|
|
1241
|
+
this.segmentDurationSec = config.segmentDurationSec ?? DEFAULT_SEGMENT_DURATION_SEC;
|
|
1231
1242
|
this.retentionManager = new RetentionManager(
|
|
1232
1243
|
this.db,
|
|
1233
1244
|
this.logger.child("retention"),
|
|
@@ -1313,7 +1324,7 @@ var init_recording_coordinator = __esm({
|
|
|
1313
1324
|
const writerConfig = {
|
|
1314
1325
|
deviceId,
|
|
1315
1326
|
streamId: sp.streamId,
|
|
1316
|
-
segmentDurationSec:
|
|
1327
|
+
segmentDurationSec: this.segmentDurationSec,
|
|
1317
1328
|
storagePath: this.storagePath,
|
|
1318
1329
|
storageName,
|
|
1319
1330
|
subDirectory,
|
|
@@ -3166,9 +3177,7 @@ var PipelineAddon = class {
|
|
|
3166
3177
|
capabilities: [
|
|
3167
3178
|
{ name: "stream-broker", mode: "singleton" },
|
|
3168
3179
|
{ name: "recording-engine", mode: "singleton" },
|
|
3169
|
-
{ name: "analysis-
|
|
3170
|
-
{ name: "analysis-data-persistence", mode: "singleton" },
|
|
3171
|
-
{ name: "webrtc", mode: "collection" }
|
|
3180
|
+
{ name: "analysis-data-persistence", mode: "singleton" }
|
|
3172
3181
|
]
|
|
3173
3182
|
};
|
|
3174
3183
|
// Stream broker
|
|
@@ -3181,11 +3190,10 @@ var PipelineAddon = class {
|
|
|
3181
3190
|
currentRecordingConfig = {
|
|
3182
3191
|
ffmpegPath: "ffmpeg",
|
|
3183
3192
|
hwaccel: void 0,
|
|
3184
|
-
threads: void 0
|
|
3193
|
+
threads: void 0,
|
|
3194
|
+
segmentDurationSeconds: 4,
|
|
3195
|
+
defaultRetentionDays: 30
|
|
3185
3196
|
};
|
|
3186
|
-
// Analysis pipeline
|
|
3187
|
-
analysisPipeline = null;
|
|
3188
|
-
analysisLogger = null;
|
|
3189
3197
|
// Analysis persistence
|
|
3190
3198
|
persistenceFacade = null;
|
|
3191
3199
|
setRecordingDependencies(deps) {
|
|
@@ -3215,10 +3223,14 @@ var PipelineAddon = class {
|
|
|
3215
3223
|
hwaccel: context.addonConfig.hwaccel ?? this.currentRecordingConfig.hwaccel,
|
|
3216
3224
|
threads: context.addonConfig.threads ?? this.currentRecordingConfig.threads
|
|
3217
3225
|
};
|
|
3226
|
+
const segmentDurationSeconds = context.addonConfig.segmentDurationSeconds ?? this.currentRecordingConfig.segmentDurationSeconds;
|
|
3227
|
+
const defaultRetentionDays = context.addonConfig.defaultRetentionDays ?? this.currentRecordingConfig.defaultRetentionDays;
|
|
3218
3228
|
this.currentRecordingConfig = {
|
|
3219
3229
|
ffmpegPath,
|
|
3220
3230
|
hwaccel: globalFfmpegConfig.hwaccel,
|
|
3221
|
-
threads: globalFfmpegConfig.threads
|
|
3231
|
+
threads: globalFfmpegConfig.threads,
|
|
3232
|
+
segmentDurationSeconds,
|
|
3233
|
+
defaultRetentionDays
|
|
3222
3234
|
};
|
|
3223
3235
|
const fileStorage = context.storage.files;
|
|
3224
3236
|
if (!fileStorage) {
|
|
@@ -3234,7 +3246,8 @@ var PipelineAddon = class {
|
|
|
3234
3246
|
fileStorage,
|
|
3235
3247
|
storagePath,
|
|
3236
3248
|
globalFfmpegConfig,
|
|
3237
|
-
detectedFfmpegConfig
|
|
3249
|
+
detectedFfmpegConfig,
|
|
3250
|
+
segmentDurationSec: segmentDurationSeconds
|
|
3238
3251
|
});
|
|
3239
3252
|
await this.coordinator.start();
|
|
3240
3253
|
context.logger.info("Recording Engine initialized");
|
|
@@ -3243,16 +3256,6 @@ var PipelineAddon = class {
|
|
|
3243
3256
|
context.logger.warn(`Recording Engine failed to initialize: ${msg}`);
|
|
3244
3257
|
}
|
|
3245
3258
|
}
|
|
3246
|
-
this.analysisLogger = context.logger;
|
|
3247
|
-
try {
|
|
3248
|
-
const mod = await import("@camstack/lib-pipeline-analysis");
|
|
3249
|
-
const instance = new mod.AnalysisPipeline();
|
|
3250
|
-
this.analysisPipeline = instance;
|
|
3251
|
-
this.analysisLogger.info("Analysis pipeline loaded successfully");
|
|
3252
|
-
} catch (error) {
|
|
3253
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
3254
|
-
this.analysisLogger.warn(`Analysis pipeline not available: ${msg} -- analysis features disabled`);
|
|
3255
|
-
}
|
|
3256
3259
|
const eventPersistence = new EventPersistenceService({
|
|
3257
3260
|
getStorageLocation: () => context.storage,
|
|
3258
3261
|
subscribe: (filter, handler) => context.eventBus.subscribe(filter, handler),
|
|
@@ -3304,7 +3307,6 @@ var PipelineAddon = class {
|
|
|
3304
3307
|
this.sqliteDb = null;
|
|
3305
3308
|
}
|
|
3306
3309
|
this.recordingDb = null;
|
|
3307
|
-
this.analysisPipeline = null;
|
|
3308
3310
|
if (this.persistenceFacade) {
|
|
3309
3311
|
this.persistenceFacade.eventPersistence.stop();
|
|
3310
3312
|
this.persistenceFacade.retention.stop();
|
|
@@ -3317,13 +3319,8 @@ var PipelineAddon = class {
|
|
|
3317
3319
|
return this.brokerManager;
|
|
3318
3320
|
case "recording-engine":
|
|
3319
3321
|
return this.coordinator;
|
|
3320
|
-
case "analysis-pipeline":
|
|
3321
|
-
return this.analysisPipeline;
|
|
3322
3322
|
case "analysis-data-persistence":
|
|
3323
3323
|
return this.persistenceFacade;
|
|
3324
|
-
case "webrtc":
|
|
3325
|
-
return null;
|
|
3326
|
-
// WebRTC is provided externally or via collection
|
|
3327
3324
|
default:
|
|
3328
3325
|
return null;
|
|
3329
3326
|
}
|
|
@@ -3337,52 +3334,9 @@ var PipelineAddon = class {
|
|
|
3337
3334
|
if (!this.recordingDb) throw new Error("PipelineAddon recording not initialized");
|
|
3338
3335
|
return this.recordingDb;
|
|
3339
3336
|
}
|
|
3340
|
-
/** Whether the analysis pipeline package loaded successfully */
|
|
3341
|
-
isAnalysisAvailable() {
|
|
3342
|
-
return this.analysisPipeline !== null;
|
|
3343
|
-
}
|
|
3344
3337
|
// --- IConfigurable ---
|
|
3345
3338
|
getConfigSchema() {
|
|
3346
|
-
return {
|
|
3347
|
-
sections: [
|
|
3348
|
-
{
|
|
3349
|
-
id: "ffmpeg",
|
|
3350
|
-
title: "FFmpeg Settings",
|
|
3351
|
-
columns: 2,
|
|
3352
|
-
fields: [
|
|
3353
|
-
{
|
|
3354
|
-
type: "text",
|
|
3355
|
-
key: "ffmpegPath",
|
|
3356
|
-
label: "FFmpeg Binary Path",
|
|
3357
|
-
description: 'Path to the ffmpeg executable, or just "ffmpeg" if it is in your PATH',
|
|
3358
|
-
placeholder: "ffmpeg"
|
|
3359
|
-
},
|
|
3360
|
-
{
|
|
3361
|
-
type: "select",
|
|
3362
|
-
key: "hwaccel",
|
|
3363
|
-
label: "Hardware Acceleration",
|
|
3364
|
-
description: "Enable GPU-accelerated video encoding if supported by your hardware",
|
|
3365
|
-
options: [
|
|
3366
|
-
{ value: "", label: "None (software)", description: "CPU-only encoding" },
|
|
3367
|
-
{ value: "nvenc", label: "NVIDIA NVENC", description: "NVIDIA GPU encoding" },
|
|
3368
|
-
{ value: "vaapi", label: "Intel VAAPI", description: "Intel GPU encoding (Linux)" },
|
|
3369
|
-
{ value: "videotoolbox", label: "Apple VideoToolbox", description: "macOS hardware encoding" }
|
|
3370
|
-
]
|
|
3371
|
-
},
|
|
3372
|
-
{
|
|
3373
|
-
type: "number",
|
|
3374
|
-
key: "threads",
|
|
3375
|
-
label: "FFmpeg Threads",
|
|
3376
|
-
description: "Number of CPU threads for software encoding (0 = auto)",
|
|
3377
|
-
min: 0,
|
|
3378
|
-
max: 64,
|
|
3379
|
-
step: 1,
|
|
3380
|
-
unit: "threads"
|
|
3381
|
-
}
|
|
3382
|
-
]
|
|
3383
|
-
}
|
|
3384
|
-
]
|
|
3385
|
-
};
|
|
3339
|
+
return { sections: [] };
|
|
3386
3340
|
}
|
|
3387
3341
|
getConfig() {
|
|
3388
3342
|
return { ...this.currentRecordingConfig };
|
|
@@ -3391,7 +3345,9 @@ var PipelineAddon = class {
|
|
|
3391
3345
|
this.currentRecordingConfig = {
|
|
3392
3346
|
ffmpegPath: config.ffmpegPath ?? this.currentRecordingConfig.ffmpegPath,
|
|
3393
3347
|
hwaccel: config.hwaccel ?? this.currentRecordingConfig.hwaccel,
|
|
3394
|
-
threads: config.threads ?? this.currentRecordingConfig.threads
|
|
3348
|
+
threads: config.threads ?? this.currentRecordingConfig.threads,
|
|
3349
|
+
segmentDurationSeconds: config.segmentDurationSeconds ?? this.currentRecordingConfig.segmentDurationSeconds,
|
|
3350
|
+
defaultRetentionDays: config.defaultRetentionDays ?? this.currentRecordingConfig.defaultRetentionDays
|
|
3395
3351
|
};
|
|
3396
3352
|
}
|
|
3397
3353
|
};
|