jmuxer 2.0.7 → 2.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.
@@ -14,6 +14,8 @@ export class MP4 {
14
14
  esds: [],
15
15
  ftyp: [],
16
16
  hdlr: [],
17
+ hev1: [],
18
+ hvcC: [],
17
19
  mdat: [],
18
20
  mdhd: [],
19
21
  mdia: [],
@@ -179,9 +181,9 @@ export class MP4 {
179
181
  (timescale >> 16) & 0xFF,
180
182
  (timescale >> 8) & 0xFF,
181
183
  timescale & 0xFF, // timescale
182
- (duration >> 24),
183
- (duration >> 16) & 0xFF,
184
- (duration >> 8) & 0xFF,
184
+ (duration >>> 24) & 0xFF,
185
+ (duration >>> 16) & 0xFF,
186
+ (duration >>> 8) & 0xFF,
185
187
  duration & 0xFF, // duration
186
188
  0x55, 0xc4, // 'und' language (undetermined)
187
189
  0x00, 0x00,
@@ -251,9 +253,9 @@ export class MP4 {
251
253
  (timescale >> 16) & 0xFF,
252
254
  (timescale >> 8) & 0xFF,
253
255
  timescale & 0xFF, // timescale
254
- (duration >> 24) & 0xFF,
255
- (duration >> 16) & 0xFF,
256
- (duration >> 8) & 0xFF,
256
+ (duration >>> 24) & 0xFF,
257
+ (duration >>> 16) & 0xFF,
258
+ (duration >>> 8) & 0xFF,
257
259
  duration & 0xFF, // duration
258
260
  0x00, 0x01, 0x00, 0x00, // 1.0 rate
259
261
  0x01, 0x00, // 1.0 volume
@@ -375,6 +377,116 @@ export class MP4 {
375
377
  0x00, 0x2d, 0xc6, 0xc0])) // avgBitrate
376
378
  );
377
379
  }
380
+
381
+ static hev1(track) {
382
+ let vps = [],
383
+ sps = [],
384
+ pps = [],
385
+ data,
386
+ len;
387
+
388
+ // assemble the VPSs
389
+ for (let i = 0; i < (track.vps?.length || 0); i++) {
390
+ data = track.vps[i];
391
+ len = data.byteLength;
392
+ vps.push((len >>> 8) & 0xFF, len & 0xFF);
393
+ vps = vps.concat(Array.prototype.slice.call(data));
394
+ }
395
+
396
+ // assemble the SPSs
397
+ for (let i = 0; i < (track.sps?.length || 0); i++) {
398
+ data = track.sps[i];
399
+ len = data.byteLength;
400
+ sps.push((len >>> 8) & 0xFF, len & 0xFF);
401
+ sps = sps.concat(Array.prototype.slice.call(data));
402
+ }
403
+
404
+ // assemble the PPSs
405
+ for (let i = 0; i < (track.pps?.length || 0); i++) {
406
+ data = track.pps[i];
407
+ len = data.byteLength;
408
+ pps.push((len >>> 8) & 0xFF, len & 0xFF);
409
+ pps = pps.concat(Array.prototype.slice.call(data));
410
+ }
411
+
412
+ let {
413
+ profile_space,
414
+ tier_flag,
415
+ profile_idc,
416
+ profile_compatibility_flags,
417
+ constraint_indicator_flags,
418
+ level_idc,
419
+ chroma_format_idc
420
+ } = track.hvcC;
421
+
422
+ const hvcc = MP4.box(MP4.types.hvcC, new Uint8Array([
423
+ 0x01, // configurationVersion
424
+ (profile_space << 6) | (tier_flag << 5) | profile_idc,
425
+ (profile_compatibility_flags >> 24) & 0xFF,
426
+ (profile_compatibility_flags >> 16) & 0xFF,
427
+ (profile_compatibility_flags >> 8) & 0xFF,
428
+ profile_compatibility_flags & 0xFF,
429
+ ...constraint_indicator_flags,
430
+ level_idc,
431
+ 0xF0, 0x00, // min_spatial_segmentation_idc = 0
432
+ 0xFC | 0, // parallelismType = 0
433
+ 0xFC | chroma_format_idc, // chromaFormat (from SPS)
434
+ 0xF8 | 0, // bitDepthLumaMinus8 = 0 (8-bit)
435
+ 0xF8 | 0, // bitDepthChromaMinus8 = 0
436
+ 0x00, 0x00, // avgFrameRate = 0
437
+ 0x03, // constantFrameRate = 0, numTemporalLayers = 0, lengthSizeMinusOne = 3 (AKA 4)
438
+ 0x03, // numOfArrays
439
+
440
+ 0x20, // array_completeness + NAL_unit_type (32 = VPS)
441
+ 0x00, 0x01, // numNalus
442
+ ...vps,
443
+
444
+ 0x21, // NAL_unit_type (33 = SPS)
445
+ 0x00, 0x01,
446
+ ...sps,
447
+
448
+ 0x22, // NAL_unit_type (34 = PPS)
449
+ 0x00, 0x01,
450
+ ...pps
451
+ ]));
452
+
453
+ const width = track.width;
454
+ const height = track.height;
455
+
456
+ return MP4.box(MP4.types.hev1, new Uint8Array([
457
+ 0x00, 0x00, 0x00, // reserved
458
+ 0x00, 0x00, 0x00, // reserved
459
+ 0x00, 0x01, // data_reference_index
460
+ 0x00, 0x00, // pre_defined
461
+ 0x00, 0x00, // reserved
462
+ 0x00, 0x00, 0x00, 0x00,
463
+ 0x00, 0x00, 0x00, 0x00,
464
+ 0x00, 0x00, 0x00, 0x00, // pre_defined
465
+ (width >> 8) & 0xFF, width & 0xff,
466
+ (height >> 8) & 0xFF, height & 0xff,
467
+ 0x00, 0x48, 0x00, 0x00, // horizresolution
468
+ 0x00, 0x48, 0x00, 0x00, // vertresolution
469
+ 0x00, 0x00, 0x00, 0x00, // reserved
470
+ 0x00, 0x01, // frame_count
471
+ 0x12,
472
+ 0x62, 0x69, 0x6E, 0x65, // 'binelpro.ru'
473
+ 0x6C, 0x70, 0x72, 0x6F,
474
+ 0x2E, 0x72, 0x75, 0x00,
475
+ 0x00, 0x00, 0x00, 0x00,
476
+ 0x00, 0x00, 0x00, 0x00,
477
+ 0x00, 0x00, 0x00, 0x00,
478
+ 0x00, 0x00, 0x00, 0x00,
479
+ 0x00, 0x00, 0x00, // compressorname padding
480
+ 0x00, 0x18, // depth = 24
481
+ 0x11, 0x11 // pre_defined = -1
482
+ ]),
483
+ hvcc,
484
+ MP4.box(MP4.types.btrt, new Uint8Array([
485
+ 0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB
486
+ 0x00, 0x2d, 0xc6, 0xc0, // maxBitrate
487
+ 0x00, 0x2d, 0xc6, 0xc0 // avgBitrate
488
+ ])));
489
+ }
378
490
 
379
491
  static esds(track) {
380
492
  var configlen = track.config.byteLength;
@@ -445,6 +557,9 @@ export class MP4 {
445
557
  if (track.type === 'audio') {
446
558
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
447
559
  } else {
560
+ if (track.codec.startsWith('hvc1')) {
561
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hev1(track));
562
+ }
448
563
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
449
564
  }
450
565
  }
@@ -465,9 +580,9 @@ export class MP4 {
465
580
  (id >> 8) & 0xFF,
466
581
  id & 0xFF, // track_ID
467
582
  0x00, 0x00, 0x00, 0x00, // reserved
468
- (duration >> 24),
469
- (duration >> 16) & 0xFF,
470
- (duration >> 8) & 0xFF,
583
+ (duration >>> 24) & 0xFF,
584
+ (duration >>> 16) & 0xFF,
585
+ (duration >>> 8) & 0xFF,
471
586
  duration & 0xFF, // duration
472
587
  0x00, 0x00, 0x00, 0x00,
473
588
  0x00, 0x00, 0x00, 0x00, // reserved
package/src/util/utils.js CHANGED
@@ -22,3 +22,23 @@ export function secToTime(sec) {
22
22
  result += (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds);
23
23
  return result;
24
24
  }
25
+
26
+ export function reverseBits(n) {
27
+ var result = 0;
28
+ for (var i = 0; i < 32; i++)
29
+ {
30
+ // Shift result left to make room
31
+ result <<= 1;
32
+ // Add the least significant bit of n
33
+ result |= (n & 1);
34
+ // Shift n right to process the next bit
35
+ n >>>= 1;
36
+ }
37
+ // Ensure result is treated as unsigned 32-bit
38
+ return result >>> 0;
39
+ }
40
+
41
+ export function removeTrailingDotZero(input) {
42
+ // Use regex to strip all trailing ".0" sequences
43
+ return input.replace(/(?:\.0)+$/, '');
44
+ }
@@ -1,13 +0,0 @@
1
- <component name="ProjectCodeStyleConfiguration">
2
- <code_scheme name="Project" version="173">
3
- <JSCodeStyleSettings version="0">
4
- <option name="FORCE_SEMICOLON_STYLE" value="true" />
5
- <option name="USE_DOUBLE_QUOTES" value="false" />
6
- <option name="FORCE_QUOTE_STYlE" value="true" />
7
- </JSCodeStyleSettings>
8
- <codeStyleSettings language="JavaScript">
9
- <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
10
- <option name="ALIGN_MULTILINE_FOR" value="false" />
11
- </codeStyleSettings>
12
- </code_scheme>
13
- </component>
@@ -1,5 +0,0 @@
1
- <component name="ProjectCodeStyleConfiguration">
2
- <state>
3
- <option name="USE_PER_PROJECT_SETTINGS" value="true" />
4
- </state>
5
- </component>
@@ -1,6 +0,0 @@
1
- <component name="InspectionProjectProfileManager">
2
- <profile version="1.0">
3
- <option name="myName" value="Project Default" />
4
- <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
- </profile>
6
- </component>
package/.idea/jmuxer.iml DELETED
@@ -1,9 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="JAVA_MODULE" version="4">
3
- <component name="NewModuleRootManager" inherit-compiler-output="true">
4
- <exclude-output />
5
- <content url="file://$MODULE_DIR$" />
6
- <orderEntry type="inheritedJdk" />
7
- <orderEntry type="sourceFolder" forTests="false" />
8
- </component>
9
- </module>
package/.idea/misc.xml DELETED
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="ProjectRootManager">
4
- <output url="file://$PROJECT_DIR$/out" />
5
- </component>
6
- </project>
package/.idea/modules.xml DELETED
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="ProjectModuleManager">
4
- <modules>
5
- <module fileurl="file://$PROJECT_DIR$/.idea/jmuxer.iml" filepath="$PROJECT_DIR$/.idea/jmuxer.iml" />
6
- </modules>
7
- </component>
8
- </project>
package/.idea/vcs.xml DELETED
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="VcsDirectoryMappings">
4
- <mapping directory="" vcs="Git" />
5
- </component>
6
- </project>
package/karma.conf.js DELETED
@@ -1,77 +0,0 @@
1
- // Karma configuration
2
- // Generated on Fri Nov 03 2017 16:10:03 GMT+0600 (+06)
3
-
4
- module.exports = function(config) {
5
- config.set({
6
-
7
- // base path that will be used to resolve all patterns (eg. files, exclude)
8
- basePath: '',
9
-
10
-
11
- // frameworks to use
12
- // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13
- frameworks: ['mocha', 'chai'],
14
-
15
- // list of files / patterns to load in the browser
16
- files: [
17
- 'test/*.js'
18
- ],
19
-
20
- // list of files to exclude
21
- exclude: [
22
- ],
23
-
24
- // preprocess matching files before serving them to the browser
25
- // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
26
- preprocessors: {
27
- 'test/*.js': ['rollup']
28
- },
29
-
30
- rollupPreprocessor: {
31
- plugins: [
32
- require('@rollup/plugin-babel')
33
- ],
34
- output: {
35
- format: 'iife', // Helps prevent naming collisions.
36
- name: 'JMuxer', // Required for 'iife' format.
37
- sourcemap: 'inline', // Sensible for testing.
38
- }
39
- },
40
-
41
- // test results reporter to use
42
- // possible values: 'dots', 'progress'
43
- // available reporters: https://npmjs.org/browse/keyword/karma-reporter
44
- reporters: ['progress'],
45
-
46
-
47
- // web server port
48
- port: 9876,
49
-
50
-
51
- // enable / disable colors in the output (reporters and logs)
52
- colors: true,
53
-
54
-
55
- // level of logging
56
- // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
57
- logLevel: config.LOG_INFO,
58
-
59
-
60
- // enable / disable watching file and executing tests whenever any file changes
61
- autoWatch: false,
62
-
63
-
64
- // start these browsers
65
- // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
66
- browsers: ['Chrome'],
67
-
68
-
69
- // Continuous Integration mode
70
- // if true, Karma captures browsers, runs the tests and exits
71
- singleRun: true,
72
-
73
- // Concurrency level
74
- // how many browser should be started simultaneous
75
- concurrency: Infinity
76
- })
77
- }
package/loader-thumb.jpg DELETED
Binary file
package/packet-format.png DELETED
Binary file
package/src/util/nalu.js DELETED
@@ -1,72 +0,0 @@
1
- export class NALU {
2
- static get NDR() { return 1; }
3
- static get IDR() { return 5; }
4
- static get SEI() { return 6; }
5
- static get SPS() { return 7; }
6
- static get PPS() { return 8; }
7
- static get AUD() { return 9; }
8
-
9
- static get TYPES() {
10
- return {
11
- [NALU.IDR]: 'IDR',
12
- [NALU.SEI]: 'SEI',
13
- [NALU.SPS]: 'SPS',
14
- [NALU.PPS]: 'PPS',
15
- [NALU.NDR]: 'NDR',
16
- [NALU.AUD]: 'AUD',
17
- };
18
- }
19
-
20
- static type(nalu) {
21
- if (nalu.ntype in NALU.TYPES) {
22
- return NALU.TYPES[nalu.ntype];
23
- } else {
24
- return 'UNKNOWN';
25
- }
26
- }
27
-
28
- constructor(data) {
29
- this.payload = data;
30
- this.nri = (this.payload[0] & 0x60) >> 5; // nal_ref_idc
31
- this.ntype = this.payload[0] & 0x1f;
32
- this.isvcl = this.ntype == 1 || this.ntype == 5;
33
- this.stype = ''; // slice_type
34
- this.isfmb = false; // first_mb_in_slice
35
- }
36
-
37
- toString() {
38
- return `${NALU.type(this)}: NRI: ${this.getNri()}`;
39
- }
40
-
41
- getNri() {
42
- return this.nri;
43
- }
44
-
45
- type() {
46
- return this.ntype;
47
- }
48
-
49
- isKeyframe() {
50
- return this.ntype === NALU.IDR;
51
- }
52
-
53
- getPayload() {
54
- return this.payload;
55
- }
56
-
57
- getPayloadSize() {
58
- return this.payload.byteLength;
59
- }
60
-
61
- getSize() {
62
- return 4 + this.getPayloadSize();
63
- }
64
-
65
- getData() {
66
- const result = new Uint8Array(this.getSize());
67
- const view = new DataView(result.buffer);
68
- view.setUint32(0, this.getSize() - 4);
69
- result.set(this.getPayload(), 4);
70
- return result;
71
- }
72
- }
package/test/event.js DELETED
@@ -1,30 +0,0 @@
1
- //import { assert } from 'chai';
2
- import Event from '../src/util/event.js';
3
-
4
- var event = new Event('XYZ');
5
-
6
- var callback = function() {
7
- };
8
-
9
- describe('event tests --', function() {
10
-
11
- beforeEach(function(){
12
- event.offAll();
13
- event.on('topic1',callback);
14
- event.on('topic1',callback);
15
- event.on('topic2',callback);
16
- });
17
-
18
- it('listener count should be 2 for the topic1', function() {
19
- assert.equal(event.listener.topic1.length, 2);
20
- });
21
-
22
- it('event dispatcher should be return true for a successful dispatcher', function() {
23
- assert.equal(event.dispatch('topic1', true), true);
24
- });
25
-
26
- it('listener count should be zero after removing all listeners', function() {
27
- event.offAll();
28
- assert.deepEqual(event.listener, {});
29
- });
30
- });
package/test/parser.js DELETED
@@ -1,35 +0,0 @@
1
- //import { assert } from 'chai';
2
-
3
- import { BaseRemuxer } from '../src/remuxer/base.js';
4
- import { H264Parser } from '../src/parsers/h264.js';
5
- import { AACParser } from '../src/parsers/aac.js';
6
-
7
- var h264 = new Uint8Array([0, 0, 0, 1, 103, 66, 192, 30, 218, 2, 128, 191, 229, 192, 90, 128, 128, 131, 32, 0, 0, 3, 0, 32, 0, 0, 7, 129, 226, 197, 212, 0, 0, 0, 1, 113, 76, 122, 37, 218, 2, 128, 191, 229, 192, 90, 128, 128, 131, 32, 0, 0, 3, 0, 32, 0, 0, 70, 129, 126, 195, 202]);
8
- var aac = new Uint8Array([255, 241, 80, 128, 35, 159, 252, 33, 10, 84, 140, 49, 34, 72, 2, 57, 103, 72, 21, 128, 32, 144, 42, 44, 7, 107, 116, 93, 199, 51, 237, 104, 181, 31, 37, 29, 169, 190, 111, 167, 139, 124, 85, 72, 37, 148, 183, 228, 87, 188, 200, 76, 226, 83, 160, 18, 11, 69, 80, 4, 118, 229, 129, 250, 22, 242, 222, 49, 146, 29, 19, 237, 71, 235, 29, 127, 235, 134, 186, 14, 8, 67, 103, 141, 13, 32, 238, 184, 3, 232, 183, 8, 109, 150, 199, 97, 203, 164, 240, 233, 12, 216, 246, 220, 78, 25, 250, 33, 10, 84, 140, 49, 34, 72, 2, 57, 103, 72, 21, 128, 32, 144, 42, 44, 7, 107, 116, 93, 199, 51, 237, 104, 181, 31, 37, 29, 169, 190, 111, 167, 139, 124, 85, 72, 37, 148, 183, 228, 87, 188, 200, 76, 226, 83, 160, 18, 11, 69, 80, 4, 118, 229, 129, 250, 22, 242, 222, 49, 146, 29, 19, 237, 71, 235, 29, 127, 235, 134, 186, 14, 8, 67, 103, 141, 13, 32, 238, 184, 3, 232, 183, 8, 109, 150, 199, 97, 203, 164, 240, 233, 12, 216, 246, 220, 78, 25, 250, 33, 10, 84, 140, 49, 34, 72, 2, 57, 103, 72, 21, 128, 32, 144, 42, 44, 7, 107, 116, 93, 199, 51, 237, 104, 181, 31, 37, 29, 169, 190, 111, 167, 139, 124, 85, 72, 37, 148, 183, 228, 87, 188, 200, 76, 226, 83, 160, 18, 11, 69, 80, 4, 118, 229, 129, 250, 22, 242, 222, 49, 146, 29, 19, 237, 71, 235, 29, 127, 235, 134,33,44,66,34,23]);
9
-
10
-
11
- describe('Parser tests --', function() {
12
-
13
- it('Number of extracted h264 NAL unit should be 2', function() {
14
- var result = H264Parser.extractNALu(h264);
15
- assert.equal(result.length, 2);
16
- });
17
-
18
- it('AAC pattern should return true', function() {
19
- assert.equal(AACParser.isAACPattern(aac), true);
20
- });
21
-
22
- it('AAC header length should be 7 since CRC not present', function() {
23
- assert.equal(AACParser.getHeaderLength(aac), 7);
24
- });
25
-
26
- it('AAC frame length should be 284', function() {
27
- assert.equal(AACParser.getFrameLength(aac), 284);
28
- });
29
-
30
- it('Number of extracted AAC frames should be 1', function() {
31
- var result = AACParser.extractAAC(aac);
32
- assert.equal(result.length, 1);
33
- });
34
- });
35
-
package/test/utils.js DELETED
@@ -1,19 +0,0 @@
1
- //import { assert } from 'chai';
2
- import { appendByteArray } from '../src/util/utils.js';
3
-
4
- var arr1 = new Uint8Array([1,2,3,4,5]);
5
- var arr2 = new Uint8Array([6,7,8]);
6
-
7
- describe('Utils tests --', function() {
8
-
9
- it('Appended array length must be 8', function() {
10
- var result = appendByteArray(arr1, arr2);
11
- assert.equal(result.byteLength, 8);
12
- });
13
-
14
- it('8th element value must be 8', function() {
15
- var result = appendByteArray(arr1, arr2);
16
- assert.equal(result[7], 8);
17
- });
18
- });
19
-