@invintusmedia/tomp4 1.1.0 → 1.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.
package/dist/tomp4.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * toMp4.js v1.1.0
2
+ * toMp4.js v1.1.1
3
3
  * Convert MPEG-TS and fMP4 to standard MP4
4
4
  * https://github.com/TVWIT/toMp4.js
5
5
  * MIT License
@@ -705,7 +705,7 @@
705
705
  toMp4.isMpegTs = isMpegTs;
706
706
  toMp4.isFmp4 = isFmp4;
707
707
  toMp4.isStandardMp4 = isStandardMp4;
708
- toMp4.version = '1.1.0';
708
+ toMp4.version = '1.1.1';
709
709
 
710
710
  return toMp4;
711
711
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invintusmedia/tomp4",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Convert MPEG-TS, fMP4, and HLS streams to MP4 with clipping support - pure JavaScript, zero dependencies",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -47,12 +47,17 @@ function createBox(type, ...payloads) {
47
47
  // Fragment Parsing
48
48
  // ============================================
49
49
 
50
- function parseTfhd(tfhdData) {
50
+ function parseTfhd(tfhdData, trexDefaults = {}) {
51
51
  const view = new DataView(tfhdData.buffer, tfhdData.byteOffset, tfhdData.byteLength);
52
52
  const flags = (tfhdData[9] << 16) | (tfhdData[10] << 8) | tfhdData[11];
53
53
  const trackId = view.getUint32(12);
54
54
  let offset = 16;
55
- let baseDataOffset = 0, defaultSampleDuration = 0, defaultSampleSize = 0, defaultSampleFlags = 0;
55
+
56
+ // Start with trex defaults, override with tfhd values if present
57
+ let baseDataOffset = 0;
58
+ let defaultSampleDuration = trexDefaults.defaultSampleDuration || 0;
59
+ let defaultSampleSize = trexDefaults.defaultSampleSize || 0;
60
+ let defaultSampleFlags = trexDefaults.defaultSampleFlags || 0;
56
61
 
57
62
  if (flags & 0x1) { baseDataOffset = Number(view.getBigUint64(offset)); offset += 8; }
58
63
  if (flags & 0x2) offset += 4; // sample description index
@@ -63,6 +68,43 @@ function parseTfhd(tfhdData) {
63
68
  return { trackId, flags, baseDataOffset, defaultSampleDuration, defaultSampleSize, defaultSampleFlags };
64
69
  }
65
70
 
71
+ /**
72
+ * Parse trex (Track Extends) box from mvex
73
+ * This contains default sample values for all fragments
74
+ */
75
+ function parseTrex(trexData) {
76
+ const view = new DataView(trexData.buffer, trexData.byteOffset, trexData.byteLength);
77
+ // Skip box header (8) + version/flags (4)
78
+ const trackId = view.getUint32(12);
79
+ const defaultSampleDescriptionIndex = view.getUint32(16);
80
+ const defaultSampleDuration = view.getUint32(20);
81
+ const defaultSampleSize = view.getUint32(24);
82
+ const defaultSampleFlags = view.getUint32(28);
83
+
84
+ return { trackId, defaultSampleDescriptionIndex, defaultSampleDuration, defaultSampleSize, defaultSampleFlags };
85
+ }
86
+
87
+ /**
88
+ * Extract trex defaults from moov's mvex box
89
+ */
90
+ function extractTrexDefaults(moovBox) {
91
+ const defaults = new Map(); // trackId -> { defaultSampleDuration, ... }
92
+ const moovChildren = parseChildBoxes(moovBox);
93
+ const mvex = findBox(moovChildren, 'mvex');
94
+
95
+ if (mvex) {
96
+ const mvexChildren = parseChildBoxes(mvex);
97
+ for (const child of mvexChildren) {
98
+ if (child.type === 'trex') {
99
+ const trex = parseTrex(child.data);
100
+ defaults.set(trex.trackId, trex);
101
+ }
102
+ }
103
+ }
104
+
105
+ return defaults;
106
+ }
107
+
66
108
  function parseTfdt(tfdtData) {
67
109
  const view = new DataView(tfdtData.buffer, tfdtData.byteOffset, tfdtData.byteLength);
68
110
  const version = tfdtData[8];
@@ -433,6 +475,7 @@ export function stitchFmp4(segments, options = {}) {
433
475
  let ftyp = null;
434
476
  let moov = null;
435
477
  let originalTrackIds = [];
478
+ let trexDefaults = new Map(); // trackId -> default sample values from trex
436
479
 
437
480
  // Process init segment if provided separately
438
481
  if (initData) {
@@ -443,6 +486,7 @@ export function stitchFmp4(segments, options = {}) {
443
486
  throw new Error('stitchFmp4: Init segment missing ftyp or moov');
444
487
  }
445
488
  originalTrackIds = extractTrackIds(moov);
489
+ trexDefaults = extractTrexDefaults(moov);
446
490
  }
447
491
 
448
492
  // Process each segment
@@ -461,6 +505,7 @@ export function stitchFmp4(segments, options = {}) {
461
505
  if (!moov && segMoov) {
462
506
  moov = segMoov;
463
507
  originalTrackIds = extractTrackIds(moov);
508
+ trexDefaults = extractTrexDefaults(moov);
464
509
  }
465
510
 
466
511
  // Process fragment boxes (moof + mdat pairs)
@@ -492,7 +537,12 @@ export function stitchFmp4(segments, options = {}) {
492
537
  const tfdtBox = findBox(trafChildren, 'tfdt');
493
538
 
494
539
  if (tfhdBox && trunBox) {
495
- const tfhd = parseTfhd(tfhdBox.data);
540
+ // Get trackId first to look up trex defaults
541
+ const tfhdView = new DataView(tfhdBox.data.buffer, tfhdBox.data.byteOffset, tfhdBox.data.byteLength);
542
+ const trackId = tfhdView.getUint32(12);
543
+ const trackTrexDefaults = trexDefaults.get(trackId) || {};
544
+
545
+ const tfhd = parseTfhd(tfhdBox.data, trackTrexDefaults);
496
546
  const { samples, dataOffset } = parseTrun(trunBox.data, tfhd);
497
547
 
498
548
  if (!tracks.has(tfhd.trackId)) {
package/src/index.js CHANGED
@@ -329,7 +329,7 @@ toMp4.TSParser = TSParser;
329
329
  toMp4.RemoteMp4 = RemoteMp4;
330
330
 
331
331
  // Version (injected at build time for dist, read from package.json for ESM)
332
- toMp4.version = '1.1.0';
332
+ toMp4.version = '1.1.1';
333
333
 
334
334
  // Export
335
335
  export {