@remotion/media-parser 4.0.231 → 4.0.233
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/add-avc-profile-to-track.d.ts +3 -0
- package/dist/add-avc-profile-to-track.js +35 -0
- package/dist/add-new-matroska-tracks.d.ts +6 -1
- package/dist/add-new-matroska-tracks.js +16 -1
- package/dist/boxes/avc/parse-avc.d.ts +18 -0
- package/dist/boxes/avc/parse-avc.js +96 -0
- package/dist/boxes/iso-base-media/esds/decoder-specific-config.d.ts +1 -2
- package/dist/boxes/iso-base-media/esds/decoder-specific-config.js +1 -5
- package/dist/boxes/iso-base-media/esds/esds-descriptors.d.ts +2 -4
- package/dist/boxes/iso-base-media/esds/esds-descriptors.js +3 -4
- package/dist/boxes/iso-base-media/esds/esds.d.ts +1 -3
- package/dist/boxes/iso-base-media/esds/esds.js +2 -2
- package/dist/boxes/iso-base-media/get-sample-positions-from-track.js +7 -1
- package/dist/boxes/iso-base-media/make-track.js +3 -3
- package/dist/boxes/iso-base-media/mdat/mdat.d.ts +2 -2
- package/dist/boxes/iso-base-media/mdat/mdat.js +5 -2
- package/dist/boxes/iso-base-media/moov/moov.js +2 -2
- package/dist/boxes/iso-base-media/process-box.d.ts +5 -5
- package/dist/boxes/iso-base-media/process-box.js +38 -38
- package/dist/boxes/iso-base-media/stsd/mebx.js +2 -2
- package/dist/boxes/iso-base-media/stsd/samples.d.ts +2 -2
- package/dist/boxes/iso-base-media/stsd/samples.js +15 -14
- package/dist/boxes/iso-base-media/trak/trak.js +2 -2
- package/dist/boxes/iso-base-media/traversal.d.ts +1 -1
- package/dist/boxes/riff/expect-riff-box.d.ts +16 -0
- package/dist/boxes/riff/expect-riff-box.js +49 -0
- package/dist/boxes/riff/get-tracks-from-avi.d.ts +21 -0
- package/dist/boxes/riff/get-tracks-from-avi.js +108 -0
- package/dist/boxes/riff/is-movi.d.ts +2 -0
- package/dist/boxes/riff/is-movi.js +12 -0
- package/dist/boxes/riff/parse-avih.d.ts +6 -0
- package/dist/boxes/riff/parse-avih.js +32 -0
- package/dist/boxes/riff/parse-box.d.ts +13 -0
- package/dist/boxes/riff/parse-box.js +113 -0
- package/dist/boxes/riff/parse-fmt-box.d.ts +7 -0
- package/dist/boxes/riff/parse-fmt-box.js +33 -0
- package/dist/boxes/riff/parse-list-box.d.ts +8 -0
- package/dist/boxes/riff/parse-list-box.js +30 -0
- package/dist/boxes/riff/parse-movi.d.ts +17 -0
- package/dist/boxes/riff/parse-movi.js +122 -0
- package/dist/boxes/riff/parse-riff-box.d.ts +10 -0
- package/dist/boxes/riff/parse-riff-box.js +33 -0
- package/dist/boxes/riff/parse-strf.d.ts +7 -0
- package/dist/boxes/riff/parse-strf.js +67 -0
- package/dist/boxes/riff/parse-strh.d.ts +6 -0
- package/dist/boxes/riff/parse-strh.js +46 -0
- package/dist/boxes/riff/riff-box.d.ts +81 -0
- package/dist/boxes/riff/riff-box.js +2 -0
- package/dist/boxes/riff/strf.d.ts +7 -0
- package/dist/boxes/riff/strf.js +67 -0
- package/dist/boxes/riff/timescale.d.ts +1 -0
- package/dist/boxes/riff/timescale.js +4 -0
- package/dist/boxes/riff/traversal.d.ts +8 -0
- package/dist/boxes/riff/traversal.js +36 -0
- package/dist/boxes/webm/parse-ebml.js +2 -2
- package/dist/boxes/webm/parse-webm-header.d.ts +2 -2
- package/dist/boxes/webm/parse-webm-header.js +7 -7
- package/dist/boxes/webm/traversal.d.ts +2 -2
- package/dist/buffer-iterator.d.ts +6 -1
- package/dist/buffer-iterator.js +24 -5
- package/dist/create/event-emitter.d.ts +31 -0
- package/dist/create/event-emitter.js +25 -0
- package/dist/create/iso-base-media/create-iso-base-media.d.ts +1 -1
- package/dist/create/iso-base-media/create-iso-base-media.js +3 -5
- package/dist/create/matroska/cluster.js +1 -1
- package/dist/create/matroska/create-matroska-media.d.ts +1 -1
- package/dist/create/matroska/create-matroska-media.js +7 -14
- package/dist/create/media-fn.d.ts +2 -1
- package/dist/create/mp3/create-mp3.d.ts +2 -0
- package/dist/create/mp3/create-mp3.js +49 -0
- package/dist/create/progress-tracker.d.ts +7 -0
- package/dist/create/progress-tracker.js +43 -0
- package/dist/create/wav/create-wav.d.ts +2 -0
- package/dist/create/wav/create-wav.js +110 -0
- package/dist/create/with-resolvers.d.ts +10 -0
- package/dist/create/with-resolvers.js +28 -0
- package/dist/emit-available-info.d.ts +2 -2
- package/dist/emit-available-info.js +17 -6
- package/dist/esm/from-node.mjs +2 -1
- package/dist/esm/index.mjs +1828 -605
- package/dist/get-audio-codec.d.ts +4 -3
- package/dist/get-audio-codec.js +17 -3
- package/dist/get-container.d.ts +3 -3
- package/dist/get-container.js +9 -7
- package/dist/get-dimensions.d.ts +3 -3
- package/dist/get-duration.d.ts +3 -3
- package/dist/get-duration.js +32 -14
- package/dist/get-fps.d.ts +3 -3
- package/dist/get-fps.js +31 -4
- package/dist/get-is-hdr.d.ts +4 -0
- package/dist/get-is-hdr.js +18 -0
- package/dist/get-sample-positions-from-lpcm.d.ts +3 -0
- package/dist/get-sample-positions-from-lpcm.js +46 -0
- package/dist/get-tracks.d.ts +7 -10
- package/dist/get-tracks.js +55 -27
- package/dist/get-video-codec.d.ts +5 -4
- package/dist/get-video-codec.js +47 -13
- package/dist/has-all-info.d.ts +2 -2
- package/dist/has-all-info.js +10 -5
- package/dist/index.d.ts +23 -3
- package/dist/index.js +9 -0
- package/dist/options.d.ts +16 -9
- package/dist/parse-media.js +3 -1
- package/dist/parse-result.d.ts +20 -6
- package/dist/parse-video.d.ts +2 -2
- package/dist/parse-video.js +5 -16
- package/dist/parser-context.d.ts +1 -0
- package/dist/parser-state.d.ts +11 -0
- package/dist/parser-state.js +30 -0
- package/dist/readers/from-node.js +2 -1
- package/dist/register-track.d.ts +13 -0
- package/dist/register-track.js +25 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/esm/index.mjs
CHANGED
|
@@ -105,6 +105,27 @@ var fetchReader = {
|
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
+
// src/create/event-emitter.ts
|
|
109
|
+
class IoEventEmitter {
|
|
110
|
+
listeners = {
|
|
111
|
+
input: [],
|
|
112
|
+
output: [],
|
|
113
|
+
processed: [],
|
|
114
|
+
progress: []
|
|
115
|
+
};
|
|
116
|
+
addEventListener(name, callback) {
|
|
117
|
+
this.listeners[name].push(callback);
|
|
118
|
+
}
|
|
119
|
+
removeEventListener(name, callback) {
|
|
120
|
+
this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
|
|
121
|
+
}
|
|
122
|
+
dispatchEvent(dispatchName, context) {
|
|
123
|
+
this.listeners[dispatchName].forEach((callback) => {
|
|
124
|
+
callback({ detail: context });
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
108
129
|
// src/boxes/webm/ebml.ts
|
|
109
130
|
var measureEBMLVarInt = (value) => {
|
|
110
131
|
if (value < (1 << 7) - 1) {
|
|
@@ -848,6 +869,15 @@ var incrementOffsetAndChildren = (offset, increment) => {
|
|
|
848
869
|
};
|
|
849
870
|
|
|
850
871
|
// src/boxes/webm/make-header.ts
|
|
872
|
+
var webmPattern = new Uint8Array([26, 69, 223, 163]);
|
|
873
|
+
var matroskaToHex = (matrId) => {
|
|
874
|
+
const numbers = new Uint8Array((matrId.length - 2) / 2);
|
|
875
|
+
for (let i = 2;i < matrId.length; i += 2) {
|
|
876
|
+
const hex = matrId.substring(i, i + 2);
|
|
877
|
+
numbers[(i - 2) / 2] = parseInt(hex, 16);
|
|
878
|
+
}
|
|
879
|
+
return numbers;
|
|
880
|
+
};
|
|
851
881
|
function putUintDynamic(number, minimumLength) {
|
|
852
882
|
if (number < 0) {
|
|
853
883
|
throw new Error("This function is designed for non-negative integers only.");
|
|
@@ -859,21 +889,6 @@ function putUintDynamic(number, minimumLength) {
|
|
|
859
889
|
}
|
|
860
890
|
return bytes;
|
|
861
891
|
}
|
|
862
|
-
function serializeUint16(value) {
|
|
863
|
-
const buffer = new ArrayBuffer(2);
|
|
864
|
-
const view = new DataView(buffer);
|
|
865
|
-
view.setUint16(0, value);
|
|
866
|
-
return new Uint8Array(buffer);
|
|
867
|
-
}
|
|
868
|
-
var webmPattern = new Uint8Array([26, 69, 223, 163]);
|
|
869
|
-
var matroskaToHex = (matrId) => {
|
|
870
|
-
const numbers = new Uint8Array((matrId.length - 2) / 2);
|
|
871
|
-
for (let i = 2;i < matrId.length; i += 2) {
|
|
872
|
-
const hex = matrId.substring(i, i + 2);
|
|
873
|
-
numbers[(i - 2) / 2] = parseInt(hex, 16);
|
|
874
|
-
}
|
|
875
|
-
return numbers;
|
|
876
|
-
};
|
|
877
892
|
var makeFromStructure = (fields) => {
|
|
878
893
|
if ("bytes" in fields) {
|
|
879
894
|
return fields;
|
|
@@ -1020,6 +1035,12 @@ var combineUint8Arrays = (arrays) => {
|
|
|
1020
1035
|
}
|
|
1021
1036
|
return result;
|
|
1022
1037
|
};
|
|
1038
|
+
function serializeUint16(value) {
|
|
1039
|
+
const buffer = new ArrayBuffer(2);
|
|
1040
|
+
const view = new DataView(buffer);
|
|
1041
|
+
view.setUint16(0, value);
|
|
1042
|
+
return new Uint8Array(buffer);
|
|
1043
|
+
}
|
|
1023
1044
|
|
|
1024
1045
|
// src/log.ts
|
|
1025
1046
|
var logLevels = ["trace", "verbose", "info", "warn", "error"];
|
|
@@ -1855,7 +1876,7 @@ var createHdlr = (type) => {
|
|
|
1855
1876
|
type === "mdir" ? numberTo32BitUIntOrInt(1634758764) : new Uint8Array([0, 0, 0, 0]),
|
|
1856
1877
|
new Uint8Array([0, 0, 0, 0]),
|
|
1857
1878
|
new Uint8Array([0, 0, 0, 0]),
|
|
1858
|
-
stringsToUint8Array(type === "mdir" ? "\
|
|
1879
|
+
stringsToUint8Array(type === "mdir" ? "\x00" : type === "video" ? "VideoHandler\x00" : "SoundHandler\x00")
|
|
1859
1880
|
]));
|
|
1860
1881
|
};
|
|
1861
1882
|
|
|
@@ -1966,7 +1987,8 @@ var createIsoBaseMedia = async ({
|
|
|
1966
1987
|
onBytesProgress,
|
|
1967
1988
|
onMillisecondsProgress,
|
|
1968
1989
|
logLevel,
|
|
1969
|
-
filename
|
|
1990
|
+
filename,
|
|
1991
|
+
progressTracker
|
|
1970
1992
|
}) => {
|
|
1971
1993
|
const header = createIsoBaseMediaFtyp({
|
|
1972
1994
|
compatibleBrands: ["isom", "iso2", "avc1", "mp42"],
|
|
@@ -2036,6 +2058,7 @@ var createIsoBaseMedia = async ({
|
|
|
2036
2058
|
await w.write(chunk.data);
|
|
2037
2059
|
mdatSize += chunk.data.length;
|
|
2038
2060
|
onBytesProgress(w.getWrittenByteCount());
|
|
2061
|
+
progressTracker.updateTrackProgress(trackNumber2, chunk.timestamp);
|
|
2039
2062
|
if (codecPrivate2) {
|
|
2040
2063
|
addCodecPrivateToTrack({ trackNumber: trackNumber2, codecPrivate: codecPrivate2 });
|
|
2041
2064
|
}
|
|
@@ -2069,6 +2092,7 @@ var createIsoBaseMedia = async ({
|
|
|
2069
2092
|
const addTrack = (track) => {
|
|
2070
2093
|
const trackNumber2 = currentTracks.length + 1;
|
|
2071
2094
|
currentTracks.push({ ...track, trackNumber: trackNumber2 });
|
|
2095
|
+
progressTracker.registerTrack(trackNumber2);
|
|
2072
2096
|
return Promise.resolve({ trackNumber: trackNumber2 });
|
|
2073
2097
|
};
|
|
2074
2098
|
const waitForFinishPromises = [];
|
|
@@ -2117,10 +2141,6 @@ var createIsoBaseMedia = async ({
|
|
|
2117
2141
|
await updateMdatSize();
|
|
2118
2142
|
Log.verbose(logLevel, "All write operations done. Waiting for finish...");
|
|
2119
2143
|
await w.waitForFinish();
|
|
2120
|
-
},
|
|
2121
|
-
updateDuration: (duration2) => {
|
|
2122
|
-
operationProm.current = operationProm.current.then(() => updateDuration(duration2));
|
|
2123
|
-
return operationProm.current;
|
|
2124
2144
|
}
|
|
2125
2145
|
};
|
|
2126
2146
|
};
|
|
@@ -2178,7 +2198,7 @@ var canFitInCluster = ({
|
|
|
2178
2198
|
}) => {
|
|
2179
2199
|
const timecodeRelativeToCluster = timestampToClusterTimestamp(chunk.timestamp, timescale) - timestampToClusterTimestamp(clusterStartTimestamp, timescale);
|
|
2180
2200
|
if (timecodeRelativeToCluster < 0) {
|
|
2181
|
-
throw new Error(`timecodeRelativeToCluster is negative`);
|
|
2201
|
+
throw new Error(`timecodeRelativeToCluster is negative, tried to add ${chunk.timestamp} to ${clusterStartTimestamp}`);
|
|
2182
2202
|
}
|
|
2183
2203
|
return timecodeRelativeToCluster <= maxClusterTimestamp;
|
|
2184
2204
|
};
|
|
@@ -2947,7 +2967,8 @@ var createMatroskaMedia = async ({
|
|
|
2947
2967
|
onBytesProgress,
|
|
2948
2968
|
onMillisecondsProgress,
|
|
2949
2969
|
filename,
|
|
2950
|
-
logLevel
|
|
2970
|
+
logLevel,
|
|
2971
|
+
progressTracker
|
|
2951
2972
|
}) => {
|
|
2952
2973
|
const header = makeMatroskaHeader();
|
|
2953
2974
|
const w = await writer.createContent({ filename, mimeType: "video/webm" });
|
|
@@ -3012,17 +3033,11 @@ var createMatroskaMedia = async ({
|
|
|
3012
3033
|
hexString: matroskaElements.Cluster,
|
|
3013
3034
|
byte: clusterOffset - seekHeadOffset
|
|
3014
3035
|
});
|
|
3015
|
-
const trackNumberProgresses = {};
|
|
3016
3036
|
const getClusterOrMakeNew = async ({
|
|
3017
3037
|
chunk,
|
|
3018
|
-
isVideo
|
|
3019
|
-
trackNumber: trackNumber2
|
|
3038
|
+
isVideo
|
|
3020
3039
|
}) => {
|
|
3021
|
-
const
|
|
3022
|
-
const smallestProgress = trackProgressValues.length === 0 ? 0 : Math.min(...trackProgressValues);
|
|
3023
|
-
if (chunk.type === "key") {
|
|
3024
|
-
trackNumberProgresses[trackNumber2] = chunk.timestamp;
|
|
3025
|
-
}
|
|
3040
|
+
const smallestProgress = progressTracker.getSmallestProgress();
|
|
3026
3041
|
if (!currentCluster.shouldMakeNewCluster({
|
|
3027
3042
|
newT: smallestProgress,
|
|
3028
3043
|
isVideo,
|
|
@@ -3050,8 +3065,7 @@ var createMatroskaMedia = async ({
|
|
|
3050
3065
|
}) => {
|
|
3051
3066
|
const { cluster, isNew, smallestProgress } = await getClusterOrMakeNew({
|
|
3052
3067
|
chunk,
|
|
3053
|
-
isVideo
|
|
3054
|
-
trackNumber: trackNumber2
|
|
3068
|
+
isVideo
|
|
3055
3069
|
});
|
|
3056
3070
|
const newDuration = Math.round((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
3057
3071
|
await updateDuration(newDuration);
|
|
@@ -3064,12 +3078,16 @@ var createMatroskaMedia = async ({
|
|
|
3064
3078
|
trackNumber: trackNumber2
|
|
3065
3079
|
});
|
|
3066
3080
|
}
|
|
3081
|
+
if (chunk.type === "key") {
|
|
3082
|
+
progressTracker.updateTrackProgress(trackNumber2, chunk.timestamp);
|
|
3083
|
+
}
|
|
3067
3084
|
onBytesProgress(w.getWrittenByteCount());
|
|
3068
3085
|
onMillisecondsProgress(newDuration);
|
|
3069
3086
|
};
|
|
3070
3087
|
const addTrack = async (track) => {
|
|
3071
3088
|
currentTracks.push(track);
|
|
3072
3089
|
const newTracks = makeMatroskaTracks(currentTracks);
|
|
3090
|
+
progressTracker.registerTrack(track.trackNumber);
|
|
3073
3091
|
await w.updateDataAt(tracksOffset, combineUint8Arrays(newTracks.map((b) => b.bytes)));
|
|
3074
3092
|
};
|
|
3075
3093
|
const operationProm = { current: Promise.resolve() };
|
|
@@ -3095,10 +3113,6 @@ var createMatroskaMedia = async ({
|
|
|
3095
3113
|
operationProm.current = operationProm.current.then(() => addSample({ chunk, trackNumber: trackNumber2, isVideo }));
|
|
3096
3114
|
return operationProm.current;
|
|
3097
3115
|
},
|
|
3098
|
-
updateDuration: (duration2) => {
|
|
3099
|
-
operationProm.current = operationProm.current.then(() => updateDuration(duration2));
|
|
3100
|
-
return operationProm.current;
|
|
3101
|
-
},
|
|
3102
3116
|
addTrack: (track) => {
|
|
3103
3117
|
const trackNumber2 = currentTracks.length + 1;
|
|
3104
3118
|
operationProm.current = operationProm.current.then(() => addTrack({ ...track, trackNumber: trackNumber2 }));
|
|
@@ -3124,6 +3138,186 @@ var createMatroskaMedia = async ({
|
|
|
3124
3138
|
};
|
|
3125
3139
|
};
|
|
3126
3140
|
|
|
3141
|
+
// src/create/with-resolvers.ts
|
|
3142
|
+
var withResolvers = function() {
|
|
3143
|
+
let resolve;
|
|
3144
|
+
let reject;
|
|
3145
|
+
const promise = new Promise((res, rej) => {
|
|
3146
|
+
resolve = res;
|
|
3147
|
+
reject = rej;
|
|
3148
|
+
});
|
|
3149
|
+
return { promise, resolve, reject };
|
|
3150
|
+
};
|
|
3151
|
+
var withResolversAndWaitForReturn = () => {
|
|
3152
|
+
const { promise, reject, resolve } = withResolvers();
|
|
3153
|
+
const { promise: returnPromise, resolve: resolveReturn } = withResolvers();
|
|
3154
|
+
return {
|
|
3155
|
+
getPromiseToImmediatelyReturn: () => {
|
|
3156
|
+
resolveReturn(undefined);
|
|
3157
|
+
return promise;
|
|
3158
|
+
},
|
|
3159
|
+
reject: (reason) => {
|
|
3160
|
+
returnPromise.then(() => reject(reason));
|
|
3161
|
+
},
|
|
3162
|
+
resolve
|
|
3163
|
+
};
|
|
3164
|
+
};
|
|
3165
|
+
|
|
3166
|
+
// src/create/progress-tracker.ts
|
|
3167
|
+
var makeProgressTracker = () => {
|
|
3168
|
+
const trackNumberProgresses = {};
|
|
3169
|
+
const eventEmitter = new IoEventEmitter;
|
|
3170
|
+
const calculateSmallestProgress = () => {
|
|
3171
|
+
const progressValues = Object.values(trackNumberProgresses);
|
|
3172
|
+
if (progressValues.length === 0) {
|
|
3173
|
+
return 0;
|
|
3174
|
+
}
|
|
3175
|
+
return Math.min(...progressValues);
|
|
3176
|
+
};
|
|
3177
|
+
return {
|
|
3178
|
+
registerTrack: (trackNumber2) => {
|
|
3179
|
+
trackNumberProgresses[trackNumber2] = 0;
|
|
3180
|
+
},
|
|
3181
|
+
getSmallestProgress: () => {
|
|
3182
|
+
return calculateSmallestProgress();
|
|
3183
|
+
},
|
|
3184
|
+
updateTrackProgress: (trackNumber2, progress) => {
|
|
3185
|
+
if (trackNumberProgresses[trackNumber2] === undefined) {
|
|
3186
|
+
throw new Error(`Tried to update progress for a track that was not registered: ${trackNumber2}`);
|
|
3187
|
+
}
|
|
3188
|
+
trackNumberProgresses[trackNumber2] = progress;
|
|
3189
|
+
eventEmitter.dispatchEvent("progress", {
|
|
3190
|
+
smallestProgress: calculateSmallestProgress()
|
|
3191
|
+
});
|
|
3192
|
+
},
|
|
3193
|
+
waitForProgress: () => {
|
|
3194
|
+
const { promise, resolve } = withResolvers();
|
|
3195
|
+
const on = () => {
|
|
3196
|
+
eventEmitter.removeEventListener("processed", on);
|
|
3197
|
+
resolve();
|
|
3198
|
+
};
|
|
3199
|
+
eventEmitter.addEventListener("processed", on);
|
|
3200
|
+
return promise;
|
|
3201
|
+
}
|
|
3202
|
+
};
|
|
3203
|
+
};
|
|
3204
|
+
|
|
3205
|
+
// src/create/wav/create-wav.ts
|
|
3206
|
+
var numberTo32BiIntLittleEndian = (num) => {
|
|
3207
|
+
return new Uint8Array([
|
|
3208
|
+
num & 255,
|
|
3209
|
+
num >> 8 & 255,
|
|
3210
|
+
num >> 16 & 255,
|
|
3211
|
+
num >> 24 & 255
|
|
3212
|
+
]);
|
|
3213
|
+
};
|
|
3214
|
+
var numberTo16BitLittleEndian = (num) => {
|
|
3215
|
+
return new Uint8Array([num & 255, num >> 8 & 255]);
|
|
3216
|
+
};
|
|
3217
|
+
var BIT_DEPTH = 16;
|
|
3218
|
+
var BYTES_PER_SAMPLE = BIT_DEPTH / 8;
|
|
3219
|
+
var createWav = async ({
|
|
3220
|
+
filename,
|
|
3221
|
+
logLevel,
|
|
3222
|
+
onBytesProgress,
|
|
3223
|
+
onMillisecondsProgress,
|
|
3224
|
+
writer,
|
|
3225
|
+
progressTracker
|
|
3226
|
+
}) => {
|
|
3227
|
+
const w = await writer.createContent({ filename, mimeType: "audio/wav" });
|
|
3228
|
+
await w.write(new Uint8Array([82, 73, 70, 70]));
|
|
3229
|
+
const sizePosition = w.getWrittenByteCount();
|
|
3230
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
3231
|
+
await w.write(new Uint8Array([87, 65, 86, 69]));
|
|
3232
|
+
await w.write(new Uint8Array([102, 109, 116, 32]));
|
|
3233
|
+
await w.write(new Uint8Array([16, 0, 0, 0]));
|
|
3234
|
+
await w.write(new Uint8Array([1, 0]));
|
|
3235
|
+
const channelNumPosition = w.getWrittenByteCount();
|
|
3236
|
+
await w.write(new Uint8Array([1, 0]));
|
|
3237
|
+
const sampleRatePosition = w.getWrittenByteCount();
|
|
3238
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
3239
|
+
const byteRatePosition = w.getWrittenByteCount();
|
|
3240
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
3241
|
+
const blockAlignPosition = w.getWrittenByteCount();
|
|
3242
|
+
await w.write(new Uint8Array([0, 0]));
|
|
3243
|
+
await w.write(numberTo16BitLittleEndian(BIT_DEPTH));
|
|
3244
|
+
await w.write(new Uint8Array([100, 97, 116, 97]));
|
|
3245
|
+
const dataSizePosition = w.getWrittenByteCount();
|
|
3246
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
3247
|
+
const operationProm = { current: Promise.resolve() };
|
|
3248
|
+
const updateSize = async () => {
|
|
3249
|
+
const size = w.getWrittenByteCount() - sizePosition - 4;
|
|
3250
|
+
await w.updateDataAt(sizePosition, numberTo32BiIntLittleEndian(size));
|
|
3251
|
+
const dataSize = w.getWrittenByteCount() - dataSizePosition - 4;
|
|
3252
|
+
await w.updateDataAt(dataSizePosition, numberTo32BiIntLittleEndian(dataSize));
|
|
3253
|
+
};
|
|
3254
|
+
const updateChannelNum = async (numberOfChannels) => {
|
|
3255
|
+
await w.updateDataAt(channelNumPosition, new Uint8Array([numberOfChannels, 0]));
|
|
3256
|
+
};
|
|
3257
|
+
const updateSampleRate = async (sampleRate) => {
|
|
3258
|
+
await w.updateDataAt(sampleRatePosition, numberTo32BiIntLittleEndian(sampleRate));
|
|
3259
|
+
};
|
|
3260
|
+
const updateByteRate = async ({
|
|
3261
|
+
sampleRate,
|
|
3262
|
+
numberOfChannels
|
|
3263
|
+
}) => {
|
|
3264
|
+
await w.updateDataAt(byteRatePosition, numberTo32BiIntLittleEndian(sampleRate * numberOfChannels + BYTES_PER_SAMPLE));
|
|
3265
|
+
};
|
|
3266
|
+
const updateBlockAlign = async (numberOfChannels) => {
|
|
3267
|
+
await w.updateDataAt(blockAlignPosition, new Uint8Array(numberTo16BitLittleEndian(numberOfChannels * BYTES_PER_SAMPLE)));
|
|
3268
|
+
};
|
|
3269
|
+
const addSample = async (chunk) => {
|
|
3270
|
+
Log.verbose(logLevel, "Adding sample", chunk);
|
|
3271
|
+
await w.write(chunk.data);
|
|
3272
|
+
onMillisecondsProgress((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
3273
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
3274
|
+
};
|
|
3275
|
+
const waitForFinishPromises = [];
|
|
3276
|
+
return {
|
|
3277
|
+
save: () => {
|
|
3278
|
+
return w.save();
|
|
3279
|
+
},
|
|
3280
|
+
remove: () => {
|
|
3281
|
+
return w.remove();
|
|
3282
|
+
},
|
|
3283
|
+
addSample: ({ chunk, trackNumber: trackNumber2 }) => {
|
|
3284
|
+
if (trackNumber2 !== 1) {
|
|
3285
|
+
throw new Error("Only one track supported for WAV");
|
|
3286
|
+
}
|
|
3287
|
+
operationProm.current = operationProm.current.then(() => addSample(chunk));
|
|
3288
|
+
progressTracker.updateTrackProgress(trackNumber2, chunk.timestamp);
|
|
3289
|
+
return operationProm.current;
|
|
3290
|
+
},
|
|
3291
|
+
updateTrackSampleRate: () => {
|
|
3292
|
+
throw new Error("updateTrackSampleRate() not implemented for WAV encoder");
|
|
3293
|
+
},
|
|
3294
|
+
addWaitForFinishPromise: (promise) => {
|
|
3295
|
+
waitForFinishPromises.push(promise);
|
|
3296
|
+
},
|
|
3297
|
+
async waitForFinish() {
|
|
3298
|
+
Log.verbose(logLevel, "All write operations queued. Waiting for finish...");
|
|
3299
|
+
await Promise.all(waitForFinishPromises.map((p) => p()));
|
|
3300
|
+
await operationProm.current;
|
|
3301
|
+
await updateSize();
|
|
3302
|
+
await w.waitForFinish();
|
|
3303
|
+
},
|
|
3304
|
+
addTrack: async (track) => {
|
|
3305
|
+
if (track.type !== "audio") {
|
|
3306
|
+
throw new Error("Only audio tracks supported for WAV");
|
|
3307
|
+
}
|
|
3308
|
+
await updateChannelNum(track.numberOfChannels);
|
|
3309
|
+
await updateSampleRate(track.sampleRate);
|
|
3310
|
+
await updateByteRate({
|
|
3311
|
+
sampleRate: track.sampleRate,
|
|
3312
|
+
numberOfChannels: track.numberOfChannels
|
|
3313
|
+
});
|
|
3314
|
+
await updateBlockAlign(track.numberOfChannels);
|
|
3315
|
+
progressTracker.registerTrack(1);
|
|
3316
|
+
return Promise.resolve({ trackNumber: 1 });
|
|
3317
|
+
}
|
|
3318
|
+
};
|
|
3319
|
+
};
|
|
3320
|
+
|
|
3127
3321
|
// src/boxes/iso-base-media/traversal.ts
|
|
3128
3322
|
var getMoovBox = (segments) => {
|
|
3129
3323
|
const moovBox = segments.find((s) => s.type === "moov-box");
|
|
@@ -3289,317 +3483,133 @@ var getMdatBox = (anySegment) => {
|
|
|
3289
3483
|
return mdat;
|
|
3290
3484
|
};
|
|
3291
3485
|
|
|
3292
|
-
// src/
|
|
3293
|
-
var
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3486
|
+
// src/boxes/riff/traversal.ts
|
|
3487
|
+
var isRiffAvi = (structure) => {
|
|
3488
|
+
return structure.boxes.some((box) => box.type === "riff-header" && box.fileType === "AVI");
|
|
3489
|
+
};
|
|
3490
|
+
var getHdlrBox = (structure) => {
|
|
3491
|
+
return structure.boxes.find((box) => box.type === "list-box" && box.listType === "hdrl");
|
|
3492
|
+
};
|
|
3493
|
+
var getAvihBox = (structure) => {
|
|
3494
|
+
const hdlrBox = getHdlrBox(structure);
|
|
3495
|
+
if (!hdlrBox) {
|
|
3496
|
+
return null;
|
|
3497
|
+
}
|
|
3498
|
+
return hdlrBox.children.find((box) => box.type === "avih-box");
|
|
3499
|
+
};
|
|
3500
|
+
var getStrlBoxes = (structure) => {
|
|
3501
|
+
const hdlrBox = getHdlrBox(structure);
|
|
3502
|
+
if (!hdlrBox) {
|
|
3503
|
+
return [];
|
|
3504
|
+
}
|
|
3505
|
+
return hdlrBox.children.filter((box) => box.type === "list-box" && box.listType === "strl");
|
|
3506
|
+
};
|
|
3507
|
+
var getStrhBox = (strlBoxChildren) => {
|
|
3508
|
+
return strlBoxChildren.find((box) => box.type === "strh-box");
|
|
3509
|
+
};
|
|
3510
|
+
var getStrfBox = (strlBoxChildren) => {
|
|
3511
|
+
return strlBoxChildren.find((box) => box.type === "strf-box-audio" || box.type === "strf-box-video") ?? null;
|
|
3512
|
+
};
|
|
3513
|
+
|
|
3514
|
+
// src/get-fps.ts
|
|
3515
|
+
var calculateFps = ({
|
|
3298
3516
|
sttsBox,
|
|
3299
|
-
|
|
3517
|
+
timeScale,
|
|
3518
|
+
durationInSamples
|
|
3300
3519
|
}) => {
|
|
3301
|
-
|
|
3302
|
-
for (const
|
|
3303
|
-
|
|
3304
|
-
sttsDeltas.push(distribution.sampleDelta);
|
|
3305
|
-
}
|
|
3520
|
+
let totalSamples = 0;
|
|
3521
|
+
for (const sample of sttsBox.sampleDistribution) {
|
|
3522
|
+
totalSamples += sample.sampleCount;
|
|
3306
3523
|
}
|
|
3307
|
-
const
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3524
|
+
const durationInSeconds = durationInSamples / timeScale;
|
|
3525
|
+
const fps = totalSamples / durationInSeconds;
|
|
3526
|
+
return fps;
|
|
3527
|
+
};
|
|
3528
|
+
var trakBoxContainsAudio = (trakBox) => {
|
|
3529
|
+
const stsd = getStsdBox(trakBox);
|
|
3530
|
+
if (!stsd) {
|
|
3531
|
+
return false;
|
|
3314
3532
|
}
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3533
|
+
const videoSample = stsd.samples.find((s) => s.type === "audio");
|
|
3534
|
+
if (!videoSample || videoSample.type !== "audio") {
|
|
3535
|
+
return false;
|
|
3536
|
+
}
|
|
3537
|
+
return true;
|
|
3538
|
+
};
|
|
3539
|
+
var trakBoxContainsVideo = (trakBox) => {
|
|
3540
|
+
const stsd = getStsdBox(trakBox);
|
|
3541
|
+
if (!stsd) {
|
|
3542
|
+
return false;
|
|
3543
|
+
}
|
|
3544
|
+
const videoSample = stsd.samples.find((s) => s.type === "video");
|
|
3545
|
+
if (!videoSample || videoSample.type !== "video") {
|
|
3546
|
+
return false;
|
|
3547
|
+
}
|
|
3548
|
+
return true;
|
|
3549
|
+
};
|
|
3550
|
+
var getTimescaleAndDuration = (trakBox) => {
|
|
3551
|
+
const mdhdBox = getMdhdBox(trakBox);
|
|
3552
|
+
if (mdhdBox) {
|
|
3553
|
+
return { timescale: mdhdBox.timescale, duration: mdhdBox.duration };
|
|
3554
|
+
}
|
|
3555
|
+
return null;
|
|
3556
|
+
};
|
|
3557
|
+
var getFpsFromMp4TrakBox = (trakBox) => {
|
|
3558
|
+
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
3559
|
+
if (!timescaleAndDuration) {
|
|
3560
|
+
return null;
|
|
3561
|
+
}
|
|
3562
|
+
const sttsBox = getSttsBox(trakBox);
|
|
3563
|
+
if (!sttsBox) {
|
|
3564
|
+
return null;
|
|
3565
|
+
}
|
|
3566
|
+
return calculateFps({
|
|
3567
|
+
sttsBox,
|
|
3568
|
+
timeScale: timescaleAndDuration.timescale,
|
|
3569
|
+
durationInSamples: timescaleAndDuration.duration
|
|
3570
|
+
});
|
|
3571
|
+
};
|
|
3572
|
+
var getFpsFromIsoMaseMedia = (structure) => {
|
|
3573
|
+
const moovBox = getMoovBox(structure.boxes);
|
|
3574
|
+
if (!moovBox) {
|
|
3575
|
+
return null;
|
|
3576
|
+
}
|
|
3577
|
+
const trackBoxes = getTraks(moovBox);
|
|
3578
|
+
const trackBox = trackBoxes.find(trakBoxContainsVideo);
|
|
3579
|
+
if (!trackBox) {
|
|
3580
|
+
return null;
|
|
3581
|
+
}
|
|
3582
|
+
return getFpsFromMp4TrakBox(trackBox);
|
|
3583
|
+
};
|
|
3584
|
+
var getFpsFromAvi = (structure) => {
|
|
3585
|
+
const strl = getStrlBoxes(structure);
|
|
3586
|
+
for (const s of strl) {
|
|
3587
|
+
const strh = getStrhBox(s.children);
|
|
3588
|
+
if (!strh) {
|
|
3589
|
+
throw new Error("No strh box");
|
|
3323
3590
|
}
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
|
|
3327
|
-
const isKeyframe = stssBox ? stssBox.sampleNumber.includes(samples.length + 1) : true;
|
|
3328
|
-
const delta = sttsDeltas[samples.length];
|
|
3329
|
-
const ctsOffset = cttsEntries[samples.length];
|
|
3330
|
-
const cts = dts + ctsOffset;
|
|
3331
|
-
samples.push({
|
|
3332
|
-
offset: Number(chunks[i]) + offsetInThisChunk,
|
|
3333
|
-
size,
|
|
3334
|
-
isKeyframe,
|
|
3335
|
-
dts,
|
|
3336
|
-
cts,
|
|
3337
|
-
duration: delta,
|
|
3338
|
-
chunk: i
|
|
3339
|
-
});
|
|
3340
|
-
dts += delta;
|
|
3341
|
-
offsetInThisChunk += size;
|
|
3591
|
+
if (strh.fccType === "auds") {
|
|
3592
|
+
continue;
|
|
3342
3593
|
}
|
|
3594
|
+
return strh.rate;
|
|
3343
3595
|
}
|
|
3344
|
-
return
|
|
3596
|
+
return null;
|
|
3345
3597
|
};
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
|
|
3350
|
-
throw new Error("Expected traf-box");
|
|
3598
|
+
var getFps = (segments) => {
|
|
3599
|
+
if (segments.type === "iso-base-media") {
|
|
3600
|
+
return getFpsFromIsoMaseMedia(segments);
|
|
3351
3601
|
}
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
|
|
3355
|
-
const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
|
|
3356
|
-
const tfdtBox = getTfdtBox(trafSegment);
|
|
3357
|
-
const trunBoxes = getTrunBoxes(trafSegment);
|
|
3358
|
-
let time = 0;
|
|
3359
|
-
let offset = 0;
|
|
3360
|
-
let dataOffset = 0;
|
|
3361
|
-
const samples = [];
|
|
3362
|
-
for (const trunBox of trunBoxes) {
|
|
3363
|
-
let i = -1;
|
|
3364
|
-
if (trunBox.dataOffset) {
|
|
3365
|
-
dataOffset = trunBox.dataOffset;
|
|
3366
|
-
offset = 0;
|
|
3367
|
-
}
|
|
3368
|
-
for (const sample of trunBox.samples) {
|
|
3369
|
-
i++;
|
|
3370
|
-
const duration2 = sample.sampleDuration ?? defaultSampleDuration;
|
|
3371
|
-
if (duration2 === null) {
|
|
3372
|
-
throw new Error("Expected duration");
|
|
3373
|
-
}
|
|
3374
|
-
const size = sample.sampleSize ?? defaultSampleSize;
|
|
3375
|
-
if (size === null) {
|
|
3376
|
-
throw new Error("Expected size");
|
|
3377
|
-
}
|
|
3378
|
-
const isFirstSample = i === 0;
|
|
3379
|
-
const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
|
|
3380
|
-
if (sampleFlags === null) {
|
|
3381
|
-
throw new Error("Expected sample flags");
|
|
3382
|
-
}
|
|
3383
|
-
const keyframe = !(sampleFlags >> 16 & 1);
|
|
3384
|
-
const dts = time + (tfdtBox?.baseMediaDecodeTime ?? 0);
|
|
3385
|
-
const samplePosition = {
|
|
3386
|
-
offset: offset + (moofOffset ?? 0) + (dataOffset ?? 0),
|
|
3387
|
-
dts,
|
|
3388
|
-
cts: dts,
|
|
3389
|
-
duration: duration2,
|
|
3390
|
-
isKeyframe: keyframe,
|
|
3391
|
-
size,
|
|
3392
|
-
chunk: 0
|
|
3393
|
-
};
|
|
3394
|
-
samples.push(samplePosition);
|
|
3395
|
-
offset += size;
|
|
3396
|
-
time += duration2;
|
|
3397
|
-
}
|
|
3398
|
-
}
|
|
3399
|
-
return samples;
|
|
3400
|
-
};
|
|
3401
|
-
var getSamplesFromMoof = ({
|
|
3402
|
-
moofBox,
|
|
3403
|
-
trackId
|
|
3404
|
-
}) => {
|
|
3405
|
-
if (moofBox.type !== "regular-box") {
|
|
3406
|
-
throw new Error("Expected moof-box");
|
|
3407
|
-
}
|
|
3408
|
-
const trafs = moofBox.children.filter((c) => c.type === "regular-box" && c.boxType === "traf");
|
|
3409
|
-
const mapped = trafs.map((traf) => {
|
|
3410
|
-
const tfhdBox = getTfhdBox(traf);
|
|
3411
|
-
return tfhdBox?.trackId === trackId ? getSamplesFromTraf(traf, moofBox.offset) : [];
|
|
3412
|
-
});
|
|
3413
|
-
return mapped.flat(1);
|
|
3414
|
-
};
|
|
3415
|
-
|
|
3416
|
-
// src/boxes/iso-base-media/get-sample-positions-from-track.ts
|
|
3417
|
-
var getSamplePositionsFromTrack = (trakBox, moofBox) => {
|
|
3418
|
-
const stszBox = getStszBox(trakBox);
|
|
3419
|
-
const stcoBox = getStcoBox(trakBox);
|
|
3420
|
-
const stscBox = getStscBox(trakBox);
|
|
3421
|
-
const stssBox = getStssBox(trakBox);
|
|
3422
|
-
const sttsBox = getSttsBox(trakBox);
|
|
3423
|
-
const tkhdBox = getTkhdBox(trakBox);
|
|
3424
|
-
const cttsBox = getCttsBox(trakBox);
|
|
3425
|
-
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
3426
|
-
if (!tkhdBox) {
|
|
3427
|
-
throw new Error("Expected tkhd box in trak box");
|
|
3428
|
-
}
|
|
3429
|
-
if (!stszBox) {
|
|
3430
|
-
throw new Error("Expected stsz box in trak box");
|
|
3431
|
-
}
|
|
3432
|
-
if (!stcoBox) {
|
|
3433
|
-
throw new Error("Expected stco box in trak box");
|
|
3434
|
-
}
|
|
3435
|
-
if (!stscBox) {
|
|
3436
|
-
throw new Error("Expected stsc box in trak box");
|
|
3437
|
-
}
|
|
3438
|
-
if (!sttsBox) {
|
|
3439
|
-
throw new Error("Expected stts box in trak box");
|
|
3440
|
-
}
|
|
3441
|
-
if (!timescaleAndDuration) {
|
|
3442
|
-
throw new Error("Expected timescale and duration in trak box");
|
|
3443
|
-
}
|
|
3444
|
-
let samplePositions = getSamplePositions({
|
|
3445
|
-
stcoBox,
|
|
3446
|
-
stscBox,
|
|
3447
|
-
stszBox,
|
|
3448
|
-
stssBox,
|
|
3449
|
-
sttsBox,
|
|
3450
|
-
cttsBox
|
|
3451
|
-
});
|
|
3452
|
-
if (samplePositions.length === 0 && moofBox) {
|
|
3453
|
-
samplePositions = getSamplesFromMoof({ moofBox, trackId: tkhdBox.trackId });
|
|
3454
|
-
}
|
|
3455
|
-
return samplePositions;
|
|
3456
|
-
};
|
|
3457
|
-
|
|
3458
|
-
// src/get-duration.ts
|
|
3459
|
-
var getDurationFromMatroska = (segments) => {
|
|
3460
|
-
const mainSegment = segments.find((s) => s.type === "Segment");
|
|
3461
|
-
if (!mainSegment || mainSegment.type !== "Segment") {
|
|
3462
|
-
return null;
|
|
3463
|
-
}
|
|
3464
|
-
const { value: children } = mainSegment;
|
|
3465
|
-
if (!children) {
|
|
3466
|
-
return null;
|
|
3467
|
-
}
|
|
3468
|
-
const infoSegment = children.find((s) => s.type === "Info");
|
|
3469
|
-
const relevantBoxes = [
|
|
3470
|
-
...mainSegment.value,
|
|
3471
|
-
...infoSegment && infoSegment.type === "Info" ? infoSegment.value : []
|
|
3472
|
-
];
|
|
3473
|
-
const timestampScale2 = relevantBoxes.find((s) => s.type === "TimestampScale");
|
|
3474
|
-
if (!timestampScale2 || timestampScale2.type !== "TimestampScale") {
|
|
3475
|
-
return null;
|
|
3476
|
-
}
|
|
3477
|
-
const duration2 = relevantBoxes.find((s) => s.type === "Duration");
|
|
3478
|
-
if (!duration2 || duration2.type !== "Duration") {
|
|
3479
|
-
return null;
|
|
3480
|
-
}
|
|
3481
|
-
return duration2.value.value / timestampScale2.value.value * 1000;
|
|
3482
|
-
};
|
|
3483
|
-
var isMatroska = (boxes) => {
|
|
3484
|
-
const matroskaBox = boxes.find((b) => b.type === "Segment");
|
|
3485
|
-
return matroskaBox;
|
|
3486
|
-
};
|
|
3487
|
-
var getDuration = (boxes, parserState) => {
|
|
3488
|
-
if (isMatroska(boxes)) {
|
|
3489
|
-
return getDurationFromMatroska(boxes);
|
|
3490
|
-
}
|
|
3491
|
-
const moovBox = getMoovBox(boxes);
|
|
3492
|
-
if (!moovBox) {
|
|
3493
|
-
return null;
|
|
3602
|
+
if (segments.type === "riff") {
|
|
3603
|
+
return getFpsFromAvi(segments);
|
|
3494
3604
|
}
|
|
3495
|
-
|
|
3496
|
-
const mvhdBox = getMvhdBox(moovBox);
|
|
3497
|
-
if (!mvhdBox) {
|
|
3498
|
-
return null;
|
|
3499
|
-
}
|
|
3500
|
-
if (mvhdBox.type !== "mvhd-box") {
|
|
3501
|
-
throw new Error("Expected mvhd-box");
|
|
3502
|
-
}
|
|
3503
|
-
if (mvhdBox.durationInSeconds > 0) {
|
|
3504
|
-
return mvhdBox.durationInSeconds;
|
|
3505
|
-
}
|
|
3506
|
-
const tracks2 = getTracks(boxes, parserState);
|
|
3507
|
-
const allTracks = [
|
|
3508
|
-
...tracks2.videoTracks,
|
|
3509
|
-
...tracks2.audioTracks,
|
|
3510
|
-
...tracks2.otherTracks
|
|
3511
|
-
];
|
|
3512
|
-
const allSamples = allTracks.map((t) => {
|
|
3513
|
-
const { timescale: ts } = t;
|
|
3514
|
-
const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
|
|
3515
|
-
const highest = samplePositions?.map((sp) => (sp.cts + sp.duration) / ts).reduce((a, b) => Math.max(a, b), 0);
|
|
3516
|
-
return highest ?? 0;
|
|
3517
|
-
});
|
|
3518
|
-
const highestTimestamp = Math.max(...allSamples);
|
|
3519
|
-
return highestTimestamp;
|
|
3520
|
-
};
|
|
3521
|
-
var hasDuration = (boxes, parserState) => {
|
|
3522
|
-
try {
|
|
3523
|
-
const duration2 = getDuration(boxes, parserState);
|
|
3524
|
-
return getDuration(boxes, parserState) !== null && duration2 !== 0;
|
|
3525
|
-
} catch {
|
|
3526
|
-
return false;
|
|
3527
|
-
}
|
|
3528
|
-
};
|
|
3529
|
-
|
|
3530
|
-
// src/get-fps.ts
|
|
3531
|
-
var calculateFps = ({
|
|
3532
|
-
sttsBox,
|
|
3533
|
-
timeScale,
|
|
3534
|
-
durationInSamples
|
|
3535
|
-
}) => {
|
|
3536
|
-
let totalSamples = 0;
|
|
3537
|
-
for (const sample of sttsBox.sampleDistribution) {
|
|
3538
|
-
totalSamples += sample.sampleCount;
|
|
3539
|
-
}
|
|
3540
|
-
const durationInSeconds = durationInSamples / timeScale;
|
|
3541
|
-
const fps = totalSamples / durationInSeconds;
|
|
3542
|
-
return fps;
|
|
3543
|
-
};
|
|
3544
|
-
var trakBoxContainsAudio = (trakBox) => {
|
|
3545
|
-
const stsd = getStsdBox(trakBox);
|
|
3546
|
-
if (!stsd) {
|
|
3547
|
-
return false;
|
|
3548
|
-
}
|
|
3549
|
-
const videoSample = stsd.samples.find((s) => s.type === "audio");
|
|
3550
|
-
if (!videoSample || videoSample.type !== "audio") {
|
|
3551
|
-
return false;
|
|
3552
|
-
}
|
|
3553
|
-
return true;
|
|
3554
|
-
};
|
|
3555
|
-
var trakBoxContainsVideo = (trakBox) => {
|
|
3556
|
-
const stsd = getStsdBox(trakBox);
|
|
3557
|
-
if (!stsd) {
|
|
3558
|
-
return false;
|
|
3559
|
-
}
|
|
3560
|
-
const videoSample = stsd.samples.find((s) => s.type === "video");
|
|
3561
|
-
if (!videoSample || videoSample.type !== "video") {
|
|
3562
|
-
return false;
|
|
3563
|
-
}
|
|
3564
|
-
return true;
|
|
3565
|
-
};
|
|
3566
|
-
var getTimescaleAndDuration = (trakBox) => {
|
|
3567
|
-
const mdhdBox = getMdhdBox(trakBox);
|
|
3568
|
-
if (mdhdBox) {
|
|
3569
|
-
return { timescale: mdhdBox.timescale, duration: mdhdBox.duration };
|
|
3570
|
-
}
|
|
3571
|
-
return null;
|
|
3572
|
-
};
|
|
3573
|
-
var getFpsFromMp4TrakBox = (trakBox) => {
|
|
3574
|
-
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
3575
|
-
if (!timescaleAndDuration) {
|
|
3576
|
-
return null;
|
|
3577
|
-
}
|
|
3578
|
-
const sttsBox = getSttsBox(trakBox);
|
|
3579
|
-
if (!sttsBox) {
|
|
3580
|
-
return null;
|
|
3581
|
-
}
|
|
3582
|
-
return calculateFps({
|
|
3583
|
-
sttsBox,
|
|
3584
|
-
timeScale: timescaleAndDuration.timescale,
|
|
3585
|
-
durationInSamples: timescaleAndDuration.duration
|
|
3586
|
-
});
|
|
3587
|
-
};
|
|
3588
|
-
var getFps = (segments) => {
|
|
3589
|
-
const moovBox = getMoovBox(segments);
|
|
3590
|
-
if (!moovBox) {
|
|
3591
|
-
return null;
|
|
3592
|
-
}
|
|
3593
|
-
const trackBoxes = getTraks(moovBox);
|
|
3594
|
-
const trackBox = trackBoxes.find(trakBoxContainsVideo);
|
|
3595
|
-
if (!trackBox) {
|
|
3605
|
+
if (segments.type === "matroska") {
|
|
3596
3606
|
return null;
|
|
3597
3607
|
}
|
|
3598
|
-
|
|
3608
|
+
throw new Error("Cannot get fps, not implemented");
|
|
3599
3609
|
};
|
|
3600
3610
|
var hasFps = (boxes) => {
|
|
3601
3611
|
try {
|
|
3602
|
-
if (
|
|
3612
|
+
if (boxes.type === "matroska") {
|
|
3603
3613
|
return true;
|
|
3604
3614
|
}
|
|
3605
3615
|
return getFps(boxes) !== null;
|
|
@@ -3624,8 +3634,8 @@ var getAudioCodec = (boxes, parserState) => {
|
|
|
3624
3634
|
}
|
|
3625
3635
|
return null;
|
|
3626
3636
|
};
|
|
3627
|
-
var hasAudioCodec = (boxes) => {
|
|
3628
|
-
return hasTracks(boxes);
|
|
3637
|
+
var hasAudioCodec = (boxes, state) => {
|
|
3638
|
+
return hasTracks(boxes, state);
|
|
3629
3639
|
};
|
|
3630
3640
|
var getCodecSpecificatorFromEsdsBox = ({
|
|
3631
3641
|
child
|
|
@@ -3741,11 +3751,20 @@ var getAudioCodecFromTrak = (trak) => {
|
|
|
3741
3751
|
}
|
|
3742
3752
|
return null;
|
|
3743
3753
|
};
|
|
3754
|
+
var isLpcmAudioCodec = (trak) => {
|
|
3755
|
+
return getAudioCodecFromTrak(trak)?.format === "lpcm";
|
|
3756
|
+
};
|
|
3744
3757
|
var getAudioCodecStringFromTrak = (trak) => {
|
|
3745
3758
|
const codec = getAudioCodecFromTrak(trak);
|
|
3746
3759
|
if (!codec) {
|
|
3747
3760
|
throw new Error("Expected codec");
|
|
3748
3761
|
}
|
|
3762
|
+
if (codec.format === "lpcm") {
|
|
3763
|
+
return {
|
|
3764
|
+
codecString: "pcm-s16",
|
|
3765
|
+
description: codec.description
|
|
3766
|
+
};
|
|
3767
|
+
}
|
|
3749
3768
|
const codecStringWithoutMp3Exception = [
|
|
3750
3769
|
codec.format,
|
|
3751
3770
|
codec.primarySpecificator ? codec.primarySpecificator.toString(16) : null,
|
|
@@ -3761,6 +3780,9 @@ var getAudioCodecFromAudioCodecInfo = (codec) => {
|
|
|
3761
3780
|
if (codec.format === "twos") {
|
|
3762
3781
|
return "pcm-s16";
|
|
3763
3782
|
}
|
|
3783
|
+
if (codec.format === "lpcm") {
|
|
3784
|
+
return "pcm-s16";
|
|
3785
|
+
}
|
|
3764
3786
|
if (codec.format === "sowt") {
|
|
3765
3787
|
return "aiff";
|
|
3766
3788
|
}
|
|
@@ -3787,16 +3809,6 @@ var getAudioCodecFromTrack = (track) => {
|
|
|
3787
3809
|
};
|
|
3788
3810
|
|
|
3789
3811
|
// src/get-sample-aspect-ratio.ts
|
|
3790
|
-
function gcd(a, b) {
|
|
3791
|
-
return b === 0 ? a : gcd(b, a % b);
|
|
3792
|
-
}
|
|
3793
|
-
function reduceFraction(numerator, denominator) {
|
|
3794
|
-
const greatestCommonDivisor = gcd(Math.abs(numerator), Math.abs(denominator));
|
|
3795
|
-
return {
|
|
3796
|
-
numerator: numerator / greatestCommonDivisor,
|
|
3797
|
-
denominator: denominator / greatestCommonDivisor
|
|
3798
|
-
};
|
|
3799
|
-
}
|
|
3800
3812
|
var getStsdVideoConfig = (trakBox) => {
|
|
3801
3813
|
const stsdBox = getStsdBox(trakBox);
|
|
3802
3814
|
if (!stsdBox) {
|
|
@@ -3908,6 +3920,16 @@ var applyAspectRatios = ({
|
|
|
3908
3920
|
height: newHeight
|
|
3909
3921
|
};
|
|
3910
3922
|
};
|
|
3923
|
+
function gcd(a, b) {
|
|
3924
|
+
return b === 0 ? a : gcd(b, a % b);
|
|
3925
|
+
}
|
|
3926
|
+
function reduceFraction(numerator, denominator) {
|
|
3927
|
+
const greatestCommonDivisor = gcd(Math.abs(numerator), Math.abs(denominator));
|
|
3928
|
+
return {
|
|
3929
|
+
numerator: numerator / greatestCommonDivisor,
|
|
3930
|
+
denominator: denominator / greatestCommonDivisor
|
|
3931
|
+
};
|
|
3932
|
+
}
|
|
3911
3933
|
var getDisplayAspectRatio = ({
|
|
3912
3934
|
sampleAspectRatio,
|
|
3913
3935
|
nativeDimensions
|
|
@@ -3987,6 +4009,9 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
3987
4009
|
const allowDiscard = () => {
|
|
3988
4010
|
discardAllowed = true;
|
|
3989
4011
|
};
|
|
4012
|
+
const discard = (length) => {
|
|
4013
|
+
counter.increment(length);
|
|
4014
|
+
};
|
|
3990
4015
|
const getUint8 = () => {
|
|
3991
4016
|
const val = view.getUint8(counter.getDiscardedOffset());
|
|
3992
4017
|
counter.increment(1);
|
|
@@ -4032,8 +4057,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4032
4057
|
}
|
|
4033
4058
|
return lastInt;
|
|
4034
4059
|
};
|
|
4035
|
-
const getUint32 = (
|
|
4036
|
-
const val = view.getUint32(counter.getDiscardedOffset()
|
|
4060
|
+
const getUint32 = () => {
|
|
4061
|
+
const val = view.getUint32(counter.getDiscardedOffset());
|
|
4037
4062
|
counter.increment(4);
|
|
4038
4063
|
return val;
|
|
4039
4064
|
};
|
|
@@ -4042,9 +4067,21 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4042
4067
|
counter.increment(8);
|
|
4043
4068
|
return val;
|
|
4044
4069
|
};
|
|
4045
|
-
const
|
|
4046
|
-
const
|
|
4047
|
-
|
|
4070
|
+
const startBox = (size) => {
|
|
4071
|
+
const startOffset = counter.getOffset();
|
|
4072
|
+
return {
|
|
4073
|
+
discardRest: () => discard(size - (counter.getOffset() - startOffset)),
|
|
4074
|
+
expectNoMoreBytes: () => {
|
|
4075
|
+
const remaining = size - (counter.getOffset() - startOffset);
|
|
4076
|
+
if (remaining !== 0) {
|
|
4077
|
+
throw new Error("expected 0 bytes, got " + remaining);
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4080
|
+
};
|
|
4081
|
+
};
|
|
4082
|
+
const getUint32Le = () => {
|
|
4083
|
+
const val = view.getUint32(counter.getDiscardedOffset(), true);
|
|
4084
|
+
counter.increment(4);
|
|
4048
4085
|
return val;
|
|
4049
4086
|
};
|
|
4050
4087
|
const getInt32Le = () => {
|
|
@@ -4185,9 +4222,7 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4185
4222
|
leb128,
|
|
4186
4223
|
removeBytesRead,
|
|
4187
4224
|
isWebm,
|
|
4188
|
-
discard
|
|
4189
|
-
counter.increment(length);
|
|
4190
|
-
},
|
|
4225
|
+
discard,
|
|
4191
4226
|
getEightByteNumber,
|
|
4192
4227
|
getFourByteNumber,
|
|
4193
4228
|
getSlice,
|
|
@@ -4281,6 +4316,11 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4281
4316
|
counter.increment(2);
|
|
4282
4317
|
return val;
|
|
4283
4318
|
},
|
|
4319
|
+
getUint16Le: () => {
|
|
4320
|
+
const val = view.getUint16(counter.getDiscardedOffset(), true);
|
|
4321
|
+
counter.increment(2);
|
|
4322
|
+
return val;
|
|
4323
|
+
},
|
|
4284
4324
|
getUint24: () => {
|
|
4285
4325
|
const val1 = view.getUint8(counter.getDiscardedOffset());
|
|
4286
4326
|
const val2 = view.getUint8(counter.getDiscardedOffset() + 1);
|
|
@@ -4336,7 +4376,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4336
4376
|
destroy,
|
|
4337
4377
|
isMp3,
|
|
4338
4378
|
disallowDiscard,
|
|
4339
|
-
allowDiscard
|
|
4379
|
+
allowDiscard,
|
|
4380
|
+
startBox
|
|
4340
4381
|
};
|
|
4341
4382
|
};
|
|
4342
4383
|
|
|
@@ -4445,14 +4486,7 @@ var getVideoCodecFromIsoTrak = (trakBox) => {
|
|
|
4445
4486
|
}
|
|
4446
4487
|
throw new Error("Could not find video codec");
|
|
4447
4488
|
};
|
|
4448
|
-
var
|
|
4449
|
-
const moovBox = getMoovBox(boxes);
|
|
4450
|
-
if (moovBox) {
|
|
4451
|
-
const trakBox = getTraks(moovBox).filter((t) => trakBoxContainsVideo(t))[0];
|
|
4452
|
-
if (trakBox) {
|
|
4453
|
-
return getVideoCodecFromIsoTrak(trakBox);
|
|
4454
|
-
}
|
|
4455
|
-
}
|
|
4489
|
+
var getVideoCodecFromMatroska = (boxes) => {
|
|
4456
4490
|
const mainSegment = boxes.find((b) => b.type === "Segment");
|
|
4457
4491
|
if (!mainSegment || mainSegment.type !== "Segment") {
|
|
4458
4492
|
return null;
|
|
@@ -4483,10 +4517,44 @@ var getVideoCodec = (boxes) => {
|
|
|
4483
4517
|
}
|
|
4484
4518
|
}
|
|
4485
4519
|
}
|
|
4520
|
+
throw new Error("Could not find video codec");
|
|
4521
|
+
};
|
|
4522
|
+
var getVideoCodecFromAvi = (structure) => {
|
|
4523
|
+
const strl = getStrlBoxes(structure);
|
|
4524
|
+
for (const s of strl) {
|
|
4525
|
+
const strh = getStrhBox(s.children);
|
|
4526
|
+
if (!strh) {
|
|
4527
|
+
throw new Error("No strh box");
|
|
4528
|
+
}
|
|
4529
|
+
if (strh.fccType === "auds") {
|
|
4530
|
+
continue;
|
|
4531
|
+
}
|
|
4532
|
+
if (strh.handler === "H264") {
|
|
4533
|
+
return "h264";
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4536
|
+
throw new Error("Unsupported codec");
|
|
4537
|
+
};
|
|
4538
|
+
var getVideoCodec = (boxes) => {
|
|
4539
|
+
if (boxes.type === "iso-base-media") {
|
|
4540
|
+
const moovBox = getMoovBox(boxes.boxes);
|
|
4541
|
+
if (moovBox) {
|
|
4542
|
+
const trakBox = getTraks(moovBox).filter((t) => trakBoxContainsVideo(t))[0];
|
|
4543
|
+
if (trakBox) {
|
|
4544
|
+
return getVideoCodecFromIsoTrak(trakBox);
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
if (boxes.type === "riff") {
|
|
4549
|
+
return getVideoCodecFromAvi(boxes);
|
|
4550
|
+
}
|
|
4551
|
+
if (boxes.type === "matroska") {
|
|
4552
|
+
return getVideoCodecFromMatroska(boxes.boxes);
|
|
4553
|
+
}
|
|
4486
4554
|
return null;
|
|
4487
4555
|
};
|
|
4488
|
-
var hasVideoCodec = (boxes) => {
|
|
4489
|
-
return hasTracks(boxes);
|
|
4556
|
+
var hasVideoCodec = (boxes, state) => {
|
|
4557
|
+
return hasTracks(boxes, state);
|
|
4490
4558
|
};
|
|
4491
4559
|
var getVideoPrivateData = (trakBox) => {
|
|
4492
4560
|
const videoSample = getStsdVideoConfig(trakBox);
|
|
@@ -4521,9 +4589,9 @@ var getIsoBmColrConfig = (trakBox) => {
|
|
|
4521
4589
|
}
|
|
4522
4590
|
return {
|
|
4523
4591
|
fullRange: colrAtom.fullRangeFlag,
|
|
4524
|
-
matrixCoefficients: colrAtom.matrixIndex === 1 ? "bt709" : colrAtom.matrixIndex === 5 ? "bt470bg" : colrAtom.matrixIndex === 6 ? "smpte170m" : null,
|
|
4525
|
-
primaries: colrAtom.primaries === 1 ? "bt709" : colrAtom.primaries === 5 ? "bt470bg" : colrAtom.primaries === 6 ? "smpte170m" : null,
|
|
4526
|
-
transferCharacteristics: colrAtom.transfer === 1 ? "bt709" : colrAtom.transfer === 6 ? "smpte170m" : colrAtom.transfer === 13 ? "iec61966-2-1" : null
|
|
4592
|
+
matrixCoefficients: colrAtom.matrixIndex === 1 ? "bt709" : colrAtom.matrixIndex === 5 ? "bt470bg" : colrAtom.matrixIndex === 6 ? "smpte170m" : colrAtom.matrixIndex === 9 ? "bt2020" : null,
|
|
4593
|
+
primaries: colrAtom.primaries === 1 ? "bt709" : colrAtom.primaries === 5 ? "bt470bg" : colrAtom.primaries === 6 ? "smpte170m" : colrAtom.primaries === 9 ? "bt2020" : null,
|
|
4594
|
+
transferCharacteristics: colrAtom.transfer === 1 ? "bt709" : colrAtom.transfer === 6 ? "smpte170m" : colrAtom.transfer === 13 ? "iec61966-2-1" : colrAtom.transfer === 18 ? "arib-std-b67" : null
|
|
4527
4595
|
};
|
|
4528
4596
|
};
|
|
4529
4597
|
var getVideoCodecString = (trakBox) => {
|
|
@@ -4577,7 +4645,7 @@ var makeBaseMediaTrack = (trakBox) => {
|
|
|
4577
4645
|
sampleRate,
|
|
4578
4646
|
description,
|
|
4579
4647
|
trakBox,
|
|
4580
|
-
codecPrivate: getCodecPrivateFromTrak(trakBox),
|
|
4648
|
+
codecPrivate: getCodecPrivateFromTrak(trakBox) ?? description ?? null,
|
|
4581
4649
|
codecWithoutConfig: getAudioCodecFromTrack(trakBox)
|
|
4582
4650
|
};
|
|
4583
4651
|
}
|
|
@@ -4636,6 +4704,135 @@ var makeBaseMediaTrack = (trakBox) => {
|
|
|
4636
4704
|
return track;
|
|
4637
4705
|
};
|
|
4638
4706
|
|
|
4707
|
+
// src/add-avc-profile-to-track.ts
|
|
4708
|
+
var addAvcProfileToTrack = (track, avc1Profile) => {
|
|
4709
|
+
if (avc1Profile === null) {
|
|
4710
|
+
return track;
|
|
4711
|
+
}
|
|
4712
|
+
return {
|
|
4713
|
+
...track,
|
|
4714
|
+
codec: `avc1.${avc1Profile.sps.profile.toString(16).padStart(2, "0")}${avc1Profile.sps.compatibility.toString(16).padStart(2, "0")}${avc1Profile.sps.level.toString(16).padStart(2, "0")}`,
|
|
4715
|
+
codecPrivate: combineUint8Arrays([
|
|
4716
|
+
new Uint8Array([
|
|
4717
|
+
1,
|
|
4718
|
+
avc1Profile.sps.level,
|
|
4719
|
+
avc1Profile.sps.compatibility,
|
|
4720
|
+
avc1Profile.sps.profile,
|
|
4721
|
+
255,
|
|
4722
|
+
225
|
|
4723
|
+
]),
|
|
4724
|
+
serializeUint16(avc1Profile.sps.sps.length),
|
|
4725
|
+
avc1Profile.sps.sps,
|
|
4726
|
+
new Uint8Array([1]),
|
|
4727
|
+
serializeUint16(avc1Profile.pps.pps.length),
|
|
4728
|
+
avc1Profile.pps.pps
|
|
4729
|
+
])
|
|
4730
|
+
};
|
|
4731
|
+
};
|
|
4732
|
+
|
|
4733
|
+
// src/boxes/riff/timescale.ts
|
|
4734
|
+
var MEDIA_PARSER_RIFF_TIMESCALE = 1e6;
|
|
4735
|
+
|
|
4736
|
+
// src/boxes/riff/get-tracks-from-avi.ts
|
|
4737
|
+
var getNumberOfTracks = (structure) => {
|
|
4738
|
+
const avihBox = getAvihBox(structure);
|
|
4739
|
+
if (avihBox) {
|
|
4740
|
+
return avihBox.streams;
|
|
4741
|
+
}
|
|
4742
|
+
throw new Error("No avih box found");
|
|
4743
|
+
};
|
|
4744
|
+
var makeAviAudioTrack = ({
|
|
4745
|
+
strf,
|
|
4746
|
+
index
|
|
4747
|
+
}) => {
|
|
4748
|
+
if (strf.formatTag !== 255) {
|
|
4749
|
+
throw new Error(`Unsupported audio format ${strf.formatTag}`);
|
|
4750
|
+
}
|
|
4751
|
+
return {
|
|
4752
|
+
type: "audio",
|
|
4753
|
+
codec: "mp4a.40.2",
|
|
4754
|
+
codecPrivate: new Uint8Array([18, 16]),
|
|
4755
|
+
codecWithoutConfig: "aac",
|
|
4756
|
+
description: new Uint8Array([18, 16]),
|
|
4757
|
+
numberOfChannels: strf.numberOfChannels,
|
|
4758
|
+
sampleRate: strf.sampleRate,
|
|
4759
|
+
timescale: MEDIA_PARSER_RIFF_TIMESCALE,
|
|
4760
|
+
trackId: index,
|
|
4761
|
+
trakBox: null
|
|
4762
|
+
};
|
|
4763
|
+
};
|
|
4764
|
+
var makeAviVideoTrack = ({
|
|
4765
|
+
strh,
|
|
4766
|
+
strf,
|
|
4767
|
+
index
|
|
4768
|
+
}) => {
|
|
4769
|
+
if (strh.handler !== "H264") {
|
|
4770
|
+
throw new Error(`Unsupported video codec ${strh.handler}`);
|
|
4771
|
+
}
|
|
4772
|
+
return {
|
|
4773
|
+
codecPrivate: null,
|
|
4774
|
+
codec: "to-be-overriden-later",
|
|
4775
|
+
codecWithoutConfig: "h264",
|
|
4776
|
+
codedHeight: strf.height,
|
|
4777
|
+
codedWidth: strf.width,
|
|
4778
|
+
width: strf.width,
|
|
4779
|
+
height: strf.height,
|
|
4780
|
+
type: "video",
|
|
4781
|
+
displayAspectHeight: strf.height,
|
|
4782
|
+
timescale: MEDIA_PARSER_RIFF_TIMESCALE,
|
|
4783
|
+
description: undefined,
|
|
4784
|
+
trackId: index,
|
|
4785
|
+
color: {
|
|
4786
|
+
fullRange: null,
|
|
4787
|
+
matrixCoefficients: null,
|
|
4788
|
+
primaries: null,
|
|
4789
|
+
transferCharacteristics: null
|
|
4790
|
+
},
|
|
4791
|
+
displayAspectWidth: strf.width,
|
|
4792
|
+
trakBox: null,
|
|
4793
|
+
rotation: 0,
|
|
4794
|
+
sampleAspectRatio: {
|
|
4795
|
+
numerator: 1,
|
|
4796
|
+
denominator: 1
|
|
4797
|
+
},
|
|
4798
|
+
fps: strh.rate / strh.scale
|
|
4799
|
+
};
|
|
4800
|
+
};
|
|
4801
|
+
var getTracksFromAvi = (structure, state) => {
|
|
4802
|
+
if (!isRiffAvi(structure)) {
|
|
4803
|
+
throw new Error("Not an AVI file");
|
|
4804
|
+
}
|
|
4805
|
+
const videoTracks = [];
|
|
4806
|
+
const audioTracks = [];
|
|
4807
|
+
const otherTracks = [];
|
|
4808
|
+
const boxes = getStrlBoxes(structure);
|
|
4809
|
+
let i = 0;
|
|
4810
|
+
for (const box of boxes) {
|
|
4811
|
+
const strh = getStrhBox(box.children);
|
|
4812
|
+
const strf = getStrfBox(box.children);
|
|
4813
|
+
if (!strh || !strf) {
|
|
4814
|
+
continue;
|
|
4815
|
+
}
|
|
4816
|
+
if (strf.type === "strf-box-video") {
|
|
4817
|
+
videoTracks.push(addAvcProfileToTrack(makeAviVideoTrack({ strh, strf, index: i }), state.getAvcProfile()));
|
|
4818
|
+
} else if (strh.fccType === "auds") {
|
|
4819
|
+
audioTracks.push(makeAviAudioTrack({ strf, index: i }));
|
|
4820
|
+
} else {
|
|
4821
|
+
throw new Error(`Unsupported track type ${strh.fccType}`);
|
|
4822
|
+
}
|
|
4823
|
+
i++;
|
|
4824
|
+
}
|
|
4825
|
+
return { audioTracks, otherTracks, videoTracks };
|
|
4826
|
+
};
|
|
4827
|
+
var hasAllTracksFromAvi = (structure, state) => {
|
|
4828
|
+
if (!isRiffAvi(structure)) {
|
|
4829
|
+
throw new Error("Not an AVI file");
|
|
4830
|
+
}
|
|
4831
|
+
const numberOfTracks = getNumberOfTracks(structure);
|
|
4832
|
+
const tracks2 = getTracksFromAvi(structure, state);
|
|
4833
|
+
return tracks2.videoTracks.length + tracks2.audioTracks.length + tracks2.otherTracks.length === numberOfTracks;
|
|
4834
|
+
};
|
|
4835
|
+
|
|
4639
4836
|
// src/make-hvc1-codec-strings.ts
|
|
4640
4837
|
var getHvc1CodecString = (data) => {
|
|
4641
4838
|
const configurationVersion = data.getUint8();
|
|
@@ -4980,147 +5177,485 @@ var getTrack = ({
|
|
|
4980
5177
|
})
|
|
4981
5178
|
};
|
|
4982
5179
|
}
|
|
4983
|
-
return null;
|
|
5180
|
+
return null;
|
|
5181
|
+
};
|
|
5182
|
+
|
|
5183
|
+
// src/boxes/webm/get-ready-tracks.ts
|
|
5184
|
+
var getTracksFromMatroska = (segment, timescale2) => {
|
|
5185
|
+
const tracksSegment = getTracksSegment(segment);
|
|
5186
|
+
if (!tracksSegment) {
|
|
5187
|
+
throw new Error("No tracks segment");
|
|
5188
|
+
}
|
|
5189
|
+
const tracks2 = [];
|
|
5190
|
+
for (const trackEntrySegment of tracksSegment.value) {
|
|
5191
|
+
if (trackEntrySegment.type === "Crc32") {
|
|
5192
|
+
continue;
|
|
5193
|
+
}
|
|
5194
|
+
if (trackEntrySegment.type !== "TrackEntry") {
|
|
5195
|
+
throw new Error("Expected track entry segment");
|
|
5196
|
+
}
|
|
5197
|
+
const track = getTrack({
|
|
5198
|
+
track: trackEntrySegment,
|
|
5199
|
+
timescale: timescale2
|
|
5200
|
+
});
|
|
5201
|
+
if (track) {
|
|
5202
|
+
tracks2.push(track);
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
return tracks2;
|
|
5206
|
+
};
|
|
5207
|
+
|
|
5208
|
+
// src/get-tracks.ts
|
|
5209
|
+
var getNumberOfTracks2 = (moovBox) => {
|
|
5210
|
+
const mvHdBox = getMvhdBox(moovBox);
|
|
5211
|
+
if (!mvHdBox) {
|
|
5212
|
+
return 0;
|
|
5213
|
+
}
|
|
5214
|
+
return mvHdBox.nextTrackId - 1;
|
|
5215
|
+
};
|
|
5216
|
+
var hasTracks = (structure, state) => {
|
|
5217
|
+
if (structure.type === "matroska") {
|
|
5218
|
+
const mainSegment = getMainSegment(structure.boxes);
|
|
5219
|
+
if (!mainSegment) {
|
|
5220
|
+
throw new Error("No main segment found");
|
|
5221
|
+
}
|
|
5222
|
+
return getTracksSegment(mainSegment) !== null;
|
|
5223
|
+
}
|
|
5224
|
+
if (structure.type === "iso-base-media") {
|
|
5225
|
+
const moovBox = getMoovBox(structure.boxes);
|
|
5226
|
+
if (!moovBox) {
|
|
5227
|
+
return false;
|
|
5228
|
+
}
|
|
5229
|
+
const numberOfTracks = getNumberOfTracks2(moovBox);
|
|
5230
|
+
const tracks2 = getTraks(moovBox);
|
|
5231
|
+
return tracks2.length === numberOfTracks;
|
|
5232
|
+
}
|
|
5233
|
+
if (structure.type === "riff") {
|
|
5234
|
+
return hasAllTracksFromAvi(structure, state);
|
|
5235
|
+
}
|
|
5236
|
+
throw new Error("Unknown container");
|
|
5237
|
+
};
|
|
5238
|
+
var getTracksFromMa = (segments, state) => {
|
|
5239
|
+
const videoTracks = [];
|
|
5240
|
+
const audioTracks = [];
|
|
5241
|
+
const otherTracks = [];
|
|
5242
|
+
const mainSegment = segments.find((s) => s.type === "Segment");
|
|
5243
|
+
if (!mainSegment) {
|
|
5244
|
+
throw new Error("No main segment found");
|
|
5245
|
+
}
|
|
5246
|
+
const matroskaTracks = getTracksFromMatroska(mainSegment, state.getTimescale());
|
|
5247
|
+
for (const track of matroskaTracks) {
|
|
5248
|
+
if (track.type === "video") {
|
|
5249
|
+
videoTracks.push(track);
|
|
5250
|
+
} else if (track.type === "audio") {
|
|
5251
|
+
audioTracks.push(track);
|
|
5252
|
+
} else if (track.type === "other") {
|
|
5253
|
+
otherTracks.push(track);
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
return {
|
|
5257
|
+
videoTracks,
|
|
5258
|
+
audioTracks,
|
|
5259
|
+
otherTracks
|
|
5260
|
+
};
|
|
5261
|
+
};
|
|
5262
|
+
var getTracksFromIsoBaseMedia = (segments) => {
|
|
5263
|
+
const videoTracks = [];
|
|
5264
|
+
const audioTracks = [];
|
|
5265
|
+
const otherTracks = [];
|
|
5266
|
+
const moovBox = getMoovBox(segments);
|
|
5267
|
+
if (!moovBox) {
|
|
5268
|
+
return {
|
|
5269
|
+
videoTracks,
|
|
5270
|
+
audioTracks,
|
|
5271
|
+
otherTracks
|
|
5272
|
+
};
|
|
5273
|
+
}
|
|
5274
|
+
const tracks2 = getTraks(moovBox);
|
|
5275
|
+
for (const trakBox of tracks2) {
|
|
5276
|
+
const track = makeBaseMediaTrack(trakBox);
|
|
5277
|
+
if (!track) {
|
|
5278
|
+
continue;
|
|
5279
|
+
}
|
|
5280
|
+
if (track.type === "video") {
|
|
5281
|
+
videoTracks.push(track);
|
|
5282
|
+
} else if (track.type === "audio") {
|
|
5283
|
+
audioTracks.push(track);
|
|
5284
|
+
} else if (track.type === "other") {
|
|
5285
|
+
otherTracks.push(track);
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
return {
|
|
5289
|
+
videoTracks,
|
|
5290
|
+
audioTracks,
|
|
5291
|
+
otherTracks
|
|
5292
|
+
};
|
|
5293
|
+
};
|
|
5294
|
+
var getTracks = (segments, state) => {
|
|
5295
|
+
if (segments.type === "matroska") {
|
|
5296
|
+
return getTracksFromMa(segments.boxes, state);
|
|
5297
|
+
}
|
|
5298
|
+
if (segments.type === "iso-base-media") {
|
|
5299
|
+
return getTracksFromIsoBaseMedia(segments.boxes);
|
|
5300
|
+
}
|
|
5301
|
+
if (segments.type === "riff") {
|
|
5302
|
+
return getTracksFromAvi(segments, state);
|
|
5303
|
+
}
|
|
5304
|
+
throw new Error("Unknown container");
|
|
5305
|
+
};
|
|
5306
|
+
|
|
5307
|
+
// src/get-container.ts
|
|
5308
|
+
var getContainer = (segments) => {
|
|
5309
|
+
if (segments.type === "iso-base-media") {
|
|
5310
|
+
return "mp4";
|
|
5311
|
+
}
|
|
5312
|
+
if (segments.type === "matroska") {
|
|
5313
|
+
return "webm";
|
|
5314
|
+
}
|
|
5315
|
+
if (segments.type === "riff") {
|
|
5316
|
+
if (isRiffAvi(segments)) {
|
|
5317
|
+
return "avi";
|
|
5318
|
+
}
|
|
5319
|
+
}
|
|
5320
|
+
throw new Error("Unknown container");
|
|
5321
|
+
};
|
|
5322
|
+
var hasContainer = (boxes) => {
|
|
5323
|
+
try {
|
|
5324
|
+
return getContainer(boxes) !== null;
|
|
5325
|
+
} catch {
|
|
5326
|
+
return false;
|
|
5327
|
+
}
|
|
5328
|
+
};
|
|
5329
|
+
|
|
5330
|
+
// src/get-dimensions.ts
|
|
5331
|
+
var getDimensions = (boxes, state) => {
|
|
5332
|
+
const { videoTracks } = getTracks(boxes, state);
|
|
5333
|
+
if (!videoTracks.length) {
|
|
5334
|
+
throw new Error("Expected video track");
|
|
5335
|
+
}
|
|
5336
|
+
const firstVideoTrack = videoTracks[0];
|
|
5337
|
+
return {
|
|
5338
|
+
width: firstVideoTrack.width,
|
|
5339
|
+
height: firstVideoTrack.height,
|
|
5340
|
+
rotation: firstVideoTrack.rotation,
|
|
5341
|
+
unrotatedHeight: firstVideoTrack.displayAspectHeight,
|
|
5342
|
+
unrotatedWidth: firstVideoTrack.displayAspectWidth
|
|
5343
|
+
};
|
|
5344
|
+
};
|
|
5345
|
+
var hasDimensions = (boxes, state) => {
|
|
5346
|
+
try {
|
|
5347
|
+
return getDimensions(boxes, state) !== null;
|
|
5348
|
+
} catch {
|
|
5349
|
+
return false;
|
|
5350
|
+
}
|
|
5351
|
+
};
|
|
5352
|
+
|
|
5353
|
+
// src/get-sample-positions.ts
|
|
5354
|
+
var getSamplePositions = ({
|
|
5355
|
+
stcoBox,
|
|
5356
|
+
stszBox,
|
|
5357
|
+
stscBox,
|
|
5358
|
+
stssBox,
|
|
5359
|
+
sttsBox,
|
|
5360
|
+
cttsBox
|
|
5361
|
+
}) => {
|
|
5362
|
+
const sttsDeltas = [];
|
|
5363
|
+
for (const distribution of sttsBox.sampleDistribution) {
|
|
5364
|
+
for (let i = 0;i < distribution.sampleCount; i++) {
|
|
5365
|
+
sttsDeltas.push(distribution.sampleDelta);
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5368
|
+
const cttsEntries = [];
|
|
5369
|
+
for (const entry of cttsBox?.entries ?? [
|
|
5370
|
+
{ sampleCount: sttsDeltas.length, sampleOffset: 0 }
|
|
5371
|
+
]) {
|
|
5372
|
+
for (let i = 0;i < entry.sampleCount; i++) {
|
|
5373
|
+
cttsEntries.push(entry.sampleOffset);
|
|
5374
|
+
}
|
|
5375
|
+
}
|
|
5376
|
+
let dts = 0;
|
|
5377
|
+
const chunks = stcoBox.entries;
|
|
5378
|
+
const samples = [];
|
|
5379
|
+
let samplesPerChunk = 1;
|
|
5380
|
+
for (let i = 0;i < chunks.length; i++) {
|
|
5381
|
+
const hasEntry = stscBox.entries.find((entry) => entry.firstChunk === i + 1);
|
|
5382
|
+
if (hasEntry) {
|
|
5383
|
+
samplesPerChunk = hasEntry.samplesPerChunk;
|
|
5384
|
+
}
|
|
5385
|
+
let offsetInThisChunk = 0;
|
|
5386
|
+
for (let j = 0;j < samplesPerChunk; j++) {
|
|
5387
|
+
const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
|
|
5388
|
+
const isKeyframe = stssBox ? stssBox.sampleNumber.includes(samples.length + 1) : true;
|
|
5389
|
+
const delta = sttsDeltas[samples.length];
|
|
5390
|
+
const ctsOffset = cttsEntries[samples.length];
|
|
5391
|
+
const cts = dts + ctsOffset;
|
|
5392
|
+
samples.push({
|
|
5393
|
+
offset: Number(chunks[i]) + offsetInThisChunk,
|
|
5394
|
+
size,
|
|
5395
|
+
isKeyframe,
|
|
5396
|
+
dts,
|
|
5397
|
+
cts,
|
|
5398
|
+
duration: delta,
|
|
5399
|
+
chunk: i
|
|
5400
|
+
});
|
|
5401
|
+
dts += delta;
|
|
5402
|
+
offsetInThisChunk += size;
|
|
5403
|
+
}
|
|
5404
|
+
}
|
|
5405
|
+
return samples;
|
|
5406
|
+
};
|
|
5407
|
+
|
|
5408
|
+
// src/get-sample-positions-from-lpcm.ts
|
|
5409
|
+
var getSamplePositionsFromLpcm = (trakBox) => {
|
|
5410
|
+
const stscBox = getStscBox(trakBox);
|
|
5411
|
+
const stszBox = getStszBox(trakBox);
|
|
5412
|
+
const stcoBox = getStcoBox(trakBox);
|
|
5413
|
+
if (!stscBox) {
|
|
5414
|
+
throw new Error("Expected stsc box in trak box");
|
|
5415
|
+
}
|
|
5416
|
+
if (!stcoBox) {
|
|
5417
|
+
throw new Error("Expected stco box in trak box");
|
|
5418
|
+
}
|
|
5419
|
+
if (!stszBox) {
|
|
5420
|
+
throw new Error("Expected stsz box in trak box");
|
|
5421
|
+
}
|
|
5422
|
+
if (stszBox.countType !== "fixed") {
|
|
5423
|
+
throw new Error("Only supporting fixed count type in stsz box");
|
|
5424
|
+
}
|
|
5425
|
+
const samples = [];
|
|
5426
|
+
let timestamp = 0;
|
|
5427
|
+
for (let i = 0;i < stcoBox.entries.length; i++) {
|
|
5428
|
+
const entry = stcoBox.entries[i];
|
|
5429
|
+
const chunk = i + 1;
|
|
5430
|
+
const stscEntry = stscBox.entries.findLast((e) => e.firstChunk <= chunk);
|
|
5431
|
+
if (!stscEntry) {
|
|
5432
|
+
throw new Error("should not be");
|
|
5433
|
+
}
|
|
5434
|
+
samples.push({
|
|
5435
|
+
chunk,
|
|
5436
|
+
cts: timestamp,
|
|
5437
|
+
dts: timestamp,
|
|
5438
|
+
offset: Number(entry),
|
|
5439
|
+
size: stszBox.sampleSize * stscEntry.samplesPerChunk,
|
|
5440
|
+
duration: stscEntry.samplesPerChunk,
|
|
5441
|
+
isKeyframe: true
|
|
5442
|
+
});
|
|
5443
|
+
timestamp += stscEntry.samplesPerChunk;
|
|
5444
|
+
}
|
|
5445
|
+
return samples;
|
|
5446
|
+
};
|
|
5447
|
+
|
|
5448
|
+
// src/samples-from-moof.ts
|
|
5449
|
+
var getSamplesFromTraf = (trafSegment, moofOffset) => {
|
|
5450
|
+
if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
|
|
5451
|
+
throw new Error("Expected traf-box");
|
|
5452
|
+
}
|
|
5453
|
+
const tfhdBox = getTfhdBox(trafSegment);
|
|
5454
|
+
const defaultSampleDuration = tfhdBox?.defaultSampleDuration ?? null;
|
|
5455
|
+
const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
|
|
5456
|
+
const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
|
|
5457
|
+
const tfdtBox = getTfdtBox(trafSegment);
|
|
5458
|
+
const trunBoxes = getTrunBoxes(trafSegment);
|
|
5459
|
+
let time = 0;
|
|
5460
|
+
let offset = 0;
|
|
5461
|
+
let dataOffset = 0;
|
|
5462
|
+
const samples = [];
|
|
5463
|
+
for (const trunBox of trunBoxes) {
|
|
5464
|
+
let i = -1;
|
|
5465
|
+
if (trunBox.dataOffset) {
|
|
5466
|
+
dataOffset = trunBox.dataOffset;
|
|
5467
|
+
offset = 0;
|
|
5468
|
+
}
|
|
5469
|
+
for (const sample of trunBox.samples) {
|
|
5470
|
+
i++;
|
|
5471
|
+
const duration2 = sample.sampleDuration ?? defaultSampleDuration;
|
|
5472
|
+
if (duration2 === null) {
|
|
5473
|
+
throw new Error("Expected duration");
|
|
5474
|
+
}
|
|
5475
|
+
const size = sample.sampleSize ?? defaultSampleSize;
|
|
5476
|
+
if (size === null) {
|
|
5477
|
+
throw new Error("Expected size");
|
|
5478
|
+
}
|
|
5479
|
+
const isFirstSample = i === 0;
|
|
5480
|
+
const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
|
|
5481
|
+
if (sampleFlags === null) {
|
|
5482
|
+
throw new Error("Expected sample flags");
|
|
5483
|
+
}
|
|
5484
|
+
const keyframe = !(sampleFlags >> 16 & 1);
|
|
5485
|
+
const dts = time + (tfdtBox?.baseMediaDecodeTime ?? 0);
|
|
5486
|
+
const samplePosition = {
|
|
5487
|
+
offset: offset + (moofOffset ?? 0) + (dataOffset ?? 0),
|
|
5488
|
+
dts,
|
|
5489
|
+
cts: dts,
|
|
5490
|
+
duration: duration2,
|
|
5491
|
+
isKeyframe: keyframe,
|
|
5492
|
+
size,
|
|
5493
|
+
chunk: 0
|
|
5494
|
+
};
|
|
5495
|
+
samples.push(samplePosition);
|
|
5496
|
+
offset += size;
|
|
5497
|
+
time += duration2;
|
|
5498
|
+
}
|
|
5499
|
+
}
|
|
5500
|
+
return samples;
|
|
4984
5501
|
};
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
if (
|
|
4990
|
-
throw new Error("
|
|
4991
|
-
}
|
|
4992
|
-
const tracks2 = [];
|
|
4993
|
-
for (const trackEntrySegment of tracksSegment.value) {
|
|
4994
|
-
if (trackEntrySegment.type === "Crc32") {
|
|
4995
|
-
continue;
|
|
4996
|
-
}
|
|
4997
|
-
if (trackEntrySegment.type !== "TrackEntry") {
|
|
4998
|
-
throw new Error("Expected track entry segment");
|
|
4999
|
-
}
|
|
5000
|
-
const track = getTrack({
|
|
5001
|
-
track: trackEntrySegment,
|
|
5002
|
-
timescale: timescale2
|
|
5003
|
-
});
|
|
5004
|
-
if (track) {
|
|
5005
|
-
tracks2.push(track);
|
|
5006
|
-
}
|
|
5502
|
+
var getSamplesFromMoof = ({
|
|
5503
|
+
moofBox,
|
|
5504
|
+
trackId
|
|
5505
|
+
}) => {
|
|
5506
|
+
if (moofBox.type !== "regular-box") {
|
|
5507
|
+
throw new Error("Expected moof-box");
|
|
5007
5508
|
}
|
|
5008
|
-
|
|
5509
|
+
const trafs = moofBox.children.filter((c) => c.type === "regular-box" && c.boxType === "traf");
|
|
5510
|
+
const mapped = trafs.map((traf) => {
|
|
5511
|
+
const tfhdBox = getTfhdBox(traf);
|
|
5512
|
+
return tfhdBox?.trackId === trackId ? getSamplesFromTraf(traf, moofBox.offset) : [];
|
|
5513
|
+
});
|
|
5514
|
+
return mapped.flat(1);
|
|
5009
5515
|
};
|
|
5010
5516
|
|
|
5011
|
-
// src/get-
|
|
5012
|
-
var
|
|
5013
|
-
const
|
|
5014
|
-
|
|
5015
|
-
|
|
5517
|
+
// src/boxes/iso-base-media/get-sample-positions-from-track.ts
|
|
5518
|
+
var getSamplePositionsFromTrack = (trakBox, moofBox) => {
|
|
5519
|
+
const isLpcm = isLpcmAudioCodec(trakBox);
|
|
5520
|
+
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
5521
|
+
if (isLpcm) {
|
|
5522
|
+
return getSamplePositionsFromLpcm(trakBox);
|
|
5016
5523
|
}
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
const
|
|
5021
|
-
|
|
5022
|
-
|
|
5524
|
+
const stszBox = getStszBox(trakBox);
|
|
5525
|
+
const stcoBox = getStcoBox(trakBox);
|
|
5526
|
+
const stscBox = getStscBox(trakBox);
|
|
5527
|
+
const stssBox = getStssBox(trakBox);
|
|
5528
|
+
const sttsBox = getSttsBox(trakBox);
|
|
5529
|
+
const tkhdBox = getTkhdBox(trakBox);
|
|
5530
|
+
const cttsBox = getCttsBox(trakBox);
|
|
5531
|
+
if (!tkhdBox) {
|
|
5532
|
+
throw new Error("Expected tkhd box in trak box");
|
|
5023
5533
|
}
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
return false;
|
|
5534
|
+
if (!stszBox) {
|
|
5535
|
+
throw new Error("Expected stsz box in trak box");
|
|
5027
5536
|
}
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5537
|
+
if (!stcoBox) {
|
|
5538
|
+
throw new Error("Expected stco box in trak box");
|
|
5539
|
+
}
|
|
5540
|
+
if (!stscBox) {
|
|
5541
|
+
throw new Error("Expected stsc box in trak box");
|
|
5542
|
+
}
|
|
5543
|
+
if (!sttsBox) {
|
|
5544
|
+
throw new Error("Expected stts box in trak box");
|
|
5545
|
+
}
|
|
5546
|
+
if (!timescaleAndDuration) {
|
|
5547
|
+
throw new Error("Expected timescale and duration in trak box");
|
|
5548
|
+
}
|
|
5549
|
+
let samplePositions = getSamplePositions({
|
|
5550
|
+
stcoBox,
|
|
5551
|
+
stscBox,
|
|
5552
|
+
stszBox,
|
|
5553
|
+
stssBox,
|
|
5554
|
+
sttsBox,
|
|
5555
|
+
cttsBox
|
|
5556
|
+
});
|
|
5557
|
+
if (samplePositions.length === 0 && moofBox) {
|
|
5558
|
+
samplePositions = getSamplesFromMoof({ moofBox, trackId: tkhdBox.trackId });
|
|
5559
|
+
}
|
|
5560
|
+
return samplePositions;
|
|
5031
5561
|
};
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
const otherTracks = [];
|
|
5562
|
+
|
|
5563
|
+
// src/get-duration.ts
|
|
5564
|
+
var getDurationFromMatroska = (segments) => {
|
|
5036
5565
|
const mainSegment = segments.find((s) => s.type === "Segment");
|
|
5037
|
-
if (mainSegment
|
|
5038
|
-
|
|
5039
|
-
for (const track of matroskaTracks) {
|
|
5040
|
-
if (track.type === "video") {
|
|
5041
|
-
videoTracks.push(track);
|
|
5042
|
-
} else if (track.type === "audio") {
|
|
5043
|
-
audioTracks.push(track);
|
|
5044
|
-
} else if (track.type === "other") {
|
|
5045
|
-
otherTracks.push(track);
|
|
5046
|
-
}
|
|
5047
|
-
}
|
|
5048
|
-
return {
|
|
5049
|
-
videoTracks,
|
|
5050
|
-
audioTracks,
|
|
5051
|
-
otherTracks
|
|
5052
|
-
};
|
|
5566
|
+
if (!mainSegment || mainSegment.type !== "Segment") {
|
|
5567
|
+
return null;
|
|
5053
5568
|
}
|
|
5054
|
-
const
|
|
5569
|
+
const { value: children } = mainSegment;
|
|
5570
|
+
if (!children) {
|
|
5571
|
+
return null;
|
|
5572
|
+
}
|
|
5573
|
+
const infoSegment = children.find((s) => s.type === "Info");
|
|
5574
|
+
const relevantBoxes = [
|
|
5575
|
+
...mainSegment.value,
|
|
5576
|
+
...infoSegment && infoSegment.type === "Info" ? infoSegment.value : []
|
|
5577
|
+
];
|
|
5578
|
+
const timestampScale2 = relevantBoxes.find((s) => s.type === "TimestampScale");
|
|
5579
|
+
if (!timestampScale2 || timestampScale2.type !== "TimestampScale") {
|
|
5580
|
+
return null;
|
|
5581
|
+
}
|
|
5582
|
+
const duration2 = relevantBoxes.find((s) => s.type === "Duration");
|
|
5583
|
+
if (!duration2 || duration2.type !== "Duration") {
|
|
5584
|
+
return null;
|
|
5585
|
+
}
|
|
5586
|
+
return duration2.value.value / timestampScale2.value.value * 1000;
|
|
5587
|
+
};
|
|
5588
|
+
var getDurationFromIsoBaseMedia = (structure, parserState) => {
|
|
5589
|
+
const moovBox = getMoovBox(structure.boxes);
|
|
5055
5590
|
if (!moovBox) {
|
|
5056
|
-
return
|
|
5057
|
-
videoTracks,
|
|
5058
|
-
audioTracks,
|
|
5059
|
-
otherTracks
|
|
5060
|
-
};
|
|
5591
|
+
return null;
|
|
5061
5592
|
}
|
|
5062
|
-
const
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5593
|
+
const moofBox = getMoofBox(structure.boxes);
|
|
5594
|
+
const mvhdBox = getMvhdBox(moovBox);
|
|
5595
|
+
if (!mvhdBox) {
|
|
5596
|
+
return null;
|
|
5597
|
+
}
|
|
5598
|
+
if (mvhdBox.type !== "mvhd-box") {
|
|
5599
|
+
throw new Error("Expected mvhd-box");
|
|
5600
|
+
}
|
|
5601
|
+
if (mvhdBox.durationInSeconds > 0) {
|
|
5602
|
+
return mvhdBox.durationInSeconds;
|
|
5603
|
+
}
|
|
5604
|
+
const tracks2 = getTracks(structure, parserState);
|
|
5605
|
+
const allTracks = [
|
|
5606
|
+
...tracks2.videoTracks,
|
|
5607
|
+
...tracks2.audioTracks,
|
|
5608
|
+
...tracks2.otherTracks
|
|
5609
|
+
];
|
|
5610
|
+
const allSamples = allTracks.map((t) => {
|
|
5611
|
+
const { timescale: ts } = t;
|
|
5612
|
+
const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
|
|
5613
|
+
const highest = samplePositions?.map((sp) => (sp.cts + sp.duration) / ts).reduce((a, b) => Math.max(a, b), 0);
|
|
5614
|
+
return highest ?? 0;
|
|
5615
|
+
});
|
|
5616
|
+
const highestTimestamp = Math.max(...allSamples);
|
|
5617
|
+
return highestTimestamp;
|
|
5618
|
+
};
|
|
5619
|
+
var getDurationFromAvi = (structure) => {
|
|
5620
|
+
const strl = getStrlBoxes(structure);
|
|
5621
|
+
const lengths = [];
|
|
5622
|
+
for (const s of strl) {
|
|
5623
|
+
const strh = getStrhBox(s.children);
|
|
5624
|
+
if (!strh) {
|
|
5625
|
+
throw new Error("No strh box");
|
|
5074
5626
|
}
|
|
5627
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
5628
|
+
const streamLength = strh.length / samplesPerSecond;
|
|
5629
|
+
lengths.push(streamLength);
|
|
5075
5630
|
}
|
|
5076
|
-
return
|
|
5077
|
-
videoTracks,
|
|
5078
|
-
audioTracks,
|
|
5079
|
-
otherTracks
|
|
5080
|
-
};
|
|
5631
|
+
return Math.max(...lengths);
|
|
5081
5632
|
};
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
const moovBox = getMoovBox(segments);
|
|
5086
|
-
if (moovBox) {
|
|
5087
|
-
return "mp4";
|
|
5633
|
+
var getDuration = (structure, parserState) => {
|
|
5634
|
+
if (structure.type === "matroska") {
|
|
5635
|
+
return getDurationFromMatroska(structure.boxes);
|
|
5088
5636
|
}
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
return "webm";
|
|
5637
|
+
if (structure.type === "iso-base-media") {
|
|
5638
|
+
return getDurationFromIsoBaseMedia(structure, parserState);
|
|
5092
5639
|
}
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
var hasContainer = (boxes) => {
|
|
5096
|
-
try {
|
|
5097
|
-
return getContainer(boxes) !== null;
|
|
5098
|
-
} catch {
|
|
5099
|
-
return false;
|
|
5640
|
+
if (structure.type === "riff") {
|
|
5641
|
+
return getDurationFromAvi(structure);
|
|
5100
5642
|
}
|
|
5643
|
+
throw new Error("Has no duration");
|
|
5644
|
+
};
|
|
5645
|
+
var hasDuration = (structure, parserState) => {
|
|
5646
|
+
return hasTracks(structure, parserState);
|
|
5101
5647
|
};
|
|
5102
5648
|
|
|
5103
|
-
// src/get-
|
|
5104
|
-
var
|
|
5649
|
+
// src/get-is-hdr.ts
|
|
5650
|
+
var isVideoTrackHdr = (track) => {
|
|
5651
|
+
return track.color.matrixCoefficients === "bt2020" && track.color.transferCharacteristics === "arib-std-b67" && track.color.primaries === "bt2020";
|
|
5652
|
+
};
|
|
5653
|
+
var getIsHdr = (boxes, state) => {
|
|
5105
5654
|
const { videoTracks } = getTracks(boxes, state);
|
|
5106
|
-
|
|
5107
|
-
throw new Error("Expected video track");
|
|
5108
|
-
}
|
|
5109
|
-
const firstVideoTrack = videoTracks[0];
|
|
5110
|
-
return {
|
|
5111
|
-
width: firstVideoTrack.width,
|
|
5112
|
-
height: firstVideoTrack.height,
|
|
5113
|
-
rotation: firstVideoTrack.rotation,
|
|
5114
|
-
unrotatedHeight: firstVideoTrack.displayAspectHeight,
|
|
5115
|
-
unrotatedWidth: firstVideoTrack.displayAspectWidth
|
|
5116
|
-
};
|
|
5655
|
+
return videoTracks.some((track) => isVideoTrackHdr(track));
|
|
5117
5656
|
};
|
|
5118
|
-
var
|
|
5119
|
-
|
|
5120
|
-
return getDimensions(boxes, state) !== null;
|
|
5121
|
-
} catch {
|
|
5122
|
-
return false;
|
|
5123
|
-
}
|
|
5657
|
+
var hasHdr = (boxes, state) => {
|
|
5658
|
+
return hasTracks(boxes, state);
|
|
5124
5659
|
};
|
|
5125
5660
|
|
|
5126
5661
|
// src/emit-available-info.ts
|
|
@@ -5135,10 +5670,10 @@ var emitAvailableInfo = ({
|
|
|
5135
5670
|
}) => {
|
|
5136
5671
|
const keys = Object.keys(hasInfo);
|
|
5137
5672
|
for (const key of keys) {
|
|
5138
|
-
if (key === "
|
|
5139
|
-
if (parseResult && hasInfo.
|
|
5140
|
-
moreFields.
|
|
5141
|
-
returnValue.
|
|
5673
|
+
if (key === "structure") {
|
|
5674
|
+
if (parseResult && hasInfo.structure && returnValue.structure === undefined) {
|
|
5675
|
+
moreFields.onStructure?.(parseResult.segments);
|
|
5676
|
+
returnValue.structure = parseResult.segments;
|
|
5142
5677
|
}
|
|
5143
5678
|
continue;
|
|
5144
5679
|
}
|
|
@@ -5238,6 +5773,14 @@ var emitAvailableInfo = ({
|
|
|
5238
5773
|
}
|
|
5239
5774
|
continue;
|
|
5240
5775
|
}
|
|
5776
|
+
if (key === "isHdr") {
|
|
5777
|
+
if (returnValue.isHdr === undefined && hasInfo.isHdr && parseResult) {
|
|
5778
|
+
const isHdr = getIsHdr(parseResult.segments, state);
|
|
5779
|
+
moreFields.onIsHdr?.(isHdr);
|
|
5780
|
+
returnValue.isHdr = isHdr;
|
|
5781
|
+
}
|
|
5782
|
+
continue;
|
|
5783
|
+
}
|
|
5241
5784
|
if (key === "container") {
|
|
5242
5785
|
if (returnValue.container === undefined && hasInfo.container && parseResult) {
|
|
5243
5786
|
const container = getContainer(parseResult.segments);
|
|
@@ -5253,8 +5796,9 @@ var emitAvailableInfo = ({
|
|
|
5253
5796
|
// src/has-all-info.ts
|
|
5254
5797
|
var getAvailableInfo = (options, parseResult, state) => {
|
|
5255
5798
|
const keys = Object.entries(options).filter(([, value]) => value);
|
|
5256
|
-
const infos = keys.map(([
|
|
5257
|
-
|
|
5799
|
+
const infos = keys.map(([_key]) => {
|
|
5800
|
+
const key = _key;
|
|
5801
|
+
if (key === "structure") {
|
|
5258
5802
|
return Boolean(parseResult && parseResult.status === "done");
|
|
5259
5803
|
}
|
|
5260
5804
|
if (key === "durationInSeconds") {
|
|
@@ -5266,14 +5810,17 @@ var getAvailableInfo = (options, parseResult, state) => {
|
|
|
5266
5810
|
if (key === "fps") {
|
|
5267
5811
|
return Boolean(parseResult && hasFps(parseResult.segments));
|
|
5268
5812
|
}
|
|
5813
|
+
if (key === "isHdr") {
|
|
5814
|
+
return Boolean(parseResult && hasHdr(parseResult.segments, state));
|
|
5815
|
+
}
|
|
5269
5816
|
if (key === "videoCodec") {
|
|
5270
|
-
return Boolean(parseResult && hasVideoCodec(parseResult.segments));
|
|
5817
|
+
return Boolean(parseResult && hasVideoCodec(parseResult.segments, state));
|
|
5271
5818
|
}
|
|
5272
5819
|
if (key === "audioCodec") {
|
|
5273
|
-
return Boolean(parseResult && hasAudioCodec(parseResult.segments));
|
|
5820
|
+
return Boolean(parseResult && hasAudioCodec(parseResult.segments, state));
|
|
5274
5821
|
}
|
|
5275
5822
|
if (key === "tracks") {
|
|
5276
|
-
return Boolean(parseResult && hasTracks(parseResult.segments));
|
|
5823
|
+
return Boolean(parseResult && hasTracks(parseResult.segments, state));
|
|
5277
5824
|
}
|
|
5278
5825
|
if (key === "internalStats") {
|
|
5279
5826
|
return false;
|
|
@@ -5297,8 +5844,37 @@ var getAvailableInfo = (options, parseResult, state) => {
|
|
|
5297
5844
|
return Object.fromEntries(entries);
|
|
5298
5845
|
};
|
|
5299
5846
|
|
|
5847
|
+
// src/register-track.ts
|
|
5848
|
+
var registerTrack = async ({
|
|
5849
|
+
state,
|
|
5850
|
+
options,
|
|
5851
|
+
track
|
|
5852
|
+
}) => {
|
|
5853
|
+
if (track.type === "video" && options.onVideoTrack) {
|
|
5854
|
+
const callback = await options.onVideoTrack(track);
|
|
5855
|
+
await state.registerVideoSampleCallback(track.trackId, callback ?? null);
|
|
5856
|
+
}
|
|
5857
|
+
if (track.type === "audio" && options.onAudioTrack) {
|
|
5858
|
+
const callback = await options.onAudioTrack(track);
|
|
5859
|
+
await state.registerAudioSampleCallback(track.trackId, callback ?? null);
|
|
5860
|
+
}
|
|
5861
|
+
};
|
|
5862
|
+
var registerVideoTrackWhenProfileIsAvailable = ({
|
|
5863
|
+
options,
|
|
5864
|
+
state,
|
|
5865
|
+
track
|
|
5866
|
+
}) => {
|
|
5867
|
+
state.registerOnAvcProfileCallback(async (profile) => {
|
|
5868
|
+
await registerTrack({
|
|
5869
|
+
options,
|
|
5870
|
+
state,
|
|
5871
|
+
track: addAvcProfileToTrack(track, profile)
|
|
5872
|
+
});
|
|
5873
|
+
});
|
|
5874
|
+
};
|
|
5875
|
+
|
|
5300
5876
|
// src/boxes/iso-base-media/esds/decoder-specific-config.ts
|
|
5301
|
-
var parseDecoderSpecificConfig = (iterator
|
|
5877
|
+
var parseDecoderSpecificConfig = (iterator) => {
|
|
5302
5878
|
const layerTag = iterator.getUint8();
|
|
5303
5879
|
const layerSize = iterator.getPaddedFourByteNumber();
|
|
5304
5880
|
const start = iterator.counter.getOffset();
|
|
@@ -5322,9 +5898,6 @@ var parseDecoderSpecificConfig = (iterator, logLevel) => {
|
|
|
5322
5898
|
if (read < layerSize) {
|
|
5323
5899
|
iterator.discard(layerSize - read);
|
|
5324
5900
|
}
|
|
5325
|
-
if (bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136) {
|
|
5326
|
-
Log.warn(logLevel, "Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330");
|
|
5327
|
-
}
|
|
5328
5901
|
return {
|
|
5329
5902
|
type: "mp4a-specific-config",
|
|
5330
5903
|
audioObjectType,
|
|
@@ -5345,8 +5918,7 @@ var mapToObjectAudioIndicator = (num) => {
|
|
|
5345
5918
|
return "unknown";
|
|
5346
5919
|
};
|
|
5347
5920
|
var processDescriptor = ({
|
|
5348
|
-
iterator
|
|
5349
|
-
logLevel
|
|
5921
|
+
iterator
|
|
5350
5922
|
}) => {
|
|
5351
5923
|
const tag = iterator.getUint8();
|
|
5352
5924
|
if (tag === 4) {
|
|
@@ -5363,7 +5935,7 @@ var processDescriptor = ({
|
|
|
5363
5935
|
const avgBitrate = iterator.getUint32();
|
|
5364
5936
|
const decoderSpecificConfigs = [];
|
|
5365
5937
|
while (size - (iterator.counter.getOffset() - initialOffset) > 0) {
|
|
5366
|
-
const decoderSpecificConfig = parseDecoderSpecificConfig(iterator
|
|
5938
|
+
const decoderSpecificConfig = parseDecoderSpecificConfig(iterator);
|
|
5367
5939
|
decoderSpecificConfigs.push(decoderSpecificConfig);
|
|
5368
5940
|
}
|
|
5369
5941
|
return {
|
|
@@ -5393,13 +5965,12 @@ var processDescriptor = ({
|
|
|
5393
5965
|
descriptor: null
|
|
5394
5966
|
};
|
|
5395
5967
|
};
|
|
5396
|
-
var parseDescriptors = (iterator, maxBytes
|
|
5968
|
+
var parseDescriptors = (iterator, maxBytes) => {
|
|
5397
5969
|
const descriptors = [];
|
|
5398
5970
|
const initialOffset = iterator.counter.getOffset();
|
|
5399
5971
|
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
|
|
5400
5972
|
const { descriptor } = processDescriptor({
|
|
5401
|
-
iterator
|
|
5402
|
-
logLevel
|
|
5973
|
+
iterator
|
|
5403
5974
|
});
|
|
5404
5975
|
if (descriptor) {
|
|
5405
5976
|
descriptors.push(descriptor);
|
|
@@ -5414,8 +5985,7 @@ var parseDescriptors = (iterator, maxBytes, logLevel) => {
|
|
|
5414
5985
|
var parseEsds = ({
|
|
5415
5986
|
data,
|
|
5416
5987
|
size,
|
|
5417
|
-
fileOffset
|
|
5418
|
-
logLevel
|
|
5988
|
+
fileOffset
|
|
5419
5989
|
}) => {
|
|
5420
5990
|
const version = data.getUint8();
|
|
5421
5991
|
data.discard(3);
|
|
@@ -5424,7 +5994,7 @@ var parseEsds = ({
|
|
|
5424
5994
|
const esId = data.getUint16();
|
|
5425
5995
|
data.discard(1);
|
|
5426
5996
|
const remaining = size - (data.counter.getOffset() - fileOffset);
|
|
5427
|
-
const descriptors = parseDescriptors(data, remaining
|
|
5997
|
+
const descriptors = parseDescriptors(data, remaining);
|
|
5428
5998
|
const remainingNow = size - (data.counter.getOffset() - fileOffset);
|
|
5429
5999
|
data.discard(remainingNow);
|
|
5430
6000
|
return {
|
|
@@ -5471,7 +6041,10 @@ var parseMdat = async ({
|
|
|
5471
6041
|
signal,
|
|
5472
6042
|
maySkipSampleProcessing
|
|
5473
6043
|
}) => {
|
|
5474
|
-
const alreadyHas = hasTracks(
|
|
6044
|
+
const alreadyHas = hasTracks({
|
|
6045
|
+
type: "iso-base-media",
|
|
6046
|
+
boxes: existingBoxes
|
|
6047
|
+
}, options.parserState);
|
|
5475
6048
|
if (!alreadyHas) {
|
|
5476
6049
|
if (maySkipSampleProcessing) {
|
|
5477
6050
|
data.discard(size - (data.counter.getOffset() - fileOffset));
|
|
@@ -5491,7 +6064,7 @@ var parseMdat = async ({
|
|
|
5491
6064
|
fileOffset
|
|
5492
6065
|
});
|
|
5493
6066
|
}
|
|
5494
|
-
const tracks2 = getTracks(existingBoxes, options.parserState);
|
|
6067
|
+
const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, options.parserState);
|
|
5495
6068
|
const allTracks = [
|
|
5496
6069
|
...tracks2.videoTracks,
|
|
5497
6070
|
...tracks2.audioTracks,
|
|
@@ -5610,7 +6183,7 @@ var parseMoov = async ({
|
|
|
5610
6183
|
signal,
|
|
5611
6184
|
logLevel
|
|
5612
6185
|
}) => {
|
|
5613
|
-
const children = await
|
|
6186
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
5614
6187
|
iterator,
|
|
5615
6188
|
maxBytes: size - (iterator.counter.getOffset() - offset),
|
|
5616
6189
|
allowIncompleteBoxes: false,
|
|
@@ -5627,7 +6200,7 @@ var parseMoov = async ({
|
|
|
5627
6200
|
offset,
|
|
5628
6201
|
boxSize: size,
|
|
5629
6202
|
type: "moov-box",
|
|
5630
|
-
children: children.segments
|
|
6203
|
+
children: children.segments.boxes
|
|
5631
6204
|
};
|
|
5632
6205
|
};
|
|
5633
6206
|
|
|
@@ -5932,7 +6505,7 @@ var parseMebx = async ({
|
|
|
5932
6505
|
}) => {
|
|
5933
6506
|
iterator.discard(6);
|
|
5934
6507
|
const dataReferenceIndex = iterator.getUint16();
|
|
5935
|
-
const children = await
|
|
6508
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
5936
6509
|
iterator,
|
|
5937
6510
|
maxBytes: iterator.counter.getOffset() - offset,
|
|
5938
6511
|
allowIncompleteBoxes: false,
|
|
@@ -5951,7 +6524,7 @@ var parseMebx = async ({
|
|
|
5951
6524
|
offset,
|
|
5952
6525
|
dataReferenceIndex,
|
|
5953
6526
|
format: "mebx",
|
|
5954
|
-
children: children.segments
|
|
6527
|
+
children: children.segments.boxes
|
|
5955
6528
|
};
|
|
5956
6529
|
};
|
|
5957
6530
|
|
|
@@ -6085,6 +6658,7 @@ var audioTags = [
|
|
|
6085
6658
|
"MAC6 ",
|
|
6086
6659
|
"ima4",
|
|
6087
6660
|
"fl32",
|
|
6661
|
+
"lpcm",
|
|
6088
6662
|
"fl64",
|
|
6089
6663
|
"in24",
|
|
6090
6664
|
"in32",
|
|
@@ -6142,7 +6716,7 @@ var processSample = async ({
|
|
|
6142
6716
|
const packetSize = iterator.getUint16();
|
|
6143
6717
|
const sampleRate = iterator.getFixedPointUnsigned1616Number();
|
|
6144
6718
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
|
|
6145
|
-
const children = await
|
|
6719
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
6146
6720
|
iterator,
|
|
6147
6721
|
allowIncompleteBoxes: false,
|
|
6148
6722
|
maxBytes: bytesRemainingInBox,
|
|
@@ -6174,7 +6748,7 @@ var processSample = async ({
|
|
|
6174
6748
|
bytesPerPacket: null,
|
|
6175
6749
|
bytesPerFrame: null,
|
|
6176
6750
|
bitsPerSample: null,
|
|
6177
|
-
children: children.segments
|
|
6751
|
+
children: children.segments.boxes
|
|
6178
6752
|
}
|
|
6179
6753
|
};
|
|
6180
6754
|
}
|
|
@@ -6189,7 +6763,7 @@ var processSample = async ({
|
|
|
6189
6763
|
const bytesPerFrame = iterator.getUint32();
|
|
6190
6764
|
const bytesPerSample = iterator.getUint32();
|
|
6191
6765
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
|
|
6192
|
-
const children = await
|
|
6766
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
6193
6767
|
iterator,
|
|
6194
6768
|
allowIncompleteBoxes: false,
|
|
6195
6769
|
maxBytes: bytesRemainingInBox,
|
|
@@ -6221,26 +6795,26 @@ var processSample = async ({
|
|
|
6221
6795
|
bytesPerPacket,
|
|
6222
6796
|
bytesPerFrame,
|
|
6223
6797
|
bitsPerSample: bytesPerSample,
|
|
6224
|
-
children: children.segments
|
|
6798
|
+
children: children.segments.boxes
|
|
6225
6799
|
}
|
|
6226
6800
|
};
|
|
6227
6801
|
}
|
|
6228
6802
|
if (version === 2) {
|
|
6229
|
-
|
|
6803
|
+
iterator.getUint16();
|
|
6230
6804
|
const sampleSize = iterator.getUint16();
|
|
6231
6805
|
const compressionId = iterator.getUint16();
|
|
6232
6806
|
const packetSize = iterator.getUint16();
|
|
6233
6807
|
iterator.getFixedPointUnsigned1616Number();
|
|
6234
6808
|
iterator.getUint32();
|
|
6235
6809
|
const higherSampleRate = iterator.getFloat64();
|
|
6810
|
+
const numAudioChannel = iterator.getUint32();
|
|
6236
6811
|
iterator.getUint32();
|
|
6237
|
-
iterator.getUint32();
|
|
6238
|
-
const bitsPerCodedSample = iterator.getUint32();
|
|
6812
|
+
const bitsPerChannel = iterator.getUint32();
|
|
6239
6813
|
iterator.getUint32();
|
|
6240
6814
|
const bytesPerFrame = iterator.getUint32();
|
|
6241
6815
|
const samplesPerPacket = iterator.getUint32();
|
|
6242
6816
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
|
|
6243
|
-
const children = await
|
|
6817
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
6244
6818
|
iterator,
|
|
6245
6819
|
allowIncompleteBoxes: false,
|
|
6246
6820
|
maxBytes: bytesRemainingInBox,
|
|
@@ -6263,7 +6837,7 @@ var processSample = async ({
|
|
|
6263
6837
|
vendor: [...Array.from(new Uint8Array(vendor))],
|
|
6264
6838
|
size: boxSize,
|
|
6265
6839
|
type: "audio",
|
|
6266
|
-
numberOfChannels,
|
|
6840
|
+
numberOfChannels: numAudioChannel,
|
|
6267
6841
|
sampleSize,
|
|
6268
6842
|
compressionId,
|
|
6269
6843
|
packetSize,
|
|
@@ -6271,8 +6845,8 @@ var processSample = async ({
|
|
|
6271
6845
|
samplesPerPacket,
|
|
6272
6846
|
bytesPerPacket: null,
|
|
6273
6847
|
bytesPerFrame,
|
|
6274
|
-
bitsPerSample:
|
|
6275
|
-
children: children.segments
|
|
6848
|
+
bitsPerSample: bitsPerChannel,
|
|
6849
|
+
children: children.segments.boxes
|
|
6276
6850
|
}
|
|
6277
6851
|
};
|
|
6278
6852
|
}
|
|
@@ -6294,7 +6868,7 @@ var processSample = async ({
|
|
|
6294
6868
|
const depth = iterator.getUint16();
|
|
6295
6869
|
const colorTableId = iterator.getInt16();
|
|
6296
6870
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
|
|
6297
|
-
const children = bytesRemainingInBox > 8 ? await
|
|
6871
|
+
const children = bytesRemainingInBox > 8 ? await parseIsoBaseMediaBoxes({
|
|
6298
6872
|
iterator,
|
|
6299
6873
|
allowIncompleteBoxes: false,
|
|
6300
6874
|
maxBytes: bytesRemainingInBox,
|
|
@@ -6303,7 +6877,7 @@ var processSample = async ({
|
|
|
6303
6877
|
continueMdat: false,
|
|
6304
6878
|
signal,
|
|
6305
6879
|
logLevel
|
|
6306
|
-
}) : (iterator.discard(bytesRemainingInBox), { status: "done", segments: [] });
|
|
6880
|
+
}) : (iterator.discard(bytesRemainingInBox), { status: "done", segments: { boxes: [], type: "iso-base-media" } });
|
|
6307
6881
|
if (children.status === "incomplete") {
|
|
6308
6882
|
throw new Error("Incomplete boxes are not allowed");
|
|
6309
6883
|
}
|
|
@@ -6328,7 +6902,7 @@ var processSample = async ({
|
|
|
6328
6902
|
compressorName,
|
|
6329
6903
|
depth,
|
|
6330
6904
|
colorTableId,
|
|
6331
|
-
descriptors: children.segments
|
|
6905
|
+
descriptors: children.segments.boxes
|
|
6332
6906
|
}
|
|
6333
6907
|
};
|
|
6334
6908
|
}
|
|
@@ -6650,7 +7224,7 @@ var parseTrak = async ({
|
|
|
6650
7224
|
signal,
|
|
6651
7225
|
logLevel
|
|
6652
7226
|
}) => {
|
|
6653
|
-
const children = await
|
|
7227
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
6654
7228
|
iterator: data,
|
|
6655
7229
|
maxBytes: size - (data.counter.getOffset() - offsetAtStart),
|
|
6656
7230
|
allowIncompleteBoxes: false,
|
|
@@ -6667,7 +7241,7 @@ var parseTrak = async ({
|
|
|
6667
7241
|
offset: offsetAtStart,
|
|
6668
7242
|
boxSize: size,
|
|
6669
7243
|
type: "trak-box",
|
|
6670
|
-
children: children.segments
|
|
7244
|
+
children: children.segments.boxes
|
|
6671
7245
|
};
|
|
6672
7246
|
};
|
|
6673
7247
|
|
|
@@ -6724,7 +7298,7 @@ var getChildren = async ({
|
|
|
6724
7298
|
}) => {
|
|
6725
7299
|
const parseChildren = boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "moof" || boxType === "dims" || boxType === "wave" || boxType === "traf" || boxType === "stsb";
|
|
6726
7300
|
if (parseChildren) {
|
|
6727
|
-
const parsed = await
|
|
7301
|
+
const parsed = await parseIsoBaseMediaBoxes({
|
|
6728
7302
|
iterator,
|
|
6729
7303
|
maxBytes: bytesRemainingInBox,
|
|
6730
7304
|
allowIncompleteBoxes: false,
|
|
@@ -6737,7 +7311,7 @@ var getChildren = async ({
|
|
|
6737
7311
|
if (parsed.status === "incomplete") {
|
|
6738
7312
|
throw new Error("Incomplete boxes are not allowed");
|
|
6739
7313
|
}
|
|
6740
|
-
return parsed.segments;
|
|
7314
|
+
return parsed.segments.boxes;
|
|
6741
7315
|
}
|
|
6742
7316
|
if (bytesRemainingInBox < 0) {
|
|
6743
7317
|
throw new Error("Box size is too big " + JSON.stringify({ boxType }));
|
|
@@ -6811,7 +7385,7 @@ var processBox = async ({
|
|
|
6811
7385
|
const boxSize = boxSizeRaw === 1 ? iterator.getEightByteNumber() : boxSizeRaw;
|
|
6812
7386
|
if (bytesRemaining < boxSize) {
|
|
6813
7387
|
if (boxType === "mdat") {
|
|
6814
|
-
const shouldSkip = (options.canSkipVideoData || !hasTracks(parsedBoxes)) && options.supportsContentRange;
|
|
7388
|
+
const shouldSkip = (options.canSkipVideoData || !hasTracks({ type: "iso-base-media", boxes: parsedBoxes }, options.parserState)) && options.supportsContentRange;
|
|
6815
7389
|
if (shouldSkip) {
|
|
6816
7390
|
const skipTo = fileOffset + boxSize;
|
|
6817
7391
|
const bytesToSkip = skipTo - iterator.counter.getOffset();
|
|
@@ -7040,14 +7614,11 @@ var processBox = async ({
|
|
|
7040
7614
|
});
|
|
7041
7615
|
const transformedTrack = makeBaseMediaTrack(box);
|
|
7042
7616
|
if (transformedTrack) {
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
const callback = await options.onVideoTrack?.(transformedTrack);
|
|
7049
|
-
await options.parserState.registerVideoSampleCallback(transformedTrack.trackId, callback ?? null);
|
|
7050
|
-
}
|
|
7617
|
+
await registerTrack({
|
|
7618
|
+
options,
|
|
7619
|
+
state: options.parserState,
|
|
7620
|
+
track: transformedTrack
|
|
7621
|
+
});
|
|
7051
7622
|
}
|
|
7052
7623
|
return {
|
|
7053
7624
|
type: "complete",
|
|
@@ -7136,8 +7707,7 @@ var processBox = async ({
|
|
|
7136
7707
|
const box = parseEsds({
|
|
7137
7708
|
data: iterator,
|
|
7138
7709
|
size: boxSize,
|
|
7139
|
-
fileOffset
|
|
7140
|
-
logLevel
|
|
7710
|
+
fileOffset
|
|
7141
7711
|
});
|
|
7142
7712
|
return {
|
|
7143
7713
|
type: "complete",
|
|
@@ -7188,7 +7758,7 @@ var processBox = async ({
|
|
|
7188
7758
|
skipTo: null
|
|
7189
7759
|
};
|
|
7190
7760
|
};
|
|
7191
|
-
var
|
|
7761
|
+
var parseIsoBaseMediaBoxes = async ({
|
|
7192
7762
|
iterator,
|
|
7193
7763
|
maxBytes,
|
|
7194
7764
|
allowIncompleteBoxes,
|
|
@@ -7198,9 +7768,12 @@ var parseBoxes = async ({
|
|
|
7198
7768
|
signal,
|
|
7199
7769
|
logLevel
|
|
7200
7770
|
}) => {
|
|
7201
|
-
|
|
7771
|
+
const structure = {
|
|
7772
|
+
type: "iso-base-media",
|
|
7773
|
+
boxes: initialBoxes
|
|
7774
|
+
};
|
|
7202
7775
|
const initialOffset = iterator.counter.getOffset();
|
|
7203
|
-
const alreadyHasMdat = boxes.find((b) => b.type === "mdat-box");
|
|
7776
|
+
const alreadyHasMdat = structure.boxes.find((b) => b.type === "mdat-box");
|
|
7204
7777
|
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
|
|
7205
7778
|
const result = continueMdat ? await parseMdatPartially({
|
|
7206
7779
|
iterator,
|
|
@@ -7223,13 +7796,13 @@ var parseBoxes = async ({
|
|
|
7223
7796
|
}
|
|
7224
7797
|
return {
|
|
7225
7798
|
status: "incomplete",
|
|
7226
|
-
segments:
|
|
7799
|
+
segments: structure,
|
|
7227
7800
|
continueParsing: () => {
|
|
7228
|
-
return
|
|
7801
|
+
return parseIsoBaseMediaBoxes({
|
|
7229
7802
|
iterator,
|
|
7230
7803
|
maxBytes,
|
|
7231
7804
|
allowIncompleteBoxes,
|
|
7232
|
-
initialBoxes: boxes,
|
|
7805
|
+
initialBoxes: structure.boxes,
|
|
7233
7806
|
options,
|
|
7234
7807
|
continueMdat: false,
|
|
7235
7808
|
signal,
|
|
@@ -7242,13 +7815,13 @@ var parseBoxes = async ({
|
|
|
7242
7815
|
if (result.type === "partial-mdat-box") {
|
|
7243
7816
|
return {
|
|
7244
7817
|
status: "incomplete",
|
|
7245
|
-
segments:
|
|
7818
|
+
segments: structure,
|
|
7246
7819
|
continueParsing: () => {
|
|
7247
|
-
return Promise.resolve(
|
|
7820
|
+
return Promise.resolve(parseIsoBaseMediaBoxes({
|
|
7248
7821
|
iterator,
|
|
7249
7822
|
maxBytes,
|
|
7250
7823
|
allowIncompleteBoxes,
|
|
7251
|
-
initialBoxes: boxes,
|
|
7824
|
+
initialBoxes: structure.boxes,
|
|
7252
7825
|
options,
|
|
7253
7826
|
continueMdat: result,
|
|
7254
7827
|
signal,
|
|
@@ -7259,15 +7832,15 @@ var parseBoxes = async ({
|
|
|
7259
7832
|
};
|
|
7260
7833
|
}
|
|
7261
7834
|
if (result.box.type === "mdat-box" && alreadyHasMdat) {
|
|
7262
|
-
boxes = boxes.filter((b) => b.type !== "mdat-box");
|
|
7263
|
-
boxes.push(result.box);
|
|
7835
|
+
structure.boxes = structure.boxes.filter((b) => b.type !== "mdat-box");
|
|
7836
|
+
structure.boxes.push(result.box);
|
|
7264
7837
|
iterator.allowDiscard();
|
|
7265
7838
|
if (result.box.status !== "samples-processed") {
|
|
7266
7839
|
throw new Error("unexpected");
|
|
7267
7840
|
}
|
|
7268
7841
|
break;
|
|
7269
7842
|
} else {
|
|
7270
|
-
boxes.push(result.box);
|
|
7843
|
+
structure.boxes.push(result.box);
|
|
7271
7844
|
}
|
|
7272
7845
|
if (result.skipTo !== null) {
|
|
7273
7846
|
if (!options.supportsContentRange) {
|
|
@@ -7275,13 +7848,13 @@ var parseBoxes = async ({
|
|
|
7275
7848
|
}
|
|
7276
7849
|
return {
|
|
7277
7850
|
status: "incomplete",
|
|
7278
|
-
segments:
|
|
7851
|
+
segments: structure,
|
|
7279
7852
|
continueParsing: () => {
|
|
7280
|
-
return
|
|
7853
|
+
return parseIsoBaseMediaBoxes({
|
|
7281
7854
|
iterator,
|
|
7282
7855
|
maxBytes,
|
|
7283
7856
|
allowIncompleteBoxes,
|
|
7284
|
-
initialBoxes: boxes,
|
|
7857
|
+
initialBoxes: structure.boxes,
|
|
7285
7858
|
options,
|
|
7286
7859
|
continueMdat: false,
|
|
7287
7860
|
signal,
|
|
@@ -7294,13 +7867,13 @@ var parseBoxes = async ({
|
|
|
7294
7867
|
if (iterator.bytesRemaining() < 0) {
|
|
7295
7868
|
return {
|
|
7296
7869
|
status: "incomplete",
|
|
7297
|
-
segments:
|
|
7870
|
+
segments: structure,
|
|
7298
7871
|
continueParsing: () => {
|
|
7299
|
-
return
|
|
7872
|
+
return parseIsoBaseMediaBoxes({
|
|
7300
7873
|
iterator,
|
|
7301
7874
|
maxBytes,
|
|
7302
7875
|
allowIncompleteBoxes,
|
|
7303
|
-
initialBoxes: boxes,
|
|
7876
|
+
initialBoxes: structure.boxes,
|
|
7304
7877
|
options,
|
|
7305
7878
|
continueMdat: false,
|
|
7306
7879
|
signal,
|
|
@@ -7312,22 +7885,22 @@ var parseBoxes = async ({
|
|
|
7312
7885
|
}
|
|
7313
7886
|
iterator.removeBytesRead();
|
|
7314
7887
|
}
|
|
7315
|
-
const mdatState = getMdatBox(boxes);
|
|
7888
|
+
const mdatState = getMdatBox(structure.boxes);
|
|
7316
7889
|
const skipped = mdatState?.status === "samples-skipped" && !options.canSkipVideoData && options.supportsContentRange;
|
|
7317
7890
|
const buffered = mdatState?.status === "samples-buffered" && !options.canSkipVideoData;
|
|
7318
7891
|
if (skipped || buffered) {
|
|
7319
7892
|
return {
|
|
7320
7893
|
status: "incomplete",
|
|
7321
|
-
segments:
|
|
7894
|
+
segments: structure,
|
|
7322
7895
|
continueParsing: () => {
|
|
7323
7896
|
if (buffered) {
|
|
7324
7897
|
iterator.skipTo(mdatState.fileOffset, false);
|
|
7325
7898
|
}
|
|
7326
|
-
return
|
|
7899
|
+
return parseIsoBaseMediaBoxes({
|
|
7327
7900
|
iterator,
|
|
7328
7901
|
maxBytes,
|
|
7329
7902
|
allowIncompleteBoxes: false,
|
|
7330
|
-
initialBoxes: boxes,
|
|
7903
|
+
initialBoxes: structure.boxes,
|
|
7331
7904
|
options,
|
|
7332
7905
|
continueMdat: false,
|
|
7333
7906
|
signal,
|
|
@@ -7339,24 +7912,651 @@ var parseBoxes = async ({
|
|
|
7339
7912
|
}
|
|
7340
7913
|
return {
|
|
7341
7914
|
status: "done",
|
|
7342
|
-
segments:
|
|
7915
|
+
segments: structure
|
|
7343
7916
|
};
|
|
7344
7917
|
};
|
|
7345
7918
|
|
|
7346
|
-
// src/
|
|
7347
|
-
var
|
|
7348
|
-
|
|
7919
|
+
// src/boxes/riff/is-movi.ts
|
|
7920
|
+
var isMoviAtom = (iterator, ckId) => {
|
|
7921
|
+
if (ckId !== "LIST") {
|
|
7922
|
+
return false;
|
|
7923
|
+
}
|
|
7924
|
+
const listType = iterator.getByteString(4);
|
|
7925
|
+
iterator.counter.decrement(4);
|
|
7926
|
+
return listType === "movi";
|
|
7927
|
+
};
|
|
7928
|
+
|
|
7929
|
+
// src/boxes/avc/parse-avc.ts
|
|
7930
|
+
var readSps = (iterator) => {
|
|
7931
|
+
const profile = iterator.getUint8();
|
|
7932
|
+
const compatibility = iterator.getUint8();
|
|
7933
|
+
const level = iterator.getUint8();
|
|
7934
|
+
return {
|
|
7935
|
+
profile,
|
|
7936
|
+
compatibility,
|
|
7937
|
+
level
|
|
7938
|
+
};
|
|
7939
|
+
};
|
|
7940
|
+
var findEnd = (buffer) => {
|
|
7941
|
+
let zeroesInARow = 0;
|
|
7942
|
+
for (let i = 0;i < buffer.length; i++) {
|
|
7943
|
+
const val = buffer[i];
|
|
7944
|
+
if (val === 0) {
|
|
7945
|
+
zeroesInARow++;
|
|
7946
|
+
continue;
|
|
7947
|
+
}
|
|
7948
|
+
if (zeroesInARow >= 2 && val === 1) {
|
|
7949
|
+
return i - zeroesInARow;
|
|
7950
|
+
}
|
|
7951
|
+
zeroesInARow = 0;
|
|
7952
|
+
}
|
|
7953
|
+
return null;
|
|
7954
|
+
};
|
|
7955
|
+
var inspect = (buffer) => {
|
|
7956
|
+
const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
|
|
7957
|
+
iterator.startReadingBits();
|
|
7958
|
+
iterator.getBits(1);
|
|
7959
|
+
iterator.getBits(2);
|
|
7960
|
+
const type = iterator.getBits(5);
|
|
7961
|
+
iterator.stopReadingBits();
|
|
7962
|
+
if (type === 7) {
|
|
7963
|
+
const end = findEnd(buffer);
|
|
7964
|
+
const data = readSps(iterator);
|
|
7965
|
+
const sps = buffer.slice(1, end === null ? Infinity : end);
|
|
7966
|
+
return {
|
|
7967
|
+
level: data.level,
|
|
7968
|
+
profile: data.profile,
|
|
7969
|
+
compatibility: data.compatibility,
|
|
7970
|
+
sps,
|
|
7971
|
+
type: "avc-profile"
|
|
7972
|
+
};
|
|
7973
|
+
}
|
|
7974
|
+
if (type === 5) {
|
|
7975
|
+
return {
|
|
7976
|
+
type: "keyframe"
|
|
7977
|
+
};
|
|
7978
|
+
}
|
|
7979
|
+
if (type === 8) {
|
|
7980
|
+
const end = findEnd(buffer);
|
|
7981
|
+
const pps = buffer.slice(0, end === null ? Infinity : end);
|
|
7982
|
+
return {
|
|
7983
|
+
type: "avc-pps",
|
|
7984
|
+
pps
|
|
7985
|
+
};
|
|
7986
|
+
}
|
|
7987
|
+
if (type === 1) {
|
|
7988
|
+
return {
|
|
7989
|
+
type: "delta-frame"
|
|
7990
|
+
};
|
|
7991
|
+
}
|
|
7992
|
+
iterator.destroy();
|
|
7993
|
+
return null;
|
|
7994
|
+
};
|
|
7995
|
+
var parseAvc = (buffer) => {
|
|
7996
|
+
let zeroesInARow = 0;
|
|
7997
|
+
const infos = [];
|
|
7998
|
+
for (let i = 0;i < buffer.length; i++) {
|
|
7999
|
+
const val = buffer[i];
|
|
8000
|
+
if (val === 0) {
|
|
8001
|
+
zeroesInARow++;
|
|
8002
|
+
continue;
|
|
8003
|
+
}
|
|
8004
|
+
if (zeroesInARow >= 2 && val === 1) {
|
|
8005
|
+
zeroesInARow = 0;
|
|
8006
|
+
const info = inspect(buffer.slice(i + 1, i + 100));
|
|
8007
|
+
if (info) {
|
|
8008
|
+
infos.push(info);
|
|
8009
|
+
if (info.type === "keyframe" || info.type === "delta-frame") {
|
|
8010
|
+
break;
|
|
8011
|
+
}
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
if (val !== 1) {
|
|
8015
|
+
zeroesInARow = 0;
|
|
8016
|
+
}
|
|
8017
|
+
}
|
|
8018
|
+
return infos;
|
|
8019
|
+
};
|
|
8020
|
+
|
|
8021
|
+
// src/boxes/riff/parse-movi.ts
|
|
8022
|
+
var getStrhForIndex = (structure, trackId) => {
|
|
8023
|
+
const boxes = getStrlBoxes(structure);
|
|
8024
|
+
const box = boxes[trackId];
|
|
8025
|
+
if (!box) {
|
|
8026
|
+
throw new Error("Expected box");
|
|
8027
|
+
}
|
|
8028
|
+
const strh = getStrhBox(box.children);
|
|
8029
|
+
if (!strh) {
|
|
8030
|
+
throw new Error("strh");
|
|
8031
|
+
}
|
|
8032
|
+
return strh;
|
|
8033
|
+
};
|
|
8034
|
+
var handleChunk = async ({
|
|
8035
|
+
iterator,
|
|
7349
8036
|
options,
|
|
7350
|
-
|
|
8037
|
+
structure,
|
|
8038
|
+
ckId,
|
|
8039
|
+
ckSize
|
|
7351
8040
|
}) => {
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
8041
|
+
const videoChunk = ckId.match(/^([0-9]{2})dc$/);
|
|
8042
|
+
if (videoChunk) {
|
|
8043
|
+
const trackId = parseInt(videoChunk[1], 10);
|
|
8044
|
+
const strh = getStrhForIndex(structure, trackId);
|
|
8045
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
8046
|
+
const nthSample = options.parserState.getSamplesForTrack(trackId);
|
|
8047
|
+
const timeInSec = nthSample / samplesPerSecond;
|
|
8048
|
+
const timestamp = Math.floor(timeInSec * MEDIA_PARSER_RIFF_TIMESCALE);
|
|
8049
|
+
const duration2 = Math.floor(1 / samplesPerSecond * MEDIA_PARSER_RIFF_TIMESCALE);
|
|
8050
|
+
const data = iterator.getSlice(ckSize);
|
|
8051
|
+
const infos = parseAvc(data);
|
|
8052
|
+
const keyOrDelta = infos.find((i) => i.type === "keyframe" || i.type === "delta-frame");
|
|
8053
|
+
if (!keyOrDelta) {
|
|
8054
|
+
throw new Error("expected avc to contain info about key or delta");
|
|
8055
|
+
}
|
|
8056
|
+
const avcProfile = infos.find((i) => i.type === "avc-profile");
|
|
8057
|
+
const ppsProfile = infos.find((i) => i.type === "avc-pps");
|
|
8058
|
+
if (avcProfile && ppsProfile) {
|
|
8059
|
+
await options.parserState.onProfile({ pps: ppsProfile, sps: avcProfile });
|
|
8060
|
+
}
|
|
8061
|
+
await options.parserState.onVideoSample(trackId, {
|
|
8062
|
+
cts: timestamp,
|
|
8063
|
+
dts: timestamp,
|
|
8064
|
+
data,
|
|
8065
|
+
duration: duration2,
|
|
8066
|
+
timestamp,
|
|
8067
|
+
trackId,
|
|
8068
|
+
type: keyOrDelta.type === "keyframe" ? "key" : "delta"
|
|
8069
|
+
});
|
|
8070
|
+
} else {
|
|
8071
|
+
const audioChunk = ckId.match(/^([0-9]{2})wb$/);
|
|
8072
|
+
if (audioChunk) {
|
|
8073
|
+
const trackId = parseInt(audioChunk[1], 10);
|
|
8074
|
+
const strh = getStrhForIndex(structure, trackId);
|
|
8075
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
8076
|
+
const nthSample = options.parserState.getSamplesForTrack(trackId);
|
|
8077
|
+
const timeInSec = nthSample / samplesPerSecond;
|
|
8078
|
+
const timestamp = timeInSec * MEDIA_PARSER_RIFF_TIMESCALE;
|
|
8079
|
+
const duration2 = 1 / samplesPerSecond * MEDIA_PARSER_RIFF_TIMESCALE;
|
|
8080
|
+
await options.parserState.onAudioSample(trackId, {
|
|
8081
|
+
cts: timestamp,
|
|
8082
|
+
dts: timestamp,
|
|
8083
|
+
data: iterator.getSlice(ckSize),
|
|
8084
|
+
duration: duration2,
|
|
8085
|
+
timestamp,
|
|
8086
|
+
trackId,
|
|
8087
|
+
type: "key"
|
|
8088
|
+
});
|
|
8089
|
+
}
|
|
7355
8090
|
}
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
8091
|
+
};
|
|
8092
|
+
var parseMovi = async ({
|
|
8093
|
+
iterator,
|
|
8094
|
+
maxOffset,
|
|
8095
|
+
options,
|
|
8096
|
+
structure
|
|
8097
|
+
}) => {
|
|
8098
|
+
while (iterator.counter.getOffset() < maxOffset) {
|
|
8099
|
+
if (iterator.bytesRemaining() < 8) {
|
|
8100
|
+
return {
|
|
8101
|
+
type: "incomplete",
|
|
8102
|
+
continueParsing: () => {
|
|
8103
|
+
return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
|
|
8104
|
+
}
|
|
8105
|
+
};
|
|
8106
|
+
}
|
|
8107
|
+
const ckId = iterator.getByteString(4);
|
|
8108
|
+
const ckSize = iterator.getUint32Le();
|
|
8109
|
+
if (iterator.bytesRemaining() < ckSize) {
|
|
8110
|
+
iterator.counter.decrement(8);
|
|
8111
|
+
return {
|
|
8112
|
+
type: "incomplete",
|
|
8113
|
+
continueParsing: () => {
|
|
8114
|
+
return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
|
|
8115
|
+
}
|
|
8116
|
+
};
|
|
8117
|
+
}
|
|
8118
|
+
await handleChunk({ iterator, options, structure, ckId, ckSize });
|
|
8119
|
+
while (iterator.counter.getOffset() < maxOffset && iterator.bytesRemaining() > 0) {
|
|
8120
|
+
if (iterator.getUint8() !== 0) {
|
|
8121
|
+
iterator.counter.decrement(1);
|
|
8122
|
+
break;
|
|
8123
|
+
}
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
if (iterator.counter.getOffset() === maxOffset) {
|
|
8127
|
+
return {
|
|
8128
|
+
type: "complete",
|
|
8129
|
+
box: {
|
|
8130
|
+
type: "movi-box"
|
|
8131
|
+
}
|
|
8132
|
+
};
|
|
8133
|
+
}
|
|
8134
|
+
if (iterator.counter.getOffset() > maxOffset) {
|
|
8135
|
+
throw new Error("Oops, this should not happen!");
|
|
8136
|
+
}
|
|
8137
|
+
return {
|
|
8138
|
+
type: "incomplete",
|
|
8139
|
+
continueParsing: () => {
|
|
8140
|
+
return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
|
|
8141
|
+
}
|
|
8142
|
+
};
|
|
8143
|
+
};
|
|
8144
|
+
|
|
8145
|
+
// src/boxes/riff/parse-avih.ts
|
|
8146
|
+
var parseAvih = ({
|
|
8147
|
+
iterator,
|
|
8148
|
+
size
|
|
8149
|
+
}) => {
|
|
8150
|
+
const { expectNoMoreBytes } = iterator.startBox(size);
|
|
8151
|
+
const dwMicroSecPerFrame = iterator.getUint32Le();
|
|
8152
|
+
const dwMaxBytesPerSec = iterator.getUint32Le();
|
|
8153
|
+
const paddingGranularity = iterator.getUint32Le();
|
|
8154
|
+
const flags = iterator.getUint32Le();
|
|
8155
|
+
const totalFrames = iterator.getUint32Le();
|
|
8156
|
+
const initialFrames = iterator.getUint32Le();
|
|
8157
|
+
const streams = iterator.getUint32Le();
|
|
8158
|
+
const suggestedBufferSize = iterator.getUint32Le();
|
|
8159
|
+
const width = iterator.getUint32Le();
|
|
8160
|
+
const height = iterator.getUint32Le();
|
|
8161
|
+
iterator.discard(16);
|
|
8162
|
+
expectNoMoreBytes();
|
|
8163
|
+
return {
|
|
8164
|
+
type: "avih-box",
|
|
8165
|
+
microSecPerFrame: dwMicroSecPerFrame,
|
|
8166
|
+
maxBytesPerSecond: dwMaxBytesPerSec,
|
|
8167
|
+
paddingGranularity,
|
|
8168
|
+
flags,
|
|
8169
|
+
totalFrames,
|
|
8170
|
+
initialFrames,
|
|
8171
|
+
streams,
|
|
8172
|
+
suggestedBufferSize,
|
|
8173
|
+
height,
|
|
8174
|
+
width
|
|
8175
|
+
};
|
|
8176
|
+
};
|
|
8177
|
+
|
|
8178
|
+
// src/boxes/riff/parse-fmt-box.ts
|
|
8179
|
+
var parseFmtBox = ({
|
|
8180
|
+
iterator,
|
|
8181
|
+
boxes,
|
|
8182
|
+
size
|
|
8183
|
+
}) => {
|
|
8184
|
+
const box = iterator.startBox(size);
|
|
8185
|
+
const header = boxes.find((b) => b.type === "riff-header");
|
|
8186
|
+
if (!header) {
|
|
8187
|
+
throw new Error("Expected RIFF header");
|
|
8188
|
+
}
|
|
8189
|
+
if (header.fileType !== "WAVE") {
|
|
8190
|
+
throw new Error("Only supporting WAVE type");
|
|
8191
|
+
}
|
|
8192
|
+
const wFormatTag = iterator.getUint16Le();
|
|
8193
|
+
if (wFormatTag !== 1) {
|
|
8194
|
+
throw new Error("Expected wFormatTag to be 1, only supporting this");
|
|
8195
|
+
}
|
|
8196
|
+
const numberOfChannels = iterator.getUint16Le();
|
|
8197
|
+
const sampleRate = iterator.getUint32Le();
|
|
8198
|
+
const byteRate = iterator.getUint32Le();
|
|
8199
|
+
const blockAlign = iterator.getUint16Le();
|
|
8200
|
+
const bitsPerSample = iterator.getUint16Le();
|
|
8201
|
+
box.expectNoMoreBytes();
|
|
8202
|
+
return {
|
|
8203
|
+
type: "wave-format-box",
|
|
8204
|
+
formatTag: wFormatTag,
|
|
8205
|
+
numberOfChannels,
|
|
8206
|
+
sampleRate,
|
|
8207
|
+
blockAlign,
|
|
8208
|
+
byteRate,
|
|
8209
|
+
bitsPerSample
|
|
8210
|
+
};
|
|
8211
|
+
};
|
|
8212
|
+
|
|
8213
|
+
// src/boxes/riff/parse-list-box.ts
|
|
8214
|
+
var parseListBox = async ({
|
|
8215
|
+
iterator,
|
|
8216
|
+
size,
|
|
8217
|
+
options
|
|
8218
|
+
}) => {
|
|
8219
|
+
const counter = iterator.counter.getOffset();
|
|
8220
|
+
const listType = iterator.getByteString(4);
|
|
8221
|
+
if (listType === "movi") {
|
|
8222
|
+
throw new Error("should not be handled here");
|
|
8223
|
+
}
|
|
8224
|
+
const structure = {
|
|
8225
|
+
type: "riff",
|
|
8226
|
+
boxes: []
|
|
8227
|
+
};
|
|
8228
|
+
const result = await parseRiffBody({
|
|
8229
|
+
structure,
|
|
8230
|
+
iterator,
|
|
8231
|
+
maxOffset: counter + size,
|
|
8232
|
+
options
|
|
8233
|
+
});
|
|
8234
|
+
if (result.status === "incomplete") {
|
|
8235
|
+
throw new Error(`Should only parse complete boxes (${listType})`);
|
|
8236
|
+
}
|
|
8237
|
+
return {
|
|
8238
|
+
type: "list-box",
|
|
8239
|
+
listType,
|
|
8240
|
+
children: structure.boxes
|
|
8241
|
+
};
|
|
8242
|
+
};
|
|
8243
|
+
|
|
8244
|
+
// src/boxes/riff/parse-strf.ts
|
|
8245
|
+
var parseStrfAudio = ({
|
|
8246
|
+
iterator,
|
|
8247
|
+
size
|
|
8248
|
+
}) => {
|
|
8249
|
+
const box = iterator.startBox(size);
|
|
8250
|
+
const formatTag = iterator.getUint16Le();
|
|
8251
|
+
const numberOfChannels = iterator.getUint16Le();
|
|
8252
|
+
const samplesPerSec = iterator.getUint32Le();
|
|
8253
|
+
const avgBytesPerSec = iterator.getUint32Le();
|
|
8254
|
+
const blockAlign = iterator.getUint16Le();
|
|
8255
|
+
const bitsPerSample = iterator.getUint16Le();
|
|
8256
|
+
const cbSize = iterator.getUint16Le();
|
|
8257
|
+
box.expectNoMoreBytes();
|
|
8258
|
+
return {
|
|
8259
|
+
type: "strf-box-audio",
|
|
8260
|
+
avgBytesPerSecond: avgBytesPerSec,
|
|
8261
|
+
bitsPerSample,
|
|
8262
|
+
blockAlign,
|
|
8263
|
+
cbSize,
|
|
8264
|
+
formatTag,
|
|
8265
|
+
numberOfChannels,
|
|
8266
|
+
sampleRate: samplesPerSec
|
|
8267
|
+
};
|
|
8268
|
+
};
|
|
8269
|
+
var parseStrfVideo = ({
|
|
8270
|
+
iterator,
|
|
8271
|
+
size
|
|
8272
|
+
}) => {
|
|
8273
|
+
const box = iterator.startBox(size);
|
|
8274
|
+
const biSize = iterator.getUint32Le();
|
|
8275
|
+
const width = iterator.getInt32Le();
|
|
8276
|
+
const height = iterator.getInt32Le();
|
|
8277
|
+
const planes = iterator.getUint16Le();
|
|
8278
|
+
const bitCount = iterator.getUint16Le();
|
|
8279
|
+
const compression = iterator.getByteString(4);
|
|
8280
|
+
const sizeImage = iterator.getUint32Le();
|
|
8281
|
+
const xPelsPerMeter = iterator.getInt32Le();
|
|
8282
|
+
const yPelsPerMeter = iterator.getInt32Le();
|
|
8283
|
+
const clrUsed = iterator.getUint32Le();
|
|
8284
|
+
const clrImportant = iterator.getUint32Le();
|
|
8285
|
+
box.expectNoMoreBytes();
|
|
8286
|
+
return {
|
|
8287
|
+
type: "strf-box-video",
|
|
8288
|
+
biSize,
|
|
8289
|
+
bitCount,
|
|
8290
|
+
clrImportant,
|
|
8291
|
+
clrUsed,
|
|
8292
|
+
compression,
|
|
8293
|
+
height,
|
|
8294
|
+
planes,
|
|
8295
|
+
sizeImage,
|
|
8296
|
+
width,
|
|
8297
|
+
xPelsPerMeter,
|
|
8298
|
+
yPelsPerMeter
|
|
8299
|
+
};
|
|
8300
|
+
};
|
|
8301
|
+
var parseStrf = ({
|
|
8302
|
+
iterator,
|
|
8303
|
+
size,
|
|
8304
|
+
boxes
|
|
8305
|
+
}) => {
|
|
8306
|
+
const strh = boxes.find((b) => b.type === "strh-box");
|
|
8307
|
+
if (!strh) {
|
|
8308
|
+
throw new Error("strh box not found");
|
|
8309
|
+
}
|
|
8310
|
+
if (strh.fccType === "vids") {
|
|
8311
|
+
return parseStrfVideo({ iterator, size });
|
|
8312
|
+
}
|
|
8313
|
+
if (strh.fccType === "auds") {
|
|
8314
|
+
return parseStrfAudio({ iterator, size });
|
|
8315
|
+
}
|
|
8316
|
+
throw new Error(`Unsupported fccType: ${strh.fccType}`);
|
|
8317
|
+
};
|
|
8318
|
+
|
|
8319
|
+
// src/boxes/riff/parse-strh.ts
|
|
8320
|
+
var parseStrh = ({
|
|
8321
|
+
iterator,
|
|
8322
|
+
size
|
|
8323
|
+
}) => {
|
|
8324
|
+
const box = iterator.startBox(size);
|
|
8325
|
+
const fccType = iterator.getByteString(4);
|
|
8326
|
+
if (fccType !== "vids" && fccType !== "auds") {
|
|
8327
|
+
throw new Error("Expected AVI handler to be vids / auds");
|
|
8328
|
+
}
|
|
8329
|
+
const handler = fccType === "vids" ? iterator.getByteString(4) : iterator.getUint32Le();
|
|
8330
|
+
if (typeof handler === "string" && handler !== "H264") {
|
|
8331
|
+
throw new Error(`Only H264 is supported as a stream type in .avi, got ${handler}`);
|
|
8332
|
+
}
|
|
8333
|
+
if (fccType === "auds" && handler !== 1) {
|
|
8334
|
+
throw new Error(`Only "1" is supported as a stream type in .avi, got ${handler}`);
|
|
8335
|
+
}
|
|
8336
|
+
const flags = iterator.getUint32Le();
|
|
8337
|
+
const priority = iterator.getUint16Le();
|
|
8338
|
+
const language2 = iterator.getUint16Le();
|
|
8339
|
+
const initialFrames = iterator.getUint32Le();
|
|
8340
|
+
const scale = iterator.getUint32Le();
|
|
8341
|
+
const rate = iterator.getUint32Le();
|
|
8342
|
+
const start = iterator.getUint32Le();
|
|
8343
|
+
const length = iterator.getUint32Le();
|
|
8344
|
+
const suggestedBufferSize = iterator.getUint32Le();
|
|
8345
|
+
const quality = iterator.getUint32Le();
|
|
8346
|
+
const sampleSize = iterator.getUint32Le();
|
|
8347
|
+
box.discardRest();
|
|
8348
|
+
return {
|
|
8349
|
+
type: "strh-box",
|
|
8350
|
+
fccType,
|
|
8351
|
+
handler,
|
|
8352
|
+
flags,
|
|
8353
|
+
priority,
|
|
8354
|
+
initialFrames,
|
|
8355
|
+
length,
|
|
8356
|
+
quality,
|
|
8357
|
+
rate,
|
|
8358
|
+
sampleSize,
|
|
8359
|
+
scale,
|
|
8360
|
+
start,
|
|
8361
|
+
suggestedBufferSize,
|
|
8362
|
+
language: language2
|
|
8363
|
+
};
|
|
8364
|
+
};
|
|
8365
|
+
|
|
8366
|
+
// src/boxes/riff/parse-riff-box.ts
|
|
8367
|
+
var parseRiffBox = ({
|
|
8368
|
+
iterator,
|
|
8369
|
+
size,
|
|
8370
|
+
id,
|
|
8371
|
+
boxes,
|
|
8372
|
+
options
|
|
8373
|
+
}) => {
|
|
8374
|
+
if (id === "fmt") {
|
|
8375
|
+
return Promise.resolve(parseFmtBox({ iterator, boxes, size }));
|
|
8376
|
+
}
|
|
8377
|
+
if (id === "LIST") {
|
|
8378
|
+
return parseListBox({ iterator, size, options });
|
|
8379
|
+
}
|
|
8380
|
+
if (id === "avih") {
|
|
8381
|
+
return Promise.resolve(parseAvih({ iterator, size }));
|
|
8382
|
+
}
|
|
8383
|
+
if (id === "strh") {
|
|
8384
|
+
return Promise.resolve(parseStrh({ iterator, size }));
|
|
8385
|
+
}
|
|
8386
|
+
if (id === "strf") {
|
|
8387
|
+
return Promise.resolve(parseStrf({ iterator, size, boxes }));
|
|
8388
|
+
}
|
|
8389
|
+
iterator.discard(size);
|
|
8390
|
+
const box = {
|
|
8391
|
+
type: "riff-box",
|
|
8392
|
+
size,
|
|
8393
|
+
id
|
|
8394
|
+
};
|
|
8395
|
+
return Promise.resolve(box);
|
|
8396
|
+
};
|
|
8397
|
+
|
|
8398
|
+
// src/boxes/riff/expect-riff-box.ts
|
|
8399
|
+
var expectRiffBox = async ({
|
|
8400
|
+
iterator,
|
|
8401
|
+
options,
|
|
8402
|
+
structure
|
|
8403
|
+
}) => {
|
|
8404
|
+
if (iterator.bytesRemaining() < 16) {
|
|
8405
|
+
return {
|
|
8406
|
+
type: "incomplete",
|
|
8407
|
+
continueParsing() {
|
|
8408
|
+
return expectRiffBox({ structure, iterator, options });
|
|
8409
|
+
}
|
|
8410
|
+
};
|
|
8411
|
+
}
|
|
8412
|
+
const ckId = iterator.getByteString(4);
|
|
8413
|
+
const ckSize = iterator.getUint32Le();
|
|
8414
|
+
if (isMoviAtom(iterator, ckId)) {
|
|
8415
|
+
iterator.discard(4);
|
|
8416
|
+
return parseMovi({
|
|
8417
|
+
iterator,
|
|
8418
|
+
maxOffset: ckSize + iterator.counter.getOffset() - 4,
|
|
8419
|
+
options,
|
|
8420
|
+
structure
|
|
8421
|
+
});
|
|
8422
|
+
}
|
|
8423
|
+
if (iterator.bytesRemaining() < ckSize) {
|
|
8424
|
+
iterator.counter.decrement(8);
|
|
8425
|
+
return {
|
|
8426
|
+
type: "incomplete",
|
|
8427
|
+
continueParsing: () => {
|
|
8428
|
+
return expectRiffBox({ structure, iterator, options });
|
|
8429
|
+
}
|
|
8430
|
+
};
|
|
8431
|
+
}
|
|
8432
|
+
return {
|
|
8433
|
+
type: "complete",
|
|
8434
|
+
box: await parseRiffBox({
|
|
8435
|
+
id: ckId,
|
|
8436
|
+
iterator,
|
|
8437
|
+
size: ckSize,
|
|
8438
|
+
boxes: structure.boxes,
|
|
8439
|
+
options
|
|
8440
|
+
})
|
|
8441
|
+
};
|
|
8442
|
+
};
|
|
8443
|
+
|
|
8444
|
+
// src/boxes/riff/parse-box.ts
|
|
8445
|
+
var continueAfterRiffBoxResult = ({
|
|
8446
|
+
result,
|
|
8447
|
+
structure,
|
|
8448
|
+
iterator,
|
|
8449
|
+
maxOffset,
|
|
8450
|
+
options
|
|
8451
|
+
}) => {
|
|
8452
|
+
if (result.type === "incomplete") {
|
|
8453
|
+
return Promise.resolve({
|
|
8454
|
+
status: "incomplete",
|
|
8455
|
+
async continueParsing() {
|
|
8456
|
+
return Promise.resolve(continueAfterRiffBoxResult({
|
|
8457
|
+
result: await result.continueParsing(),
|
|
8458
|
+
structure,
|
|
8459
|
+
iterator,
|
|
8460
|
+
maxOffset,
|
|
8461
|
+
options
|
|
8462
|
+
}));
|
|
8463
|
+
},
|
|
8464
|
+
segments: structure,
|
|
8465
|
+
skipTo: null
|
|
8466
|
+
});
|
|
8467
|
+
}
|
|
8468
|
+
if (result.type === "complete") {
|
|
8469
|
+
if (result.box) {
|
|
8470
|
+
structure.boxes.push(result.box);
|
|
8471
|
+
}
|
|
8472
|
+
}
|
|
8473
|
+
return parseRiffBody({ iterator, maxOffset, options, structure });
|
|
8474
|
+
};
|
|
8475
|
+
var parseRiffBody = async ({
|
|
8476
|
+
iterator,
|
|
8477
|
+
structure,
|
|
8478
|
+
maxOffset,
|
|
8479
|
+
options
|
|
8480
|
+
}) => {
|
|
8481
|
+
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() < maxOffset) {
|
|
8482
|
+
const result = await expectRiffBox({
|
|
8483
|
+
iterator,
|
|
8484
|
+
options,
|
|
8485
|
+
structure
|
|
8486
|
+
});
|
|
8487
|
+
if (result.type === "incomplete") {
|
|
8488
|
+
return {
|
|
8489
|
+
status: "incomplete",
|
|
8490
|
+
async continueParsing() {
|
|
8491
|
+
return Promise.resolve(continueAfterRiffBoxResult({
|
|
8492
|
+
iterator,
|
|
8493
|
+
maxOffset,
|
|
8494
|
+
options,
|
|
8495
|
+
result: await result.continueParsing(),
|
|
8496
|
+
structure
|
|
8497
|
+
}));
|
|
8498
|
+
},
|
|
8499
|
+
segments: structure,
|
|
8500
|
+
skipTo: null
|
|
8501
|
+
};
|
|
8502
|
+
}
|
|
8503
|
+
if (result.box === null) {
|
|
8504
|
+
continue;
|
|
8505
|
+
}
|
|
8506
|
+
structure.boxes.push(result.box);
|
|
8507
|
+
if (result.box.type === "strf-box-video" || result.box.type === "strf-box-audio") {
|
|
8508
|
+
const strh = getStrhBox(structure.boxes);
|
|
8509
|
+
const strf = getStrfBox(structure.boxes);
|
|
8510
|
+
if (!strh || !strf) {
|
|
8511
|
+
throw new Error("strh or strf box missing");
|
|
8512
|
+
}
|
|
8513
|
+
if (strf.type === "strf-box-audio" && options.onAudioTrack) {
|
|
8514
|
+
const audioTrack = makeAviAudioTrack({
|
|
8515
|
+
index: options.nextTrackIndex,
|
|
8516
|
+
strf
|
|
8517
|
+
});
|
|
8518
|
+
await registerTrack({
|
|
8519
|
+
options,
|
|
8520
|
+
state: options.parserState,
|
|
8521
|
+
track: audioTrack
|
|
8522
|
+
});
|
|
8523
|
+
}
|
|
8524
|
+
if (options.onVideoTrack && strf.type === "strf-box-video") {
|
|
8525
|
+
const videoTrack = makeAviVideoTrack({
|
|
8526
|
+
strh,
|
|
8527
|
+
index: options.nextTrackIndex,
|
|
8528
|
+
strf
|
|
8529
|
+
});
|
|
8530
|
+
registerVideoTrackWhenProfileIsAvailable({
|
|
8531
|
+
options,
|
|
8532
|
+
state: options.parserState,
|
|
8533
|
+
track: videoTrack
|
|
8534
|
+
});
|
|
8535
|
+
}
|
|
8536
|
+
options.nextTrackIndex++;
|
|
8537
|
+
}
|
|
8538
|
+
}
|
|
8539
|
+
return {
|
|
8540
|
+
status: "done",
|
|
8541
|
+
segments: structure
|
|
8542
|
+
};
|
|
8543
|
+
};
|
|
8544
|
+
var parseRiff = ({
|
|
8545
|
+
iterator,
|
|
8546
|
+
options
|
|
8547
|
+
}) => {
|
|
8548
|
+
const structure = { type: "riff", boxes: [] };
|
|
8549
|
+
const riff = iterator.getByteString(4);
|
|
8550
|
+
if (riff !== "RIFF") {
|
|
8551
|
+
throw new Error("Not a RIFF file");
|
|
7359
8552
|
}
|
|
8553
|
+
const size = iterator.getUint32Le();
|
|
8554
|
+
const fileType = iterator.getByteString(4);
|
|
8555
|
+
if (fileType !== "WAVE" && fileType !== "AVI") {
|
|
8556
|
+
throw new Error(`File type ${fileType} not supported`);
|
|
8557
|
+
}
|
|
8558
|
+
structure.boxes.push({ type: "riff-header", fileSize: size, fileType });
|
|
8559
|
+
return parseRiffBody({ iterator, structure, maxOffset: Infinity, options });
|
|
7360
8560
|
};
|
|
7361
8561
|
|
|
7362
8562
|
// src/boxes/webm/segments/block-simple-block-flags.ts
|
|
@@ -7904,33 +9104,33 @@ var expectChildren = async ({
|
|
|
7904
9104
|
};
|
|
7905
9105
|
|
|
7906
9106
|
// src/boxes/webm/parse-webm-header.ts
|
|
7907
|
-
var continueAfterMatroskaResult = (result,
|
|
9107
|
+
var continueAfterMatroskaResult = (result, structure) => {
|
|
7908
9108
|
if (result.status === "done") {
|
|
7909
9109
|
return {
|
|
7910
9110
|
status: "done",
|
|
7911
|
-
segments:
|
|
9111
|
+
segments: structure
|
|
7912
9112
|
};
|
|
7913
9113
|
}
|
|
7914
9114
|
return {
|
|
7915
9115
|
status: "incomplete",
|
|
7916
|
-
segments:
|
|
9116
|
+
segments: structure,
|
|
7917
9117
|
continueParsing: async () => {
|
|
7918
9118
|
const newResult = await result.continueParsing();
|
|
7919
|
-
return continueAfterMatroskaResult(newResult,
|
|
9119
|
+
return continueAfterMatroskaResult(newResult, structure);
|
|
7920
9120
|
},
|
|
7921
9121
|
skipTo: null
|
|
7922
9122
|
};
|
|
7923
9123
|
};
|
|
7924
9124
|
var parseWebm = async (counter, parserContext) => {
|
|
7925
|
-
const
|
|
9125
|
+
const structure = { type: "matroska", boxes: [] };
|
|
7926
9126
|
const results = await expectChildren({
|
|
7927
9127
|
iterator: counter,
|
|
7928
9128
|
length: Infinity,
|
|
7929
|
-
children,
|
|
9129
|
+
children: structure.boxes,
|
|
7930
9130
|
parserContext,
|
|
7931
9131
|
startOffset: counter.counter.getOffset()
|
|
7932
9132
|
});
|
|
7933
|
-
return continueAfterMatroskaResult(results,
|
|
9133
|
+
return continueAfterMatroskaResult(results, structure);
|
|
7934
9134
|
};
|
|
7935
9135
|
|
|
7936
9136
|
// src/parse-video.ts
|
|
@@ -7941,26 +9141,14 @@ var parseVideo = ({
|
|
|
7941
9141
|
logLevel
|
|
7942
9142
|
}) => {
|
|
7943
9143
|
if (iterator.bytesRemaining() === 0) {
|
|
7944
|
-
return Promise.
|
|
7945
|
-
status: "incomplete",
|
|
7946
|
-
segments: [],
|
|
7947
|
-
continueParsing: () => {
|
|
7948
|
-
return parseVideo({
|
|
7949
|
-
iterator,
|
|
7950
|
-
options,
|
|
7951
|
-
signal,
|
|
7952
|
-
logLevel
|
|
7953
|
-
});
|
|
7954
|
-
},
|
|
7955
|
-
skipTo: null
|
|
7956
|
-
});
|
|
9144
|
+
return Promise.reject(new Error("no bytes"));
|
|
7957
9145
|
}
|
|
7958
9146
|
if (iterator.isRiff()) {
|
|
7959
|
-
|
|
9147
|
+
return Promise.resolve(parseRiff({ iterator, options }));
|
|
7960
9148
|
}
|
|
7961
9149
|
if (iterator.isIsoBaseMedia()) {
|
|
7962
9150
|
Log.verbose(logLevel, "Detected ISO Base Media container");
|
|
7963
|
-
return
|
|
9151
|
+
return parseIsoBaseMediaBoxes({
|
|
7964
9152
|
iterator,
|
|
7965
9153
|
maxBytes: Infinity,
|
|
7966
9154
|
allowIncompleteBoxes: true,
|
|
@@ -7973,7 +9161,7 @@ var parseVideo = ({
|
|
|
7973
9161
|
}
|
|
7974
9162
|
if (iterator.isWebm()) {
|
|
7975
9163
|
Log.verbose(logLevel, "Detected Matroska container");
|
|
7976
|
-
return
|
|
9164
|
+
return parseWebm(iterator, options);
|
|
7977
9165
|
}
|
|
7978
9166
|
if (iterator.isMp3()) {
|
|
7979
9167
|
return Promise.reject(new Error("MP3 files are not yet supported"));
|
|
@@ -8038,8 +9226,23 @@ var makeParserState = ({
|
|
|
8038
9226
|
}
|
|
8039
9227
|
return timestampMap.get(byteOffset);
|
|
8040
9228
|
};
|
|
9229
|
+
const samplesForTrack = {};
|
|
9230
|
+
const profileCallbacks = [];
|
|
9231
|
+
const registerOnAvcProfileCallback = (callback) => {
|
|
9232
|
+
profileCallbacks.push(callback);
|
|
9233
|
+
};
|
|
9234
|
+
let avcProfile = null;
|
|
9235
|
+
const onProfile = async (profile) => {
|
|
9236
|
+
avcProfile = profile;
|
|
9237
|
+
for (const callback of profileCallbacks) {
|
|
9238
|
+
await callback(profile);
|
|
9239
|
+
}
|
|
9240
|
+
profileCallbacks.length = 0;
|
|
9241
|
+
};
|
|
8041
9242
|
return {
|
|
8042
9243
|
onTrackEntrySegment,
|
|
9244
|
+
onProfile,
|
|
9245
|
+
registerOnAvcProfileCallback,
|
|
8043
9246
|
getTrackInfoByNumber: (id) => trackEntries[id],
|
|
8044
9247
|
registerVideoSampleCallback: async (id, callback) => {
|
|
8045
9248
|
if (callback === null) {
|
|
@@ -8071,6 +9274,10 @@ var makeParserState = ({
|
|
|
8071
9274
|
if (signal?.aborted) {
|
|
8072
9275
|
throw new Error("Aborted");
|
|
8073
9276
|
}
|
|
9277
|
+
if (typeof samplesForTrack[trackId] === "undefined") {
|
|
9278
|
+
samplesForTrack[trackId] = 0;
|
|
9279
|
+
}
|
|
9280
|
+
samplesForTrack[trackId]++;
|
|
8074
9281
|
const callback = audioSampleCallbacks[trackId];
|
|
8075
9282
|
if (callback) {
|
|
8076
9283
|
await callback(audioSample);
|
|
@@ -8087,6 +9294,10 @@ var makeParserState = ({
|
|
|
8087
9294
|
if (signal?.aborted) {
|
|
8088
9295
|
throw new Error("Aborted");
|
|
8089
9296
|
}
|
|
9297
|
+
if (typeof samplesForTrack[trackId] === "undefined") {
|
|
9298
|
+
samplesForTrack[trackId] = 0;
|
|
9299
|
+
}
|
|
9300
|
+
samplesForTrack[trackId]++;
|
|
8090
9301
|
const callback = videoSampleCallbacks[trackId];
|
|
8091
9302
|
if (callback) {
|
|
8092
9303
|
await callback(videoSample);
|
|
@@ -8101,7 +9312,13 @@ var makeParserState = ({
|
|
|
8101
9312
|
},
|
|
8102
9313
|
getInternalStats: () => ({}),
|
|
8103
9314
|
getTimescale,
|
|
8104
|
-
setTimescale
|
|
9315
|
+
setTimescale,
|
|
9316
|
+
getSamplesForTrack: (trackId) => {
|
|
9317
|
+
return samplesForTrack[trackId] ?? 0;
|
|
9318
|
+
},
|
|
9319
|
+
getAvcProfile: () => {
|
|
9320
|
+
return avcProfile;
|
|
9321
|
+
}
|
|
8105
9322
|
};
|
|
8106
9323
|
};
|
|
8107
9324
|
|
|
@@ -8146,7 +9363,8 @@ var parseMedia = async ({
|
|
|
8146
9363
|
onVideoTrack: onVideoTrack ?? null,
|
|
8147
9364
|
parserState: state,
|
|
8148
9365
|
nullifySamples: !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.KEEP_SAMPLES === "true"),
|
|
8149
|
-
supportsContentRange
|
|
9366
|
+
supportsContentRange,
|
|
9367
|
+
nextTrackIndex: 0
|
|
8150
9368
|
};
|
|
8151
9369
|
const hasAllInfo = () => {
|
|
8152
9370
|
if (parseResult === null) {
|
|
@@ -8201,7 +9419,7 @@ var parseMedia = async ({
|
|
|
8201
9419
|
});
|
|
8202
9420
|
triggerInfoEmit();
|
|
8203
9421
|
if (parseResult && parseResult.status === "incomplete") {
|
|
8204
|
-
Log.verbose(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset()
|
|
9422
|
+
Log.verbose(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset());
|
|
8205
9423
|
parseResult = await parseResult.continueParsing();
|
|
8206
9424
|
} else {
|
|
8207
9425
|
parseResult = await parseVideo({
|
|
@@ -8242,13 +9460,18 @@ var parseMedia = async ({
|
|
|
8242
9460
|
return returnValue;
|
|
8243
9461
|
};
|
|
8244
9462
|
// src/version.ts
|
|
8245
|
-
var VERSION = "4.0.
|
|
9463
|
+
var VERSION = "4.0.233";
|
|
8246
9464
|
|
|
8247
9465
|
// src/index.ts
|
|
8248
9466
|
var MediaParserInternals = {
|
|
8249
9467
|
createMatroskaMedia,
|
|
8250
9468
|
createIsoBaseMedia,
|
|
8251
|
-
|
|
9469
|
+
createWav,
|
|
9470
|
+
Log,
|
|
9471
|
+
IoEventEmitter,
|
|
9472
|
+
makeProgressTracker,
|
|
9473
|
+
withResolvers,
|
|
9474
|
+
withResolversAndWaitForReturn
|
|
8252
9475
|
};
|
|
8253
9476
|
export {
|
|
8254
9477
|
parseMedia,
|