@camstack/addon-pipeline 1.2.362 → 1.2.364
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/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-C77XAnt9.mjs → custom-model-catalog-DHFPSu0E.mjs} +2 -2
- package/dist/{custom-model-catalog-CL9Tcn2Y.js → custom-model-catalog-nx2TXAGS.js} +2 -2
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-D629dz5x.mjs → dist-BX9VTm12.mjs} +177 -3
- package/dist/{dist-tclsRHCk.js → dist-CGOb--t-.js} +177 -3
- package/dist/{model-catalogs-Y1WJrGyS.js → model-catalogs-DHV48cdY.js} +1 -1
- package/dist/{model-catalogs-BxQBJBt4.mjs → model-catalogs-DNL4ydAg.mjs} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-D2D0N7_h.mjs → node-C8bbmV3c.mjs} +1 -1
- package/dist/{node-BYrYuZdh.js → node-UBMRK8SK.js} +1 -1
- package/dist/pipeline-runner/index.js +3 -3
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/{process-memory-eM4qLFdC.js → process-memory-1BwIq2Ks.js} +1 -1
- package/dist/{process-memory-BR1e6q_Q.mjs → process-memory-BHG2uCeq.mjs} +1 -1
- package/dist/recorder/index.js +3 -3
- package/dist/recorder/index.mjs +3 -3
- package/dist/{segment-demux-js-C5IOs4lZ.mjs → segment-demux-js-BhnT__dA.mjs} +1 -1
- package/dist/{segment-demux-js-B9EqRfBi.js → segment-demux-js-PkDP-xQg.js} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C4Cp_OAY.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-vdmrukBk.mjs} +2 -2
- package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CICWhpXS.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-ScPS8ZWM.mjs} +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Cq5NPjBX.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-CZ_HBwki.mjs → hostInit-D_DBY5wu.mjs} +2 -2
- package/dist/stream-broker/index.js +357 -71
- package/dist/stream-broker/index.mjs +357 -71
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-7VuNrr9l.mjs +0 -26
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { r as __toESM } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $n as discriminatedUnion, An as BaseAddon, D as G711_SCALE_CORRECTION_DB, Dn as DeviceType, Dt as gifDeriveSpeed, En as DeviceFeature, Gn as maskUrlCredentials, Hn as isEvent, I as RATE_CONTROL_RELAXED, In as createEvent, J as addonWidgetsSourceCapability, Kn as nodePin, L as RATE_CONTROL_TIGHT, Mn as CamProfileSchema, Nt as loadContributionCapability, On as errMsg, Ot as gifFromMp4Args, Pt as logChannelsCapability, Qn as boolean, Rt as memoizePinnedFfmpeg, Sn as buildFfmpegArgs, Tn as isSoftwareDecode, Tt as ffmpegRate, Un as makeProfileBrokerId, W as RingBuffer, Wn as makeSourceBrokerId, Xn as _enum, Xt as rankStreams, Zn as array, _t as egressTranscodeSharingKey, ar as record, at as clipExportFailureOf, c as CLIP_STILL_REASON_CODE_HEADER, cr as EventCategory, ct as createHwAccelCache, et as batteryCapability, ft as deriveBatteryPresence, jn as CAM_PROFILE_ORDER, kn as BOOT_RECOVERY_BACKOFF_MS, lt as createLogChannelsProvider, mn as streamBrokerCapability, nr as number, o as BatteryStatusSchema, or as string, qn as parseProfileBrokerId, rn as resolveEgressDecodeHwAccel, rr as object, rt as cameraStreamsCapability, s as CLIP_BROKER_PACED_RATES, sr as union, tr as literal, ut as declareLogChannel, vn as webrtcSessionCapability, vt as egressTransportFromRequest, w as EncodeProfileSchema, wn as invocationFromEncodeProfile, yn as AUDIO_PRESETS, zn as expandAudioChunkToF32le } from "../dist-
|
|
3
|
-
import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, o as probeFfmpegBinary, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-
|
|
2
|
+
import { $n as discriminatedUnion, An as BaseAddon, D as G711_SCALE_CORRECTION_DB, Dn as DeviceType, Dt as gifDeriveSpeed, En as DeviceFeature, Gn as maskUrlCredentials, Hn as isEvent, I as RATE_CONTROL_RELAXED, In as createEvent, J as addonWidgetsSourceCapability, Kn as nodePin, L as RATE_CONTROL_TIGHT, Mn as CamProfileSchema, Nt as loadContributionCapability, On as errMsg, Ot as gifFromMp4Args, Pt as logChannelsCapability, Qn as boolean, Rt as memoizePinnedFfmpeg, Sn as buildFfmpegArgs, Tn as isSoftwareDecode, Tt as ffmpegRate, Un as makeProfileBrokerId, W as RingBuffer, Wn as makeSourceBrokerId, Xn as _enum, Xt as rankStreams, Zn as array, _t as egressTranscodeSharingKey, ar as record, at as clipExportFailureOf, c as CLIP_STILL_REASON_CODE_HEADER, cr as EventCategory, ct as createHwAccelCache, et as batteryCapability, ft as deriveBatteryPresence, jn as CAM_PROFILE_ORDER, kn as BOOT_RECOVERY_BACKOFF_MS, lt as createLogChannelsProvider, mn as streamBrokerCapability, nr as number, o as BatteryStatusSchema, or as string, qn as parseProfileBrokerId, rn as resolveEgressDecodeHwAccel, rr as object, rt as cameraStreamsCapability, s as CLIP_BROKER_PACED_RATES, sr as union, tr as literal, ut as declareLogChannel, vn as webrtcSessionCapability, vt as egressTransportFromRequest, w as EncodeProfileSchema, wn as invocationFromEncodeProfile, yn as AUDIO_PRESETS, zn as expandAudioChunkToF32le } from "../dist-BX9VTm12.mjs";
|
|
3
|
+
import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, o as probeFfmpegBinary, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-C8bbmV3c.mjs";
|
|
4
4
|
import { a as parseRestreamPath, d as PREBUFFER_MAX_MS, f as capPreRollRequestMs, i as isLiveEdgeOnlyDial, m as resolvePrebuffer, n as NO_DECLARATION, p as prebufferRetentionMs, s as sdpVariantFor, u as withSentryIntent } from "../restream-intent-DyGmLAU9.mjs";
|
|
5
5
|
import { n as profileForStreamId } from "../remote-restream-BeHi78PZ.mjs";
|
|
6
6
|
import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
|
|
7
|
-
import { a as require_mp4box_all, c as parseNalLengthSize, i as runFfmpegOnce, n as demuxSegmentPreferJs, o as avccSampleToAnnexB, r as FfmpegFallbackRefusedError, s as buildKeyframeAnnexB, t as demuxSegmentFullJs } from "../segment-demux-js-
|
|
7
|
+
import { a as require_mp4box_all, c as parseNalLengthSize, i as runFfmpegOnce, n as demuxSegmentPreferJs, o as avccSampleToAnnexB, r as FfmpegFallbackRefusedError, s as buildKeyframeAnnexB, t as demuxSegmentFullJs } from "../segment-demux-js-BhnT__dA.mjs";
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
9
|
import * as os$1 from "node:os";
|
|
10
10
|
import { networkInterfaces, tmpdir } from "node:os";
|
|
@@ -3727,7 +3727,12 @@ var RtspRestreamer = class {
|
|
|
3727
3727
|
* Forwarded directly to all connected RTSP sessions — zero re-packetization.
|
|
3728
3728
|
*
|
|
3729
3729
|
* @param rtpData Complete RTP packet (header + payload)
|
|
3730
|
-
* @param isKeyframe True if this packet is part of a keyframe
|
|
3730
|
+
* @param isKeyframe True if this packet is part of a keyframe ACCESS UNIT —
|
|
3731
|
+
* judged per picture by the broker's `RtpAccessUnitTracker`: every
|
|
3732
|
+
* fragment of a fragmented IDR and a prefix SEI inside the picture carry
|
|
3733
|
+
* it, not only the packet that completed an IRAP NAL. The keyframe cache
|
|
3734
|
+
* below collects exactly that run, and the transition into it is the
|
|
3735
|
+
* once-per-picture `keyframeAuStart` the sessions resume and count on.
|
|
3731
3736
|
* @param isParameterSet True if this packet contains SPS/PPS/VPS
|
|
3732
3737
|
*/
|
|
3733
3738
|
pushRtpPassthrough(rtpData, isKeyframe, isParameterSet) {
|
|
@@ -3743,14 +3748,14 @@ var RtspRestreamer = class {
|
|
|
3743
3748
|
this.lastKeyframeRtpBytes = 0;
|
|
3744
3749
|
}
|
|
3745
3750
|
}
|
|
3751
|
+
if (this.collectingKeyframeRtp && !isKeyframe && !isParameterSet) this.collectingKeyframeRtp = false;
|
|
3746
3752
|
if (this.collectingKeyframeRtp) {
|
|
3747
3753
|
this.lastKeyframeRtpPackets.push({
|
|
3748
3754
|
data: Buffer.from(rtpData),
|
|
3749
3755
|
marker: rtpPacket.marker
|
|
3750
3756
|
});
|
|
3751
3757
|
this.lastKeyframeRtpBytes += rtpData.length;
|
|
3752
|
-
if (
|
|
3753
|
-
else if (this.lastKeyframeRtpBytes > MAX_KEYFRAME_CACHE_BYTES) {
|
|
3758
|
+
if (this.lastKeyframeRtpBytes > MAX_KEYFRAME_CACHE_BYTES) {
|
|
3754
3759
|
this.warnCacheCapExceeded("rtp", this.lastKeyframeRtpBytes, this.lastKeyframeRtpPackets.length);
|
|
3755
3760
|
this.lastKeyframeRtpPackets = [];
|
|
3756
3761
|
this.lastKeyframeRtpBytes = 0;
|
|
@@ -3763,17 +3768,16 @@ var RtspRestreamer = class {
|
|
|
3763
3768
|
if (!session.isPlaying()) continue;
|
|
3764
3769
|
this.pendingKeyframe.delete(session.getSessionId());
|
|
3765
3770
|
}
|
|
3766
|
-
const keyframeAu = isKeyframe || isParameterSet;
|
|
3767
3771
|
for (const session of this.sessions.values()) {
|
|
3768
3772
|
const sessionId = session.getSessionId();
|
|
3769
3773
|
if (this.activeReplays.get(sessionId)?.enqueue({
|
|
3770
3774
|
packet: rtpPacket,
|
|
3771
3775
|
prime: false,
|
|
3772
|
-
keyframeAuStart
|
|
3776
|
+
keyframeAuStart
|
|
3773
3777
|
})) continue;
|
|
3774
3778
|
if (this.pendingKeyframe.has(sessionId)) continue;
|
|
3775
3779
|
if (!session.isPlaying()) continue;
|
|
3776
|
-
this.recordLiveOutcome(session.sendRtp(rtpPacket, false,
|
|
3780
|
+
this.recordLiveOutcome(session.sendRtp(rtpPacket, false, keyframeAuStart));
|
|
3777
3781
|
}
|
|
3778
3782
|
}
|
|
3779
3783
|
/**
|
|
@@ -4626,15 +4630,16 @@ var RtspSession = class {
|
|
|
4626
4630
|
*
|
|
4627
4631
|
* ## Why sharing the payload is safe, and what would make it unsafe
|
|
4628
4632
|
*
|
|
4629
|
-
* The payload buffer handed here is
|
|
4630
|
-
* broker's `rtpRing` for the life of a GOP (`captureRtpForPreBuffer` pushes
|
|
4631
|
-
* the same object). A pending `socket.write` cannot outlive that, so the
|
|
4632
|
-
* lifetime requirement this adds is strictly weaker than one the broker
|
|
4633
|
-
* already meets. Its provenance is a private allocation per packet —
|
|
4633
|
+
* The payload buffer handed here is a private allocation per packet —
|
|
4634
4634
|
* `Buffer.from(readBuffer.subarray(...))` in `rtsp-client.ts`'s `onData`, for
|
|
4635
4635
|
* video and audio alike — never a view of the reader's socket buffer, which
|
|
4636
4636
|
* advances on the next read. Nothing in the broker writes into a captured
|
|
4637
4637
|
* packet: every mutation in this path targets a freshly allocated buffer.
|
|
4638
|
+
* (The broker's `rtpRing` keeps its OWN copy of a pooled packet —
|
|
4639
|
+
* `detachFromPool`, so a ring entry never pins a shared pool slab — so the
|
|
4640
|
+
* ring no longer vouches for THIS object's lifetime, and it does not need
|
|
4641
|
+
* to: a pending write holds its own reference, and the rule below is about
|
|
4642
|
+
* mutation, not retention.)
|
|
4638
4643
|
*
|
|
4639
4644
|
* The rule to keep: **`socket.write` forbids MUTATION before the write
|
|
4640
4645
|
* completes, not retention.** So the header, which IS built per call, must
|
|
@@ -10123,6 +10128,16 @@ function allocAnnexBNal(byteLength) {
|
|
|
10123
10128
|
buf[3] = 1;
|
|
10124
10129
|
return buf;
|
|
10125
10130
|
}
|
|
10131
|
+
var NO_PAYLOAD_CLASS = {
|
|
10132
|
+
keyframe: false,
|
|
10133
|
+
parameterSet: false
|
|
10134
|
+
};
|
|
10135
|
+
function isH265IrapType(type) {
|
|
10136
|
+
return type >= H265_NAL_IRAP_MIN && type <= H265_NAL_IRAP_MAX;
|
|
10137
|
+
}
|
|
10138
|
+
function isH265ParameterSetType(type) {
|
|
10139
|
+
return type === H265_NAL_VPS || type === H265_NAL_SPS || type === H265_NAL_PPS;
|
|
10140
|
+
}
|
|
10126
10141
|
/** Total byte length of the reassembly fragments, without allocating a closure. */
|
|
10127
10142
|
function totalFragmentBytes(fragments) {
|
|
10128
10143
|
let total = 0;
|
|
@@ -10168,16 +10183,92 @@ var RtpDepacketizer = class {
|
|
|
10168
10183
|
}
|
|
10169
10184
|
/**
|
|
10170
10185
|
* Process a raw RTP packet (including 12-byte RTP header).
|
|
10171
|
-
* Emits zero or more complete NAL units via the callback
|
|
10186
|
+
* Emits zero or more complete NAL units via the callback and returns what
|
|
10187
|
+
* THIS packet carried ({@link RtpPacketClass}) — `null` for a packet too
|
|
10188
|
+
* short to be RTP with a payload.
|
|
10172
10189
|
*/
|
|
10173
10190
|
processPacket(rtpData) {
|
|
10174
|
-
if (rtpData.length < 12) return;
|
|
10191
|
+
if (rtpData.length < 12) return null;
|
|
10175
10192
|
const marker = (rtpData[1] & 128) !== 0;
|
|
10176
10193
|
const timestamp = rtpData.readUInt32BE(4);
|
|
10177
10194
|
const payload = rtpData.subarray(12);
|
|
10178
|
-
if (payload.length === 0) return;
|
|
10195
|
+
if (payload.length === 0) return null;
|
|
10196
|
+
const carried = this.codec === "h264" ? this.classifyH264Payload(payload) : this.classifyH265Payload(payload);
|
|
10179
10197
|
if (this.codec === "h264") this.processH264(payload, timestamp, marker);
|
|
10180
10198
|
else this.processH265(payload, timestamp, marker);
|
|
10199
|
+
return {
|
|
10200
|
+
timestamp,
|
|
10201
|
+
marker,
|
|
10202
|
+
keyframe: carried.keyframe,
|
|
10203
|
+
parameterSet: carried.parameterSet
|
|
10204
|
+
};
|
|
10205
|
+
}
|
|
10206
|
+
/** H.264: single NAL by its type; STAP-A by every aggregated type; FU-A by the FU header. */
|
|
10207
|
+
classifyH264Payload(payload) {
|
|
10208
|
+
const nalType = payload[0] & 31;
|
|
10209
|
+
if (nalType === H264_NAL_STAP_A) {
|
|
10210
|
+
let keyframe = false;
|
|
10211
|
+
let parameterSet = false;
|
|
10212
|
+
let offset = 1;
|
|
10213
|
+
while (offset + 2 <= payload.length) {
|
|
10214
|
+
const nalSize = payload.readUInt16BE(offset);
|
|
10215
|
+
offset += 2;
|
|
10216
|
+
if (nalSize === 0 || offset + nalSize > payload.length) break;
|
|
10217
|
+
const type = payload[offset] & 31;
|
|
10218
|
+
keyframe ||= type === H264_NAL_IDR;
|
|
10219
|
+
parameterSet ||= type === H264_NAL_SPS || type === H264_NAL_PPS;
|
|
10220
|
+
offset += nalSize;
|
|
10221
|
+
}
|
|
10222
|
+
return {
|
|
10223
|
+
keyframe,
|
|
10224
|
+
parameterSet
|
|
10225
|
+
};
|
|
10226
|
+
}
|
|
10227
|
+
if (nalType === 28) {
|
|
10228
|
+
if (payload.length < 2) return NO_PAYLOAD_CLASS;
|
|
10229
|
+
return {
|
|
10230
|
+
keyframe: (payload[1] & 31) === H264_NAL_IDR,
|
|
10231
|
+
parameterSet: false
|
|
10232
|
+
};
|
|
10233
|
+
}
|
|
10234
|
+
return {
|
|
10235
|
+
keyframe: nalType === H264_NAL_IDR,
|
|
10236
|
+
parameterSet: nalType === H264_NAL_SPS || nalType === H264_NAL_PPS
|
|
10237
|
+
};
|
|
10238
|
+
}
|
|
10239
|
+
/** H.265: single NAL by its type; AP by every aggregated type; FU by the FU header. */
|
|
10240
|
+
classifyH265Payload(payload) {
|
|
10241
|
+
if (payload.length < 2) return NO_PAYLOAD_CLASS;
|
|
10242
|
+
const nalType = payload[0] >> 1 & 63;
|
|
10243
|
+
if (nalType === H265_NAL_AP) {
|
|
10244
|
+
let keyframe = false;
|
|
10245
|
+
let parameterSet = false;
|
|
10246
|
+
let offset = 2;
|
|
10247
|
+
while (offset + 2 <= payload.length) {
|
|
10248
|
+
const nalSize = payload.readUInt16BE(offset);
|
|
10249
|
+
offset += 2;
|
|
10250
|
+
if (nalSize === 0 || offset + nalSize > payload.length) break;
|
|
10251
|
+
const type = payload[offset] >> 1 & 63;
|
|
10252
|
+
keyframe ||= isH265IrapType(type);
|
|
10253
|
+
parameterSet ||= isH265ParameterSetType(type);
|
|
10254
|
+
offset += nalSize;
|
|
10255
|
+
}
|
|
10256
|
+
return {
|
|
10257
|
+
keyframe,
|
|
10258
|
+
parameterSet
|
|
10259
|
+
};
|
|
10260
|
+
}
|
|
10261
|
+
if (nalType === 49) {
|
|
10262
|
+
if (payload.length < 3) return NO_PAYLOAD_CLASS;
|
|
10263
|
+
return {
|
|
10264
|
+
keyframe: isH265IrapType(payload[2] & 63),
|
|
10265
|
+
parameterSet: false
|
|
10266
|
+
};
|
|
10267
|
+
}
|
|
10268
|
+
return {
|
|
10269
|
+
keyframe: isH265IrapType(nalType),
|
|
10270
|
+
parameterSet: isH265ParameterSetType(nalType)
|
|
10271
|
+
};
|
|
10181
10272
|
}
|
|
10182
10273
|
processH264(payload, timestamp, marker) {
|
|
10183
10274
|
const nalType = payload[0] & 31;
|
|
@@ -10323,6 +10414,138 @@ var RtpDepacketizer = class {
|
|
|
10323
10414
|
}
|
|
10324
10415
|
};
|
|
10325
10416
|
//#endregion
|
|
10417
|
+
//#region src/stream-broker/rtsp/rtp-access-unit-tracker.ts
|
|
10418
|
+
/**
|
|
10419
|
+
* Tracks access-unit membership across the source RTP packets of ONE stream.
|
|
10420
|
+
*
|
|
10421
|
+
* The RTSP restreamer forwards source RTP untouched and must know, per
|
|
10422
|
+
* packet, whether it is part of a keyframe picture: that is what its keyframe
|
|
10423
|
+
* cache collects and what a backlog-latched session resumes on. The
|
|
10424
|
+
* depacketizer can only say so about a NAL that COMPLETED, so the fragments of
|
|
10425
|
+
* a fragmented IDR before the last one, and a prefix SEI between the parameter
|
|
10426
|
+
* sets and the slice, were reported as plain packets: the cache latch closed
|
|
10427
|
+
* on them and re-opened on the final fragment, and a backlogged session
|
|
10428
|
+
* counted every IRAP slice as a missed keyframe. Here a packet is classified
|
|
10429
|
+
* by what it carries ({@link RtpPacketClass}) and the verdict is carried
|
|
10430
|
+
* across the whole picture, bounded by the RTP timestamp and marker bit.
|
|
10431
|
+
*
|
|
10432
|
+
* A parameter-set-only run is not a picture: a camera that stamps SPS/PPS
|
|
10433
|
+
* with the previous timestamp still announces ONE keyframe, so the keyframe
|
|
10434
|
+
* verdict carries over into the slice that follows instead of starting twice.
|
|
10435
|
+
*/
|
|
10436
|
+
var RtpAccessUnitTracker = class {
|
|
10437
|
+
timestamp = -1;
|
|
10438
|
+
previousMarker = true;
|
|
10439
|
+
keyframeAu = false;
|
|
10440
|
+
/** The picture in progress has received something other than a parameter set. */
|
|
10441
|
+
pictureSeen = false;
|
|
10442
|
+
classify(packet) {
|
|
10443
|
+
const auStart = this.previousMarker || packet.timestamp !== this.timestamp;
|
|
10444
|
+
if (auStart && this.pictureSeen) this.keyframeAu = false;
|
|
10445
|
+
if (auStart) this.pictureSeen = false;
|
|
10446
|
+
this.timestamp = packet.timestamp;
|
|
10447
|
+
this.previousMarker = packet.marker;
|
|
10448
|
+
const keyframeContent = packet.keyframe || packet.parameterSet;
|
|
10449
|
+
const keyframeAuStart = keyframeContent && !this.keyframeAu;
|
|
10450
|
+
if (keyframeContent) this.keyframeAu = true;
|
|
10451
|
+
if (!packet.parameterSet) this.pictureSeen = true;
|
|
10452
|
+
return {
|
|
10453
|
+
auStart,
|
|
10454
|
+
keyframeAu: this.keyframeAu,
|
|
10455
|
+
keyframeAuStart,
|
|
10456
|
+
parameterSet: packet.parameterSet
|
|
10457
|
+
};
|
|
10458
|
+
}
|
|
10459
|
+
/** A redial re-bases the clock; nothing carries over. */
|
|
10460
|
+
reset() {
|
|
10461
|
+
this.timestamp = -1;
|
|
10462
|
+
this.previousMarker = true;
|
|
10463
|
+
this.keyframeAu = false;
|
|
10464
|
+
this.pictureSeen = false;
|
|
10465
|
+
}
|
|
10466
|
+
};
|
|
10467
|
+
//#endregion
|
|
10468
|
+
//#region src/stream-broker/stream-broker/access-unit-assembler.ts
|
|
10469
|
+
/**
|
|
10470
|
+
* Groups depacketized NALs into ACCESS UNITS — one per picture.
|
|
10471
|
+
*
|
|
10472
|
+
* The broker's `EncodedPacket` is one access unit, and every consumer judges it
|
|
10473
|
+
* that way: `keyframe` gates where a clip ring widens to, where a late joiner
|
|
10474
|
+
* can start, how the pre-roll window is cut; the stats count it as one picture
|
|
10475
|
+
* and time the GOP from one `keyframe` to the next. A multi-slice camera (a
|
|
10476
|
+
* Hikvision G2 main stream is 3 slices per picture) used to hand each slice —
|
|
10477
|
+
* and each prefix SEI — down as its own "frame": 75 input fps on a 25 fps
|
|
10478
|
+
* camera, an 8–34 ms "GOP", a clip ring that widened to the LAST IRAP slice
|
|
10479
|
+
* (a third of the picture, without its parameter sets), and a prefix SEI that
|
|
10480
|
+
* inherited the welded VPS/SPS/PPS instead of the IDR.
|
|
10481
|
+
*
|
|
10482
|
+
* Boundary rule (RFC 3550 / 6184 / 7798): the RTP marker bit closes the
|
|
10483
|
+
* picture it ends — flushed on the spot, so a single-slice stream pays no
|
|
10484
|
+
* latency — and a timestamp change closes the one before it, for cameras that
|
|
10485
|
+
* never set the marker. Parameter sets are held and welded onto the picture
|
|
10486
|
+
* that follows them, so a keyframe access unit is self-contained
|
|
10487
|
+
* (VPS/SPS/PPS + IDR) exactly as before; a prefix SEI stays inside its
|
|
10488
|
+
* picture and is never a frame of its own.
|
|
10489
|
+
*/
|
|
10490
|
+
var AccessUnitAssembler = class {
|
|
10491
|
+
onAccessUnit;
|
|
10492
|
+
/** Parameter sets seen since the last picture closed; welded onto the next one. */
|
|
10493
|
+
pendingParamNals = [];
|
|
10494
|
+
/** NALs of the picture in progress (parameter sets first when welded). */
|
|
10495
|
+
pictureNals = [];
|
|
10496
|
+
pictureTimestamp = 0;
|
|
10497
|
+
pictureKeyframe = false;
|
|
10498
|
+
constructor(onAccessUnit) {
|
|
10499
|
+
this.onAccessUnit = onAccessUnit;
|
|
10500
|
+
}
|
|
10501
|
+
push(depacketized) {
|
|
10502
|
+
const { annexB, keyframe, parameterSet, timestamp, marker } = depacketized;
|
|
10503
|
+
if (this.pictureNals.length > 0 && timestamp !== this.pictureTimestamp) this.flush();
|
|
10504
|
+
if (parameterSet) {
|
|
10505
|
+
this.pendingParamNals.push(annexB);
|
|
10506
|
+
return;
|
|
10507
|
+
}
|
|
10508
|
+
if (this.pictureNals.length === 0) {
|
|
10509
|
+
this.pictureTimestamp = timestamp;
|
|
10510
|
+
this.pictureKeyframe = false;
|
|
10511
|
+
}
|
|
10512
|
+
if (this.pendingParamNals.length > 0) {
|
|
10513
|
+
for (const paramNal of this.pendingParamNals) this.pictureNals.push(paramNal);
|
|
10514
|
+
this.pendingParamNals = [];
|
|
10515
|
+
this.pictureKeyframe = true;
|
|
10516
|
+
}
|
|
10517
|
+
this.pictureNals.push(annexB);
|
|
10518
|
+
if (keyframe) this.pictureKeyframe = true;
|
|
10519
|
+
if (marker) this.flush();
|
|
10520
|
+
}
|
|
10521
|
+
/**
|
|
10522
|
+
* Emit the picture in progress, if any. Called on the marker bit, on a
|
|
10523
|
+
* timestamp change, and by the broker when the stream stops or redials so
|
|
10524
|
+
* the last picture of a marker-less stream is not lost.
|
|
10525
|
+
*/
|
|
10526
|
+
flush() {
|
|
10527
|
+
if (this.pictureNals.length === 0) return;
|
|
10528
|
+
const nals = this.pictureNals;
|
|
10529
|
+
const timestamp = this.pictureTimestamp;
|
|
10530
|
+
const keyframe = this.pictureKeyframe;
|
|
10531
|
+
this.pictureNals = [];
|
|
10532
|
+
this.pictureKeyframe = false;
|
|
10533
|
+
const annexB = nals.length === 1 ? nals[0] : Buffer.concat(nals);
|
|
10534
|
+
this.onAccessUnit({
|
|
10535
|
+
annexB,
|
|
10536
|
+
timestamp,
|
|
10537
|
+
keyframe
|
|
10538
|
+
});
|
|
10539
|
+
}
|
|
10540
|
+
/** Drop everything held — a redial re-bases the clock, nothing carries over. */
|
|
10541
|
+
reset() {
|
|
10542
|
+
this.pendingParamNals = [];
|
|
10543
|
+
this.pictureNals = [];
|
|
10544
|
+
this.pictureTimestamp = 0;
|
|
10545
|
+
this.pictureKeyframe = false;
|
|
10546
|
+
}
|
|
10547
|
+
};
|
|
10548
|
+
//#endregion
|
|
10326
10549
|
//#region src/stream-broker/rtsp/rtsp-client.ts
|
|
10327
10550
|
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
10328
10551
|
var DEFAULT_KEEPALIVE_INTERVAL_MS = 3e4;
|
|
@@ -11291,6 +11514,49 @@ var AudioCodecSession = class {
|
|
|
11291
11514
|
}
|
|
11292
11515
|
};
|
|
11293
11516
|
//#endregion
|
|
11517
|
+
//#region src/stream-broker/stream-broker/owned-buffer.ts
|
|
11518
|
+
/**
|
|
11519
|
+
* Buffers that enter a LONG-LIVED ring own their backing store.
|
|
11520
|
+
*
|
|
11521
|
+
* Node serves `Buffer.from(...)`, `Buffer.allocUnsafe(n)` and `Buffer.concat`
|
|
11522
|
+
* below `Buffer.poolSize >>> 1` (4 KiB) as views of shared 8 KiB pool slabs.
|
|
11523
|
+
* That is the right choice for the ingest path — a start code, a 4-byte
|
|
11524
|
+
* interleave header, a 1.3 KB RTP packet that is fanned out and forgotten
|
|
11525
|
+
* within a tick — and the wrong one for anything RETAINED: a 600-byte NAL kept
|
|
11526
|
+
* for 60 s in a clip ring pins its whole slab, and with it every short-lived
|
|
11527
|
+
* packet that happened to be allocated beside it. On the hub that held
|
|
11528
|
+
* 550–980 MB of ArrayBuffers for ~150–250 MB of payload, and the full GCs the
|
|
11529
|
+
* pinned slabs caused ran every 0.2–0.5 s at 40–65 % of a core.
|
|
11530
|
+
*
|
|
11531
|
+
* The ring byte caps counted payload bytes, so they never saw it. Both rings
|
|
11532
|
+
* now pass every entry through {@link detachFromPool} on the way in and
|
|
11533
|
+
* account it with {@link backingStoreBytes}, so the cap measures what the
|
|
11534
|
+
* entry costs. Short-lived traffic stays pooled.
|
|
11535
|
+
*/
|
|
11536
|
+
/** True when `buf` is the whole of its ArrayBuffer — nothing else shares it. */
|
|
11537
|
+
function ownsBackingStore(buf) {
|
|
11538
|
+
return buf.byteOffset === 0 && buf.buffer.byteLength === buf.length;
|
|
11539
|
+
}
|
|
11540
|
+
/**
|
|
11541
|
+
* What retaining `buf` really costs: its own length when it owns its
|
|
11542
|
+
* ArrayBuffer, the whole shared slab when it is a view of one.
|
|
11543
|
+
*/
|
|
11544
|
+
function backingStoreBytes(buf) {
|
|
11545
|
+
return ownsBackingStore(buf) ? buf.length : buf.buffer.byteLength;
|
|
11546
|
+
}
|
|
11547
|
+
/**
|
|
11548
|
+
* `buf` itself when it already owns its ArrayBuffer (decided by inspecting the
|
|
11549
|
+
* buffer, never by its size: whether a large `allocUnsafe` is pooled is a Node
|
|
11550
|
+
* runtime detail), else a copy that does. One copy, never two: a buffer that is
|
|
11551
|
+
* already unpooled is returned as-is.
|
|
11552
|
+
*/
|
|
11553
|
+
function detachFromPool(buf) {
|
|
11554
|
+
if (ownsBackingStore(buf)) return buf;
|
|
11555
|
+
const owned = Buffer.allocUnsafeSlow(buf.length);
|
|
11556
|
+
buf.copy(owned);
|
|
11557
|
+
return owned;
|
|
11558
|
+
}
|
|
11559
|
+
//#endregion
|
|
11294
11560
|
//#region src/stream-broker/stream-broker/encoded-ring-buffer.ts
|
|
11295
11561
|
/**
|
|
11296
11562
|
* Time-based ring buffer for encoded video packets.
|
|
@@ -11301,6 +11567,12 @@ var AudioCodecSession = class {
|
|
|
11301
11567
|
*
|
|
11302
11568
|
* The buffer always starts from the most recent keyframe to ensure
|
|
11303
11569
|
* consumers can decode the returned data.
|
|
11570
|
+
*
|
|
11571
|
+
* Every entry OWNS its backing store (`owned-buffer.ts`): a sub-stream NAL
|
|
11572
|
+
* arrives as a view of a shared 8 KiB pool slab, and a ring that kept it for
|
|
11573
|
+
* 60 s pinned the slab and every short-lived packet beside it — the clip
|
|
11574
|
+
* rings of ~70 brokers were the largest holder of the hub broker's
|
|
11575
|
+
* 550–980 MB of ArrayBuffers. The byte budget charges what an entry pins.
|
|
11304
11576
|
*/
|
|
11305
11577
|
var EncodedRingBuffer = class {
|
|
11306
11578
|
packets = [];
|
|
@@ -11332,13 +11604,25 @@ var EncodedRingBuffer = class {
|
|
|
11332
11604
|
getDuration() {
|
|
11333
11605
|
return this.maxDurationMs / 1e3;
|
|
11334
11606
|
}
|
|
11335
|
-
/**
|
|
11607
|
+
/**
|
|
11608
|
+
* Push a new packet into the buffer and evict expired ones.
|
|
11609
|
+
*
|
|
11610
|
+
* A pooled payload is copied into its own allocation on the way in; one
|
|
11611
|
+
* that already owns its ArrayBuffer is stored as-is. The consumers fanned
|
|
11612
|
+
* out from the same packet keep the original, so the copy is the ring's
|
|
11613
|
+
* alone and is freed with it.
|
|
11614
|
+
*/
|
|
11336
11615
|
push(packet) {
|
|
11337
|
-
|
|
11338
|
-
|
|
11616
|
+
const data = detachFromPool(packet.data);
|
|
11617
|
+
const stored = data === packet.data ? packet : {
|
|
11618
|
+
...packet,
|
|
11619
|
+
data
|
|
11620
|
+
};
|
|
11621
|
+
this.packets.push(stored);
|
|
11622
|
+
this.bytes += backingStoreBytes(data);
|
|
11339
11623
|
this.evict();
|
|
11340
11624
|
}
|
|
11341
|
-
/** What the retained window currently costs, in bytes. */
|
|
11625
|
+
/** What the retained window currently costs, in bytes of backing store. */
|
|
11342
11626
|
getBufferedBytes() {
|
|
11343
11627
|
return this.bytes;
|
|
11344
11628
|
}
|
|
@@ -11416,14 +11700,14 @@ var EncodedRingBuffer = class {
|
|
|
11416
11700
|
let removeCount = 0;
|
|
11417
11701
|
while (removeCount < this.packets.length && (this.packets[removeCount].pts < cutoff || this.packets[removeCount].pts > newest)) removeCount++;
|
|
11418
11702
|
if (removeCount > 0) {
|
|
11419
|
-
for (let i = 0; i < removeCount; i++) this.bytes -= this.packets[i].data
|
|
11703
|
+
for (let i = 0; i < removeCount; i++) this.bytes -= backingStoreBytes(this.packets[i].data);
|
|
11420
11704
|
this.packets.splice(0, removeCount);
|
|
11421
11705
|
}
|
|
11422
11706
|
if (this.maxBytes > 0 && this.bytes > this.maxBytes) {
|
|
11423
11707
|
this.clampedByBytes = true;
|
|
11424
11708
|
let dropped = 0;
|
|
11425
11709
|
while (dropped < this.packets.length && this.bytes > this.maxBytes) {
|
|
11426
|
-
this.bytes -= this.packets[dropped].data
|
|
11710
|
+
this.bytes -= backingStoreBytes(this.packets[dropped].data);
|
|
11427
11711
|
dropped++;
|
|
11428
11712
|
}
|
|
11429
11713
|
if (dropped > 0) this.packets.splice(0, dropped);
|
|
@@ -13087,7 +13371,7 @@ var StreamBroker = class StreamBroker {
|
|
|
13087
13371
|
this.rtspRestreamer.destroy();
|
|
13088
13372
|
this.preBuffer.clear();
|
|
13089
13373
|
this.clipBuffer?.clear();
|
|
13090
|
-
this.
|
|
13374
|
+
this.annexBAssembler.reset();
|
|
13091
13375
|
this.encodedCallbacks.clear();
|
|
13092
13376
|
this.audioChunkPlane.dispose();
|
|
13093
13377
|
}
|
|
@@ -13550,7 +13834,7 @@ var StreamBroker = class StreamBroker {
|
|
|
13550
13834
|
this.reconcilePrestreamWindow();
|
|
13551
13835
|
this.preBuffer.clear();
|
|
13552
13836
|
this.clipBuffer?.clear();
|
|
13553
|
-
this.
|
|
13837
|
+
this.annexBAssembler.reset();
|
|
13554
13838
|
this.rtspRestreamer.resetStreamState();
|
|
13555
13839
|
this.totalBytes = 0;
|
|
13556
13840
|
this.bytesInWindow = 0;
|
|
@@ -13859,8 +14143,9 @@ var StreamBroker = class StreamBroker {
|
|
|
13859
14143
|
captureRtpForPreBuffer(rtpData) {
|
|
13860
14144
|
const marker = rtpData.length > 1 && (rtpData[1] & 128) !== 0;
|
|
13861
14145
|
if (this.rtpRingPrevMarker || this.rtpRing.length === 0) this.rtpRingCurAuStart = this.rtpRing.length;
|
|
13862
|
-
|
|
13863
|
-
this.
|
|
14146
|
+
const owned = detachFromPool(rtpData);
|
|
14147
|
+
this.rtpRing.push(owned);
|
|
14148
|
+
this.rtpRingBytes += backingStoreBytes(owned);
|
|
13864
14149
|
if (this._lastNalParamSet || this._lastNalKeyframe) {
|
|
13865
14150
|
const auStart = this.rtpRingCurAuStart;
|
|
13866
14151
|
const lastMark = this.rtpRingKeyframeMarks[this.rtpRingKeyframeMarks.length - 1];
|
|
@@ -14038,18 +14323,18 @@ var StreamBroker = class StreamBroker {
|
|
|
14038
14323
|
this.reportPreRollClamp(budget, retentionMs);
|
|
14039
14324
|
const historyEnd = this.rtpRingKeyframeMarks[this.rtpRingKeyframeMarks.length - 1].index;
|
|
14040
14325
|
let retained = 0;
|
|
14041
|
-
for (let i = cut; i < historyEnd; i++) retained += this.rtpRing[i]
|
|
14326
|
+
for (let i = cut; i < historyEnd; i++) retained += backingStoreBytes(this.rtpRing[i]);
|
|
14042
14327
|
let markIdx = this.rtpRingKeyframeMarks.findIndex((m) => m.index === cut);
|
|
14043
14328
|
while (retained > budget.bytes && markIdx >= 0 && markIdx < this.rtpRingKeyframeMarks.length - 1) {
|
|
14044
14329
|
const nextCut = this.rtpRingKeyframeMarks[markIdx + 1].index;
|
|
14045
|
-
for (let i = cut; i < nextCut; i++) retained -= this.rtpRing[i]
|
|
14330
|
+
for (let i = cut; i < nextCut; i++) retained -= backingStoreBytes(this.rtpRing[i]);
|
|
14046
14331
|
cut = nextCut;
|
|
14047
14332
|
markIdx++;
|
|
14048
14333
|
}
|
|
14049
14334
|
}
|
|
14050
14335
|
if (cut <= 0) return;
|
|
14051
14336
|
const dropped = this.rtpRing.splice(0, cut);
|
|
14052
|
-
for (const b of dropped) this.rtpRingBytes -= b
|
|
14337
|
+
for (const b of dropped) this.rtpRingBytes -= backingStoreBytes(b);
|
|
14053
14338
|
this.rtpRingKeyframeMarks = this.rtpRingKeyframeMarks.filter((mark) => mark.index >= cut).map((mark) => ({
|
|
14054
14339
|
index: mark.index - cut,
|
|
14055
14340
|
ts: mark.ts
|
|
@@ -14389,11 +14674,15 @@ var StreamBroker = class StreamBroker {
|
|
|
14389
14674
|
if (clamped === this.clipRetentionSec) return;
|
|
14390
14675
|
const previous = this.clipRetentionSec;
|
|
14391
14676
|
this.clipRetentionSec = clamped;
|
|
14392
|
-
this.logger?.info(clamped === 0 ? "Clip retention off" : "Clip retention set", {
|
|
14393
|
-
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
|
|
14677
|
+
this.logger?.info(clamped === 0 ? "Clip retention off" : "Clip retention set", {
|
|
14678
|
+
tags: { deviceId: this.numericDeviceId },
|
|
14679
|
+
meta: {
|
|
14680
|
+
seconds: clamped,
|
|
14681
|
+
requested: seconds,
|
|
14682
|
+
previousSeconds: previous,
|
|
14683
|
+
capBytes: StreamBroker.CLIP_RING_MAX_BYTES
|
|
14684
|
+
}
|
|
14685
|
+
});
|
|
14397
14686
|
if (clamped === 0) {
|
|
14398
14687
|
this.clipBuffer = null;
|
|
14399
14688
|
return;
|
|
@@ -14626,8 +14915,9 @@ var StreamBroker = class StreamBroker {
|
|
|
14626
14915
|
} });
|
|
14627
14916
|
this._lastNalKeyframe = false;
|
|
14628
14917
|
this._lastNalParamSet = false;
|
|
14629
|
-
this.rtpDepacketizer?.processPacket(rtpData);
|
|
14630
|
-
this.
|
|
14918
|
+
const carried = this.rtpDepacketizer?.processPacket(rtpData) ?? null;
|
|
14919
|
+
const auFlags = carried ? this.rtpAuTracker.classify(carried) : null;
|
|
14920
|
+
this.rtspRestreamer.pushRtpPassthrough(rtpData, auFlags?.keyframeAu ?? false, auFlags?.parameterSet ?? false);
|
|
14631
14921
|
this.captureRtpForPreBuffer(rtpData);
|
|
14632
14922
|
if (this.rtpVideoCallbacks.size > 0) for (const [cb, entry] of this.rtpVideoCallbacks) try {
|
|
14633
14923
|
cb(rtpData);
|
|
@@ -14823,51 +15113,44 @@ var StreamBroker = class StreamBroker {
|
|
|
14823
15113
|
* RTSP restreamer's pushRtpPassthrough.
|
|
14824
15114
|
*/
|
|
14825
15115
|
/**
|
|
14826
|
-
*
|
|
14827
|
-
*
|
|
14828
|
-
*
|
|
14829
|
-
*
|
|
14830
|
-
* with a single `EncodedPacket` that contains SPS+PPS+IDR together.
|
|
15116
|
+
* Groups the depacketizer's NALs into access units — ONE `EncodedPacket`
|
|
15117
|
+
* per picture, parameter sets welded onto the keyframe picture they
|
|
15118
|
+
* precede. See `access-unit-assembler.ts` for the boundary rule and the
|
|
15119
|
+
* per-NAL emit it replaced.
|
|
14831
15120
|
*/
|
|
14832
|
-
|
|
15121
|
+
annexBAssembler = new AccessUnitAssembler((accessUnit) => this.emitAccessUnit(accessUnit));
|
|
15122
|
+
/** Access-unit membership of the source RTP packets, for the restreamer's flags. */
|
|
15123
|
+
rtpAuTracker = new RtpAccessUnitTracker();
|
|
14833
15124
|
/**
|
|
14834
15125
|
* handleDepacketizedNal receives individual NALs from the RTP depacketizer
|
|
14835
|
-
* and
|
|
14836
|
-
*
|
|
14837
|
-
*
|
|
14838
|
-
*
|
|
14839
|
-
* This guarantees every keyframe EncodedPacket is a self-contained access
|
|
14840
|
-
* unit that a decoder can initialise from — critical for WebRTC (Chrome
|
|
14841
|
-
* can't decode an IDR without preceding SPS/PPS).
|
|
15126
|
+
* and hands them to the access-unit assembler, which emits one
|
|
15127
|
+
* `EncodedPacket` per PICTURE (`emitAccessUnit`) — never per NAL. A
|
|
15128
|
+
* multi-slice IDR, its parameter sets and its prefix SEI are one keyframe
|
|
15129
|
+
* packet; three P slices are one P packet.
|
|
14842
15130
|
*
|
|
14843
|
-
* The RTSP restreamer
|
|
14844
|
-
* not
|
|
15131
|
+
* The RTSP restreamer forwards source RTP separately (`onVideoRtp`) and is
|
|
15132
|
+
* not fed from here.
|
|
14845
15133
|
*/
|
|
14846
15134
|
handleDepacketizedNal(depacketized) {
|
|
14847
|
-
|
|
15135
|
+
if (depacketized.keyframe) this._lastNalKeyframe = true;
|
|
15136
|
+
if (depacketized.parameterSet) this._lastNalParamSet = true;
|
|
15137
|
+
this.annexBAssembler.push(depacketized);
|
|
15138
|
+
}
|
|
15139
|
+
/**
|
|
15140
|
+
* One assembled access unit → one `EncodedPacket` for every Annex-B
|
|
15141
|
+
* consumer (prebuffer, clip ring, pipe, WebRTC). A keyframe packet is
|
|
15142
|
+
* self-contained (VPS/SPS/PPS + every IDR slice), which is what a decoder
|
|
15143
|
+
* initialises from and what a clip or a pre-roll window may start at.
|
|
15144
|
+
*/
|
|
15145
|
+
emitAccessUnit(accessUnit) {
|
|
14848
15146
|
const codec = this.detectedCodec ?? "h264";
|
|
14849
|
-
|
|
14850
|
-
if (parameterSet) this._lastNalParamSet = true;
|
|
14851
|
-
const isH264 = codec === "h264";
|
|
14852
|
-
const nalType = isH264 ? nal[0] & 31 : (nal[0] & 126) >> 1;
|
|
14853
|
-
if (isH264 ? nalType === 7 || nalType === 8 : nalType === 32 || nalType === 33 || nalType === 34) {
|
|
14854
|
-
this.pendingParamNals.push(depacketized.annexB);
|
|
14855
|
-
return;
|
|
14856
|
-
}
|
|
14857
|
-
const hadParamSets = this.pendingParamNals.length > 0;
|
|
14858
|
-
let annexBData;
|
|
14859
|
-
if (hadParamSets) {
|
|
14860
|
-
this.pendingParamNals.push(depacketized.annexB);
|
|
14861
|
-
annexBData = Buffer.concat(this.pendingParamNals);
|
|
14862
|
-
this.pendingParamNals = [];
|
|
14863
|
-
} else annexBData = depacketized.annexB;
|
|
14864
|
-
const pts = Math.floor(timestamp / 90);
|
|
15147
|
+
const pts = Math.floor(accessUnit.timestamp / 90);
|
|
14865
15148
|
const packet = {
|
|
14866
15149
|
type: "video",
|
|
14867
|
-
data:
|
|
15150
|
+
data: accessUnit.annexB,
|
|
14868
15151
|
pts,
|
|
14869
15152
|
dts: pts,
|
|
14870
|
-
keyframe: keyframe
|
|
15153
|
+
keyframe: accessUnit.keyframe,
|
|
14871
15154
|
codec
|
|
14872
15155
|
};
|
|
14873
15156
|
this.pushEncodedPacket(packet);
|
|
@@ -15271,6 +15554,9 @@ var StreamBroker = class StreamBroker {
|
|
|
15271
15554
|
this.rtpDepacketizer.reset();
|
|
15272
15555
|
this.rtpDepacketizer = null;
|
|
15273
15556
|
}
|
|
15557
|
+
this.annexBAssembler.flush();
|
|
15558
|
+
this.annexBAssembler.reset();
|
|
15559
|
+
this.rtpAuTracker.reset();
|
|
15274
15560
|
if (this.pushRtpFlagDepacketizer) {
|
|
15275
15561
|
this.pushRtpFlagDepacketizer.reset();
|
|
15276
15562
|
this.pushRtpFlagDepacketizer = null;
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-vdmrukBk.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.364",
|
|
4
4
|
"description": "Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|