mediabunny 1.42.0 → 1.43.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundles/mediabunny.cjs +289 -66
- package/dist/bundles/mediabunny.min.cjs +14 -14
- package/dist/bundles/mediabunny.min.mjs +14 -14
- package/dist/bundles/mediabunny.mjs +289 -66
- package/dist/bundles/mediabunny.node.cjs +289 -66
- package/dist/mediabunny.d.ts +12 -0
- package/dist/modules/src/codec-data.d.ts +2 -0
- package/dist/modules/src/codec-data.d.ts.map +1 -1
- package/dist/modules/src/codec-data.js +103 -0
- package/dist/modules/src/codec.d.ts.map +1 -1
- package/dist/modules/src/codec.js +15 -0
- package/dist/modules/src/conversion.d.ts +7 -0
- package/dist/modules/src/conversion.d.ts.map +1 -1
- package/dist/modules/src/conversion.js +25 -11
- package/dist/modules/src/encode.d.ts +5 -0
- package/dist/modules/src/encode.d.ts.map +1 -1
- package/dist/modules/src/encode.js +5 -1
- package/dist/modules/src/index.d.ts +20 -20
- package/dist/modules/src/index.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-boxes.d.ts +2 -0
- package/dist/modules/src/isobmff/isobmff-boxes.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-boxes.js +36 -4
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-demuxer.js +8 -5
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts +4 -2
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-muxer.js +47 -21
- package/dist/modules/src/matroska/matroska-demuxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-demuxer.js +7 -5
- package/dist/modules/src/media-sink.d.ts.map +1 -1
- package/dist/modules/src/media-sink.js +20 -11
- package/dist/modules/src/media-source.d.ts.map +1 -1
- package/dist/modules/src/media-source.js +14 -1
- package/dist/modules/src/misc.d.ts.map +1 -1
- package/dist/modules/src/misc.js +2 -0
- package/dist/modules/src/mpeg-ts/mpeg-ts-demuxer.d.ts.map +1 -1
- package/dist/modules/src/mpeg-ts/mpeg-ts-demuxer.js +11 -9
- package/dist/modules/src/sample.d.ts +2 -0
- package/dist/modules/src/sample.d.ts.map +1 -1
- package/dist/modules/src/sample.js +27 -0
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/codec-data.ts +112 -0
- package/src/codec.ts +31 -0
- package/src/conversion.ts +45 -11
- package/src/encode.ts +12 -1
- package/src/index.ts +82 -82
- package/src/isobmff/isobmff-boxes.ts +46 -8
- package/src/isobmff/isobmff-demuxer.ts +7 -4
- package/src/isobmff/isobmff-muxer.ts +71 -28
- package/src/matroska/matroska-demuxer.ts +10 -8
- package/src/media-sink.ts +20 -11
- package/src/media-source.ts +26 -1
- package/src/misc.ts +2 -0
- package/src/mpeg-ts/mpeg-ts-demuxer.ts +16 -12
- package/src/sample.ts +30 -0
|
@@ -881,6 +881,8 @@ var Mediabunny = (() => {
|
|
|
881
881
|
return maxIndex;
|
|
882
882
|
};
|
|
883
883
|
var simplifyRational = (rational) => {
|
|
884
|
+
assert(Number.isInteger(rational.num));
|
|
885
|
+
assert(Number.isInteger(rational.den));
|
|
884
886
|
assert(rational.den !== 0);
|
|
885
887
|
let a = Math.abs(rational.num);
|
|
886
888
|
let b = Math.abs(rational.den);
|
|
@@ -2069,6 +2071,21 @@ var Mediabunny = (() => {
|
|
|
2069
2071
|
"Video chunk metadata decoder configuration must specify a valid codedHeight (positive integer)."
|
|
2070
2072
|
);
|
|
2071
2073
|
}
|
|
2074
|
+
if (metadata.decoderConfig.displayAspectWidth !== void 0 && (!Number.isInteger(metadata.decoderConfig.displayAspectWidth) || metadata.decoderConfig.displayAspectWidth <= 0)) {
|
|
2075
|
+
throw new TypeError(
|
|
2076
|
+
"Video chunk metadata decoder configuration displayAspectWidth, when defined, must be a positive integer."
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
if (metadata.decoderConfig.displayAspectHeight !== void 0 && (!Number.isInteger(metadata.decoderConfig.displayAspectHeight) || metadata.decoderConfig.displayAspectHeight <= 0)) {
|
|
2080
|
+
throw new TypeError(
|
|
2081
|
+
"Video chunk metadata decoder configuration displayAspectHeight, when defined, must be a positive integer."
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
if (metadata.decoderConfig.displayAspectWidth !== void 0 !== (metadata.decoderConfig.displayAspectHeight !== void 0)) {
|
|
2085
|
+
throw new TypeError(
|
|
2086
|
+
"Video chunk metadata decoder configuration must specify both displayAspectWidth and displayAspectHeight, or neither."
|
|
2087
|
+
);
|
|
2088
|
+
}
|
|
2072
2089
|
if (metadata.decoderConfig.description !== void 0) {
|
|
2073
2090
|
if (!isAllowSharedBufferSource(metadata.decoderConfig.description)) {
|
|
2074
2091
|
throw new TypeError(
|
|
@@ -3064,6 +3081,16 @@ var Mediabunny = (() => {
|
|
|
3064
3081
|
bitstream.skipBits(5);
|
|
3065
3082
|
bitstream.skipBits(5);
|
|
3066
3083
|
};
|
|
3084
|
+
var concatHevcNalUnits = (nalUnits, decoderConfig) => {
|
|
3085
|
+
if (decoderConfig.description) {
|
|
3086
|
+
const bytes2 = toUint8Array(decoderConfig.description);
|
|
3087
|
+
const lengthSizeMinusOne = bytes2[21] & 3;
|
|
3088
|
+
const lengthSize = lengthSizeMinusOne + 1;
|
|
3089
|
+
return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize);
|
|
3090
|
+
} else {
|
|
3091
|
+
return concatNalUnitsInAnnexB(nalUnits);
|
|
3092
|
+
}
|
|
3093
|
+
};
|
|
3067
3094
|
var iterateHevcNalUnits = (packetData, decoderConfig) => {
|
|
3068
3095
|
if (decoderConfig.description) {
|
|
3069
3096
|
const bytes2 = toUint8Array(decoderConfig.description);
|
|
@@ -3663,6 +3690,70 @@ var Mediabunny = (() => {
|
|
|
3663
3690
|
return null;
|
|
3664
3691
|
}
|
|
3665
3692
|
};
|
|
3693
|
+
var sanitizeHevcPacketForChromium = (packetData, decoderConfig) => {
|
|
3694
|
+
const removedNalUnits = /* @__PURE__ */ new Set();
|
|
3695
|
+
let orderState = 0 /* audAllowed */;
|
|
3696
|
+
for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {
|
|
3697
|
+
if (orderState === 4 /* noMoreDataAllowed */) {
|
|
3698
|
+
removedNalUnits.add(loc.offset);
|
|
3699
|
+
continue;
|
|
3700
|
+
}
|
|
3701
|
+
const type = extractNalUnitTypeForHevc(packetData[loc.offset]);
|
|
3702
|
+
if (orderState === 3 /* eoBitstreamAllowed */ && type !== 37) {
|
|
3703
|
+
removedNalUnits.add(loc.offset);
|
|
3704
|
+
continue;
|
|
3705
|
+
}
|
|
3706
|
+
let remove = false;
|
|
3707
|
+
if (type === 35) {
|
|
3708
|
+
if (orderState > 0 /* audAllowed */) {
|
|
3709
|
+
remove = true;
|
|
3710
|
+
} else {
|
|
3711
|
+
orderState = 1 /* beforeFirstVcl */;
|
|
3712
|
+
}
|
|
3713
|
+
} else if (type <= 31) {
|
|
3714
|
+
if (orderState > 2 /* afterFirstVcl */) {
|
|
3715
|
+
remove = true;
|
|
3716
|
+
} else {
|
|
3717
|
+
orderState = 2 /* afterFirstVcl */;
|
|
3718
|
+
}
|
|
3719
|
+
} else if (type === 36) {
|
|
3720
|
+
if (orderState !== 2 /* afterFirstVcl */) {
|
|
3721
|
+
remove = true;
|
|
3722
|
+
} else {
|
|
3723
|
+
orderState = 3 /* eoBitstreamAllowed */;
|
|
3724
|
+
}
|
|
3725
|
+
} else if (type === 37) {
|
|
3726
|
+
if (orderState < 2 /* afterFirstVcl */) {
|
|
3727
|
+
remove = true;
|
|
3728
|
+
} else {
|
|
3729
|
+
orderState = 4 /* noMoreDataAllowed */;
|
|
3730
|
+
}
|
|
3731
|
+
} else if (type === 32 || type === 33 || type === 34 || type === 39 || type >= 41 && type <= 44 || type >= 48 && type <= 55) {
|
|
3732
|
+
if (orderState > 1 /* beforeFirstVcl */) {
|
|
3733
|
+
remove = true;
|
|
3734
|
+
} else {
|
|
3735
|
+
orderState = 1 /* beforeFirstVcl */;
|
|
3736
|
+
}
|
|
3737
|
+
} else if (type === 38 || type === 40 || type >= 45 && type <= 47 || type >= 56 && type <= 63) {
|
|
3738
|
+
if (orderState < 2 /* afterFirstVcl */) {
|
|
3739
|
+
remove = true;
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
if (remove) {
|
|
3743
|
+
removedNalUnits.add(loc.offset);
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
if (removedNalUnits.size === 0) {
|
|
3747
|
+
return null;
|
|
3748
|
+
}
|
|
3749
|
+
const filteredNalUnits = [];
|
|
3750
|
+
for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {
|
|
3751
|
+
if (!removedNalUnits.has(loc.offset)) {
|
|
3752
|
+
filteredNalUnits.push(packetData.subarray(loc.offset, loc.offset + loc.length));
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
return concatHevcNalUnits(filteredNalUnits, decoderConfig);
|
|
3756
|
+
};
|
|
3666
3757
|
var extractVp9CodecInfoFromPacket = (packet) => {
|
|
3667
3758
|
const bitstream = new Bitstream(packet);
|
|
3668
3759
|
const frameMarker = bitstream.readBits(2);
|
|
@@ -6280,10 +6371,12 @@ var Mediabunny = (() => {
|
|
|
6280
6371
|
assert(track.info?.type === "video");
|
|
6281
6372
|
const num = readU32Be(slice);
|
|
6282
6373
|
const den = readU32Be(slice);
|
|
6283
|
-
if (num > den) {
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6374
|
+
if (num > 0 && den > 0) {
|
|
6375
|
+
if (num > den) {
|
|
6376
|
+
track.info.squarePixelWidth = Math.round(track.info.width * num / den);
|
|
6377
|
+
} else {
|
|
6378
|
+
track.info.squarePixelHeight = Math.round(track.info.height * den / num);
|
|
6379
|
+
}
|
|
6287
6380
|
}
|
|
6288
6381
|
}
|
|
6289
6382
|
;
|
|
@@ -9414,14 +9507,16 @@ var Mediabunny = (() => {
|
|
|
9414
9507
|
if (this.currentTrack.info.displayWidth !== null && this.currentTrack.info.displayHeight !== null) {
|
|
9415
9508
|
const num = this.currentTrack.info.displayWidth * this.currentTrack.info.height;
|
|
9416
9509
|
const den = this.currentTrack.info.displayHeight * this.currentTrack.info.width;
|
|
9417
|
-
if (num > den) {
|
|
9418
|
-
|
|
9419
|
-
this.currentTrack.info.
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
this.currentTrack.info.
|
|
9424
|
-
|
|
9510
|
+
if (num > 0 && den > 0) {
|
|
9511
|
+
if (num > den) {
|
|
9512
|
+
this.currentTrack.info.squarePixelWidth = Math.round(
|
|
9513
|
+
this.currentTrack.info.width * num / den
|
|
9514
|
+
);
|
|
9515
|
+
} else {
|
|
9516
|
+
this.currentTrack.info.squarePixelHeight = Math.round(
|
|
9517
|
+
this.currentTrack.info.height * den / num
|
|
9518
|
+
);
|
|
9519
|
+
}
|
|
9425
9520
|
}
|
|
9426
9521
|
}
|
|
9427
9522
|
if (this.currentTrack.codecId === CODEC_STRING_MAP.avc) {
|
|
@@ -13637,16 +13732,20 @@ var Mediabunny = (() => {
|
|
|
13637
13732
|
const spsInfo = parseAvcSps(spsUnit);
|
|
13638
13733
|
elementaryStream.info.width = spsInfo.displayWidth;
|
|
13639
13734
|
elementaryStream.info.height = spsInfo.displayHeight;
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
)
|
|
13644
|
-
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13735
|
+
const num = spsInfo.pixelAspectRatio.num;
|
|
13736
|
+
const den = spsInfo.pixelAspectRatio.den;
|
|
13737
|
+
if (num > 0 && den > 0) {
|
|
13738
|
+
if (num > den) {
|
|
13739
|
+
elementaryStream.info.squarePixelWidth = Math.round(
|
|
13740
|
+
elementaryStream.info.width * num / den
|
|
13741
|
+
);
|
|
13742
|
+
elementaryStream.info.squarePixelHeight = elementaryStream.info.height;
|
|
13743
|
+
} else {
|
|
13744
|
+
elementaryStream.info.squarePixelWidth = elementaryStream.info.width;
|
|
13745
|
+
elementaryStream.info.squarePixelHeight = Math.round(
|
|
13746
|
+
elementaryStream.info.height * den / num
|
|
13747
|
+
);
|
|
13748
|
+
}
|
|
13650
13749
|
}
|
|
13651
13750
|
elementaryStream.info.colorSpace = {
|
|
13652
13751
|
primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries],
|
|
@@ -20021,6 +20120,20 @@ var Mediabunny = (() => {
|
|
|
20021
20120
|
var isAudioData = (x) => {
|
|
20022
20121
|
return typeof AudioData !== "undefined" && x instanceof AudioData;
|
|
20023
20122
|
};
|
|
20123
|
+
var toInterleavedAudioFormat = (format) => {
|
|
20124
|
+
switch (format) {
|
|
20125
|
+
case "u8-planar":
|
|
20126
|
+
return "u8";
|
|
20127
|
+
case "s16-planar":
|
|
20128
|
+
return "s16";
|
|
20129
|
+
case "s32-planar":
|
|
20130
|
+
return "s32";
|
|
20131
|
+
case "f32-planar":
|
|
20132
|
+
return "f32";
|
|
20133
|
+
default:
|
|
20134
|
+
return format;
|
|
20135
|
+
}
|
|
20136
|
+
};
|
|
20024
20137
|
var doAudioDataCopyToWebKitWorkaround = (audioData, destView, srcFormat, destFormat, numChannels, planeIndex, frameOffset, copyFrameCount) => {
|
|
20025
20138
|
const readFn = getReadFunction(srcFormat);
|
|
20026
20139
|
const writeFn = getWriteFunction(destFormat);
|
|
@@ -20100,6 +20213,19 @@ var Mediabunny = (() => {
|
|
|
20100
20213
|
}
|
|
20101
20214
|
}
|
|
20102
20215
|
};
|
|
20216
|
+
var audioSampleToInterleavedFormat = (sample, format) => {
|
|
20217
|
+
const size = sample.allocationSize({ format, planeIndex: 0 });
|
|
20218
|
+
const buffer = new ArrayBuffer(size);
|
|
20219
|
+
sample.copyTo(buffer, { format, planeIndex: 0 });
|
|
20220
|
+
return new AudioSample({
|
|
20221
|
+
data: buffer,
|
|
20222
|
+
format,
|
|
20223
|
+
numberOfChannels: sample.numberOfChannels,
|
|
20224
|
+
sampleRate: sample.sampleRate,
|
|
20225
|
+
timestamp: sample.timestamp,
|
|
20226
|
+
duration: sample.duration
|
|
20227
|
+
});
|
|
20228
|
+
};
|
|
20103
20229
|
|
|
20104
20230
|
// src/encode.ts
|
|
20105
20231
|
var canEncodeVideoMemo = /* @__PURE__ */ new Map();
|
|
@@ -20233,7 +20359,7 @@ var Mediabunny = (() => {
|
|
|
20233
20359
|
if (!AUDIO_CODECS.includes(config.codec)) {
|
|
20234
20360
|
throw new TypeError(`Invalid audio codec '${config.codec}'. Must be one of: ${AUDIO_CODECS.join(", ")}.`);
|
|
20235
20361
|
}
|
|
20236
|
-
if (config.bitrate === void 0 && (
|
|
20362
|
+
if (config.bitrate === void 0 && !(PCM_AUDIO_CODECS.includes(config.codec) || config.codec === "flac")) {
|
|
20237
20363
|
throw new TypeError("config.bitrate must be provided for compressed audio codecs.");
|
|
20238
20364
|
}
|
|
20239
20365
|
if (config.bitrate !== void 0 && !(config.bitrate instanceof Quality) && (!Number.isInteger(config.bitrate) || config.bitrate <= 0)) {
|
|
@@ -20249,6 +20375,9 @@ var Mediabunny = (() => {
|
|
|
20249
20375
|
if (config.transform.sampleRate !== void 0 && (!Number.isInteger(config.transform.sampleRate) || config.transform.sampleRate <= 0)) {
|
|
20250
20376
|
throw new TypeError("config.transform.sampleRate, when provided, must be a positive integer.");
|
|
20251
20377
|
}
|
|
20378
|
+
if (config.transform.sampleFormat !== void 0 && !["u8", "s16", "s32", "f32"].includes(config.transform.sampleFormat)) {
|
|
20379
|
+
throw new TypeError("config.transform.sampleFormat, when provided, must be one of: u8, s16, s32, f32.");
|
|
20380
|
+
}
|
|
20252
20381
|
if (config.transform.process !== void 0 && typeof config.transform.process !== "function") {
|
|
20253
20382
|
throw new TypeError("config.transform.process, when provided, must be a function.");
|
|
20254
20383
|
}
|
|
@@ -21389,16 +21518,23 @@ var Mediabunny = (() => {
|
|
|
21389
21518
|
if (!isWebKit()) {
|
|
21390
21519
|
insertSorted(this.inputTimestamps, packet.timestamp, (x) => x);
|
|
21391
21520
|
}
|
|
21392
|
-
if (isChromium() && this.currentPacketIndex === 0
|
|
21393
|
-
|
|
21394
|
-
|
|
21395
|
-
const
|
|
21396
|
-
|
|
21397
|
-
|
|
21521
|
+
if (isChromium() && this.currentPacketIndex === 0) {
|
|
21522
|
+
if (this.codec === "avc") {
|
|
21523
|
+
const filteredNalUnits = [];
|
|
21524
|
+
for (const loc of iterateAvcNalUnits(packet.data, this.decoderConfig)) {
|
|
21525
|
+
const type = extractNalUnitTypeForAvc(packet.data[loc.offset]);
|
|
21526
|
+
if (!(type >= 20 && type <= 31)) {
|
|
21527
|
+
filteredNalUnits.push(packet.data.subarray(loc.offset, loc.offset + loc.length));
|
|
21528
|
+
}
|
|
21529
|
+
}
|
|
21530
|
+
const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig);
|
|
21531
|
+
packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration);
|
|
21532
|
+
} else if (this.codec === "hevc") {
|
|
21533
|
+
const sanitizedData = sanitizeHevcPacketForChromium(packet.data, this.decoderConfig);
|
|
21534
|
+
if (sanitizedData) {
|
|
21535
|
+
packet = new EncodedPacket(sanitizedData, packet.type, packet.timestamp, packet.duration);
|
|
21398
21536
|
}
|
|
21399
21537
|
}
|
|
21400
|
-
const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig);
|
|
21401
|
-
packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration);
|
|
21402
21538
|
}
|
|
21403
21539
|
this.decoder.decode(packet.toEncodedVideoChunk());
|
|
21404
21540
|
this.decodeAlphaData(packet);
|
|
@@ -25266,6 +25402,11 @@ var Mediabunny = (() => {
|
|
|
25266
25402
|
view.setUint32(4, value, false);
|
|
25267
25403
|
return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]];
|
|
25268
25404
|
};
|
|
25405
|
+
var i64 = (value) => {
|
|
25406
|
+
view.setInt32(0, Math.floor(value / 2 ** 32), false);
|
|
25407
|
+
view.setUint32(4, value, false);
|
|
25408
|
+
return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]];
|
|
25409
|
+
};
|
|
25269
25410
|
var fixed_8_8 = (value) => {
|
|
25270
25411
|
view.setInt16(0, 2 ** 8 * value, false);
|
|
25271
25412
|
return [bytes[0], bytes[1]];
|
|
@@ -25436,10 +25577,10 @@ var Mediabunny = (() => {
|
|
|
25436
25577
|
udta(muxer)
|
|
25437
25578
|
]);
|
|
25438
25579
|
var mvhd = (creationTime, trackDatas) => {
|
|
25439
|
-
const duration =
|
|
25580
|
+
const duration = Math.max(
|
|
25440
25581
|
0,
|
|
25441
|
-
...trackDatas.map((
|
|
25442
|
-
)
|
|
25582
|
+
...trackDatas.map((trackData) => intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE) + intoTimescale(trackData.startTimestampOffset ?? 0, GLOBAL_TIMESCALE))
|
|
25583
|
+
);
|
|
25443
25584
|
const nextTrackId = Math.max(0, ...trackDatas.map((x) => x.track.id)) + 1;
|
|
25444
25585
|
const needsU64 = !isU32(creationTime) || !isU32(duration);
|
|
25445
25586
|
const u32OrU64 = needsU64 ? u64 : u32;
|
|
@@ -25472,7 +25613,8 @@ var Mediabunny = (() => {
|
|
|
25472
25613
|
}
|
|
25473
25614
|
let minTimestamp = Infinity;
|
|
25474
25615
|
let maxEndTimestamp = -Infinity;
|
|
25475
|
-
for (
|
|
25616
|
+
for (let i = 0; i < trackData.samples.length; i++) {
|
|
25617
|
+
const sample = trackData.samples[i];
|
|
25476
25618
|
if (sample.timestamp < minTimestamp) {
|
|
25477
25619
|
minTimestamp = sample.timestamp;
|
|
25478
25620
|
}
|
|
@@ -25487,8 +25629,10 @@ var Mediabunny = (() => {
|
|
|
25487
25629
|
};
|
|
25488
25630
|
var trak = (trackData, creationTime) => {
|
|
25489
25631
|
const trackMetadata = getTrackMetadata(trackData);
|
|
25632
|
+
const needsEditList = trackData.startTimestampOffset !== null && trackData.startTimestampOffset > 0;
|
|
25490
25633
|
return box("trak", void 0, [
|
|
25491
25634
|
tkhd(trackData, creationTime),
|
|
25635
|
+
needsEditList ? edts(trackData, trackData.startTimestampOffset) : null,
|
|
25492
25636
|
mdia(trackData, creationTime),
|
|
25493
25637
|
trackMetadata.name !== void 0 ? box("udta", void 0, [
|
|
25494
25638
|
box("name", [
|
|
@@ -25499,10 +25643,7 @@ var Mediabunny = (() => {
|
|
|
25499
25643
|
]);
|
|
25500
25644
|
};
|
|
25501
25645
|
var tkhd = (trackData, creationTime) => {
|
|
25502
|
-
const durationInGlobalTimescale = intoTimescale(
|
|
25503
|
-
presentationSpan(trackData),
|
|
25504
|
-
GLOBAL_TIMESCALE
|
|
25505
|
-
);
|
|
25646
|
+
const durationInGlobalTimescale = intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE) + intoTimescale(trackData.startTimestampOffset ?? 0, GLOBAL_TIMESCALE);
|
|
25506
25647
|
const needsU64 = !isU32(creationTime) || !isU32(durationInGlobalTimescale);
|
|
25507
25648
|
const u32OrU64 = needsU64 ? u64 : u32;
|
|
25508
25649
|
let matrix;
|
|
@@ -25545,6 +25686,33 @@ var Mediabunny = (() => {
|
|
|
25545
25686
|
// Track height
|
|
25546
25687
|
]);
|
|
25547
25688
|
};
|
|
25689
|
+
var edts = (trackData, offset) => {
|
|
25690
|
+
const startOffset = intoTimescale(offset, GLOBAL_TIMESCALE);
|
|
25691
|
+
const mediaDuration = intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE);
|
|
25692
|
+
const needs64Bits = !isU32(startOffset) || !isU32(mediaDuration);
|
|
25693
|
+
const u32OrU64 = needs64Bits ? u64 : u32;
|
|
25694
|
+
const i32OrI64 = needs64Bits ? i64 : i32;
|
|
25695
|
+
return box("edts", void 0, [
|
|
25696
|
+
fullBox("elst", needs64Bits ? 1 : 0, 0, [
|
|
25697
|
+
u32(2),
|
|
25698
|
+
// Entry count
|
|
25699
|
+
// #1
|
|
25700
|
+
u32OrU64(startOffset),
|
|
25701
|
+
// Segment duration
|
|
25702
|
+
i32OrI64(-1),
|
|
25703
|
+
// Media time
|
|
25704
|
+
fixed_16_16(1),
|
|
25705
|
+
// Media rate
|
|
25706
|
+
// #2
|
|
25707
|
+
u32OrU64(mediaDuration),
|
|
25708
|
+
// Segment duration
|
|
25709
|
+
i32OrI64(0),
|
|
25710
|
+
// Media time
|
|
25711
|
+
fixed_16_16(1)
|
|
25712
|
+
// Media rate
|
|
25713
|
+
])
|
|
25714
|
+
]);
|
|
25715
|
+
};
|
|
25548
25716
|
var mdia = (trackData, creationTime) => box("mdia", void 0, [
|
|
25549
25717
|
mdhd(trackData, creationTime),
|
|
25550
25718
|
hdlr(true, TRACK_TYPE_TO_COMPONENT_SUBTYPE[trackData.type], TRACK_TYPE_TO_HANDLER_NAME[trackData.type]),
|
|
@@ -27473,7 +27641,7 @@ var Mediabunny = (() => {
|
|
|
27473
27641
|
};
|
|
27474
27642
|
|
|
27475
27643
|
// src/isobmff/isobmff-muxer.ts
|
|
27476
|
-
var GLOBAL_TIMESCALE =
|
|
27644
|
+
var GLOBAL_TIMESCALE = 57600;
|
|
27477
27645
|
var TIMESTAMP_OFFSET = 2082844800;
|
|
27478
27646
|
var getTrackMetadata = (trackData) => {
|
|
27479
27647
|
const metadata = {};
|
|
@@ -27641,7 +27809,10 @@ var Mediabunny = (() => {
|
|
|
27641
27809
|
decoderConfig.description = serializeHevcDecoderConfigurationRecord(decoderConfigurationRecord);
|
|
27642
27810
|
requiresAnnexBTransformation = true;
|
|
27643
27811
|
}
|
|
27644
|
-
const timescale = computeRationalApproximation(
|
|
27812
|
+
const timescale = computeRationalApproximation(
|
|
27813
|
+
1 / (track.metadata.frameRate ?? GLOBAL_TIMESCALE),
|
|
27814
|
+
1e6
|
|
27815
|
+
).denominator;
|
|
27645
27816
|
const displayAspectWidth = decoderConfig.displayAspectWidth;
|
|
27646
27817
|
const displayAspectHeight = decoderConfig.displayAspectHeight;
|
|
27647
27818
|
const pixelAspectRatio = displayAspectWidth === void 0 || displayAspectHeight === void 0 ? { num: 1, den: 1 } : simplifyRational({
|
|
@@ -27667,6 +27838,7 @@ var Mediabunny = (() => {
|
|
|
27667
27838
|
compositionTimeOffsetTable: [],
|
|
27668
27839
|
lastTimescaleUnits: null,
|
|
27669
27840
|
lastSample: null,
|
|
27841
|
+
startTimestampOffset: null,
|
|
27670
27842
|
finalizedChunks: [],
|
|
27671
27843
|
currentChunk: null,
|
|
27672
27844
|
compactlyCodedChunkTable: [],
|
|
@@ -27717,6 +27889,7 @@ var Mediabunny = (() => {
|
|
|
27717
27889
|
sampleRate: meta.decoderConfig.sampleRate,
|
|
27718
27890
|
decoderConfig,
|
|
27719
27891
|
requiresPcmTransformation: !this.isFragmented && PCM_AUDIO_CODECS.includes(track.source._codec),
|
|
27892
|
+
expectedNextPcmPacketTimestamp: null,
|
|
27720
27893
|
requiresAdtsStripping,
|
|
27721
27894
|
firstPacket: packet
|
|
27722
27895
|
},
|
|
@@ -27728,6 +27901,7 @@ var Mediabunny = (() => {
|
|
|
27728
27901
|
compositionTimeOffsetTable: [],
|
|
27729
27902
|
lastTimescaleUnits: null,
|
|
27730
27903
|
lastSample: null,
|
|
27904
|
+
startTimestampOffset: null,
|
|
27731
27905
|
finalizedChunks: [],
|
|
27732
27906
|
currentChunk: null,
|
|
27733
27907
|
compactlyCodedChunkTable: [],
|
|
@@ -27764,6 +27938,7 @@ var Mediabunny = (() => {
|
|
|
27764
27938
|
compositionTimeOffsetTable: [],
|
|
27765
27939
|
lastTimescaleUnits: null,
|
|
27766
27940
|
lastSample: null,
|
|
27941
|
+
startTimestampOffset: null,
|
|
27767
27942
|
finalizedChunks: [],
|
|
27768
27943
|
currentChunk: null,
|
|
27769
27944
|
compactlyCodedChunkTable: [],
|
|
@@ -27824,31 +27999,48 @@ var Mediabunny = (() => {
|
|
|
27824
27999
|
const headerLength = adtsFrame.crcCheck === null ? MIN_ADTS_FRAME_HEADER_SIZE : MAX_ADTS_FRAME_HEADER_SIZE;
|
|
27825
28000
|
packetData = packetData.subarray(headerLength);
|
|
27826
28001
|
}
|
|
27827
|
-
|
|
28002
|
+
let timestamp = this.validateAndNormalizeTimestamp(
|
|
27828
28003
|
trackData.track,
|
|
27829
28004
|
packet.timestamp,
|
|
27830
28005
|
packet.type === "key"
|
|
27831
28006
|
);
|
|
28007
|
+
let duration = packet.duration;
|
|
28008
|
+
if (trackData.info.requiresPcmTransformation) {
|
|
28009
|
+
const pcmInfo = parsePcmCodec(
|
|
28010
|
+
trackData.info.decoderConfig.codec
|
|
28011
|
+
);
|
|
28012
|
+
const frameSize = pcmInfo.sampleSize * trackData.info.numberOfChannels;
|
|
28013
|
+
duration = packetData.byteLength / frameSize / trackData.info.sampleRate;
|
|
28014
|
+
if (trackData.info.expectedNextPcmPacketTimestamp !== null) {
|
|
28015
|
+
const diff = timestamp - trackData.info.expectedNextPcmPacketTimestamp;
|
|
28016
|
+
if (diff < 0.01) {
|
|
28017
|
+
timestamp = trackData.info.expectedNextPcmPacketTimestamp;
|
|
28018
|
+
} else {
|
|
28019
|
+
const paddedDuration = await this.padWithSilence(
|
|
28020
|
+
trackData,
|
|
28021
|
+
trackData.info.expectedNextPcmPacketTimestamp,
|
|
28022
|
+
diff
|
|
28023
|
+
);
|
|
28024
|
+
timestamp = trackData.info.expectedNextPcmPacketTimestamp + paddedDuration;
|
|
28025
|
+
}
|
|
28026
|
+
}
|
|
28027
|
+
trackData.info.expectedNextPcmPacketTimestamp = timestamp + duration;
|
|
28028
|
+
}
|
|
27832
28029
|
const internalSample = this.createSampleForTrack(
|
|
27833
28030
|
trackData,
|
|
27834
28031
|
packetData,
|
|
27835
28032
|
timestamp,
|
|
27836
|
-
|
|
28033
|
+
duration,
|
|
27837
28034
|
packet.type
|
|
27838
28035
|
);
|
|
27839
|
-
if (trackData.info.requiresPcmTransformation) {
|
|
27840
|
-
await this.maybePadWithSilence(trackData, timestamp);
|
|
27841
|
-
}
|
|
27842
28036
|
await this.registerSample(trackData, internalSample);
|
|
27843
28037
|
} finally {
|
|
27844
28038
|
release();
|
|
27845
28039
|
}
|
|
27846
28040
|
}
|
|
27847
|
-
async
|
|
27848
|
-
const
|
|
27849
|
-
|
|
27850
|
-
const delta = untilTimestamp - lastEndTimestamp;
|
|
27851
|
-
const deltaInTimescale = intoTimescale(delta, trackData.timescale);
|
|
28041
|
+
async padWithSilence(trackData, timestamp, duration) {
|
|
28042
|
+
const deltaInTimescale = intoTimescale(duration, trackData.timescale);
|
|
28043
|
+
duration = deltaInTimescale / trackData.timescale;
|
|
27852
28044
|
if (deltaInTimescale > 0) {
|
|
27853
28045
|
const { sampleSize, silentValue } = parsePcmCodec(
|
|
27854
28046
|
trackData.info.decoderConfig.codec
|
|
@@ -27858,12 +28050,13 @@ var Mediabunny = (() => {
|
|
|
27858
28050
|
const paddingSample = this.createSampleForTrack(
|
|
27859
28051
|
trackData,
|
|
27860
28052
|
new Uint8Array(data.buffer),
|
|
27861
|
-
|
|
27862
|
-
|
|
28053
|
+
timestamp,
|
|
28054
|
+
duration,
|
|
27863
28055
|
"key"
|
|
27864
28056
|
);
|
|
27865
28057
|
await this.registerSample(trackData, paddingSample);
|
|
27866
28058
|
}
|
|
28059
|
+
return duration;
|
|
27867
28060
|
}
|
|
27868
28061
|
async addSubtitleCue(track, cue, meta) {
|
|
27869
28062
|
const release = await this.mutex.acquire();
|
|
@@ -27964,6 +28157,9 @@ var Mediabunny = (() => {
|
|
|
27964
28157
|
return;
|
|
27965
28158
|
}
|
|
27966
28159
|
if (trackData.type === "audio" && trackData.info.requiresPcmTransformation) {
|
|
28160
|
+
if (!this.isFragmented) {
|
|
28161
|
+
trackData.startTimestampOffset ??= trackData.timestampProcessingQueue[0].timestamp;
|
|
28162
|
+
}
|
|
27967
28163
|
let totalDuration = 0;
|
|
27968
28164
|
for (let i = 0; i < trackData.timestampProcessingQueue.length; i++) {
|
|
27969
28165
|
const sample = trackData.timestampProcessingQueue[i];
|
|
@@ -27983,12 +28179,12 @@ var Mediabunny = (() => {
|
|
|
27983
28179
|
return;
|
|
27984
28180
|
}
|
|
27985
28181
|
const sortedTimestamps = trackData.timestampProcessingQueue.map((x) => x.timestamp).sort((a, b) => a - b);
|
|
28182
|
+
if (!this.isFragmented) {
|
|
28183
|
+
trackData.startTimestampOffset ??= sortedTimestamps[0];
|
|
28184
|
+
}
|
|
27986
28185
|
for (let i = 0; i < trackData.timestampProcessingQueue.length; i++) {
|
|
27987
28186
|
const sample = trackData.timestampProcessingQueue[i];
|
|
27988
28187
|
sample.decodeTimestamp = sortedTimestamps[i];
|
|
27989
|
-
if (!this.isFragmented && trackData.lastTimescaleUnits === null) {
|
|
27990
|
-
sample.decodeTimestamp = 0;
|
|
27991
|
-
}
|
|
27992
28188
|
const sampleCompositionTimeOffset = intoTimescale(sample.timestamp - sample.decodeTimestamp, trackData.timescale);
|
|
27993
28189
|
const durationInTimescale = intoTimescale(sample.duration, trackData.timescale);
|
|
27994
28190
|
if (trackData.lastTimescaleUnits !== null) {
|
|
@@ -28352,6 +28548,12 @@ var Mediabunny = (() => {
|
|
|
28352
28548
|
} else {
|
|
28353
28549
|
for (const trackData of this.trackDatas) {
|
|
28354
28550
|
await this.finalizeCurrentChunk(trackData);
|
|
28551
|
+
assert(trackData.startTimestampOffset !== null);
|
|
28552
|
+
for (let i = 0; i < trackData.samples.length; i++) {
|
|
28553
|
+
const sample = trackData.samples[i];
|
|
28554
|
+
sample.timestamp -= trackData.startTimestampOffset;
|
|
28555
|
+
sample.decodeTimestamp -= trackData.startTimestampOffset;
|
|
28556
|
+
}
|
|
28355
28557
|
}
|
|
28356
28558
|
}
|
|
28357
28559
|
assert(this.writer);
|
|
@@ -32320,6 +32522,14 @@ ${cue.notes ?? ""}`;
|
|
|
32320
32522
|
*/
|
|
32321
32523
|
async processAndEncode(audioSample, shouldClose) {
|
|
32322
32524
|
const config = this.encodingConfig;
|
|
32525
|
+
if (config.transform?.sampleFormat !== void 0 && toInterleavedAudioFormat(audioSample.format) !== config.transform.sampleFormat) {
|
|
32526
|
+
const newSample = audioSampleToInterleavedFormat(audioSample, config.transform.sampleFormat);
|
|
32527
|
+
if (shouldClose) {
|
|
32528
|
+
audioSample.close();
|
|
32529
|
+
}
|
|
32530
|
+
audioSample = newSample;
|
|
32531
|
+
shouldClose = true;
|
|
32532
|
+
}
|
|
32323
32533
|
if (config.transform?.process) {
|
|
32324
32534
|
let processed = config.transform.process(audioSample);
|
|
32325
32535
|
if (processed instanceof Promise) {
|
|
@@ -32339,6 +32549,9 @@ ${cue.notes ?? ""}`;
|
|
|
32339
32549
|
}
|
|
32340
32550
|
await this.encodeSample(sample, true);
|
|
32341
32551
|
}
|
|
32552
|
+
if (shouldClose) {
|
|
32553
|
+
audioSample.close();
|
|
32554
|
+
}
|
|
32342
32555
|
} else {
|
|
32343
32556
|
await this.encodeSample(audioSample, shouldClose);
|
|
32344
32557
|
}
|
|
@@ -35418,6 +35631,9 @@ ${cue.notes ?? ""}`;
|
|
|
35418
35631
|
if (audioOptions?.sampleRate !== void 0 && (!Number.isInteger(audioOptions.sampleRate) || audioOptions.sampleRate <= 0)) {
|
|
35419
35632
|
throw new TypeError("options.audio.sampleRate, when provided, must be a positive integer.");
|
|
35420
35633
|
}
|
|
35634
|
+
if (audioOptions?.sampleFormat !== void 0 && !["u8", "s16", "s32", "f32"].includes(audioOptions.sampleFormat)) {
|
|
35635
|
+
throw new TypeError("options.audio.sampleFormat, when provided, must be one of: u8, s16, s32, f32.");
|
|
35636
|
+
}
|
|
35421
35637
|
if (audioOptions?.process !== void 0 && typeof audioOptions.process !== "function") {
|
|
35422
35638
|
throw new TypeError("options.audio.process, when provided, must be a function.");
|
|
35423
35639
|
}
|
|
@@ -36036,7 +36252,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36036
36252
|
timestamp: lastCanvasTimestamp + i / frameRate,
|
|
36037
36253
|
duration: 1 / frameRate
|
|
36038
36254
|
});
|
|
36039
|
-
await this._registerVideoSample(
|
|
36255
|
+
await this._registerVideoSample(trackOptions, outputTrackId, source, sample);
|
|
36040
36256
|
sample.close();
|
|
36041
36257
|
}
|
|
36042
36258
|
};
|
|
@@ -36063,7 +36279,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36063
36279
|
timestamp: adjustedSampleTimestamp,
|
|
36064
36280
|
duration: frameRate !== void 0 ? 1 / frameRate : duration
|
|
36065
36281
|
});
|
|
36066
|
-
await this._registerVideoSample(
|
|
36282
|
+
await this._registerVideoSample(trackOptions, outputTrackId, source, sample);
|
|
36067
36283
|
sample.close();
|
|
36068
36284
|
if (frameRate !== void 0) {
|
|
36069
36285
|
lastCanvas = canvas;
|
|
@@ -36093,7 +36309,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36093
36309
|
for (let i = 1; i < frameDifference; i++) {
|
|
36094
36310
|
lastSample.setTimestamp(lastSampleTimestamp + i / frameRate);
|
|
36095
36311
|
lastSample.setDuration(1 / frameRate);
|
|
36096
|
-
await this._registerVideoSample(
|
|
36312
|
+
await this._registerVideoSample(trackOptions, outputTrackId, source, lastSample);
|
|
36097
36313
|
}
|
|
36098
36314
|
lastSample.close();
|
|
36099
36315
|
};
|
|
@@ -36121,7 +36337,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36121
36337
|
sample.setDuration(1 / frameRate);
|
|
36122
36338
|
}
|
|
36123
36339
|
sample.setTimestamp(adjustedSampleTimestamp);
|
|
36124
|
-
await this._registerVideoSample(
|
|
36340
|
+
await this._registerVideoSample(trackOptions, outputTrackId, source, sample);
|
|
36125
36341
|
if (frameRate !== void 0) {
|
|
36126
36342
|
lastSample = sample;
|
|
36127
36343
|
lastSampleTimestamp = adjustedSampleTimestamp;
|
|
@@ -36160,7 +36376,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36160
36376
|
this._outputOwnTrackGroups.push(ownGroup);
|
|
36161
36377
|
}
|
|
36162
36378
|
/** @internal */
|
|
36163
|
-
async _registerVideoSample(
|
|
36379
|
+
async _registerVideoSample(trackOptions, outputTrackId, source, sample) {
|
|
36164
36380
|
if (this._canceled) {
|
|
36165
36381
|
return;
|
|
36166
36382
|
}
|
|
@@ -36224,7 +36440,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36224
36440
|
let sampleRate = trackOptions.sampleRate ?? originalSampleRate;
|
|
36225
36441
|
let needsResample = numberOfChannels !== originalNumberOfChannels || sampleRate !== originalSampleRate || firstTimestamp < this._startTimestamp || firstTimestamp > this._startTimestamp && !this.output.format.supportsTimestampedMediaData;
|
|
36226
36442
|
let audioCodecs = this.output.format.getSupportedAudioCodecs();
|
|
36227
|
-
if (!trackOptions.forceTranscode && !trackOptions.bitrate && !needsResample && audioCodecs.includes(sourceCodec) && (!trackOptions.codec || trackOptions.codec === sourceCodec) && !trackOptions.process) {
|
|
36443
|
+
if (!trackOptions.forceTranscode && !trackOptions.bitrate && !needsResample && audioCodecs.includes(sourceCodec) && (!trackOptions.codec || trackOptions.codec === sourceCodec) && !trackOptions.process && trackOptions.sampleFormat === void 0) {
|
|
36228
36444
|
const source = new EncodedAudioPacketSource(sourceCodec);
|
|
36229
36445
|
audioSource = source;
|
|
36230
36446
|
this._trackPromises.push((async () => {
|
|
@@ -36321,7 +36537,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36321
36537
|
return;
|
|
36322
36538
|
}
|
|
36323
36539
|
sample.setTimestamp(sample.timestamp - this._startTimestamp);
|
|
36324
|
-
await this._registerAudioSample(
|
|
36540
|
+
await this._registerAudioSample(trackOptions, outputTrackId, source, sample);
|
|
36325
36541
|
sample.close();
|
|
36326
36542
|
}
|
|
36327
36543
|
source.close();
|
|
@@ -36348,10 +36564,14 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36348
36564
|
this._outputOwnTrackGroups.push(ownGroup);
|
|
36349
36565
|
}
|
|
36350
36566
|
/** @internal */
|
|
36351
|
-
async _registerAudioSample(
|
|
36567
|
+
async _registerAudioSample(trackOptions, outputTrackId, source, inputSample) {
|
|
36352
36568
|
if (this._canceled) {
|
|
36353
36569
|
return;
|
|
36354
36570
|
}
|
|
36571
|
+
let sample = inputSample;
|
|
36572
|
+
if (trackOptions.sampleFormat !== void 0 && toInterleavedAudioFormat(sample.format) !== trackOptions.sampleFormat) {
|
|
36573
|
+
sample = audioSampleToInterleavedFormat(sample, trackOptions.sampleFormat);
|
|
36574
|
+
}
|
|
36355
36575
|
this._reportProgress(outputTrackId, sample.timestamp + sample.duration);
|
|
36356
36576
|
let finalSamples;
|
|
36357
36577
|
if (!trackOptions.process) {
|
|
@@ -36380,8 +36600,11 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36380
36600
|
}
|
|
36381
36601
|
}
|
|
36382
36602
|
} finally {
|
|
36603
|
+
if (sample !== inputSample) {
|
|
36604
|
+
sample.close();
|
|
36605
|
+
}
|
|
36383
36606
|
for (const finalSample of finalSamples) {
|
|
36384
|
-
if (finalSample !==
|
|
36607
|
+
if (finalSample !== inputSample) {
|
|
36385
36608
|
finalSample.close();
|
|
36386
36609
|
}
|
|
36387
36610
|
}
|
|
@@ -36402,7 +36625,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
36402
36625
|
endTime: this._endTimestamp,
|
|
36403
36626
|
onSample: async (sample) => {
|
|
36404
36627
|
sample.setTimestamp(sample.timestamp - this._startTimestamp);
|
|
36405
|
-
await this._registerAudioSample(
|
|
36628
|
+
await this._registerAudioSample(trackOptions, outputTrackId, source, sample);
|
|
36406
36629
|
sample.close();
|
|
36407
36630
|
}
|
|
36408
36631
|
});
|