0
# Utilities and Helpers
1
2
Shared utilities for time conversion, binary data handling, stream processing, and mathematical operations that support the core functionality across all mux.js modules.
3
4
## Capabilities
5
6
### Stream Base Class
7
8
Foundation class for all streaming operations in mux.js, providing consistent event-driven processing patterns.
9
10
```javascript { .api }
11
/**
12
* Base class for all stream processing in mux.js
13
* Provides event system and pipeline connectivity
14
*/
15
class Stream {
16
constructor();
17
18
/** Initialize stream (called during construction) */
19
init(): void;
20
21
/** Add event listener */
22
on(type: string, listener: Function): void;
23
24
/** Remove event listener */
25
off(type: string, listener: Function): void;
26
27
/** Trigger event with optional arguments */
28
trigger(type: string, ...args: any[]): void;
29
30
/** Clean up resources and remove listeners */
31
dispose(): void;
32
33
/** Connect this stream to another stream */
34
pipe(destination: Stream): Stream;
35
36
/** Process data (override in subclasses) */
37
push(data: any): void;
38
39
/** Complete processing and emit final data */
40
flush(flushSource?: Stream): void;
41
42
/** Partial flush for segment boundaries */
43
partialFlush(flushSource?: Stream): void;
44
45
/** End timeline processing */
46
endTimeline(flushSource?: Stream): void;
47
48
/** Reset stream state */
49
reset(flushSource?: Stream): void;
50
}
51
```
52
53
**Usage Example:**
54
55
```javascript
56
const muxjs = require("mux.js");
57
58
// Create custom stream by extending base class
59
class CustomTransformStream extends muxjs.utils.Stream {
60
constructor() {
61
super();
62
this.buffer = [];
63
}
64
65
push(data) {
66
// Transform incoming data
67
const transformed = this.transformData(data);
68
this.buffer.push(transformed);
69
70
// Emit when buffer is full
71
if (this.buffer.length >= 10) {
72
this.trigger('data', this.buffer.splice(0, 10));
73
}
74
}
75
76
flush() {
77
// Emit remaining data
78
if (this.buffer.length > 0) {
79
this.trigger('data', this.buffer.splice(0));
80
}
81
this.trigger('done');
82
}
83
84
transformData(data) {
85
// Custom transformation logic
86
return data;
87
}
88
}
89
90
// Use custom stream
91
const customStream = new CustomTransformStream();
92
93
customStream.on('data', function(transformedData) {
94
console.log('Transformed data:', transformedData);
95
});
96
97
customStream.on('done', function() {
98
console.log('Processing complete');
99
});
100
```
101
102
### Clock and Time Conversion Utilities
103
104
Comprehensive time conversion utilities for handling different timestamp formats used in video streaming.
105
106
```javascript { .api }
107
/** 90kHz clock rate used in video timestamps */
108
const ONE_SECOND_IN_TS = 90000;
109
110
/**
111
* Convert seconds to video timestamps (90kHz)
112
* @param seconds - Time in seconds
113
* @returns Timestamp in 90kHz units
114
*/
115
function secondsToVideoTs(seconds: number): number;
116
117
/**
118
* Convert seconds to audio timestamps
119
* @param seconds - Time in seconds
120
* @param sampleRate - Audio sample rate (e.g., 44100, 48000)
121
* @returns Timestamp in sample rate units
122
*/
123
function secondsToAudioTs(seconds: number, sampleRate: number): number;
124
125
/**
126
* Convert video timestamps to seconds
127
* @param timestamp - Timestamp in 90kHz units
128
* @returns Time in seconds
129
*/
130
function videoTsToSeconds(timestamp: number): number;
131
132
/**
133
* Convert audio timestamps to seconds
134
* @param timestamp - Timestamp in sample rate units
135
* @param sampleRate - Audio sample rate
136
* @returns Time in seconds
137
*/
138
function audioTsToSeconds(timestamp: number, sampleRate: number): number;
139
140
/**
141
* Convert audio timestamps to video timestamps
142
* @param timestamp - Audio timestamp in sample rate units
143
* @param sampleRate - Audio sample rate
144
* @returns Video timestamp in 90kHz units
145
*/
146
function audioTsToVideoTs(timestamp: number, sampleRate: number): number;
147
148
/**
149
* Convert video timestamps to audio timestamps
150
* @param timestamp - Video timestamp in 90kHz units
151
* @param sampleRate - Audio sample rate
152
* @returns Audio timestamp in sample rate units
153
*/
154
function videoTsToAudioTs(timestamp: number, sampleRate: number): number;
155
156
/**
157
* Convert metadata timestamps to seconds with timeline adjustment
158
* @param timestamp - Metadata timestamp
159
* @param timelineStartPts - Timeline start PTS
160
* @param keepOriginalTimestamps - Whether to preserve original timing
161
* @returns Time in seconds
162
*/
163
function metadataTsToSeconds(
164
timestamp: number,
165
timelineStartPts: number,
166
keepOriginalTimestamps: boolean
167
): number;
168
```
169
170
**Usage Example:**
171
172
```javascript
173
const muxjs = require("mux.js");
174
const clock = muxjs.utils.clock;
175
176
// Convert between different timestamp formats
177
const seconds = 10.5;
178
const videoTs = clock.secondsToVideoTs(seconds);
179
console.log('10.5 seconds =', videoTs, 'video timestamp units');
180
181
const audioTs = clock.secondsToAudioTs(seconds, 48000);
182
console.log('10.5 seconds =', audioTs, 'audio timestamp units at 48kHz');
183
184
// Convert back to seconds
185
const backToSeconds = clock.videoTsToSeconds(videoTs);
186
console.log('Converted back:', backToSeconds, 'seconds');
187
188
// Cross-format conversion
189
const audioToVideo = clock.audioTsToVideoTs(audioTs, 48000);
190
console.log('Audio timestamp as video timestamp:', audioToVideo);
191
192
// Timeline calculations
193
const metadataTime = clock.metadataTsToSeconds(
194
945000, // metadata timestamp
195
90000, // timeline start (1 second)
196
false // adjust for timeline
197
);
198
console.log('Metadata time:', metadataTime, 'seconds');
199
```
200
201
### Binary Data Utilities
202
203
Low-level utilities for binary data manipulation and parsing.
204
205
```javascript { .api }
206
/**
207
* Binary data manipulation utilities
208
*/
209
const bin = {
210
/**
211
* Read big-endian 32-bit unsigned integer
212
* @param data - Data buffer
213
* @param offset - Byte offset
214
* @returns 32-bit unsigned integer
215
*/
216
readUint32BE(data: Uint8Array, offset: number): number;
217
218
/**
219
* Read big-endian 16-bit unsigned integer
220
* @param data - Data buffer
221
* @param offset - Byte offset
222
* @returns 16-bit unsigned integer
223
*/
224
readUint16BE(data: Uint8Array, offset: number): number;
225
226
/**
227
* Write big-endian 32-bit unsigned integer
228
* @param data - Data buffer
229
* @param offset - Byte offset
230
* @param value - Value to write
231
*/
232
writeUint32BE(data: Uint8Array, offset: number, value: number): void;
233
234
/**
235
* Write big-endian 16-bit unsigned integer
236
* @param data - Data buffer
237
* @param offset - Byte offset
238
* @param value - Value to write
239
*/
240
writeUint16BE(data: Uint8Array, offset: number, value: number): void;
241
};
242
```
243
244
### Exponential Golomb Decoder
245
246
Specialized decoder for exponential Golomb encoded values used in H.264 streams.
247
248
```javascript { .api }
249
/**
250
* Exponential Golomb decoder for H.264 parameter parsing
251
*/
252
class ExpGolomb {
253
constructor(data: Uint8Array);
254
255
/** Read unsigned exponential Golomb coded integer */
256
readUnsignedExpGolomb(): number;
257
258
/** Read signed exponential Golomb coded integer */
259
readSignedExpGolomb(): number;
260
261
/** Read single bit */
262
readBits(count: number): number;
263
264
/** Skip bits */
265
skipBits(count: number): void;
266
267
/** Skip leading zero bits */
268
skipLeadingZeros(): number;
269
}
270
```
271
272
**Usage Example:**
273
274
```javascript
275
const muxjs = require("mux.js");
276
277
// Parse H.264 SPS (Sequence Parameter Set) data
278
function parseSPS(spsData) {
279
const expGolomb = new muxjs.utils.ExpGolomb(spsData);
280
281
// Skip NAL header
282
expGolomb.skipBits(8);
283
284
// Read profile information
285
const profileIdc = expGolomb.readBits(8);
286
const constraintFlags = expGolomb.readBits(8);
287
const levelIdc = expGolomb.readBits(8);
288
289
// Read SPS ID
290
const spsId = expGolomb.readUnsignedExpGolomb();
291
292
console.log('H.264 SPS Info:');
293
console.log(' Profile IDC:', profileIdc);
294
console.log(' Level IDC:', levelIdc);
295
console.log(' SPS ID:', spsId);
296
297
return {
298
profileIdc,
299
constraintFlags,
300
levelIdc,
301
spsId
302
};
303
}
304
```
305
306
### String Utilities
307
308
String processing utilities for codec and container data handling.
309
310
```javascript { .api }
311
/**
312
* String manipulation utilities
313
*/
314
const stringUtils = {
315
/**
316
* Convert byte array to ASCII string
317
* @param data - Byte array
318
* @param offset - Start offset (default: 0)
319
* @param length - Length to read (default: remaining)
320
* @returns ASCII string
321
*/
322
bytesToString(data: Uint8Array, offset?: number, length?: number): string;
323
324
/**
325
* Convert ASCII string to byte array
326
* @param str - ASCII string
327
* @returns Byte array
328
*/
329
stringToBytes(str: string): Uint8Array;
330
331
/**
332
* Parse null-terminated string from byte array
333
* @param data - Byte array
334
* @param offset - Start offset
335
* @returns Parsed string and new offset
336
*/
337
parseNullTerminatedString(data: Uint8Array, offset: number): {
338
string: string;
339
offset: number;
340
};
341
};
342
```
343
344
### Typed Array Utilities
345
346
Utilities for working with typed arrays and memory management.
347
348
```javascript { .api }
349
/**
350
* Typed array manipulation utilities
351
*/
352
const typedArray = {
353
/**
354
* Concatenate multiple typed arrays
355
* @param arrays - Arrays to concatenate
356
* @returns New concatenated array
357
*/
358
concat(...arrays: Uint8Array[]): Uint8Array;
359
360
/**
361
* Slice typed array (similar to Array.slice)
362
* @param array - Source array
363
* @param start - Start index
364
* @param end - End index (exclusive)
365
* @returns New sliced array
366
*/
367
slice(array: Uint8Array, start: number, end?: number): Uint8Array;
368
369
/**
370
* Compare two typed arrays for equality
371
* @param a - First array
372
* @param b - Second array
373
* @returns True if arrays are equal
374
*/
375
equal(a: Uint8Array, b: Uint8Array): boolean;
376
377
/**
378
* Find byte pattern in array
379
* @param haystack - Array to search in
380
* @param needle - Pattern to find
381
* @param start - Start search index
382
* @returns Index of pattern or -1 if not found
383
*/
384
indexOf(haystack: Uint8Array, needle: Uint8Array, start?: number): number;
385
};
386
```
387
388
### Number Utilities
389
390
Mathematical utilities for bit operations and number manipulation.
391
392
```javascript { .api }
393
/**
394
* Number and bit manipulation utilities
395
*/
396
const numbers = {
397
/**
398
* Convert number to hexadecimal string
399
* @param num - Number to convert
400
* @param padding - Minimum string length with zero padding
401
* @returns Hexadecimal string
402
*/
403
toHex(num: number, padding?: number): string;
404
405
/**
406
* Extract bits from number
407
* @param value - Source value
408
* @param offset - Bit offset from right (0-based)
409
* @param length - Number of bits to extract
410
* @returns Extracted bits as number
411
*/
412
getBits(value: number, offset: number, length: number): number;
413
414
/**
415
* Set bits in number
416
* @param target - Target value
417
* @param offset - Bit offset from right (0-based)
418
* @param length - Number of bits to set
419
* @param value - Value to set
420
* @returns Modified number
421
*/
422
setBits(target: number, offset: number, length: number, value: number): number;
423
424
/**
425
* Count leading zeros in 32-bit integer
426
* @param value - Input value
427
* @returns Number of leading zeros
428
*/
429
clz32(value: number): number;
430
};
431
```
432
433
## Advanced Usage
434
435
### Custom Stream Implementation
436
437
```javascript
438
const muxjs = require("mux.js");
439
440
// Advanced custom stream with buffering and error handling
441
class BufferedProcessorStream extends muxjs.utils.Stream {
442
constructor(options = {}) {
443
super();
444
this.bufferSize = options.bufferSize || 1024;
445
this.buffer = new Uint8Array(this.bufferSize);
446
this.bufferFill = 0;
447
this.processingOptions = options;
448
}
449
450
push(data) {
451
try {
452
// Buffer incoming data
453
if (this.bufferFill + data.length > this.bufferSize) {
454
this.processBuffer();
455
}
456
457
this.buffer.set(data, this.bufferFill);
458
this.bufferFill += data.length;
459
460
// Process if buffer is full
461
if (this.bufferFill >= this.bufferSize) {
462
this.processBuffer();
463
}
464
} catch (error) {
465
this.trigger('error', error);
466
}
467
}
468
469
flush() {
470
if (this.bufferFill > 0) {
471
this.processBuffer();
472
}
473
this.trigger('done');
474
}
475
476
processBuffer() {
477
if (this.bufferFill === 0) return;
478
479
const dataToProcess = this.buffer.subarray(0, this.bufferFill);
480
const processedData = this.processData(dataToProcess);
481
482
if (processedData) {
483
this.trigger('data', processedData);
484
}
485
486
this.bufferFill = 0;
487
}
488
489
processData(data) {
490
// Override in subclasses
491
return data;
492
}
493
494
reset() {
495
this.bufferFill = 0;
496
super.reset();
497
}
498
}
499
```
500
501
### Time Synchronization Helper
502
503
```javascript
504
const muxjs = require("mux.js");
505
506
class TimestampSync {
507
constructor() {
508
this.audioTimebase = null;
509
this.videoTimebase = null;
510
this.syncOffset = 0;
511
}
512
513
setAudioTimebase(sampleRate) {
514
this.audioTimebase = sampleRate;
515
}
516
517
setVideoTimebase() {
518
this.videoTimebase = 90000; // Standard video timebase
519
}
520
521
syncTimestamps(audioTs, videoTs) {
522
if (!this.audioTimebase || !this.videoTimebase) {
523
throw new Error('Timebases not set');
524
}
525
526
// Convert both to common timebase (video)
527
const audioInVideoTs = muxjs.utils.clock.audioTsToVideoTs(audioTs, this.audioTimebase);
528
529
// Calculate sync offset
530
this.syncOffset = videoTs - audioInVideoTs;
531
532
return {
533
audioSync: audioInVideoTs + this.syncOffset,
534
videoSync: videoTs,
535
offset: this.syncOffset
536
};
537
}
538
539
adjustAudioTimestamp(audioTs) {
540
const audioInVideoTs = muxjs.utils.clock.audioTsToVideoTs(audioTs, this.audioTimebase);
541
return audioInVideoTs + this.syncOffset;
542
}
543
}
544
```
545
546
## Error Handling
547
548
Utility functions provide detailed error information:
549
550
```javascript
551
const muxjs = require("mux.js");
552
553
// Stream error handling
554
const customStream = new muxjs.utils.Stream();
555
556
customStream.on('error', function(error) {
557
console.error('Stream error:', error.message);
558
console.error('Stack trace:', error.stack);
559
});
560
561
// Binary data parsing with error checking
562
try {
563
const value = muxjs.utils.bin.readUint32BE(data, offset);
564
console.log('Parsed value:', value);
565
} catch (error) {
566
console.error('Binary parsing error:', error.message);
567
// Common errors: insufficient data, invalid offset
568
}
569
570
// Exponential Golomb parsing with error handling
571
try {
572
const expGolomb = new muxjs.utils.ExpGolomb(spsData);
573
const value = expGolomb.readUnsignedExpGolomb();
574
} catch (error) {
575
console.error('ExpGolomb parsing error:', error.message);
576
// Common errors: truncated data, invalid encoding
577
}
578
```