@remotion/media-parser 4.0.202 → 4.0.205
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/av1-codec-string.d.ts +0 -5
- package/dist/av1-codec-string.js +1 -18
- package/dist/boxes/iso-base-media/esds/decoder-specific-config.js +6 -1
- package/dist/boxes/iso-base-media/ftype.d.ts +9 -0
- package/dist/boxes/iso-base-media/ftype.js +31 -0
- package/dist/boxes/iso-base-media/get-sample-positions-from-track.d.ts +4 -0
- package/dist/boxes/iso-base-media/get-sample-positions-from-track.js +48 -0
- package/dist/boxes/iso-base-media/make-track.js +3 -30
- package/dist/boxes/iso-base-media/mdat/mdat.js +25 -22
- package/dist/boxes/iso-base-media/mdhd.d.ts +2 -0
- package/dist/boxes/iso-base-media/mdhd.js +6 -7
- package/dist/boxes/iso-base-media/mvhd.js +11 -13
- package/dist/boxes/iso-base-media/process-box.js +36 -0
- package/dist/boxes/iso-base-media/tfdt.d.ts +12 -0
- package/dist/boxes/iso-base-media/tfdt.js +20 -0
- package/dist/boxes/iso-base-media/tfhd.d.ts +16 -0
- package/dist/boxes/iso-base-media/tfhd.js +41 -0
- package/dist/boxes/iso-base-media/tkhd.js +9 -12
- package/dist/boxes/iso-base-media/trun.d.ts +21 -0
- package/dist/boxes/iso-base-media/trun.js +44 -0
- package/dist/boxes/webm/bitstream/av1.js +1 -10
- package/dist/boxes/webm/ebml.d.ts +1 -1
- package/dist/boxes/webm/get-track.js +2 -2
- package/dist/boxes/webm/segments/seek-position.js +1 -1
- package/dist/boxes/webm/segments/seek.d.ts +1 -1
- package/dist/boxes/webm/segments/seek.js +8 -2
- package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
- package/dist/boxes/webm/tracks.d.ts +8 -0
- package/dist/boxes/webm/tracks.js +21 -0
- package/dist/buffer-iterator.d.ts +1 -0
- package/dist/buffer-iterator.js +3 -2
- package/dist/create/cluster-segment.d.ts +10 -0
- package/dist/create/cluster-segment.js +41 -0
- package/dist/create/create-media.d.ts +6 -1
- package/dist/create/create-media.js +58 -4
- package/dist/create/matroska-header.d.ts +1 -1
- package/dist/create/matroska-info.d.ts +1 -1
- package/dist/create/matroska-info.js +2 -2
- package/dist/create/matroska-segment.d.ts +2 -1
- package/dist/create/matroska-trackentry.d.ts +5 -4
- package/dist/from-web.js +6 -15
- package/dist/get-duration.d.ts +3 -2
- package/dist/get-duration.js +24 -4
- package/dist/get-tracks.d.ts +4 -4
- package/dist/get-video-metadata.d.ts +2 -0
- package/dist/get-video-metadata.js +44 -0
- package/dist/has-all-info.js +1 -1
- package/dist/parse-media.js +1 -1
- package/dist/parse-result.d.ts +4 -1
- package/dist/read-and-increment-offset.d.ts +28 -0
- package/dist/read-and-increment-offset.js +177 -0
- package/dist/samples-from-moof.d.ts +6 -0
- package/dist/samples-from-moof.js +75 -0
- package/dist/traversal.d.ts +8 -1
- package/dist/traversal.js +39 -1
- package/dist/understand-vorbis.d.ts +1 -0
- package/dist/understand-vorbis.js +12 -0
- package/dist/writers/web-fs.js +21 -5
- package/dist/writers/writer.d.ts +3 -1
- package/package.json +2 -2
- package/src/boxes/iso-base-media/esds/decoder-specific-config.ts +8 -1
- package/src/boxes/iso-base-media/get-sample-positions-from-track.ts +69 -0
- package/src/boxes/iso-base-media/make-track.ts +4 -45
- package/src/boxes/iso-base-media/mdat/mdat.ts +33 -24
- package/src/boxes/iso-base-media/mdhd.ts +10 -7
- package/src/boxes/iso-base-media/mvhd.ts +15 -14
- package/src/boxes/iso-base-media/process-box.ts +42 -0
- package/src/boxes/iso-base-media/tfdt.ts +37 -0
- package/src/boxes/iso-base-media/tfhd.ts +66 -0
- package/src/boxes/iso-base-media/tkhd.ts +11 -13
- package/src/boxes/iso-base-media/trun.ts +74 -0
- package/src/boxes/webm/get-track.ts +2 -2
- package/src/buffer-iterator.ts +3 -2
- package/src/get-duration.ts +40 -5
- package/src/get-tracks.ts +4 -4
- package/src/has-all-info.ts +1 -1
- package/src/parse-media.ts +1 -1
- package/src/parse-result.ts +7 -1
- package/src/samples-from-moof.ts +102 -0
- package/src/test/samples-from-moof.test.ts +2496 -0
- package/src/test/stream-local.test.ts +28 -30
- package/src/test/stream-samples.test.ts +153 -231
- package/src/traversal.ts +56 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/bitstream/av1.d.ts +0 -2
- package/dist/bitstream/av1.js +0 -12
- package/dist/boxes/iso-base-media/avcc-hvcc.d.ts +0 -20
- package/dist/boxes/iso-base-media/avcc-hvcc.js +0 -73
- package/dist/boxes/iso-base-media/avcc.d.ts +0 -18
- package/dist/boxes/iso-base-media/avcc.js +0 -27
- package/dist/boxes/iso-base-media/esds-descriptors.d.ts +0 -21
- package/dist/boxes/iso-base-media/esds-descriptors.js +0 -62
- package/dist/boxes/iso-base-media/esds.d.ts +0 -15
- package/dist/boxes/iso-base-media/esds.js +0 -27
- package/dist/create-media.d.ts +0 -1
- package/dist/create-media.js +0 -78
- package/dist/from-input-type-file.d.ts +0 -2
- package/dist/from-input-type-file.js +0 -37
- package/dist/get-codec.d.ts +0 -4
- package/dist/get-codec.js +0 -22
- package/dist/web-file.d.ts +0 -2
- package/dist/web-file.js +0 -37
- /package/dist/{get-samples.d.ts → boxes/webm/bitstream/av1/frame.d.ts} +0 -0
- /package/dist/{get-samples.js → boxes/webm/bitstream/av1/frame.js} +0 -0
- /package/dist/{sample-aspect-ratio.d.ts → boxes/webm/bitstream/h264/get-h264-descriptor.d.ts} +0 -0
- /package/dist/{sample-aspect-ratio.js → boxes/webm/bitstream/h264/get-h264-descriptor.js} +0 -0
|
@@ -15,31 +15,15 @@ import {
|
|
|
15
15
|
getSampleAspectRatio,
|
|
16
16
|
getVideoSample,
|
|
17
17
|
} from '../../get-sample-aspect-ratio';
|
|
18
|
-
import {getSamplePositions} from '../../get-sample-positions';
|
|
19
18
|
import type {AudioTrack, OtherTrack, VideoTrack} from '../../get-tracks';
|
|
20
19
|
import {getVideoCodecString} from '../../get-video-codec';
|
|
21
|
-
import {
|
|
22
|
-
getCttsBox,
|
|
23
|
-
getStcoBox,
|
|
24
|
-
getStscBox,
|
|
25
|
-
getStssBox,
|
|
26
|
-
getStszBox,
|
|
27
|
-
getSttsBox,
|
|
28
|
-
getTkhdBox,
|
|
29
|
-
getVideoDescriptors,
|
|
30
|
-
} from '../../traversal';
|
|
20
|
+
import {getTkhdBox, getVideoDescriptors} from '../../traversal';
|
|
31
21
|
import type {TrakBox} from './trak/trak';
|
|
32
22
|
|
|
33
23
|
export const makeBaseMediaTrack = (
|
|
34
24
|
trakBox: TrakBox,
|
|
35
25
|
): VideoTrack | AudioTrack | OtherTrack | null => {
|
|
36
|
-
const stszBox = getStszBox(trakBox);
|
|
37
|
-
const stcoBox = getStcoBox(trakBox);
|
|
38
|
-
const stscBox = getStscBox(trakBox);
|
|
39
|
-
const stssBox = getStssBox(trakBox);
|
|
40
|
-
const sttsBox = getSttsBox(trakBox);
|
|
41
26
|
const tkhdBox = getTkhdBox(trakBox);
|
|
42
|
-
const cttsBox = getCttsBox(trakBox);
|
|
43
27
|
|
|
44
28
|
const videoDescriptors = getVideoDescriptors(trakBox);
|
|
45
29
|
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
@@ -48,35 +32,10 @@ export const makeBaseMediaTrack = (
|
|
|
48
32
|
throw new Error('Expected tkhd box in trak box');
|
|
49
33
|
}
|
|
50
34
|
|
|
51
|
-
if (!stszBox) {
|
|
52
|
-
throw new Error('Expected stsz box in trak box');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (!stcoBox) {
|
|
56
|
-
throw new Error('Expected stco box in trak box');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!stscBox) {
|
|
60
|
-
throw new Error('Expected stsc box in trak box');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!sttsBox) {
|
|
64
|
-
throw new Error('Expected stts box in trak box');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
35
|
if (!timescaleAndDuration) {
|
|
68
36
|
throw new Error('Expected timescale and duration in trak box');
|
|
69
37
|
}
|
|
70
38
|
|
|
71
|
-
const samplePositions = getSamplePositions({
|
|
72
|
-
stcoBox,
|
|
73
|
-
stscBox,
|
|
74
|
-
stszBox,
|
|
75
|
-
stssBox,
|
|
76
|
-
sttsBox,
|
|
77
|
-
cttsBox,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
39
|
if (trakBoxContainsAudio(trakBox)) {
|
|
81
40
|
const numberOfChannels = getNumberOfChannelsFromTrak(trakBox);
|
|
82
41
|
if (numberOfChannels === null) {
|
|
@@ -92,22 +51,22 @@ export const makeBaseMediaTrack = (
|
|
|
92
51
|
|
|
93
52
|
return {
|
|
94
53
|
type: 'audio',
|
|
95
|
-
samplePositions,
|
|
96
54
|
trackId: tkhdBox.trackId,
|
|
97
55
|
timescale: timescaleAndDuration.timescale,
|
|
98
56
|
codec: codecString,
|
|
99
57
|
numberOfChannels,
|
|
100
58
|
sampleRate,
|
|
101
59
|
description,
|
|
60
|
+
trakBox,
|
|
102
61
|
};
|
|
103
62
|
}
|
|
104
63
|
|
|
105
64
|
if (!trakBoxContainsVideo(trakBox)) {
|
|
106
65
|
return {
|
|
107
66
|
type: 'other',
|
|
108
|
-
samplePositions,
|
|
109
67
|
trackId: tkhdBox.trackId,
|
|
110
68
|
timescale: timescaleAndDuration.timescale,
|
|
69
|
+
trakBox,
|
|
111
70
|
};
|
|
112
71
|
}
|
|
113
72
|
|
|
@@ -138,7 +97,6 @@ export const makeBaseMediaTrack = (
|
|
|
138
97
|
|
|
139
98
|
const track: VideoTrack = {
|
|
140
99
|
type: 'video',
|
|
141
|
-
samplePositions,
|
|
142
100
|
trackId: tkhdBox.trackId,
|
|
143
101
|
description: videoDescriptors ?? undefined,
|
|
144
102
|
timescale: timescaleAndDuration.timescale,
|
|
@@ -152,6 +110,7 @@ export const makeBaseMediaTrack = (
|
|
|
152
110
|
displayAspectWidth,
|
|
153
111
|
displayAspectHeight,
|
|
154
112
|
rotation,
|
|
113
|
+
trakBox,
|
|
155
114
|
};
|
|
156
115
|
return track;
|
|
157
116
|
};
|
|
@@ -3,6 +3,9 @@ import type {BufferIterator} from '../../../buffer-iterator';
|
|
|
3
3
|
import {getTracks, hasTracks} from '../../../get-tracks';
|
|
4
4
|
import type {AnySegment} from '../../../parse-result';
|
|
5
5
|
import type {ParserContext} from '../../../parser-context';
|
|
6
|
+
import {getMoofBox} from '../../../traversal';
|
|
7
|
+
import {getSamplePositionsFromTrack} from '../get-sample-positions-from-track';
|
|
8
|
+
import type {TrakBox} from '../trak/trak';
|
|
6
9
|
|
|
7
10
|
export interface MdatBox {
|
|
8
11
|
type: 'mdat-box';
|
|
@@ -44,13 +47,17 @@ export const parseMdat = async ({
|
|
|
44
47
|
|
|
45
48
|
const flatSamples = allTracks
|
|
46
49
|
.map((track) => {
|
|
47
|
-
|
|
50
|
+
const samplePositions = getSamplePositionsFromTrack(
|
|
51
|
+
track.trakBox as TrakBox,
|
|
52
|
+
getMoofBox(existingBoxes),
|
|
53
|
+
);
|
|
54
|
+
if (!samplePositions) {
|
|
48
55
|
throw new Error('No sample positions');
|
|
49
56
|
}
|
|
50
57
|
|
|
51
|
-
return
|
|
58
|
+
return samplePositions.map((samplePosition) => {
|
|
52
59
|
return {
|
|
53
|
-
track,
|
|
60
|
+
track: {...track},
|
|
54
61
|
samplePosition,
|
|
55
62
|
};
|
|
56
63
|
});
|
|
@@ -59,10 +66,10 @@ export const parseMdat = async ({
|
|
|
59
66
|
|
|
60
67
|
// eslint-disable-next-line no-constant-condition
|
|
61
68
|
while (true) {
|
|
62
|
-
const
|
|
69
|
+
const samplesWithIndex = flatSamples.find((sample) => {
|
|
63
70
|
return sample.samplePosition.offset === data.counter.getOffset();
|
|
64
71
|
});
|
|
65
|
-
if (!
|
|
72
|
+
if (!samplesWithIndex) {
|
|
66
73
|
// There are various reasons why in mdat we find weird stuff:
|
|
67
74
|
// - iphonevideo.hevc has a fake hoov atom which is not mapped
|
|
68
75
|
// - corrupted.mp4 has a corrupt table
|
|
@@ -81,37 +88,39 @@ export const parseMdat = async ({
|
|
|
81
88
|
}
|
|
82
89
|
}
|
|
83
90
|
|
|
84
|
-
if (data.bytesRemaining() <
|
|
91
|
+
if (data.bytesRemaining() < samplesWithIndex.samplePosition.size) {
|
|
85
92
|
break;
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
const bytes = data.getSlice(
|
|
95
|
+
const bytes = data.getSlice(samplesWithIndex.samplePosition.size);
|
|
89
96
|
|
|
90
|
-
if (
|
|
91
|
-
await options.parserState.onAudioSample(
|
|
97
|
+
if (samplesWithIndex.track.type === 'audio') {
|
|
98
|
+
await options.parserState.onAudioSample(samplesWithIndex.track.trackId, {
|
|
92
99
|
data: bytes,
|
|
93
|
-
timestamp:
|
|
94
|
-
trackId:
|
|
95
|
-
type:
|
|
100
|
+
timestamp: samplesWithIndex.samplePosition.offset,
|
|
101
|
+
trackId: samplesWithIndex.track.trackId,
|
|
102
|
+
type: samplesWithIndex.samplePosition.isKeyframe ? 'key' : 'delta',
|
|
96
103
|
});
|
|
97
104
|
}
|
|
98
105
|
|
|
99
|
-
if (
|
|
100
|
-
const timestamp =
|
|
101
|
-
(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
if (samplesWithIndex.track.type === 'video') {
|
|
107
|
+
const timestamp = Math.floor(
|
|
108
|
+
(samplesWithIndex.samplePosition.cts * 1_000_000) /
|
|
109
|
+
samplesWithIndex.track.timescale,
|
|
110
|
+
);
|
|
111
|
+
const duration = Math.floor(
|
|
112
|
+
(samplesWithIndex.samplePosition.duration * 1_000_000) /
|
|
113
|
+
samplesWithIndex.track.timescale,
|
|
114
|
+
);
|
|
106
115
|
|
|
107
|
-
await options.parserState.onVideoSample(
|
|
116
|
+
await options.parserState.onVideoSample(samplesWithIndex.track.trackId, {
|
|
108
117
|
data: bytes,
|
|
109
118
|
timestamp,
|
|
110
119
|
duration,
|
|
111
|
-
cts:
|
|
112
|
-
dts:
|
|
113
|
-
trackId:
|
|
114
|
-
type:
|
|
120
|
+
cts: samplesWithIndex.samplePosition.cts,
|
|
121
|
+
dts: samplesWithIndex.samplePosition.dts,
|
|
122
|
+
trackId: samplesWithIndex.track.trackId,
|
|
123
|
+
type: samplesWithIndex.samplePosition.isKeyframe ? 'key' : 'delta',
|
|
115
124
|
});
|
|
116
125
|
}
|
|
117
126
|
|
|
@@ -7,6 +7,8 @@ export interface MdhdBox {
|
|
|
7
7
|
duration: number;
|
|
8
8
|
language: number;
|
|
9
9
|
quality: number;
|
|
10
|
+
creationTime: number | null;
|
|
11
|
+
modificationTime: number | null;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export const parseMdhd = ({
|
|
@@ -19,21 +21,20 @@ export const parseMdhd = ({
|
|
|
19
21
|
fileOffset: number;
|
|
20
22
|
}): MdhdBox => {
|
|
21
23
|
const version = data.getUint8();
|
|
22
|
-
if (version !== 0) {
|
|
23
|
-
throw new Error(`Unsupported MDHD version ${version}`);
|
|
24
|
-
}
|
|
25
24
|
|
|
26
25
|
// flags, we discard them
|
|
27
26
|
data.discard(3);
|
|
28
27
|
|
|
29
28
|
// creation time
|
|
30
|
-
|
|
29
|
+
const creationTime =
|
|
30
|
+
version === 1 ? Number(data.getUint64()) : data.getUint32();
|
|
31
31
|
|
|
32
32
|
// modification time
|
|
33
|
-
|
|
33
|
+
const modificationTime =
|
|
34
|
+
version === 1 ? Number(data.getUint64()) : data.getUint32();
|
|
34
35
|
|
|
35
36
|
const timescale = data.getUint32();
|
|
36
|
-
const duration = data.getUint32();
|
|
37
|
+
const duration = version === 1 ? data.getUint64() : data.getUint32();
|
|
37
38
|
|
|
38
39
|
const language = data.getUint16();
|
|
39
40
|
|
|
@@ -47,10 +48,12 @@ export const parseMdhd = ({
|
|
|
47
48
|
|
|
48
49
|
return {
|
|
49
50
|
type: 'mdhd-box',
|
|
50
|
-
duration,
|
|
51
|
+
duration: Number(duration),
|
|
51
52
|
timescale,
|
|
52
53
|
version,
|
|
53
54
|
language,
|
|
54
55
|
quality,
|
|
56
|
+
creationTime,
|
|
57
|
+
modificationTime,
|
|
55
58
|
};
|
|
56
59
|
};
|
|
@@ -38,25 +38,21 @@ export const parseMvhd = ({
|
|
|
38
38
|
size: number;
|
|
39
39
|
}): MvhdBox => {
|
|
40
40
|
const version = iterator.getUint8();
|
|
41
|
-
if (version !== 0) {
|
|
42
|
-
throw new Error(`Unsupported MVHD version ${version}`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (size !== 108) {
|
|
46
|
-
throw new Error(`Expected mvhd size of version 0 to be 108, got ${size}`);
|
|
47
|
-
}
|
|
48
41
|
|
|
49
42
|
// Flags, we discard them
|
|
50
43
|
iterator.discard(3);
|
|
51
44
|
|
|
52
|
-
const creationTime =
|
|
45
|
+
const creationTime =
|
|
46
|
+
version === 1 ? iterator.getUint64() : iterator.getUint32();
|
|
53
47
|
|
|
54
|
-
const modificationTime =
|
|
48
|
+
const modificationTime =
|
|
49
|
+
version === 1 ? iterator.getUint64() : iterator.getUint32();
|
|
55
50
|
|
|
56
51
|
const timeScale = iterator.getUint32();
|
|
57
52
|
|
|
58
|
-
const durationInUnits =
|
|
59
|
-
|
|
53
|
+
const durationInUnits =
|
|
54
|
+
version === 1 ? iterator.getUint64() : iterator.getUint32();
|
|
55
|
+
const durationInSeconds = Number(durationInUnits) / timeScale;
|
|
60
56
|
|
|
61
57
|
const rateArray = iterator.getSlice(4);
|
|
62
58
|
const rateView = getArrayBufferIterator(rateArray, rateArray.length);
|
|
@@ -96,11 +92,16 @@ export const parseMvhd = ({
|
|
|
96
92
|
|
|
97
93
|
volumeView.destroy();
|
|
98
94
|
|
|
95
|
+
const bytesRemaining = size - (iterator.counter.getOffset() - offset);
|
|
96
|
+
if (bytesRemaining !== 0) {
|
|
97
|
+
throw new Error('expected 0 bytes ' + bytesRemaining);
|
|
98
|
+
}
|
|
99
|
+
|
|
99
100
|
return {
|
|
100
|
-
creationTime: toUnixTimestamp(creationTime),
|
|
101
|
-
modificationTime: toUnixTimestamp(modificationTime),
|
|
101
|
+
creationTime: toUnixTimestamp(Number(creationTime)),
|
|
102
|
+
modificationTime: toUnixTimestamp(Number(modificationTime)),
|
|
102
103
|
timeScale,
|
|
103
|
-
durationInUnits,
|
|
104
|
+
durationInUnits: Number(durationInUnits),
|
|
104
105
|
durationInSeconds,
|
|
105
106
|
rate,
|
|
106
107
|
volume,
|
|
@@ -29,8 +29,11 @@ import {parseStsd} from './stsd/stsd';
|
|
|
29
29
|
import {parseStss} from './stsd/stss';
|
|
30
30
|
import {parseStsz} from './stsd/stsz';
|
|
31
31
|
import {parseStts} from './stsd/stts';
|
|
32
|
+
import {parseTfdt} from './tfdt';
|
|
33
|
+
import {getTfhd} from './tfhd';
|
|
32
34
|
import {parseTkhd} from './tkhd';
|
|
33
35
|
import {parseTrak} from './trak/trak';
|
|
36
|
+
import {parseTrun} from './trun';
|
|
34
37
|
|
|
35
38
|
const getChildren = async ({
|
|
36
39
|
boxType,
|
|
@@ -49,8 +52,10 @@ const getChildren = async ({
|
|
|
49
52
|
boxType === 'mdia' ||
|
|
50
53
|
boxType === 'minf' ||
|
|
51
54
|
boxType === 'stbl' ||
|
|
55
|
+
boxType === 'moof' ||
|
|
52
56
|
boxType === 'dims' ||
|
|
53
57
|
boxType === 'wave' ||
|
|
58
|
+
boxType === 'traf' ||
|
|
54
59
|
boxType === 'stsb';
|
|
55
60
|
|
|
56
61
|
if (parseChildren) {
|
|
@@ -260,6 +265,28 @@ export const processBox = async ({
|
|
|
260
265
|
};
|
|
261
266
|
}
|
|
262
267
|
|
|
268
|
+
if (boxType === 'trun') {
|
|
269
|
+
const box = parseTrun({iterator, offset: fileOffset, size: boxSize});
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
type: 'complete',
|
|
273
|
+
box,
|
|
274
|
+
size: boxSize,
|
|
275
|
+
skipTo: null,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (boxType === 'tfdt') {
|
|
280
|
+
const box = parseTfdt({iterator, size: boxSize, offset: fileOffset});
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
type: 'complete',
|
|
284
|
+
box,
|
|
285
|
+
size: boxSize,
|
|
286
|
+
skipTo: null,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
263
290
|
if (boxType === 'stsd') {
|
|
264
291
|
const box = await parseStsd({
|
|
265
292
|
iterator,
|
|
@@ -492,6 +519,21 @@ export const processBox = async ({
|
|
|
492
519
|
};
|
|
493
520
|
}
|
|
494
521
|
|
|
522
|
+
if (boxType === 'tfhd') {
|
|
523
|
+
const box = getTfhd({
|
|
524
|
+
iterator,
|
|
525
|
+
offset: fileOffset,
|
|
526
|
+
size: boxSize,
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
return {
|
|
530
|
+
type: 'complete',
|
|
531
|
+
box,
|
|
532
|
+
size: boxSize,
|
|
533
|
+
skipTo: null,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
|
|
495
537
|
if (boxType === 'mdhd') {
|
|
496
538
|
const box = parseMdhd({
|
|
497
539
|
data: iterator,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type {BufferIterator} from '../../buffer-iterator';
|
|
2
|
+
|
|
3
|
+
export interface TfdtBox {
|
|
4
|
+
type: 'tfdt-box';
|
|
5
|
+
version: number;
|
|
6
|
+
baseMediaDecodeTime: number;
|
|
7
|
+
offset: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const parseTfdt = ({
|
|
11
|
+
iterator,
|
|
12
|
+
size,
|
|
13
|
+
offset,
|
|
14
|
+
}: {
|
|
15
|
+
iterator: BufferIterator;
|
|
16
|
+
size: number;
|
|
17
|
+
offset: number;
|
|
18
|
+
}): TfdtBox => {
|
|
19
|
+
const version = iterator.getUint8();
|
|
20
|
+
iterator.discard(3);
|
|
21
|
+
// Flags, discard them
|
|
22
|
+
const num =
|
|
23
|
+
version === 0 ? iterator.getUint32() : Number(iterator.getUint64());
|
|
24
|
+
|
|
25
|
+
const bytesRemaining = size - (iterator.counter.getOffset() - offset);
|
|
26
|
+
|
|
27
|
+
if (bytesRemaining !== 0) {
|
|
28
|
+
throw new Error('expected 0 bytes ' + bytesRemaining);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
type: 'tfdt-box',
|
|
33
|
+
version,
|
|
34
|
+
baseMediaDecodeTime: num,
|
|
35
|
+
offset,
|
|
36
|
+
};
|
|
37
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type {BufferIterator} from '../../buffer-iterator';
|
|
2
|
+
|
|
3
|
+
export interface TfhdBox {
|
|
4
|
+
type: 'tfhd-box';
|
|
5
|
+
version: number;
|
|
6
|
+
trackId: number;
|
|
7
|
+
baseDataOffset: number;
|
|
8
|
+
baseSampleDescriptionIndex: number;
|
|
9
|
+
defaultSampleDuration: number;
|
|
10
|
+
defaultSampleSize: number;
|
|
11
|
+
defaultSampleFlags: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const getTfhd = ({
|
|
15
|
+
iterator,
|
|
16
|
+
offset,
|
|
17
|
+
size,
|
|
18
|
+
}: {
|
|
19
|
+
iterator: BufferIterator;
|
|
20
|
+
size: number;
|
|
21
|
+
offset: number;
|
|
22
|
+
}): TfhdBox => {
|
|
23
|
+
const version = iterator.getUint8();
|
|
24
|
+
const flags = iterator.getUint24();
|
|
25
|
+
|
|
26
|
+
const trackId = iterator.getUint32();
|
|
27
|
+
|
|
28
|
+
const baseDataOffsetPresent = flags & 0x01;
|
|
29
|
+
const baseDataOffset = baseDataOffsetPresent
|
|
30
|
+
? Number(iterator.getUint64())
|
|
31
|
+
: 0;
|
|
32
|
+
|
|
33
|
+
const baseSampleDescriptionIndexPresent = flags & 0x02;
|
|
34
|
+
const baseSampleDescriptionIndex = baseSampleDescriptionIndexPresent
|
|
35
|
+
? iterator.getUint32()
|
|
36
|
+
: 0;
|
|
37
|
+
|
|
38
|
+
const defaultSampleDurationPresent = flags & 0x08;
|
|
39
|
+
const defaultSampleDuration = defaultSampleDurationPresent
|
|
40
|
+
? iterator.getUint32()
|
|
41
|
+
: 0;
|
|
42
|
+
|
|
43
|
+
const defaultSampleSizePresent = flags & 0x10;
|
|
44
|
+
const defaultSampleSize = defaultSampleSizePresent ? iterator.getUint32() : 0;
|
|
45
|
+
|
|
46
|
+
const defaultSampleFlagsPresent = flags & 0x20;
|
|
47
|
+
const defaultSampleFlags = defaultSampleFlagsPresent
|
|
48
|
+
? iterator.getUint32()
|
|
49
|
+
: 0;
|
|
50
|
+
|
|
51
|
+
const bytesRemaining = size - (iterator.counter.getOffset() - offset);
|
|
52
|
+
if (bytesRemaining !== 0) {
|
|
53
|
+
throw new Error('expected 0 bytes ' + bytesRemaining);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
type: 'tfhd-box',
|
|
58
|
+
version,
|
|
59
|
+
trackId,
|
|
60
|
+
baseDataOffset,
|
|
61
|
+
baseSampleDescriptionIndex,
|
|
62
|
+
defaultSampleDuration,
|
|
63
|
+
defaultSampleSize,
|
|
64
|
+
defaultSampleFlags,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -26,6 +26,9 @@ type Matrix2x2 = readonly [number, number, number, number];
|
|
|
26
26
|
function getRotationAngleFromMatrix(matrix: Matrix2x2): number {
|
|
27
27
|
// Extract elements from the matrix
|
|
28
28
|
const [a, b, c, d] = matrix;
|
|
29
|
+
if (a === 0 && b === 0 && c === 0 && d === 0) {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
29
32
|
|
|
30
33
|
// Check if the matrix is a valid rotation matrix
|
|
31
34
|
if (Math.round(a * a + b * b) !== 1 || Math.round(c * c + d * d) !== 1) {
|
|
@@ -66,28 +69,23 @@ export const parseTkhd = ({
|
|
|
66
69
|
offset: number;
|
|
67
70
|
size: number;
|
|
68
71
|
}): TkhdBox => {
|
|
69
|
-
if (size !== 92) {
|
|
70
|
-
throw new Error(`Expected tkhd size of version 0 to be 92, got ${size}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
72
|
const version = iterator.getUint8();
|
|
74
|
-
if (version !== 0) {
|
|
75
|
-
throw new Error(`Unsupported TKHD version ${version}`);
|
|
76
|
-
}
|
|
77
73
|
|
|
78
74
|
// Flags, we discard them
|
|
79
75
|
iterator.discard(3);
|
|
80
76
|
|
|
81
|
-
const creationTime =
|
|
77
|
+
const creationTime =
|
|
78
|
+
version === 1 ? iterator.getUint64() : iterator.getUint32();
|
|
82
79
|
|
|
83
|
-
const modificationTime =
|
|
80
|
+
const modificationTime =
|
|
81
|
+
version === 1 ? iterator.getUint64() : iterator.getUint32();
|
|
84
82
|
|
|
85
83
|
const trackId = iterator.getUint32();
|
|
86
84
|
|
|
87
85
|
// reserved
|
|
88
86
|
iterator.discard(4);
|
|
89
87
|
|
|
90
|
-
const duration = iterator.getUint32();
|
|
88
|
+
const duration = version === 1 ? iterator.getUint64() : iterator.getUint32();
|
|
91
89
|
|
|
92
90
|
// reserved 2
|
|
93
91
|
iterator.discard(4);
|
|
@@ -134,10 +132,10 @@ export const parseTkhd = ({
|
|
|
134
132
|
offset,
|
|
135
133
|
boxSize: size,
|
|
136
134
|
type: 'tkhd-box',
|
|
137
|
-
creationTime: toUnixTimestamp(creationTime),
|
|
138
|
-
modificationTime: toUnixTimestamp(modificationTime),
|
|
135
|
+
creationTime: toUnixTimestamp(Number(creationTime)),
|
|
136
|
+
modificationTime: toUnixTimestamp(Number(modificationTime)),
|
|
139
137
|
trackId,
|
|
140
|
-
duration,
|
|
138
|
+
duration: Number(duration),
|
|
141
139
|
layer,
|
|
142
140
|
alternateGroup,
|
|
143
141
|
volume,
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type {BufferIterator} from '../../buffer-iterator';
|
|
2
|
+
|
|
3
|
+
export interface TrunBox {
|
|
4
|
+
type: 'trun-box';
|
|
5
|
+
version: number;
|
|
6
|
+
sampleCount: number;
|
|
7
|
+
dataOffset: number | null;
|
|
8
|
+
firstSampleFlags: number | null;
|
|
9
|
+
samples: TRunSample[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type TRunSample = {
|
|
13
|
+
sampleDuration: number | null;
|
|
14
|
+
sampleSize: number | null;
|
|
15
|
+
sampleFlags: number | null;
|
|
16
|
+
sampleCompositionTimeOffset: number | null;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const parseTrun = ({
|
|
20
|
+
iterator,
|
|
21
|
+
offset,
|
|
22
|
+
size,
|
|
23
|
+
}: {
|
|
24
|
+
iterator: BufferIterator;
|
|
25
|
+
offset: number;
|
|
26
|
+
size: number;
|
|
27
|
+
}): TrunBox => {
|
|
28
|
+
const version = iterator.getUint8();
|
|
29
|
+
if (version !== 0) {
|
|
30
|
+
throw new Error(`Unsupported TRUN version ${version}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const flags = iterator.getUint24();
|
|
34
|
+
const sampleCount = iterator.getUint32();
|
|
35
|
+
|
|
36
|
+
const dataOffset = flags & 0x01 ? iterator.getInt32() : null;
|
|
37
|
+
const firstSampleFlags = flags & 0x04 ? iterator.getUint32() : null;
|
|
38
|
+
|
|
39
|
+
const samples: TRunSample[] = [];
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
42
|
+
const sampleDuration = flags & 0x100 ? iterator.getUint32() : null;
|
|
43
|
+
const sampleSize = flags & 0x200 ? iterator.getUint32() : null;
|
|
44
|
+
const sampleFlags = flags & 0x400 ? iterator.getUint32() : null;
|
|
45
|
+
const sampleCompositionTimeOffset =
|
|
46
|
+
flags & 0x800
|
|
47
|
+
? version === 0
|
|
48
|
+
? iterator.getUint32()
|
|
49
|
+
: iterator.getInt32Le()
|
|
50
|
+
: null;
|
|
51
|
+
|
|
52
|
+
samples.push({
|
|
53
|
+
sampleDuration,
|
|
54
|
+
sampleSize,
|
|
55
|
+
sampleFlags,
|
|
56
|
+
sampleCompositionTimeOffset,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const currentOffset = iterator.counter.getOffset();
|
|
61
|
+
const left = size - (currentOffset - offset);
|
|
62
|
+
if (left !== 0) {
|
|
63
|
+
throw new Error(`Unexpected data left in TRUN box: ${left}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
type: 'trun-box',
|
|
68
|
+
version,
|
|
69
|
+
sampleCount,
|
|
70
|
+
dataOffset,
|
|
71
|
+
firstSampleFlags,
|
|
72
|
+
samples,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
@@ -221,7 +221,6 @@ export const getTrack = ({
|
|
|
221
221
|
denominator: 1,
|
|
222
222
|
},
|
|
223
223
|
timescale,
|
|
224
|
-
samplePositions: [],
|
|
225
224
|
codedHeight: height.value.value,
|
|
226
225
|
codedWidth: width.value.value,
|
|
227
226
|
displayAspectHeight: displayHeight
|
|
@@ -231,6 +230,7 @@ export const getTrack = ({
|
|
|
231
230
|
? displayWidth.value.value
|
|
232
231
|
: width.value.value,
|
|
233
232
|
rotation: 0,
|
|
233
|
+
trakBox: null,
|
|
234
234
|
};
|
|
235
235
|
}
|
|
236
236
|
|
|
@@ -245,11 +245,11 @@ export const getTrack = ({
|
|
|
245
245
|
type: 'audio',
|
|
246
246
|
trackId,
|
|
247
247
|
codec: getMatroskaAudioCodecString(track),
|
|
248
|
-
samplePositions: null,
|
|
249
248
|
timescale,
|
|
250
249
|
numberOfChannels,
|
|
251
250
|
sampleRate,
|
|
252
251
|
description: getAudioDescription(track),
|
|
252
|
+
trakBox: null,
|
|
253
253
|
};
|
|
254
254
|
}
|
|
255
255
|
|
package/src/buffer-iterator.ts
CHANGED
|
@@ -483,8 +483,8 @@ export const getArrayBufferIterator = (
|
|
|
483
483
|
},
|
|
484
484
|
getUint24: () => {
|
|
485
485
|
const val1 = view.getUint8(counter.getDiscardedOffset());
|
|
486
|
-
const val2 = view.getUint8(counter.getDiscardedOffset());
|
|
487
|
-
const val3 = view.getUint8(counter.getDiscardedOffset());
|
|
486
|
+
const val2 = view.getUint8(counter.getDiscardedOffset() + 1);
|
|
487
|
+
const val3 = view.getUint8(counter.getDiscardedOffset() + 2);
|
|
488
488
|
counter.increment(3);
|
|
489
489
|
return (val1 << 16) | (val2 << 8) | val3;
|
|
490
490
|
},
|
|
@@ -539,6 +539,7 @@ export const getArrayBufferIterator = (
|
|
|
539
539
|
},
|
|
540
540
|
getUint32Le,
|
|
541
541
|
getInt32Le,
|
|
542
|
+
getInt32,
|
|
542
543
|
destroy,
|
|
543
544
|
isMp3,
|
|
544
545
|
};
|