Class: shaka.msf.LOCParser

Constructor

new LOCParser(codecnon-null, frameDuration, normalizedCodecopt)

Parameters:
Name Type Attributes Description
codec shaka.extern.MsfCodec The negotiated draft's primitive codec, used to read the variable-length integers inside the Object Properties block. Draft-17 changed that encoding, so the same property bytes mean different numbers depending on which draft delivered them.
frameDuration number
normalizedCodec string <optional>
The track's codec as returned by shaka.util.MimeUtils.getNormalizedCodec, used to decode the Video Config property. Omit for tracks that cannot carry one.
Source:
See:

Members

SNAP_TOLERANCE_FRAMES_ :number

How far, in frame durations, a LOC timestamp may sit from the previous reference's end and still be treated as publish-clock noise rather than a discontinuity. A real discontinuity is a track switch or a source change, which is orders of magnitude larger than this.
Type:
  • number
Source:

SNAP_TOLERANCE_MIN_SEC_ :number

Minimum snap tolerance in seconds, regardless of frame duration. Jitter is absolute, not proportional to frame rate, so a frame-counted tolerance under-serves short frames: two frames of 48 kHz AAC is 42.7 ms, which is inside the range ordinary publish-clock wander reaches.
Type:
  • number
Source:

TIMESCALE_ID_ :number

ID of the LOC Timescale property (draft-ietf-moq-loc-04 §2.3.1.2). Unchanged across draft-02 and draft-04. Even, so the value is a bare vi64.
Type:
  • number
Source:

TIMESTAMP_ID_ :number

ID of the LOC Timestamp property (draft-ietf-moq-loc-04 §2.3.1.1). Even, so the value is a bare vi64.
Type:
  • number
Source:

TIMESTAMP_ID_LEGACY_ :number

ID the LOC Timestamp property used up to draft-ietf-moq-loc-02. Accepted alongside the current ID because publishers of both vintages are deployed. It is read only when the current ID is absent, so a publisher that sends 0x10 is never affected by it.
Type:
  • number
Source:

VIDEO_CONFIG_ID_ :number

ID of the LOC Video Config property (draft-ietf-moq-loc-04 §2.3.2.1). Odd, so the value is a length-prefixed byte string: the codec's extradata, which is an AVCDecoderConfigurationRecord for H.264 and an HEVCDecoderConfigurationRecord for H.265. Carried only on key frames, and only by publishers that strip parameter sets from the bitstream.
Type:
  • number
Source:

frameDuration_ :number

Type:
  • number
Source:

lastEndTime_ :number

End time of the last reference this parser emitted, or null before the first one. See snapStartTime_.
Type:
  • number
Source:

normalizedCodec_ :string

Type:
  • string
Source:

Methods

avcParameterSets_(confignon-null) → {Array<!Uint8Array>}

Extracts the SPS and PPS NAL units from an AVCDecoderConfigurationRecord (ISO/IEC 14496-15 §5.3.3.1), or null if the record is malformed.
Parameters:
Name Type Description
config Uint8Array
Source:
Returns:
Type
Array<!Uint8Array>

frameDurationFromTrack(track) → {number}

Computes the fixed frame duration (seconds) for a LOC track from MSF catalog fields. Rules: - Video: `1 / track.framerate` - Audio AAC (`mp4a.40.2`, AAC-LC): `1024 / track.samplerate` (AAC-LC always uses 1024 samples per frame per ISO 14496-3) - Audio Opus: `960 / track.samplerate` (standard 20 ms Opus frame at any sample rate)
Parameters:
Name Type Description
track msfCatalog.Track
Source:
Returns:
Type
number

hevcParameterSets_(confignon-null) → {Array<!Uint8Array>}

Extracts the VPS, SPS and PPS NAL units from an HEVCDecoderConfigurationRecord (ISO/IEC 14496-15 §8.3.3.1), or null if the record is malformed. The record groups NAL units into arrays keyed by type rather than listing them in a fixed order, and H265.parseInfo() needs all three, so every array is emitted in the order the record lists them.
Parameters:
Name Type Description
config Uint8Array
Source:
Returns:
Type
Array<!Uint8Array>

prependAv1ConfigObus_(payloadnon-null, confignon-null) → {Uint8Array}

Prepends the configOBUs of an AV1CodecConfigurationRecord to `payload`. The record (AV1 ISOBMFF binding §2.3.3) is four fixed bytes describing the decoder requirements, followed by configOBUs — the sequence header OBU, byte for byte as it would appear in the bitstream. Only those trailing bytes belong in the temporal unit; the fixed four are a container-level summary and would decode as a stray OBU. Returns `payload` unchanged when the record is malformed or carries no OBUs, so a bad config degrades to the previous behaviour.
Parameters:
Name Type Description
payload Uint8Array
config Uint8Array
Source:
Returns:
Type
Uint8Array

readSizedNalu_(confignon-null, offset) → {?{data: !Uint8Array, offset: number}}

Reads one 2-byte big-endian length-prefixed NAL unit from a decoder configuration record, or null if it does not fit.
Parameters:
Name Type Description
config Uint8Array
offset number
Source:
Returns:
Type
?{data: !Uint8Array, offset: number}

parse(objnon-null) → {!{startTime: number, duration: number, payload: !Uint8Array}}

Parses a single LOC MoQ object. Resolves `startTime` in priority order: 1. Timestamp property in public properties (`obj.extensions`) 2. Fallback: `groupId × frameDuration`
Parameters:
Name Type Description
obj shaka.msf.Utils.MOQObject
Source:
Returns:
Type
!{startTime: number, duration: number, payload: !Uint8Array}

parseExtensions_(datanon-null) → {Map<bigint, (bigint|!Uint8Array)>}

Parses the raw MOQ Object Properties buffer into a property map. Wire format — a flat sequence of MOQT Key-Value-Pairs (draft-ietf-moq-transport-18 §1.4.3) running to the end of the buffer; the total-length prefix was already consumed by the transport layer before storing the bytes in `obj.extensions`: delta type (vi64) value: vi64 when the resolved type is even length (vi64) + bytes when the resolved type is odd Types are DELTA encoded against the previous type in the block, starting from 0. Reading them as absolute is worse than dropping the trailing properties: a delta can collide with a real type and bind an unrelated property's value to it. With Timestamp and Timescale present the deltas are 6 and 2, so an absolute read loses Timescale entirely and timestampToSeconds_ silently falls back to its microsecond default. If parsing throws at any point the partial map built so far is returned, so callers always receive a valid (possibly empty) map.
Parameters:
Name Type Description
data Uint8Array Raw bytes from `obj.extensions`.
Source:
Returns:
Type
Map<bigint, (bigint|!Uint8Array)>

prependParameterSets_(payloadnon-null, confignon-null) → {Uint8Array}

Prepends the parameter sets carried in the Video Config property to `payload`, as 4-byte length-prefixed NAL units. LOC-04 §2.3.2.1 defines Video Config as "the extradata bytes defined by the corresponding codec specification", so its layout depends on the codec: an AVCDecoderConfigurationRecord for H.264, an HEVCDecoderConfigurationRecord for H.265, and an AV1CodecConfigurationRecord for AV1. A publisher that uses it has stripped the parameter sets from the bitstream (§2.1.2), so re-inlining them here restores exactly what was removed, at the earliest point, and every downstream consumer stays unchanged — in-band parameter sets ahead of a key frame are what decoders expect anyway. The record's own `lengthSizeMinusOne` describes how the RECORD frames its entries, not how the bitstream frames its NAL units, so the restored sets are always emitted with the 4-byte prefix LOC-04 §2.1.3 specifies. AV1 is the exception to that framing: OBUs are self-delimiting, carrying their own type and size, and a temporal unit is a bare concatenation of them. A length prefix would be read as an OBU header and desynchronise the whole unit, so the sequence header OBUs are concatenated raw. Returns `payload` unchanged when the codec has no known record layout or the record is malformed: a bad config must degrade to the previous behaviour rather than corrupt the bitstream.
Parameters:
Name Type Description
payload Uint8Array
config Uint8Array The Video Config property value.
Source:
Returns:
Type
Uint8Array

readVi64At_(buffernon-null, offset) → {{value: bigint, bytesRead: number}}

Reads one variable-length integer from `buffer` at byte `offset`, in whichever encoding the negotiated draft uses. Draft-17 replaced the QUIC two-bit size tag with a leading-ones count, so the same bytes mean different numbers under the two, and Object Properties are the one place a packaging has to read them itself. Synchronous equivalent of `Reader.u62WithSize()` in msf_classes.js.
Parameters:
Name Type Description
buffer Uint8Array
offset number
Source:
Returns:
Type
{value: bigint, bytesRead: number}

snapStartTime_(startTime) → {number}

Snaps `startTime` onto the previous reference's end time when it is close enough to be publish-clock noise rather than a real discontinuity. A LOC reference is assembled from two different clocks: `startTime` comes from the publisher's Timestamp, `duration` is a constant derived from the catalog. The two cannot agree exactly, so consecutive references overlap or leave a hole — even a publisher whose timestamps are exact leaves sub-microsecond gaps, because a frame duration such as 1024/48000 s is not representable in whole timestamp units. That is not cosmetic, and the size of the gap barely matters. StreamingEngine asks for the segment covering the previous reference's endTime; when that instant falls in a hole of ANY width, SegmentIndex.find() returns null and update_ takes its "segment could not be found ... just try again" path, backing off half a segment and retrying instead of appending. Beyond the tolerance the publisher's clock stays authoritative, so a real discontinuity still resyncs the timeline. The trade-off is explicit: within the tolerance a genuinely lost frame is closed up rather than preserved as a gap, which advances this track against the others by that frame's duration. For live playback that is the right trade — a lost frame is inaudible or invisible, a hole stalls outright, and the drift is bounded because any real discontinuity re-anchors on the publisher's clock.
Parameters:
Name Type Description
startTime number
Source:
Returns:
Type
number

timestampToSeconds_(timestamp, timescale) → {number}

Converts a raw LOC Timestamp value to presentation seconds. Per LOC §2.3.1.1–§2.3.1.2: - When `timescale` is present: `seconds = timestamp / timescale` - When `timescale` is absent: the timestamp is wall-clock µs since the Unix epoch, so the implicit timescale is 1 000 000.
Parameters:
Name Type Description
timestamp bigint Raw vi64 timestamp value.
timescale bigint | undefined Raw vi64 timescale, or `undefined` if the Timescale property was absent.
Source:
Returns:
Type
number