@remotion/media-parser 4.0.231 → 4.0.232
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/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 -37
- 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 +9 -9
- 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/iso-base-media/create-iso-base-media.js +0 -4
- package/dist/create/matroska/create-matroska-media.js +0 -4
- package/dist/create/media-fn.d.ts +0 -1
- package/dist/create/mp3/create-mp3.d.ts +2 -0
- package/dist/create/mp3/create-mp3.js +49 -0
- package/dist/create/wav/create-wav.d.ts +2 -0
- package/dist/create/wav/create-wav.js +108 -0
- package/dist/emit-available-info.d.ts +2 -2
- package/dist/emit-available-info.js +6 -4
- package/dist/esm/from-node.mjs +2 -1
- package/dist/esm/index.mjs +1487 -431
- package/dist/get-audio-codec.d.ts +3 -3
- package/dist/get-audio-codec.js +2 -2
- 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-tracks.d.ts +4 -7
- package/dist/get-tracks.js +55 -27
- package/dist/get-video-codec.d.ts +5 -4
- package/dist/get-video-codec.js +38 -10
- package/dist/has-all-info.d.ts +2 -2
- package/dist/has-all-info.js +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/options.d.ts +9 -9
- package/dist/parse-media.js +2 -0
- 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
|
@@ -17,7 +17,7 @@ import type { TkhdBox } from './tkhd';
|
|
|
17
17
|
import type { TrakBox } from './trak/trak';
|
|
18
18
|
import type { TrunBox } from './trun';
|
|
19
19
|
export declare const getFtypBox: (segments: AnySegment[]) => FtypBox | null;
|
|
20
|
-
export declare const getMoovBox: (segments:
|
|
20
|
+
export declare const getMoovBox: (segments: IsoBaseMediaBox[]) => MoovBox | null;
|
|
21
21
|
export declare const getMoofBox: (main: AnySegment[]) => IsoBaseMediaBox | null;
|
|
22
22
|
export declare const getMvhdBox: (moovBox: MoovBox) => MvhdBox | null;
|
|
23
23
|
export declare const getTraks: (moovBox: MoovBox) => TrakBox[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BufferIterator } from '../../buffer-iterator';
|
|
2
|
+
import type { RiffStructure } from '../../parse-result';
|
|
3
|
+
import type { ParserContext } from '../../parser-context';
|
|
4
|
+
import type { RiffBox } from './riff-box';
|
|
5
|
+
export type RiffResult = {
|
|
6
|
+
type: 'incomplete';
|
|
7
|
+
continueParsing: () => Promise<RiffResult>;
|
|
8
|
+
} | {
|
|
9
|
+
type: 'complete';
|
|
10
|
+
box: RiffBox | null;
|
|
11
|
+
};
|
|
12
|
+
export declare const expectRiffBox: ({ iterator, options, structure, }: {
|
|
13
|
+
iterator: BufferIterator;
|
|
14
|
+
options: ParserContext;
|
|
15
|
+
structure: RiffStructure;
|
|
16
|
+
}) => Promise<RiffResult>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expectRiffBox = void 0;
|
|
4
|
+
const is_movi_1 = require("./is-movi");
|
|
5
|
+
const parse_movi_1 = require("./parse-movi");
|
|
6
|
+
const parse_riff_box_1 = require("./parse-riff-box");
|
|
7
|
+
const expectRiffBox = async ({ iterator, options, structure, }) => {
|
|
8
|
+
// Need at least 16 bytes to read LIST,size,movi,size
|
|
9
|
+
if (iterator.bytesRemaining() < 16) {
|
|
10
|
+
return {
|
|
11
|
+
type: 'incomplete',
|
|
12
|
+
continueParsing() {
|
|
13
|
+
return (0, exports.expectRiffBox)({ structure, iterator, options });
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const ckId = iterator.getByteString(4);
|
|
18
|
+
const ckSize = iterator.getUint32Le();
|
|
19
|
+
if ((0, is_movi_1.isMoviAtom)(iterator, ckId)) {
|
|
20
|
+
iterator.discard(4);
|
|
21
|
+
return (0, parse_movi_1.parseMovi)({
|
|
22
|
+
iterator,
|
|
23
|
+
maxOffset: ckSize + iterator.counter.getOffset() - 4,
|
|
24
|
+
options,
|
|
25
|
+
structure,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// TODO: Add capability to read partially
|
|
29
|
+
if (iterator.bytesRemaining() < ckSize) {
|
|
30
|
+
iterator.counter.decrement(8);
|
|
31
|
+
return {
|
|
32
|
+
type: 'incomplete',
|
|
33
|
+
continueParsing: () => {
|
|
34
|
+
return (0, exports.expectRiffBox)({ structure, iterator, options });
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
type: 'complete',
|
|
40
|
+
box: await (0, parse_riff_box_1.parseRiffBox)({
|
|
41
|
+
id: ckId,
|
|
42
|
+
iterator,
|
|
43
|
+
size: ckSize,
|
|
44
|
+
boxes: structure.boxes,
|
|
45
|
+
options,
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
exports.expectRiffBox = expectRiffBox;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AudioTrack, OtherTrack, VideoTrack } from '../../get-tracks';
|
|
2
|
+
import type { RiffStructure } from '../../parse-result';
|
|
3
|
+
import type { ParserState } from '../../parser-state';
|
|
4
|
+
import type { StrfBoxAudio, StrfBoxVideo, StrhBox } from './riff-box';
|
|
5
|
+
export type AllTracks = {
|
|
6
|
+
videoTracks: VideoTrack[];
|
|
7
|
+
audioTracks: AudioTrack[];
|
|
8
|
+
otherTracks: OtherTrack[];
|
|
9
|
+
};
|
|
10
|
+
export declare const getNumberOfTracks: (structure: RiffStructure) => number;
|
|
11
|
+
export declare const makeAviAudioTrack: ({ strf, index, }: {
|
|
12
|
+
strf: StrfBoxAudio;
|
|
13
|
+
index: number;
|
|
14
|
+
}) => AudioTrack;
|
|
15
|
+
export declare const makeAviVideoTrack: ({ strh, strf, index, }: {
|
|
16
|
+
strh: StrhBox;
|
|
17
|
+
strf: StrfBoxVideo;
|
|
18
|
+
index: number;
|
|
19
|
+
}) => VideoTrack;
|
|
20
|
+
export declare const getTracksFromAvi: (structure: RiffStructure, state: ParserState) => AllTracks;
|
|
21
|
+
export declare const hasAllTracksFromAvi: (structure: RiffStructure, state: ParserState) => boolean;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasAllTracksFromAvi = exports.getTracksFromAvi = exports.makeAviVideoTrack = exports.makeAviAudioTrack = exports.getNumberOfTracks = void 0;
|
|
4
|
+
const add_avc_profile_to_track_1 = require("../../add-avc-profile-to-track");
|
|
5
|
+
const timescale_1 = require("./timescale");
|
|
6
|
+
const traversal_1 = require("./traversal");
|
|
7
|
+
const getNumberOfTracks = (structure) => {
|
|
8
|
+
const avihBox = (0, traversal_1.getAvihBox)(structure);
|
|
9
|
+
if (avihBox) {
|
|
10
|
+
return avihBox.streams;
|
|
11
|
+
}
|
|
12
|
+
throw new Error('No avih box found');
|
|
13
|
+
};
|
|
14
|
+
exports.getNumberOfTracks = getNumberOfTracks;
|
|
15
|
+
const makeAviAudioTrack = ({ strf, index, }) => {
|
|
16
|
+
// 255 = AAC
|
|
17
|
+
if (strf.formatTag !== 255) {
|
|
18
|
+
throw new Error(`Unsupported audio format ${strf.formatTag}`);
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
type: 'audio',
|
|
22
|
+
codec: 'mp4a.40.2', // According to Claude 3.5 Sonnet
|
|
23
|
+
codecPrivate: new Uint8Array([18, 16]),
|
|
24
|
+
codecWithoutConfig: 'aac',
|
|
25
|
+
description: new Uint8Array([18, 16]),
|
|
26
|
+
numberOfChannels: strf.numberOfChannels,
|
|
27
|
+
sampleRate: strf.sampleRate,
|
|
28
|
+
timescale: timescale_1.MEDIA_PARSER_RIFF_TIMESCALE,
|
|
29
|
+
trackId: index,
|
|
30
|
+
trakBox: null,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
exports.makeAviAudioTrack = makeAviAudioTrack;
|
|
34
|
+
const makeAviVideoTrack = ({ strh, strf, index, }) => {
|
|
35
|
+
if (strh.handler !== 'H264') {
|
|
36
|
+
throw new Error(`Unsupported video codec ${strh.handler}`);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
codecPrivate: null,
|
|
40
|
+
codec: 'to-be-overriden-later',
|
|
41
|
+
codecWithoutConfig: 'h264',
|
|
42
|
+
codedHeight: strf.height,
|
|
43
|
+
codedWidth: strf.width,
|
|
44
|
+
width: strf.width,
|
|
45
|
+
height: strf.height,
|
|
46
|
+
type: 'video',
|
|
47
|
+
displayAspectHeight: strf.height,
|
|
48
|
+
timescale: timescale_1.MEDIA_PARSER_RIFF_TIMESCALE,
|
|
49
|
+
description: undefined,
|
|
50
|
+
trackId: index,
|
|
51
|
+
color: {
|
|
52
|
+
fullRange: null,
|
|
53
|
+
matrixCoefficients: null,
|
|
54
|
+
primaries: null,
|
|
55
|
+
transferCharacteristics: null,
|
|
56
|
+
},
|
|
57
|
+
displayAspectWidth: strf.width,
|
|
58
|
+
trakBox: null,
|
|
59
|
+
rotation: 0,
|
|
60
|
+
sampleAspectRatio: {
|
|
61
|
+
numerator: 1,
|
|
62
|
+
denominator: 1,
|
|
63
|
+
},
|
|
64
|
+
fps: strh.rate / strh.scale,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
exports.makeAviVideoTrack = makeAviVideoTrack;
|
|
68
|
+
const getTracksFromAvi = (structure, state) => {
|
|
69
|
+
if (!(0, traversal_1.isRiffAvi)(structure)) {
|
|
70
|
+
throw new Error('Not an AVI file');
|
|
71
|
+
}
|
|
72
|
+
const videoTracks = [];
|
|
73
|
+
const audioTracks = [];
|
|
74
|
+
const otherTracks = [];
|
|
75
|
+
const boxes = (0, traversal_1.getStrlBoxes)(structure);
|
|
76
|
+
let i = 0;
|
|
77
|
+
for (const box of boxes) {
|
|
78
|
+
const strh = (0, traversal_1.getStrhBox)(box.children);
|
|
79
|
+
const strf = (0, traversal_1.getStrfBox)(box.children);
|
|
80
|
+
if (!strh || !strf) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (strf.type === 'strf-box-video') {
|
|
84
|
+
videoTracks.push((0, add_avc_profile_to_track_1.addAvcProfileToTrack)((0, exports.makeAviVideoTrack)({ strh, strf, index: i }), state.getAvcProfile()));
|
|
85
|
+
}
|
|
86
|
+
else if (strh.fccType === 'auds') {
|
|
87
|
+
audioTracks.push((0, exports.makeAviAudioTrack)({ strf, index: i }));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
throw new Error(`Unsupported track type ${strh.fccType}`);
|
|
91
|
+
}
|
|
92
|
+
i++;
|
|
93
|
+
}
|
|
94
|
+
return { audioTracks, otherTracks, videoTracks };
|
|
95
|
+
};
|
|
96
|
+
exports.getTracksFromAvi = getTracksFromAvi;
|
|
97
|
+
const hasAllTracksFromAvi = (structure, state) => {
|
|
98
|
+
if (!(0, traversal_1.isRiffAvi)(structure)) {
|
|
99
|
+
throw new Error('Not an AVI file');
|
|
100
|
+
}
|
|
101
|
+
const numberOfTracks = (0, exports.getNumberOfTracks)(structure);
|
|
102
|
+
const tracks = (0, exports.getTracksFromAvi)(structure, state);
|
|
103
|
+
return (tracks.videoTracks.length +
|
|
104
|
+
tracks.audioTracks.length +
|
|
105
|
+
tracks.otherTracks.length ===
|
|
106
|
+
numberOfTracks);
|
|
107
|
+
};
|
|
108
|
+
exports.hasAllTracksFromAvi = hasAllTracksFromAvi;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isMoviAtom = void 0;
|
|
4
|
+
const isMoviAtom = (iterator, ckId) => {
|
|
5
|
+
if (ckId !== 'LIST') {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const listType = iterator.getByteString(4);
|
|
9
|
+
iterator.counter.decrement(4);
|
|
10
|
+
return listType === 'movi';
|
|
11
|
+
};
|
|
12
|
+
exports.isMoviAtom = isMoviAtom;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseAvih = void 0;
|
|
4
|
+
const parseAvih = ({ iterator, size, }) => {
|
|
5
|
+
const { expectNoMoreBytes } = iterator.startBox(size);
|
|
6
|
+
const dwMicroSecPerFrame = iterator.getUint32Le();
|
|
7
|
+
const dwMaxBytesPerSec = iterator.getUint32Le();
|
|
8
|
+
const paddingGranularity = iterator.getUint32Le();
|
|
9
|
+
const flags = iterator.getUint32Le();
|
|
10
|
+
const totalFrames = iterator.getUint32Le();
|
|
11
|
+
const initialFrames = iterator.getUint32Le();
|
|
12
|
+
const streams = iterator.getUint32Le();
|
|
13
|
+
const suggestedBufferSize = iterator.getUint32Le();
|
|
14
|
+
const width = iterator.getUint32Le();
|
|
15
|
+
const height = iterator.getUint32Le();
|
|
16
|
+
iterator.discard(16);
|
|
17
|
+
expectNoMoreBytes();
|
|
18
|
+
return {
|
|
19
|
+
type: 'avih-box',
|
|
20
|
+
microSecPerFrame: dwMicroSecPerFrame,
|
|
21
|
+
maxBytesPerSecond: dwMaxBytesPerSec,
|
|
22
|
+
paddingGranularity,
|
|
23
|
+
flags,
|
|
24
|
+
totalFrames,
|
|
25
|
+
initialFrames,
|
|
26
|
+
streams,
|
|
27
|
+
suggestedBufferSize,
|
|
28
|
+
height,
|
|
29
|
+
width,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
exports.parseAvih = parseAvih;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BufferIterator } from '../../buffer-iterator';
|
|
2
|
+
import type { ParseResult, RiffStructure } from '../../parse-result';
|
|
3
|
+
import type { ParserContext } from '../../parser-context';
|
|
4
|
+
export declare const parseRiffBody: ({ iterator, structure, maxOffset, options, }: {
|
|
5
|
+
iterator: BufferIterator;
|
|
6
|
+
structure: RiffStructure;
|
|
7
|
+
maxOffset: number;
|
|
8
|
+
options: ParserContext;
|
|
9
|
+
}) => Promise<ParseResult<RiffStructure>>;
|
|
10
|
+
export declare const parseRiff: ({ iterator, options, }: {
|
|
11
|
+
iterator: BufferIterator;
|
|
12
|
+
options: ParserContext;
|
|
13
|
+
}) => Promise<ParseResult<RiffStructure>>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseRiff = exports.parseRiffBody = void 0;
|
|
4
|
+
const register_track_1 = require("../../register-track");
|
|
5
|
+
const expect_riff_box_1 = require("./expect-riff-box");
|
|
6
|
+
const get_tracks_from_avi_1 = require("./get-tracks-from-avi");
|
|
7
|
+
const traversal_1 = require("./traversal");
|
|
8
|
+
const continueAfterRiffBoxResult = ({ result, structure, iterator, maxOffset, options, }) => {
|
|
9
|
+
if (result.type === 'incomplete') {
|
|
10
|
+
return Promise.resolve({
|
|
11
|
+
status: 'incomplete',
|
|
12
|
+
async continueParsing() {
|
|
13
|
+
return Promise.resolve(continueAfterRiffBoxResult({
|
|
14
|
+
result: await result.continueParsing(),
|
|
15
|
+
structure,
|
|
16
|
+
iterator,
|
|
17
|
+
maxOffset,
|
|
18
|
+
options,
|
|
19
|
+
}));
|
|
20
|
+
},
|
|
21
|
+
segments: structure,
|
|
22
|
+
skipTo: null,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (result.type === 'complete') {
|
|
26
|
+
if (result.box) {
|
|
27
|
+
structure.boxes.push(result.box);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return (0, exports.parseRiffBody)({ iterator, maxOffset, options, structure });
|
|
31
|
+
};
|
|
32
|
+
const parseRiffBody = async ({ iterator, structure, maxOffset, options, }) => {
|
|
33
|
+
while (iterator.bytesRemaining() > 0 &&
|
|
34
|
+
iterator.counter.getOffset() < maxOffset) {
|
|
35
|
+
const result = await (0, expect_riff_box_1.expectRiffBox)({
|
|
36
|
+
iterator,
|
|
37
|
+
options,
|
|
38
|
+
structure,
|
|
39
|
+
});
|
|
40
|
+
if (result.type === 'incomplete') {
|
|
41
|
+
return {
|
|
42
|
+
status: 'incomplete',
|
|
43
|
+
async continueParsing() {
|
|
44
|
+
return Promise.resolve(continueAfterRiffBoxResult({
|
|
45
|
+
iterator,
|
|
46
|
+
maxOffset,
|
|
47
|
+
options,
|
|
48
|
+
result: await result.continueParsing(),
|
|
49
|
+
structure,
|
|
50
|
+
}));
|
|
51
|
+
},
|
|
52
|
+
segments: structure,
|
|
53
|
+
skipTo: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (result.box === null) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
structure.boxes.push(result.box);
|
|
60
|
+
if (result.box.type === 'strf-box-video' ||
|
|
61
|
+
result.box.type === 'strf-box-audio') {
|
|
62
|
+
const strh = (0, traversal_1.getStrhBox)(structure.boxes);
|
|
63
|
+
const strf = (0, traversal_1.getStrfBox)(structure.boxes);
|
|
64
|
+
if (!strh || !strf) {
|
|
65
|
+
throw new Error('strh or strf box missing');
|
|
66
|
+
}
|
|
67
|
+
if (strf.type === 'strf-box-audio' && options.onAudioTrack) {
|
|
68
|
+
const audioTrack = (0, get_tracks_from_avi_1.makeAviAudioTrack)({
|
|
69
|
+
index: options.nextTrackIndex,
|
|
70
|
+
strf,
|
|
71
|
+
});
|
|
72
|
+
await (0, register_track_1.registerTrack)({
|
|
73
|
+
options,
|
|
74
|
+
state: options.parserState,
|
|
75
|
+
track: audioTrack,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (options.onVideoTrack && strf.type === 'strf-box-video') {
|
|
79
|
+
const videoTrack = (0, get_tracks_from_avi_1.makeAviVideoTrack)({
|
|
80
|
+
strh,
|
|
81
|
+
index: options.nextTrackIndex,
|
|
82
|
+
strf,
|
|
83
|
+
});
|
|
84
|
+
(0, register_track_1.registerVideoTrackWhenProfileIsAvailable)({
|
|
85
|
+
options,
|
|
86
|
+
state: options.parserState,
|
|
87
|
+
track: videoTrack,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
options.nextTrackIndex++;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
status: 'done',
|
|
95
|
+
segments: structure,
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
exports.parseRiffBody = parseRiffBody;
|
|
99
|
+
const parseRiff = ({ iterator, options, }) => {
|
|
100
|
+
const structure = { type: 'riff', boxes: [] };
|
|
101
|
+
const riff = iterator.getByteString(4);
|
|
102
|
+
if (riff !== 'RIFF') {
|
|
103
|
+
throw new Error('Not a RIFF file');
|
|
104
|
+
}
|
|
105
|
+
const size = iterator.getUint32Le();
|
|
106
|
+
const fileType = iterator.getByteString(4);
|
|
107
|
+
if (fileType !== 'WAVE' && fileType !== 'AVI') {
|
|
108
|
+
throw new Error(`File type ${fileType} not supported`);
|
|
109
|
+
}
|
|
110
|
+
structure.boxes.push({ type: 'riff-header', fileSize: size, fileType });
|
|
111
|
+
return (0, exports.parseRiffBody)({ iterator, structure, maxOffset: Infinity, options });
|
|
112
|
+
};
|
|
113
|
+
exports.parseRiff = parseRiff;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseFmtBox = void 0;
|
|
4
|
+
const parseFmtBox = ({ iterator, boxes, size, }) => {
|
|
5
|
+
const box = iterator.startBox(size);
|
|
6
|
+
const header = boxes.find((b) => b.type === 'riff-header');
|
|
7
|
+
if (!header) {
|
|
8
|
+
throw new Error('Expected RIFF header');
|
|
9
|
+
}
|
|
10
|
+
if (header.fileType !== 'WAVE') {
|
|
11
|
+
throw new Error('Only supporting WAVE type');
|
|
12
|
+
}
|
|
13
|
+
const wFormatTag = iterator.getUint16Le();
|
|
14
|
+
if (wFormatTag !== 1) {
|
|
15
|
+
throw new Error('Expected wFormatTag to be 1, only supporting this');
|
|
16
|
+
}
|
|
17
|
+
const numberOfChannels = iterator.getUint16Le();
|
|
18
|
+
const sampleRate = iterator.getUint32Le();
|
|
19
|
+
const byteRate = iterator.getUint32Le();
|
|
20
|
+
const blockAlign = iterator.getUint16Le();
|
|
21
|
+
const bitsPerSample = iterator.getUint16Le();
|
|
22
|
+
box.expectNoMoreBytes();
|
|
23
|
+
return {
|
|
24
|
+
type: 'wave-format-box',
|
|
25
|
+
formatTag: wFormatTag,
|
|
26
|
+
numberOfChannels,
|
|
27
|
+
sampleRate,
|
|
28
|
+
blockAlign,
|
|
29
|
+
byteRate,
|
|
30
|
+
bitsPerSample,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
exports.parseFmtBox = parseFmtBox;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BufferIterator } from '../../buffer-iterator';
|
|
2
|
+
import type { ParserContext } from '../../parser-context';
|
|
3
|
+
import type { RiffBox } from './riff-box';
|
|
4
|
+
export declare const parseListBox: ({ iterator, size, options, }: {
|
|
5
|
+
iterator: BufferIterator;
|
|
6
|
+
size: number;
|
|
7
|
+
options: ParserContext;
|
|
8
|
+
}) => Promise<RiffBox>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseListBox = void 0;
|
|
4
|
+
const parse_box_1 = require("./parse-box");
|
|
5
|
+
const parseListBox = async ({ iterator, size, options, }) => {
|
|
6
|
+
const counter = iterator.counter.getOffset();
|
|
7
|
+
const listType = iterator.getByteString(4);
|
|
8
|
+
if (listType === 'movi') {
|
|
9
|
+
throw new Error('should not be handled here');
|
|
10
|
+
}
|
|
11
|
+
const structure = {
|
|
12
|
+
type: 'riff',
|
|
13
|
+
boxes: [],
|
|
14
|
+
};
|
|
15
|
+
const result = await (0, parse_box_1.parseRiffBody)({
|
|
16
|
+
structure,
|
|
17
|
+
iterator,
|
|
18
|
+
maxOffset: counter + size,
|
|
19
|
+
options,
|
|
20
|
+
});
|
|
21
|
+
if (result.status === 'incomplete') {
|
|
22
|
+
throw new Error(`Should only parse complete boxes (${listType})`);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
type: 'list-box',
|
|
26
|
+
listType,
|
|
27
|
+
children: structure.boxes,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
exports.parseListBox = parseListBox;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BufferIterator } from '../../buffer-iterator';
|
|
2
|
+
import type { RiffStructure } from '../../parse-result';
|
|
3
|
+
import type { ParserContext } from '../../parser-context';
|
|
4
|
+
import type { RiffResult } from './expect-riff-box';
|
|
5
|
+
export declare const handleChunk: ({ iterator, options, structure, ckId, ckSize, }: {
|
|
6
|
+
iterator: BufferIterator;
|
|
7
|
+
options: ParserContext;
|
|
8
|
+
structure: RiffStructure;
|
|
9
|
+
ckId: string;
|
|
10
|
+
ckSize: number;
|
|
11
|
+
}) => Promise<void>;
|
|
12
|
+
export declare const parseMovi: ({ iterator, maxOffset, options, structure, }: {
|
|
13
|
+
iterator: BufferIterator;
|
|
14
|
+
maxOffset: number;
|
|
15
|
+
options: ParserContext;
|
|
16
|
+
structure: RiffStructure;
|
|
17
|
+
}) => Promise<RiffResult>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseMovi = exports.handleChunk = void 0;
|
|
4
|
+
const parse_avc_1 = require("../avc/parse-avc");
|
|
5
|
+
const timescale_1 = require("./timescale");
|
|
6
|
+
const traversal_1 = require("./traversal");
|
|
7
|
+
const getStrhForIndex = (structure, trackId) => {
|
|
8
|
+
const boxes = (0, traversal_1.getStrlBoxes)(structure);
|
|
9
|
+
const box = boxes[trackId];
|
|
10
|
+
if (!box) {
|
|
11
|
+
throw new Error('Expected box');
|
|
12
|
+
}
|
|
13
|
+
const strh = (0, traversal_1.getStrhBox)(box.children);
|
|
14
|
+
if (!strh) {
|
|
15
|
+
throw new Error('strh');
|
|
16
|
+
}
|
|
17
|
+
return strh;
|
|
18
|
+
};
|
|
19
|
+
const handleChunk = async ({ iterator, options, structure, ckId, ckSize, }) => {
|
|
20
|
+
const videoChunk = ckId.match(/^([0-9]{2})dc$/);
|
|
21
|
+
if (videoChunk) {
|
|
22
|
+
const trackId = parseInt(videoChunk[1], 10);
|
|
23
|
+
const strh = getStrhForIndex(structure, trackId);
|
|
24
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
25
|
+
const nthSample = options.parserState.getSamplesForTrack(trackId);
|
|
26
|
+
const timeInSec = nthSample / samplesPerSecond;
|
|
27
|
+
const timestamp = Math.floor(timeInSec * timescale_1.MEDIA_PARSER_RIFF_TIMESCALE);
|
|
28
|
+
const duration = Math.floor((1 / samplesPerSecond) * timescale_1.MEDIA_PARSER_RIFF_TIMESCALE);
|
|
29
|
+
const data = iterator.getSlice(ckSize);
|
|
30
|
+
const infos = (0, parse_avc_1.parseAvc)(data);
|
|
31
|
+
const keyOrDelta = infos.find((i) => i.type === 'keyframe' || i.type === 'delta-frame');
|
|
32
|
+
if (!keyOrDelta) {
|
|
33
|
+
throw new Error('expected avc to contain info about key or delta');
|
|
34
|
+
}
|
|
35
|
+
const avcProfile = infos.find((i) => i.type === 'avc-profile');
|
|
36
|
+
const ppsProfile = infos.find((i) => i.type === 'avc-pps');
|
|
37
|
+
if (avcProfile && ppsProfile) {
|
|
38
|
+
await options.parserState.onProfile({ pps: ppsProfile, sps: avcProfile });
|
|
39
|
+
}
|
|
40
|
+
await options.parserState.onVideoSample(trackId, {
|
|
41
|
+
cts: timestamp,
|
|
42
|
+
dts: timestamp,
|
|
43
|
+
data,
|
|
44
|
+
duration,
|
|
45
|
+
timestamp,
|
|
46
|
+
trackId,
|
|
47
|
+
type: keyOrDelta.type === 'keyframe' ? 'key' : 'delta',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const audioChunk = ckId.match(/^([0-9]{2})wb$/);
|
|
52
|
+
if (audioChunk) {
|
|
53
|
+
const trackId = parseInt(audioChunk[1], 10);
|
|
54
|
+
const strh = getStrhForIndex(structure, trackId);
|
|
55
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
56
|
+
const nthSample = options.parserState.getSamplesForTrack(trackId);
|
|
57
|
+
const timeInSec = nthSample / samplesPerSecond;
|
|
58
|
+
const timestamp = timeInSec * timescale_1.MEDIA_PARSER_RIFF_TIMESCALE;
|
|
59
|
+
const duration = (1 / samplesPerSecond) * timescale_1.MEDIA_PARSER_RIFF_TIMESCALE;
|
|
60
|
+
await options.parserState.onAudioSample(trackId, {
|
|
61
|
+
cts: timestamp,
|
|
62
|
+
dts: timestamp,
|
|
63
|
+
data: iterator.getSlice(ckSize),
|
|
64
|
+
duration,
|
|
65
|
+
timestamp,
|
|
66
|
+
trackId,
|
|
67
|
+
type: 'key',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
exports.handleChunk = handleChunk;
|
|
73
|
+
const parseMovi = async ({ iterator, maxOffset, options, structure, }) => {
|
|
74
|
+
while (iterator.counter.getOffset() < maxOffset) {
|
|
75
|
+
if (iterator.bytesRemaining() < 8) {
|
|
76
|
+
return {
|
|
77
|
+
type: 'incomplete',
|
|
78
|
+
continueParsing: () => {
|
|
79
|
+
return Promise.resolve((0, exports.parseMovi)({ iterator, maxOffset, options, structure }));
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const ckId = iterator.getByteString(4);
|
|
84
|
+
const ckSize = iterator.getUint32Le();
|
|
85
|
+
if (iterator.bytesRemaining() < ckSize) {
|
|
86
|
+
iterator.counter.decrement(8);
|
|
87
|
+
return {
|
|
88
|
+
type: 'incomplete',
|
|
89
|
+
continueParsing: () => {
|
|
90
|
+
return Promise.resolve((0, exports.parseMovi)({ iterator, maxOffset, options, structure }));
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
await (0, exports.handleChunk)({ iterator, options, structure, ckId, ckSize });
|
|
95
|
+
// Discard added zeroes
|
|
96
|
+
while (iterator.counter.getOffset() < maxOffset &&
|
|
97
|
+
iterator.bytesRemaining() > 0) {
|
|
98
|
+
if (iterator.getUint8() !== 0) {
|
|
99
|
+
iterator.counter.decrement(1);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (iterator.counter.getOffset() === maxOffset) {
|
|
105
|
+
return {
|
|
106
|
+
type: 'complete',
|
|
107
|
+
box: {
|
|
108
|
+
type: 'movi-box',
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (iterator.counter.getOffset() > maxOffset) {
|
|
113
|
+
throw new Error('Oops, this should not happen!');
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
type: 'incomplete',
|
|
117
|
+
continueParsing: () => {
|
|
118
|
+
return Promise.resolve((0, exports.parseMovi)({ iterator, maxOffset, options, structure }));
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
exports.parseMovi = parseMovi;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BufferIterator } from '../../buffer-iterator';
|
|
2
|
+
import type { ParserContext } from '../../parser-context';
|
|
3
|
+
import type { RiffBox } from './riff-box';
|
|
4
|
+
export declare const parseRiffBox: ({ iterator, size, id, boxes, options, }: {
|
|
5
|
+
iterator: BufferIterator;
|
|
6
|
+
size: number;
|
|
7
|
+
id: string;
|
|
8
|
+
boxes: RiffBox[];
|
|
9
|
+
options: ParserContext;
|
|
10
|
+
}) => Promise<RiffBox>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseRiffBox = void 0;
|
|
4
|
+
const parse_avih_1 = require("./parse-avih");
|
|
5
|
+
const parse_fmt_box_1 = require("./parse-fmt-box");
|
|
6
|
+
const parse_list_box_1 = require("./parse-list-box");
|
|
7
|
+
const parse_strf_1 = require("./parse-strf");
|
|
8
|
+
const parse_strh_1 = require("./parse-strh");
|
|
9
|
+
const parseRiffBox = ({ iterator, size, id, boxes, options, }) => {
|
|
10
|
+
if (id === 'fmt') {
|
|
11
|
+
return Promise.resolve((0, parse_fmt_box_1.parseFmtBox)({ iterator, boxes, size }));
|
|
12
|
+
}
|
|
13
|
+
if (id === 'LIST') {
|
|
14
|
+
return (0, parse_list_box_1.parseListBox)({ iterator, size, options });
|
|
15
|
+
}
|
|
16
|
+
if (id === 'avih') {
|
|
17
|
+
return Promise.resolve((0, parse_avih_1.parseAvih)({ iterator, size }));
|
|
18
|
+
}
|
|
19
|
+
if (id === 'strh') {
|
|
20
|
+
return Promise.resolve((0, parse_strh_1.parseStrh)({ iterator, size }));
|
|
21
|
+
}
|
|
22
|
+
if (id === 'strf') {
|
|
23
|
+
return Promise.resolve((0, parse_strf_1.parseStrf)({ iterator, size, boxes }));
|
|
24
|
+
}
|
|
25
|
+
iterator.discard(size);
|
|
26
|
+
const box = {
|
|
27
|
+
type: 'riff-box',
|
|
28
|
+
size,
|
|
29
|
+
id,
|
|
30
|
+
};
|
|
31
|
+
return Promise.resolve(box);
|
|
32
|
+
};
|
|
33
|
+
exports.parseRiffBox = parseRiffBox;
|