@apocaliss92/nodelink-js 0.5.2 → 0.6.0

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/index.cjs CHANGED
@@ -35165,10 +35165,18 @@ var CompositeStream = class extends import_node_events6.EventEmitter {
35165
35165
  }
35166
35166
  }
35167
35167
  async startFfmpegCompositionFromRtspUrls(mainWidth, mainHeight, pipWidth, pipHeight, position, widerRtspUrl, teleRtspUrl, rtspTransport) {
35168
+ const videoEncoder = this.options.videoEncoder ?? "libx264";
35169
+ const isX264 = videoEncoder === "libx264";
35170
+ const encoderPreset = this.options.encoderPreset ?? "ultrafast";
35171
+ const crf = this.options.crf ?? 23;
35172
+ const gopSeconds = this.options.gopSeconds ?? 1;
35173
+ const assumedFps = 30;
35174
+ const gopFrames = Math.max(1, Math.round(gopSeconds * assumedFps));
35168
35175
  const ffmpegArgs = [
35169
35176
  "-hide_banner",
35170
35177
  "-loglevel",
35171
35178
  "error",
35179
+ ...this.options.extraGlobalArgs ?? [],
35172
35180
  "-fflags",
35173
35181
  "+genpts",
35174
35182
  // Input 0: wider
@@ -35189,27 +35197,33 @@ var CompositeStream = class extends import_node_events6.EventEmitter {
35189
35197
  // Output: always H.264 Annex-B
35190
35198
  "-an",
35191
35199
  "-c:v",
35192
- "libx264",
35200
+ videoEncoder,
35193
35201
  "-g",
35194
- "30",
35202
+ String(gopFrames),
35195
35203
  "-keyint_min",
35196
- "30",
35204
+ String(gopFrames),
35197
35205
  "-sc_threshold",
35198
35206
  "0",
35199
- "-x264-params",
35200
- "aud=1:repeat-headers=1:keyint=30:min-keyint=30:scenecut=0",
35201
- "-preset",
35202
- "ultrafast",
35203
- "-tune",
35204
- "zerolatency",
35205
- "-crf",
35206
- "23",
35207
+ ...isX264 ? [
35208
+ "-x264-params",
35209
+ `aud=1:repeat-headers=1:keyint=${gopFrames}:min-keyint=${gopFrames}:scenecut=0`,
35210
+ "-preset",
35211
+ encoderPreset,
35212
+ "-tune",
35213
+ "zerolatency",
35214
+ "-crf",
35215
+ String(crf)
35216
+ ] : [],
35217
+ ...this.options.extraOutputArgs ?? [],
35207
35218
  "-f",
35208
35219
  "h264",
35209
35220
  "pipe:1"
35210
35221
  ];
35211
- this.logger.log?.(`[CompositeStream] Starting ffmpeg (rtsp inputs): ${ffmpegArgs.join(" ")}`);
35212
- this.ffmpegProcess = (0, import_node_child_process7.spawn)("ffmpeg", ffmpegArgs, {
35222
+ const ffmpegBin = this.options.ffmpegPath ?? "ffmpeg";
35223
+ this.logger.log?.(
35224
+ `[CompositeStream] Starting ffmpeg (rtsp inputs): bin=${ffmpegBin} args=${ffmpegArgs.join(" ")}`
35225
+ );
35226
+ this.ffmpegProcess = (0, import_node_child_process7.spawn)(ffmpegBin, ffmpegArgs, {
35213
35227
  stdio: ["ignore", "pipe", "pipe"]
35214
35228
  });
35215
35229
  this.ffmpegProcess.on("error", (error) => {
@@ -35276,10 +35290,18 @@ var CompositeStream = class extends import_node_events6.EventEmitter {
35276
35290
  "-i",
35277
35291
  "pipe:3"
35278
35292
  ];
35293
+ const videoEncoder = this.options.videoEncoder ?? "libx264";
35294
+ const isX264 = videoEncoder === "libx264";
35295
+ const encoderPreset = this.options.encoderPreset ?? "ultrafast";
35296
+ const crf = this.options.crf ?? 23;
35297
+ const gopSeconds = this.options.gopSeconds ?? 1;
35298
+ const assumedFps = 30;
35299
+ const gopFrames = Math.max(1, Math.round(gopSeconds * assumedFps));
35279
35300
  const ffmpegArgs = [
35280
35301
  "-hide_banner",
35281
35302
  "-loglevel",
35282
35303
  "error",
35304
+ ...this.options.extraGlobalArgs ?? [],
35283
35305
  "-fflags",
35284
35306
  "+genpts",
35285
35307
  "-probesize",
@@ -35298,33 +35320,40 @@ var CompositeStream = class extends import_node_events6.EventEmitter {
35298
35320
  "-map",
35299
35321
  "[out]",
35300
35322
  "-c:v",
35301
- "libx264",
35302
- // Re-encode for compatibility
35303
- // Make the stream easy to join mid-flight: frequent IDRs + in-band headers + AUD.
35304
- // Without this, a new client may wait many seconds for the next keyframe.
35323
+ videoEncoder,
35324
+ // Make the stream easy to join mid-flight: frequent IDRs + in-band
35325
+ // headers + AUD. Without this, a new client may wait many seconds
35326
+ // for the next keyframe.
35305
35327
  "-g",
35306
- "30",
35328
+ String(gopFrames),
35307
35329
  "-keyint_min",
35308
- "30",
35330
+ String(gopFrames),
35309
35331
  "-sc_threshold",
35310
35332
  "0",
35311
- "-x264-params",
35312
- "aud=1:repeat-headers=1:keyint=30:min-keyint=30:scenecut=0",
35313
- "-preset",
35314
- "ultrafast",
35315
- "-tune",
35316
- "zerolatency",
35317
- "-crf",
35318
- "23",
35333
+ // libx264-specific knobs. We deliberately skip these for HW encoders
35334
+ // — each one has its own option vocabulary (`-q:v`, `-rc`, etc.)
35335
+ // and the user is expected to express them via extraOutputArgs.
35336
+ ...isX264 ? [
35337
+ "-x264-params",
35338
+ `aud=1:repeat-headers=1:keyint=${gopFrames}:min-keyint=${gopFrames}:scenecut=0`,
35339
+ "-preset",
35340
+ encoderPreset,
35341
+ "-tune",
35342
+ "zerolatency",
35343
+ "-crf",
35344
+ String(crf)
35345
+ ] : [],
35346
+ ...this.options.extraOutputArgs ?? [],
35319
35347
  "-f",
35320
35348
  "h264",
35321
35349
  "pipe:1"
35322
35350
  // Output (stdout)
35323
35351
  ];
35352
+ const ffmpegBin = this.options.ffmpegPath ?? "ffmpeg";
35324
35353
  this.logger.log?.(
35325
- `[CompositeStream] Starting ffmpeg: ${ffmpegArgs.join(" ")}`
35354
+ `[CompositeStream] Starting ffmpeg: bin=${ffmpegBin} args=${ffmpegArgs.join(" ")}`
35326
35355
  );
35327
- this.ffmpegProcess = (0, import_node_child_process7.spawn)("ffmpeg", ffmpegArgs, {
35356
+ this.ffmpegProcess = (0, import_node_child_process7.spawn)(ffmpegBin, ffmpegArgs, {
35328
35357
  stdio: ["pipe", "pipe", "pipe", "pipe"]
35329
35358
  });
35330
35359
  this.ffmpegProcess.on("error", (error) => {
@@ -36032,6 +36061,20 @@ async function createRfc4571TcpServerInternal(options) {
36032
36061
  ...forceH264 !== void 0 ? { forceH264 } : defaultForceH264 ? { forceH264: true } : {},
36033
36062
  ...compositeOptions?.assumeH264Inputs !== void 0 ? { assumeH264Inputs: compositeOptions.assumeH264Inputs } : {},
36034
36063
  ...compositeOptions?.disableTranscode !== void 0 ? { disableTranscode: compositeOptions.disableTranscode } : {},
36064
+ // Propagate ffmpeg binary path — required when the embedder strips
36065
+ // PATH (Scrypted on Windows, Electron sandboxes, distroless Docker)
36066
+ // and the bundled ffmpeg is at a fixed absolute path only the
36067
+ // embedder knows.
36068
+ ...compositeOptions?.ffmpegPath ? { ffmpegPath: compositeOptions.ffmpegPath } : {},
36069
+ // Encoder tuning knobs — see CompositeStreamPipOptions for the
36070
+ // semantic contract on each one. Plumbed verbatim so the
36071
+ // CompositeStream layer can apply defaults.
36072
+ ...compositeOptions?.videoEncoder ? { videoEncoder: compositeOptions.videoEncoder } : {},
36073
+ ...compositeOptions?.encoderPreset ? { encoderPreset: compositeOptions.encoderPreset } : {},
36074
+ ...typeof compositeOptions?.crf === "number" ? { crf: compositeOptions.crf } : {},
36075
+ ...typeof compositeOptions?.gopSeconds === "number" ? { gopSeconds: compositeOptions.gopSeconds } : {},
36076
+ ...compositeOptions?.extraGlobalArgs ? { extraGlobalArgs: compositeOptions.extraGlobalArgs } : {},
36077
+ ...compositeOptions?.extraOutputArgs ? { extraOutputArgs: compositeOptions.extraOutputArgs } : {},
36035
36078
  logger
36036
36079
  });
36037
36080
  isCompositeStream = true;