mediabunny 1.49.0 → 1.50.0
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 +352 -590
- package/dist/bundles/mediabunny.min.cjs +13 -99
- package/dist/bundles/mediabunny.min.mjs +13 -99
- package/dist/bundles/mediabunny.mjs +352 -590
- package/dist/bundles/mediabunny.node.cjs +352 -590
- package/dist/mediabunny.d.ts +12 -3
- package/dist/modules/src/codec-data.d.ts.map +1 -1
- package/dist/modules/src/codec-data.js +5 -0
- package/dist/modules/src/codec.d.ts +5 -2
- package/dist/modules/src/codec.d.ts.map +1 -1
- package/dist/modules/src/codec.js +57 -6
- package/dist/modules/src/conversion.d.ts.map +1 -1
- package/dist/modules/src/conversion.js +23 -14
- package/dist/modules/src/custom-coder.d.ts +8 -0
- package/dist/modules/src/custom-coder.d.ts.map +1 -1
- package/dist/modules/src/decode.js +1 -1
- package/dist/modules/src/encode.d.ts +3 -2
- package/dist/modules/src/encode.d.ts.map +1 -1
- package/dist/modules/src/encode.js +6 -5
- package/dist/modules/src/isobmff/isobmff-boxes.js +3 -1
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts +2 -1
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-demuxer.js +8 -2
- package/dist/modules/src/matroska/ebml.d.ts.map +1 -1
- package/dist/modules/src/matroska/ebml.js +1 -0
- package/dist/modules/src/matroska/matroska-demuxer.d.ts +2 -1
- package/dist/modules/src/matroska/matroska-demuxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-demuxer.js +19 -3
- package/dist/modules/src/matroska/matroska-muxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-muxer.js +14 -23
- package/dist/modules/src/media-sink.d.ts +4 -17
- package/dist/modules/src/media-sink.d.ts.map +1 -1
- package/dist/modules/src/media-sink.js +149 -246
- package/dist/modules/src/media-source.d.ts +2 -21
- package/dist/modules/src/media-source.d.ts.map +1 -1
- package/dist/modules/src/media-source.js +66 -287
- package/dist/modules/src/mpeg-ts/mpeg-ts-demuxer.d.ts.map +1 -1
- package/dist/modules/src/mpeg-ts/mpeg-ts-demuxer.js +1 -0
- package/dist/modules/src/sample.d.ts +1 -0
- package/dist/modules/src/sample.d.ts.map +1 -1
- package/dist/modules/src/sample.js +17 -8
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/codec-data.ts +4 -0
- package/src/codec.ts +76 -5
- package/src/conversion.ts +27 -15
- package/src/custom-coder.ts +8 -0
- package/src/decode.ts +1 -1
- package/src/encode.ts +10 -8
- package/src/isobmff/isobmff-boxes.ts +7 -2
- package/src/isobmff/isobmff-demuxer.ts +11 -1
- package/src/matroska/ebml.ts +1 -0
- package/src/matroska/matroska-demuxer.ts +24 -1
- package/src/matroska/matroska-muxer.ts +18 -27
- package/src/media-sink.ts +171 -307
- package/src/media-source.ts +79 -351
- package/src/mpeg-ts/mpeg-ts-demuxer.ts +1 -0
- package/src/sample.ts +21 -10
|
@@ -1498,7 +1498,8 @@ var Mediabunny = (() => {
|
|
|
1498
1498
|
"hevc",
|
|
1499
1499
|
"vp9",
|
|
1500
1500
|
"av1",
|
|
1501
|
-
"vp8"
|
|
1501
|
+
"vp8",
|
|
1502
|
+
"prores"
|
|
1502
1503
|
];
|
|
1503
1504
|
var PCM_AUDIO_CODECS = [
|
|
1504
1505
|
"pcm-s16",
|
|
@@ -1699,7 +1700,35 @@ var Mediabunny = (() => {
|
|
|
1699
1700
|
];
|
|
1700
1701
|
var VP9_DEFAULT_SUFFIX = ".01.01.01.01.00";
|
|
1701
1702
|
var AV1_DEFAULT_SUFFIX = ".0.110.01.01.01.0";
|
|
1702
|
-
var
|
|
1703
|
+
var PRORES_FOURCCS = [
|
|
1704
|
+
"ap4x",
|
|
1705
|
+
// ProRes 4444 XQ
|
|
1706
|
+
"ap4h",
|
|
1707
|
+
// ProRes 4444
|
|
1708
|
+
"apch",
|
|
1709
|
+
// ProRes 422 High Quality
|
|
1710
|
+
"apcn",
|
|
1711
|
+
// ProRes 422 Standard Definition
|
|
1712
|
+
"apcs",
|
|
1713
|
+
// ProRes 422 LT
|
|
1714
|
+
"apco"
|
|
1715
|
+
// ProRes 422 Proxy
|
|
1716
|
+
];
|
|
1717
|
+
var PRORES_PROFILE_TARGET_BITRATES = [
|
|
1718
|
+
{ fourCc: "apco", bitrate: 45e6, alpha: false },
|
|
1719
|
+
// 422 Proxy
|
|
1720
|
+
{ fourCc: "apcs", bitrate: 102e6, alpha: false },
|
|
1721
|
+
// 422 LT
|
|
1722
|
+
{ fourCc: "apcn", bitrate: 147e6, alpha: false },
|
|
1723
|
+
// 422 Standard
|
|
1724
|
+
{ fourCc: "apch", bitrate: 22e7, alpha: false },
|
|
1725
|
+
// 422 HQ
|
|
1726
|
+
{ fourCc: "ap4h", bitrate: 33e7, alpha: true },
|
|
1727
|
+
// 4444
|
|
1728
|
+
{ fourCc: "ap4x", bitrate: 5e8, alpha: true }
|
|
1729
|
+
// 4444 XQ
|
|
1730
|
+
];
|
|
1731
|
+
var buildVideoCodecString = (codec, width, height, bitrate, alpha) => {
|
|
1703
1732
|
if (codec === "avc") {
|
|
1704
1733
|
const profileIndication = 100;
|
|
1705
1734
|
const totalMacroblocks = Math.ceil(width / 16) * Math.ceil(height / 16);
|
|
@@ -1740,8 +1769,24 @@ var Mediabunny = (() => {
|
|
|
1740
1769
|
const level = levelInfo.level.toString().padStart(2, "0");
|
|
1741
1770
|
const bitDepth = "08";
|
|
1742
1771
|
return `av01.${profile}.${level}${levelInfo.tier}.${bitDepth}`;
|
|
1772
|
+
} else if (codec === "prores") {
|
|
1773
|
+
const referencePixels = 1920 * 1080;
|
|
1774
|
+
const scaleFactor = Math.pow(width * height / referencePixels, 0.95);
|
|
1775
|
+
const candidates = PRORES_PROFILE_TARGET_BITRATES.filter((x) => x.alpha === alpha);
|
|
1776
|
+
let bestFourCc = candidates[0].fourCc;
|
|
1777
|
+
let smallestDifference = Infinity;
|
|
1778
|
+
for (const { fourCc, bitrate: targetBitrate } of candidates) {
|
|
1779
|
+
const difference = Math.abs(targetBitrate * scaleFactor - bitrate);
|
|
1780
|
+
if (difference < smallestDifference) {
|
|
1781
|
+
smallestDifference = difference;
|
|
1782
|
+
bestFourCc = fourCc;
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
return bestFourCc;
|
|
1786
|
+
} else {
|
|
1787
|
+
assertNever(codec);
|
|
1743
1788
|
}
|
|
1744
|
-
throw new TypeError(`Unhandled codec '${codec}'.`);
|
|
1789
|
+
throw new TypeError(`Unhandled codec '${String(codec)}'.`);
|
|
1745
1790
|
};
|
|
1746
1791
|
var generateVp9CodecConfigurationFromCodecString = (codecString) => {
|
|
1747
1792
|
const parts = codecString.split(".");
|
|
@@ -1787,7 +1832,16 @@ var Mediabunny = (() => {
|
|
|
1787
1832
|
return [firstByte, secondByte, thirdByte, fourthByte];
|
|
1788
1833
|
};
|
|
1789
1834
|
var extractVideoCodecString = (trackInfo) => {
|
|
1790
|
-
const {
|
|
1835
|
+
const {
|
|
1836
|
+
codec,
|
|
1837
|
+
codecDescription,
|
|
1838
|
+
colorSpace,
|
|
1839
|
+
avcCodecInfo,
|
|
1840
|
+
hevcCodecInfo,
|
|
1841
|
+
vp9CodecInfo,
|
|
1842
|
+
av1CodecInfo,
|
|
1843
|
+
proresFormat
|
|
1844
|
+
} = trackInfo;
|
|
1791
1845
|
if (codec === "avc") {
|
|
1792
1846
|
assert(trackInfo.avcType !== null);
|
|
1793
1847
|
if (avcCodecInfo) {
|
|
@@ -1907,6 +1961,10 @@ var Mediabunny = (() => {
|
|
|
1907
1961
|
string = string.slice(0, -AV1_DEFAULT_SUFFIX.length);
|
|
1908
1962
|
}
|
|
1909
1963
|
return string;
|
|
1964
|
+
} else if (codec === "prores") {
|
|
1965
|
+
return proresFormat ?? "apch";
|
|
1966
|
+
} else if (codec !== null) {
|
|
1967
|
+
assertNever(codec);
|
|
1910
1968
|
}
|
|
1911
1969
|
throw new TypeError(`Unhandled codec '${codec}'.`);
|
|
1912
1970
|
};
|
|
@@ -2036,6 +2094,8 @@ var Mediabunny = (() => {
|
|
|
2036
2094
|
return "vp9";
|
|
2037
2095
|
} else if (codecString.startsWith("av01")) {
|
|
2038
2096
|
return "av1";
|
|
2097
|
+
} else if (PRORES_FOURCCS.includes(codecString)) {
|
|
2098
|
+
return "prores";
|
|
2039
2099
|
}
|
|
2040
2100
|
if (codecString === "mp3" || codecString === "mp4a.69" || codecString === "mp4a.6B" || codecString === "mp4a.6b" || codecString === "mp4a.40.34") {
|
|
2041
2101
|
return "mp3";
|
|
@@ -2098,7 +2158,7 @@ var Mediabunny = (() => {
|
|
|
2098
2158
|
}
|
|
2099
2159
|
return {};
|
|
2100
2160
|
};
|
|
2101
|
-
var VALID_VIDEO_CODEC_STRING_PREFIXES = ["avc1", "avc3", "hev1", "hvc1", "vp8", "vp09", "av01"];
|
|
2161
|
+
var VALID_VIDEO_CODEC_STRING_PREFIXES = ["avc1", "avc3", "hev1", "hvc1", "vp8", "vp09", "av01", ...PRORES_FOURCCS];
|
|
2102
2162
|
var AVC_CODEC_STRING_REGEX = /^(avc1|avc3)\.[0-9a-fA-F]{6}$/;
|
|
2103
2163
|
var HEVC_CODEC_STRING_REGEX = /^(hev1|hvc1)\.(?:[ABC]?\d+)\.[0-9a-fA-F]{1,8}\.[LH]\d+(?:\.[0-9a-fA-F]{1,2}){0,6}$/;
|
|
2104
2164
|
var VP9_CODEC_STRING_REGEX = /^vp09(?:\.\d{2}){3}(?:(?:\.\d{2}){5})?$/;
|
|
@@ -2215,6 +2275,12 @@ var Mediabunny = (() => {
|
|
|
2215
2275
|
'Video chunk metadata decoder configuration codec string for AV1 must be a valid AV1 codec string as specified in Section "Codecs Parameter String" of https://aomediacodec.github.io/av1-isobmff/.'
|
|
2216
2276
|
);
|
|
2217
2277
|
}
|
|
2278
|
+
} else if (PRORES_FOURCCS.some((x) => metadata.decoderConfig.codec.startsWith(x))) {
|
|
2279
|
+
if (!PRORES_FOURCCS.some((x) => metadata.decoderConfig.codec === x)) {
|
|
2280
|
+
throw new TypeError(
|
|
2281
|
+
`Video chunk metadata decoder configuration codec string for ProRes must be one of the valid ProRes four-character codes: ${PRORES_FOURCCS.join(", ")}.`
|
|
2282
|
+
);
|
|
2283
|
+
}
|
|
2218
2284
|
}
|
|
2219
2285
|
};
|
|
2220
2286
|
var VALID_AUDIO_CODEC_STRING_PREFIXES = [
|
|
@@ -4338,6 +4404,11 @@ var Mediabunny = (() => {
|
|
|
4338
4404
|
return null;
|
|
4339
4405
|
}
|
|
4340
4406
|
;
|
|
4407
|
+
case "prores":
|
|
4408
|
+
{
|
|
4409
|
+
return "key";
|
|
4410
|
+
}
|
|
4411
|
+
;
|
|
4341
4412
|
default:
|
|
4342
4413
|
{
|
|
4343
4414
|
assertNever(codec);
|
|
@@ -6009,7 +6080,8 @@ var Mediabunny = (() => {
|
|
|
6009
6080
|
avcCodecInfo: null,
|
|
6010
6081
|
hevcCodecInfo: null,
|
|
6011
6082
|
vp9CodecInfo: null,
|
|
6012
|
-
av1CodecInfo: null
|
|
6083
|
+
av1CodecInfo: null,
|
|
6084
|
+
proresFormat: null
|
|
6013
6085
|
};
|
|
6014
6086
|
} else if (handlerType === "soun") {
|
|
6015
6087
|
track.info = {
|
|
@@ -6084,6 +6156,9 @@ var Mediabunny = (() => {
|
|
|
6084
6156
|
track.info.codec = "vp9";
|
|
6085
6157
|
} else if (codecName === "av01") {
|
|
6086
6158
|
track.info.codec = "av1";
|
|
6159
|
+
} else if (PRORES_FOURCCS.includes(lowercaseBoxName)) {
|
|
6160
|
+
track.info.codec = "prores";
|
|
6161
|
+
track.info.proresFormat = lowercaseBoxName;
|
|
6087
6162
|
} else if (codecName === null) {
|
|
6088
6163
|
Logging._warn(`Unknown encrypted video codec due to missing frma box.`);
|
|
6089
6164
|
} else {
|
|
@@ -8046,7 +8121,7 @@ var Mediabunny = (() => {
|
|
|
8046
8121
|
};
|
|
8047
8122
|
}
|
|
8048
8123
|
async canBeTransparent() {
|
|
8049
|
-
return
|
|
8124
|
+
return this.internalTrack.info.codec === "prores" && (this.internalTrack.info.proresFormat === "ap4h" || this.internalTrack.info.proresFormat === "ap4x");
|
|
8050
8125
|
}
|
|
8051
8126
|
async getDecoderConfig() {
|
|
8052
8127
|
if (!this.internalTrack.info.codec) {
|
|
@@ -8941,6 +9016,7 @@ var Mediabunny = (() => {
|
|
|
8941
9016
|
"vp8": "V_VP8",
|
|
8942
9017
|
"vp9": "V_VP9",
|
|
8943
9018
|
"av1": "V_AV1",
|
|
9019
|
+
"prores": "V_PRORES",
|
|
8944
9020
|
"aac": "A_AAC",
|
|
8945
9021
|
"mp3": "A_MPEG/L3",
|
|
8946
9022
|
"opus": "A_OPUS",
|
|
@@ -9604,6 +9680,13 @@ var Mediabunny = (() => {
|
|
|
9604
9680
|
this.currentTrack.info.codec = "vp9";
|
|
9605
9681
|
} else if (codecIdWithoutSuffix === CODEC_STRING_MAP.av1) {
|
|
9606
9682
|
this.currentTrack.info.codec = "av1";
|
|
9683
|
+
} else if (codecIdWithoutSuffix === CODEC_STRING_MAP.prores) {
|
|
9684
|
+
const format = this.currentTrack.codecPrivate ? textDecoder.decode(this.currentTrack.codecPrivate) : "";
|
|
9685
|
+
if (PRORES_FOURCCS.includes(format)) {
|
|
9686
|
+
this.currentTrack.info.codec = "prores";
|
|
9687
|
+
this.currentTrack.info.proresFormat = format;
|
|
9688
|
+
} else {
|
|
9689
|
+
}
|
|
9607
9690
|
}
|
|
9608
9691
|
const videoTrack = this.currentTrack;
|
|
9609
9692
|
this.currentTrack.trackBacking = new MatroskaVideoTrackBacking(videoTrack);
|
|
@@ -9695,7 +9778,8 @@ var Mediabunny = (() => {
|
|
|
9695
9778
|
codec: null,
|
|
9696
9779
|
codecDescription: null,
|
|
9697
9780
|
colorSpace: null,
|
|
9698
|
-
alphaMode: false
|
|
9781
|
+
alphaMode: false,
|
|
9782
|
+
proresFormat: null
|
|
9699
9783
|
};
|
|
9700
9784
|
} else if (type === 2) {
|
|
9701
9785
|
this.currentTrack.info = {
|
|
@@ -10878,7 +10962,7 @@ var Mediabunny = (() => {
|
|
|
10878
10962
|
};
|
|
10879
10963
|
}
|
|
10880
10964
|
async canBeTransparent() {
|
|
10881
|
-
return this.internalTrack.info.alphaMode;
|
|
10965
|
+
return this.internalTrack.info.alphaMode || this.internalTrack.info.codec === "prores" && (this.internalTrack.info.proresFormat === "ap4h" || this.internalTrack.info.proresFormat === "ap4x");
|
|
10882
10966
|
}
|
|
10883
10967
|
async getDecoderConfig() {
|
|
10884
10968
|
if (!this.internalTrack.info.codec) {
|
|
@@ -10902,7 +10986,8 @@ var Mediabunny = (() => {
|
|
|
10902
10986
|
avcCodecInfo: this.internalTrack.info.codec === "avc" && firstPacket ? extractAvcDecoderConfigurationRecord(firstPacket.data) : null,
|
|
10903
10987
|
hevcCodecInfo: this.internalTrack.info.codec === "hevc" && firstPacket ? extractHevcDecoderConfigurationRecord(firstPacket.data) : null,
|
|
10904
10988
|
vp9CodecInfo: this.internalTrack.info.codec === "vp9" && firstPacket ? extractVp9CodecInfoFromPacket(firstPacket.data) : null,
|
|
10905
|
-
av1CodecInfo: this.internalTrack.info.codec === "av1" && firstPacket ? extractAv1CodecInfoFromPacket(firstPacket.data) : null
|
|
10989
|
+
av1CodecInfo: this.internalTrack.info.codec === "av1" && firstPacket ? extractAv1CodecInfoFromPacket(firstPacket.data) : null,
|
|
10990
|
+
proresFormat: this.internalTrack.info.proresFormat
|
|
10906
10991
|
}),
|
|
10907
10992
|
codedWidth: this.internalTrack.info.width,
|
|
10908
10993
|
codedHeight: this.internalTrack.info.height,
|
|
@@ -13922,7 +14007,8 @@ var Mediabunny = (() => {
|
|
|
13922
14007
|
avcCodecInfo: elementaryStream.info.avcCodecInfo,
|
|
13923
14008
|
hevcCodecInfo: elementaryStream.info.hevcCodecInfo,
|
|
13924
14009
|
vp9CodecInfo: null,
|
|
13925
|
-
av1CodecInfo: null
|
|
14010
|
+
av1CodecInfo: null,
|
|
14011
|
+
proresFormat: null
|
|
13926
14012
|
}),
|
|
13927
14013
|
codedWidth: elementaryStream.info.width,
|
|
13928
14014
|
codedHeight: elementaryStream.info.height,
|
|
@@ -19064,7 +19150,7 @@ var Mediabunny = (() => {
|
|
|
19064
19150
|
...options,
|
|
19065
19151
|
codedWidth: options.codedWidth ?? 1280,
|
|
19066
19152
|
codedHeight: options.codedHeight ?? 720,
|
|
19067
|
-
codec: options.codec ?? buildVideoCodecString(codec, 1280, 720, 1e6)
|
|
19153
|
+
codec: options.codec ?? buildVideoCodecString(codec, 1280, 720, 1e6, false)
|
|
19068
19154
|
};
|
|
19069
19155
|
resolvedOptions.description ??= guessDescriptionForVideo(resolvedOptions);
|
|
19070
19156
|
const key = JSON.stringify(resolvedOptions);
|
|
@@ -19272,12 +19358,11 @@ var Mediabunny = (() => {
|
|
|
19272
19358
|
"init.displayWidth and init.displayHeight must be either both provided or both omitted."
|
|
19273
19359
|
);
|
|
19274
19360
|
}
|
|
19275
|
-
this._data = init._doNotCopy ? toUint8Array(data) : toUint8Array(data).slice();
|
|
19276
|
-
this._layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight);
|
|
19277
19361
|
this.format = init.format;
|
|
19278
19362
|
this.rotation = init.rotation ?? 0;
|
|
19279
19363
|
this.timestamp = init.timestamp;
|
|
19280
19364
|
this.duration = init.duration ?? 0;
|
|
19365
|
+
const layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight);
|
|
19281
19366
|
let colorSpaceInit = init.colorSpace ?? null;
|
|
19282
19367
|
if (colorSpaceInit === null) {
|
|
19283
19368
|
if (this.format === "RGBA" || this.format === "RGBX" || this.format === "BGRA" || this.format === "BGRX") {
|
|
@@ -19296,7 +19381,6 @@ var Mediabunny = (() => {
|
|
|
19296
19381
|
};
|
|
19297
19382
|
}
|
|
19298
19383
|
}
|
|
19299
|
-
this.colorSpace = new VideoSampleColorSpace(colorSpaceInit);
|
|
19300
19384
|
this.visibleRect = {
|
|
19301
19385
|
left: init.visibleRect?.left ?? 0,
|
|
19302
19386
|
top: init.visibleRect?.top ?? 0,
|
|
@@ -19310,6 +19394,9 @@ var Mediabunny = (() => {
|
|
|
19310
19394
|
this.squarePixelWidth = this.visibleRect.width;
|
|
19311
19395
|
this.squarePixelHeight = this.visibleRect.height;
|
|
19312
19396
|
}
|
|
19397
|
+
this._data = init._doNotCopy ? toUint8Array(data) : toUint8Array(data).slice();
|
|
19398
|
+
this._layout = layout;
|
|
19399
|
+
this.colorSpace = new VideoSampleColorSpace(colorSpaceInit);
|
|
19313
19400
|
} else if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) {
|
|
19314
19401
|
if (init?.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) {
|
|
19315
19402
|
throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");
|
|
@@ -19768,6 +19855,7 @@ var Mediabunny = (() => {
|
|
|
19768
19855
|
timestamp: this.microsecondTimestamp,
|
|
19769
19856
|
duration: this.microsecondDuration,
|
|
19770
19857
|
colorSpace: this.colorSpace,
|
|
19858
|
+
visibleRect: this.visibleRect,
|
|
19771
19859
|
displayWidth: this.squarePixelWidth,
|
|
19772
19860
|
// Not display* since we're not passing rotation
|
|
19773
19861
|
displayHeight: this.squarePixelHeight
|
|
@@ -19779,13 +19867,18 @@ var Mediabunny = (() => {
|
|
|
19779
19867
|
// Drag 0 duration to undefined, glitches some codecs
|
|
19780
19868
|
});
|
|
19781
19869
|
} else if (this._data instanceof Uint8Array) {
|
|
19870
|
+
assert(this._layout);
|
|
19782
19871
|
return new VideoFrame(this._data, {
|
|
19783
19872
|
format: this.format,
|
|
19784
19873
|
codedWidth: this.codedWidth,
|
|
19874
|
+
// This is technically wrong! codedWidth is a lie technically. But, since
|
|
19785
19875
|
codedHeight: this.codedHeight,
|
|
19876
|
+
// we pass the layout (which contains the true coded width), we're good.
|
|
19877
|
+
layout: this._layout,
|
|
19786
19878
|
timestamp: this.microsecondTimestamp,
|
|
19787
19879
|
duration: this.microsecondDuration || void 0,
|
|
19788
19880
|
colorSpace: this.colorSpace,
|
|
19881
|
+
visibleRect: this.visibleRect,
|
|
19789
19882
|
displayWidth: this.squarePixelWidth,
|
|
19790
19883
|
// Not display* since we're not passing rotation
|
|
19791
19884
|
displayHeight: this.squarePixelHeight
|
|
@@ -21303,7 +21396,8 @@ var Mediabunny = (() => {
|
|
|
21303
21396
|
options.codec,
|
|
21304
21397
|
options.width,
|
|
21305
21398
|
options.height,
|
|
21306
|
-
resolvedBitrate
|
|
21399
|
+
resolvedBitrate,
|
|
21400
|
+
options.alpha === "keep"
|
|
21307
21401
|
),
|
|
21308
21402
|
width: options.width,
|
|
21309
21403
|
height: options.height,
|
|
@@ -21400,6 +21494,10 @@ var Mediabunny = (() => {
|
|
|
21400
21494
|
/** @internal */
|
|
21401
21495
|
_toVideoBitrate(codec, width, height) {
|
|
21402
21496
|
const pixels = width * height;
|
|
21497
|
+
const referencePixels = 1920 * 1080;
|
|
21498
|
+
const referenceBitrate = 3e6;
|
|
21499
|
+
const scaleFactor = Math.pow(pixels / referencePixels, 0.95);
|
|
21500
|
+
const baseBitrate = referenceBitrate * scaleFactor;
|
|
21403
21501
|
const codecEfficiencyFactors = {
|
|
21404
21502
|
avc: 1,
|
|
21405
21503
|
// H.264/AVC (baseline)
|
|
@@ -21409,13 +21507,11 @@ var Mediabunny = (() => {
|
|
|
21409
21507
|
// Similar to HEVC
|
|
21410
21508
|
av1: 0.4,
|
|
21411
21509
|
// ~60% more efficient than AVC
|
|
21412
|
-
vp8: 1.2
|
|
21510
|
+
vp8: 1.2,
|
|
21413
21511
|
// Slightly less efficient than AVC
|
|
21512
|
+
prores: 22e7 / referenceBitrate
|
|
21513
|
+
// Apple ProRes white paper claims 220 Mbps for 1080p 422 HQ @30Hz
|
|
21414
21514
|
};
|
|
21415
|
-
const referencePixels = 1920 * 1080;
|
|
21416
|
-
const referenceBitrate = 3e6;
|
|
21417
|
-
const scaleFactor = Math.pow(pixels / referencePixels, 0.95);
|
|
21418
|
-
const baseBitrate = referenceBitrate * scaleFactor;
|
|
21419
21515
|
const codecAdjustedBitrate = baseBitrate * codecEfficiencyFactors[codec];
|
|
21420
21516
|
const finalBitrate = codecAdjustedBitrate * this._factor;
|
|
21421
21517
|
return Math.ceil(finalBitrate / 1e3) * 1e3;
|
|
@@ -22009,6 +22105,7 @@ var Mediabunny = (() => {
|
|
|
22009
22105
|
let ended = false;
|
|
22010
22106
|
let terminated = false;
|
|
22011
22107
|
let outOfBandError = null;
|
|
22108
|
+
let hasOutOfBandError = false;
|
|
22012
22109
|
const timestamps = [];
|
|
22013
22110
|
const maxQueueSize = () => Math.max(2, timestamps.length);
|
|
22014
22111
|
(async () => {
|
|
@@ -22030,8 +22127,9 @@ var Mediabunny = (() => {
|
|
|
22030
22127
|
ended = true;
|
|
22031
22128
|
onQueueNotEmpty();
|
|
22032
22129
|
})().catch((error) => {
|
|
22033
|
-
if (!
|
|
22130
|
+
if (!hasOutOfBandError) {
|
|
22034
22131
|
outOfBandError = error;
|
|
22132
|
+
hasOutOfBandError = true;
|
|
22035
22133
|
onQueueNotEmpty();
|
|
22036
22134
|
}
|
|
22037
22135
|
});
|
|
@@ -22043,7 +22141,7 @@ var Mediabunny = (() => {
|
|
|
22043
22141
|
throw new InputDisposedError();
|
|
22044
22142
|
} else if (terminated) {
|
|
22045
22143
|
return { value: void 0, done: true };
|
|
22046
|
-
} else if (
|
|
22144
|
+
} else if (hasOutOfBandError) {
|
|
22047
22145
|
throw outOfBandError;
|
|
22048
22146
|
} else if (packetQueue.length > 0) {
|
|
22049
22147
|
const value = packetQueue.shift();
|
|
@@ -22096,6 +22194,7 @@ var Mediabunny = (() => {
|
|
|
22096
22194
|
let ended = false;
|
|
22097
22195
|
let terminated = false;
|
|
22098
22196
|
let outOfBandError = null;
|
|
22197
|
+
let hasOutOfBandError = false;
|
|
22099
22198
|
const packetRetrievalOptions = {
|
|
22100
22199
|
...options,
|
|
22101
22200
|
verifyKeyPackets: true,
|
|
@@ -22129,8 +22228,9 @@ var Mediabunny = (() => {
|
|
|
22129
22228
|
({ promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers());
|
|
22130
22229
|
}
|
|
22131
22230
|
}, (error) => {
|
|
22132
|
-
if (!
|
|
22231
|
+
if (!hasOutOfBandError) {
|
|
22133
22232
|
outOfBandError = error;
|
|
22233
|
+
hasOutOfBandError = true;
|
|
22134
22234
|
onQueueNotEmpty();
|
|
22135
22235
|
}
|
|
22136
22236
|
});
|
|
@@ -22165,8 +22265,9 @@ var Mediabunny = (() => {
|
|
|
22165
22265
|
decoderIsFlushed = true;
|
|
22166
22266
|
onQueueNotEmpty();
|
|
22167
22267
|
})().catch((error) => {
|
|
22168
|
-
if (!
|
|
22268
|
+
if (!hasOutOfBandError) {
|
|
22169
22269
|
outOfBandError = error;
|
|
22270
|
+
hasOutOfBandError = true;
|
|
22170
22271
|
onQueueNotEmpty();
|
|
22171
22272
|
}
|
|
22172
22273
|
});
|
|
@@ -22185,7 +22286,7 @@ var Mediabunny = (() => {
|
|
|
22185
22286
|
throw new InputDisposedError();
|
|
22186
22287
|
} else if (terminated) {
|
|
22187
22288
|
return { value: void 0, done: true };
|
|
22188
|
-
} else if (
|
|
22289
|
+
} else if (hasOutOfBandError) {
|
|
22189
22290
|
closeSamples();
|
|
22190
22291
|
throw outOfBandError;
|
|
22191
22292
|
} else if (sampleQueue.length > 0) {
|
|
@@ -22226,6 +22327,7 @@ var Mediabunny = (() => {
|
|
|
22226
22327
|
let decoderIsFlushed = false;
|
|
22227
22328
|
let terminated = false;
|
|
22228
22329
|
let outOfBandError = null;
|
|
22330
|
+
let hasOutOfBandError = false;
|
|
22229
22331
|
const pushToQueue = (sample) => {
|
|
22230
22332
|
sampleQueue.push(sample);
|
|
22231
22333
|
onQueueNotEmpty();
|
|
@@ -22256,8 +22358,9 @@ var Mediabunny = (() => {
|
|
|
22256
22358
|
sample.close();
|
|
22257
22359
|
}
|
|
22258
22360
|
}, (error) => {
|
|
22259
|
-
if (!
|
|
22361
|
+
if (!hasOutOfBandError) {
|
|
22260
22362
|
outOfBandError = error;
|
|
22363
|
+
hasOutOfBandError = true;
|
|
22261
22364
|
onQueueNotEmpty();
|
|
22262
22365
|
}
|
|
22263
22366
|
});
|
|
@@ -22327,8 +22430,9 @@ var Mediabunny = (() => {
|
|
|
22327
22430
|
decoderIsFlushed = true;
|
|
22328
22431
|
onQueueNotEmpty();
|
|
22329
22432
|
})().catch((error) => {
|
|
22330
|
-
if (!
|
|
22433
|
+
if (!hasOutOfBandError) {
|
|
22331
22434
|
outOfBandError = error;
|
|
22435
|
+
hasOutOfBandError = true;
|
|
22332
22436
|
onQueueNotEmpty();
|
|
22333
22437
|
}
|
|
22334
22438
|
});
|
|
@@ -22346,7 +22450,7 @@ var Mediabunny = (() => {
|
|
|
22346
22450
|
throw new InputDisposedError();
|
|
22347
22451
|
} else if (terminated) {
|
|
22348
22452
|
return { value: void 0, done: true };
|
|
22349
|
-
} else if (
|
|
22453
|
+
} else if (hasOutOfBandError) {
|
|
22350
22454
|
closeSamples();
|
|
22351
22455
|
throw outOfBandError;
|
|
22352
22456
|
} else if (sampleQueue.length > 0) {
|
|
@@ -22411,7 +22515,8 @@ var Mediabunny = (() => {
|
|
|
22411
22515
|
this.currentAlphaPacketIndex = 0;
|
|
22412
22516
|
this.alphaRaslSkipped = false;
|
|
22413
22517
|
// For HEVC stuff
|
|
22414
|
-
this.
|
|
22518
|
+
this.finalSamples = [];
|
|
22519
|
+
this.mergeAlphaPromises = [];
|
|
22415
22520
|
const MatchingCustomDecoder = customVideoDecoders.find((x) => x.supports(codec, decoderConfig));
|
|
22416
22521
|
if (MatchingCustomDecoder) {
|
|
22417
22522
|
this.customDecoder = new MatchingCustomDecoder();
|
|
@@ -22423,18 +22528,19 @@ var Mediabunny = (() => {
|
|
|
22423
22528
|
}
|
|
22424
22529
|
this.finalizeAndEmitSample(sample);
|
|
22425
22530
|
};
|
|
22426
|
-
|
|
22531
|
+
this.customDecoder.onError = (error) => {
|
|
22532
|
+
onError(error);
|
|
22533
|
+
};
|
|
22534
|
+
void this.customDecoderCallSerializer.call(() => this.customDecoder.init()).catch((error) => onError(error));
|
|
22427
22535
|
} else {
|
|
22428
22536
|
const colorHandler = (frame) => {
|
|
22429
|
-
this.
|
|
22430
|
-
|
|
22431
|
-
|
|
22432
|
-
|
|
22433
|
-
|
|
22434
|
-
|
|
22435
|
-
|
|
22436
|
-
}
|
|
22437
|
-
}).catch((error) => this.onError(error));
|
|
22537
|
+
if (this.alphaQueue.length > 0) {
|
|
22538
|
+
const alphaFrame = this.alphaQueue.shift();
|
|
22539
|
+
assert(alphaFrame !== void 0);
|
|
22540
|
+
void this.mergeAlpha(frame, alphaFrame);
|
|
22541
|
+
} else {
|
|
22542
|
+
this.colorQueue.push(frame);
|
|
22543
|
+
}
|
|
22438
22544
|
};
|
|
22439
22545
|
if (codec === "avc" && this.decoderConfig.description && isChromium()) {
|
|
22440
22546
|
const record = deserializeAvcDecoderConfigurationRecord(toUint8Array(this.decoderConfig.description));
|
|
@@ -22485,7 +22591,7 @@ var Mediabunny = (() => {
|
|
|
22485
22591
|
}
|
|
22486
22592
|
if (this.customDecoder) {
|
|
22487
22593
|
this.customDecoderQueueSize++;
|
|
22488
|
-
void this.customDecoderCallSerializer.call(() => this.customDecoder.decode(packet)).
|
|
22594
|
+
void this.customDecoderCallSerializer.call(() => this.customDecoder.decode(packet)).catch((error) => this.onError(error)).finally(() => this.customDecoderQueueSize--);
|
|
22489
22595
|
} else {
|
|
22490
22596
|
assert(this.decoder);
|
|
22491
22597
|
if (!isWebKit()) {
|
|
@@ -22527,27 +22633,25 @@ var Mediabunny = (() => {
|
|
|
22527
22633
|
}
|
|
22528
22634
|
if (!this.alphaDecoder) {
|
|
22529
22635
|
const alphaHandler = (frame) => {
|
|
22530
|
-
this.
|
|
22636
|
+
if (this.colorQueue.length > 0) {
|
|
22637
|
+
const colorFrame = this.colorQueue.shift();
|
|
22638
|
+
assert(colorFrame !== void 0);
|
|
22639
|
+
void this.mergeAlpha(colorFrame, frame);
|
|
22640
|
+
} else {
|
|
22641
|
+
this.alphaQueue.push(frame);
|
|
22642
|
+
}
|
|
22643
|
+
this.decodedAlphaChunkCount++;
|
|
22644
|
+
while (this.nullAlphaFrameQueue.length > 0 && this.nullAlphaFrameQueue[0] === this.decodedAlphaChunkCount) {
|
|
22645
|
+
this.nullAlphaFrameQueue.shift();
|
|
22531
22646
|
if (this.colorQueue.length > 0) {
|
|
22532
22647
|
const colorFrame = this.colorQueue.shift();
|
|
22533
22648
|
assert(colorFrame !== void 0);
|
|
22534
|
-
|
|
22649
|
+
void this.mergeAlpha(colorFrame, null);
|
|
22535
22650
|
} else {
|
|
22536
|
-
this.alphaQueue.push(
|
|
22537
|
-
}
|
|
22538
|
-
this.decodedAlphaChunkCount++;
|
|
22539
|
-
while (this.nullAlphaFrameQueue.length > 0 && this.nullAlphaFrameQueue[0] === this.decodedAlphaChunkCount) {
|
|
22540
|
-
this.nullAlphaFrameQueue.shift();
|
|
22541
|
-
if (this.colorQueue.length > 0) {
|
|
22542
|
-
const colorFrame = this.colorQueue.shift();
|
|
22543
|
-
assert(colorFrame !== void 0);
|
|
22544
|
-
await this.mergeAlpha(colorFrame, null);
|
|
22545
|
-
} else {
|
|
22546
|
-
this.alphaQueue.push(null);
|
|
22547
|
-
}
|
|
22651
|
+
this.alphaQueue.push(null);
|
|
22548
22652
|
}
|
|
22549
|
-
|
|
22550
|
-
|
|
22653
|
+
}
|
|
22654
|
+
this.alphaDecoderQueueSize--;
|
|
22551
22655
|
};
|
|
22552
22656
|
const stack = new Error("Decoding error").stack;
|
|
22553
22657
|
this.alphaDecoder = new VideoDecoder({
|
|
@@ -22630,15 +22734,29 @@ var Mediabunny = (() => {
|
|
|
22630
22734
|
this.onSample(sample);
|
|
22631
22735
|
}
|
|
22632
22736
|
async mergeAlpha(color, alpha) {
|
|
22633
|
-
|
|
22634
|
-
|
|
22635
|
-
|
|
22636
|
-
|
|
22737
|
+
const resolver = promiseWithResolvers();
|
|
22738
|
+
this.mergeAlphaPromises.push(resolver.promise);
|
|
22739
|
+
const result = { sample: null };
|
|
22740
|
+
this.finalSamples.push(result);
|
|
22741
|
+
try {
|
|
22742
|
+
if (!alpha) {
|
|
22743
|
+
result.sample = new VideoSample(color);
|
|
22744
|
+
} else {
|
|
22745
|
+
assert(this.merger);
|
|
22746
|
+
const finalFrame = await this.merger.merge(color, alpha);
|
|
22747
|
+
result.sample = new VideoSample(finalFrame);
|
|
22748
|
+
}
|
|
22749
|
+
while (this.finalSamples.length > 0 && this.finalSamples[0].sample !== null) {
|
|
22750
|
+
const next = this.finalSamples.shift();
|
|
22751
|
+
this.sampleHandler(next.sample);
|
|
22752
|
+
}
|
|
22753
|
+
} catch (error) {
|
|
22754
|
+
removeItem(this.finalSamples, result);
|
|
22755
|
+
this.onError(error);
|
|
22756
|
+
} finally {
|
|
22757
|
+
removeItem(this.mergeAlphaPromises, resolver.promise);
|
|
22758
|
+
resolver.resolve();
|
|
22637
22759
|
}
|
|
22638
|
-
assert(this.merger);
|
|
22639
|
-
const finalFrame = await this.merger.update(color, alpha);
|
|
22640
|
-
const finalSample = new VideoSample(finalFrame);
|
|
22641
|
-
this.sampleHandler(finalSample);
|
|
22642
22760
|
}
|
|
22643
22761
|
async flush() {
|
|
22644
22762
|
if (this.customDecoder) {
|
|
@@ -22649,7 +22767,7 @@ var Mediabunny = (() => {
|
|
|
22649
22767
|
this.decoder.flush(),
|
|
22650
22768
|
this.alphaDecoder?.flush()
|
|
22651
22769
|
]);
|
|
22652
|
-
await this.
|
|
22770
|
+
await Promise.all(this.mergeAlphaPromises);
|
|
22653
22771
|
this.colorQueue.forEach((x) => x.close());
|
|
22654
22772
|
this.colorQueue.length = 0;
|
|
22655
22773
|
this.alphaQueue.forEach((x) => x?.close());
|
|
@@ -22689,205 +22807,62 @@ var Mediabunny = (() => {
|
|
|
22689
22807
|
this.sampleQueue.length = 0;
|
|
22690
22808
|
}
|
|
22691
22809
|
};
|
|
22692
|
-
var
|
|
22693
|
-
var
|
|
22810
|
+
var mergerWorkerUrl = null;
|
|
22811
|
+
var ColorAlphaMerger = class {
|
|
22694
22812
|
constructor() {
|
|
22695
|
-
this.
|
|
22696
|
-
this.
|
|
22697
|
-
this.program = null;
|
|
22698
|
-
this.vao = null;
|
|
22699
|
-
this.colorTexture = null;
|
|
22700
|
-
this.alphaTexture = null;
|
|
22701
|
-
this.worker = null;
|
|
22813
|
+
this.workers = [];
|
|
22814
|
+
this.nextWorkerIndex = 0;
|
|
22702
22815
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
22703
22816
|
this.nextRequestId = 0;
|
|
22704
|
-
|
|
22705
|
-
|
|
22706
|
-
|
|
22707
|
-
|
|
22708
|
-
|
|
22709
|
-
|
|
22710
|
-
|
|
22711
|
-
|
|
22712
|
-
|
|
22713
|
-
|
|
22817
|
+
}
|
|
22818
|
+
merge(color, alpha) {
|
|
22819
|
+
if (this.workers.length === 0) {
|
|
22820
|
+
if (!mergerWorkerUrl) {
|
|
22821
|
+
const blob = new Blob(
|
|
22822
|
+
[`(${colorAlphaMergerWorkerCode.toString()})()`],
|
|
22823
|
+
{ type: "application/javascript" }
|
|
22824
|
+
);
|
|
22825
|
+
mergerWorkerUrl = URL.createObjectURL(blob);
|
|
22826
|
+
}
|
|
22827
|
+
const poolSize = clamp(navigator.hardwareConcurrency, 1, 4);
|
|
22828
|
+
for (let i = 0; i < poolSize; i++) {
|
|
22829
|
+
const worker2 = new Worker(mergerWorkerUrl);
|
|
22830
|
+
worker2.addEventListener("message", (event) => {
|
|
22831
|
+
const data = event.data;
|
|
22832
|
+
const pending2 = this.pendingRequests.get(data.id);
|
|
22833
|
+
if (!pending2) {
|
|
22834
|
+
return;
|
|
22835
|
+
}
|
|
22836
|
+
this.pendingRequests.delete(data.id);
|
|
22837
|
+
if ("error" in data) {
|
|
22838
|
+
pending2.reject(new Error(data.error));
|
|
22839
|
+
} else {
|
|
22840
|
+
pending2.resolve(data.frame);
|
|
22841
|
+
}
|
|
22714
22842
|
});
|
|
22715
|
-
|
|
22716
|
-
|
|
22717
|
-
|
|
22718
|
-
|
|
22719
|
-
|
|
22720
|
-
|
|
22721
|
-
|
|
22722
|
-
this.
|
|
22723
|
-
this.gl.useProgram(this.program);
|
|
22724
|
-
this.gl.uniform1i(this.gl.getUniformLocation(this.program, "u_colorTexture"), 0);
|
|
22725
|
-
this.gl.uniform1i(this.gl.getUniformLocation(this.program, "u_alphaTexture"), 1);
|
|
22726
|
-
} catch (error) {
|
|
22727
|
-
this.gl = null;
|
|
22728
|
-
this.canvas = null;
|
|
22729
|
-
mergerGpuUnavailable = true;
|
|
22730
|
-
Logging._warn("Falling back to CPU for color/alpha merging.", error);
|
|
22843
|
+
worker2.addEventListener("error", (event) => {
|
|
22844
|
+
const error = new Error(event.message || "Color/alpha merge worker error.");
|
|
22845
|
+
for (const pending2 of this.pendingRequests.values()) {
|
|
22846
|
+
pending2.reject(error);
|
|
22847
|
+
}
|
|
22848
|
+
this.pendingRequests.clear();
|
|
22849
|
+
});
|
|
22850
|
+
this.workers.push(worker2);
|
|
22731
22851
|
}
|
|
22732
22852
|
}
|
|
22733
|
-
}
|
|
22734
|
-
async update(color, alpha) {
|
|
22735
|
-
if (this.gl) {
|
|
22736
|
-
return this.updateGpu(color, alpha);
|
|
22737
|
-
} else {
|
|
22738
|
-
return this.updateCpu(color, alpha);
|
|
22739
|
-
}
|
|
22740
|
-
}
|
|
22741
|
-
createProgram() {
|
|
22742
|
-
assert(this.gl);
|
|
22743
|
-
const vertexShader = this.createShader(this.gl.VERTEX_SHADER, `#version 300 es
|
|
22744
|
-
in vec2 a_position;
|
|
22745
|
-
in vec2 a_texCoord;
|
|
22746
|
-
out vec2 v_texCoord;
|
|
22747
|
-
|
|
22748
|
-
void main() {
|
|
22749
|
-
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
22750
|
-
v_texCoord = a_texCoord;
|
|
22751
|
-
}
|
|
22752
|
-
`);
|
|
22753
|
-
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, `#version 300 es
|
|
22754
|
-
precision highp float;
|
|
22755
|
-
|
|
22756
|
-
uniform sampler2D u_colorTexture;
|
|
22757
|
-
uniform sampler2D u_alphaTexture;
|
|
22758
|
-
in vec2 v_texCoord;
|
|
22759
|
-
out vec4 fragColor;
|
|
22760
|
-
|
|
22761
|
-
void main() {
|
|
22762
|
-
vec3 color = texture(u_colorTexture, v_texCoord).rgb;
|
|
22763
|
-
float alpha = texture(u_alphaTexture, v_texCoord).r;
|
|
22764
|
-
fragColor = vec4(color, alpha);
|
|
22765
|
-
}
|
|
22766
|
-
`);
|
|
22767
|
-
const program = this.gl.createProgram();
|
|
22768
|
-
this.gl.attachShader(program, vertexShader);
|
|
22769
|
-
this.gl.attachShader(program, fragmentShader);
|
|
22770
|
-
this.gl.linkProgram(program);
|
|
22771
|
-
return program;
|
|
22772
|
-
}
|
|
22773
|
-
createShader(type, source) {
|
|
22774
|
-
assert(this.gl);
|
|
22775
|
-
const shader = this.gl.createShader(type);
|
|
22776
|
-
this.gl.shaderSource(shader, source);
|
|
22777
|
-
this.gl.compileShader(shader);
|
|
22778
|
-
return shader;
|
|
22779
|
-
}
|
|
22780
|
-
createVAO() {
|
|
22781
|
-
assert(this.gl);
|
|
22782
|
-
assert(this.program);
|
|
22783
|
-
const vao = this.gl.createVertexArray();
|
|
22784
|
-
this.gl.bindVertexArray(vao);
|
|
22785
|
-
const vertices = new Float32Array([
|
|
22786
|
-
-1,
|
|
22787
|
-
-1,
|
|
22788
|
-
0,
|
|
22789
|
-
1,
|
|
22790
|
-
1,
|
|
22791
|
-
-1,
|
|
22792
|
-
1,
|
|
22793
|
-
1,
|
|
22794
|
-
-1,
|
|
22795
|
-
1,
|
|
22796
|
-
0,
|
|
22797
|
-
0,
|
|
22798
|
-
1,
|
|
22799
|
-
1,
|
|
22800
|
-
1,
|
|
22801
|
-
0
|
|
22802
|
-
]);
|
|
22803
|
-
const buffer = this.gl.createBuffer();
|
|
22804
|
-
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
|
|
22805
|
-
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW);
|
|
22806
|
-
const positionLocation = this.gl.getAttribLocation(this.program, "a_position");
|
|
22807
|
-
const texCoordLocation = this.gl.getAttribLocation(this.program, "a_texCoord");
|
|
22808
|
-
this.gl.enableVertexAttribArray(positionLocation);
|
|
22809
|
-
this.gl.vertexAttribPointer(positionLocation, 2, this.gl.FLOAT, false, 16, 0);
|
|
22810
|
-
this.gl.enableVertexAttribArray(texCoordLocation);
|
|
22811
|
-
this.gl.vertexAttribPointer(texCoordLocation, 2, this.gl.FLOAT, false, 16, 8);
|
|
22812
|
-
return vao;
|
|
22813
|
-
}
|
|
22814
|
-
createTexture() {
|
|
22815
|
-
assert(this.gl);
|
|
22816
|
-
const texture = this.gl.createTexture();
|
|
22817
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
22818
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
22819
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
22820
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
|
22821
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
|
|
22822
|
-
return texture;
|
|
22823
|
-
}
|
|
22824
|
-
updateGpu(color, alpha) {
|
|
22825
|
-
assert(this.gl);
|
|
22826
|
-
assert(this.canvas);
|
|
22827
|
-
if (color.displayWidth !== this.canvas.width || color.displayHeight !== this.canvas.height) {
|
|
22828
|
-
this.canvas.width = color.displayWidth;
|
|
22829
|
-
this.canvas.height = color.displayHeight;
|
|
22830
|
-
}
|
|
22831
|
-
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
22832
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, this.colorTexture);
|
|
22833
|
-
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, color);
|
|
22834
|
-
this.gl.activeTexture(this.gl.TEXTURE1);
|
|
22835
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, this.alphaTexture);
|
|
22836
|
-
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, alpha);
|
|
22837
|
-
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
22838
|
-
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
22839
|
-
this.gl.bindVertexArray(this.vao);
|
|
22840
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
22841
|
-
const finalFrame = new VideoFrame(this.canvas, {
|
|
22842
|
-
timestamp: color.timestamp,
|
|
22843
|
-
duration: color.duration ?? void 0
|
|
22844
|
-
});
|
|
22845
|
-
color.close();
|
|
22846
|
-
alpha.close();
|
|
22847
|
-
return finalFrame;
|
|
22848
|
-
}
|
|
22849
|
-
updateCpu(color, alpha) {
|
|
22850
|
-
if (!this.worker) {
|
|
22851
|
-
const blob = new Blob(
|
|
22852
|
-
[`(${colorAlphaMergerWorkerCode.toString()})()`],
|
|
22853
|
-
{ type: "application/javascript" }
|
|
22854
|
-
);
|
|
22855
|
-
const url2 = URL.createObjectURL(blob);
|
|
22856
|
-
this.worker = new Worker(url2);
|
|
22857
|
-
URL.revokeObjectURL(url2);
|
|
22858
|
-
this.worker.addEventListener("message", (event) => {
|
|
22859
|
-
const data = event.data;
|
|
22860
|
-
const pending2 = this.pendingRequests.get(data.id);
|
|
22861
|
-
if (!pending2) {
|
|
22862
|
-
return;
|
|
22863
|
-
}
|
|
22864
|
-
this.pendingRequests.delete(data.id);
|
|
22865
|
-
if ("error" in data) {
|
|
22866
|
-
pending2.reject(new Error(data.error));
|
|
22867
|
-
} else {
|
|
22868
|
-
pending2.resolve(data.frame);
|
|
22869
|
-
}
|
|
22870
|
-
});
|
|
22871
|
-
this.worker.addEventListener("error", (event) => {
|
|
22872
|
-
const error = new Error(event.message || "Color/alpha merge worker error.");
|
|
22873
|
-
for (const pending2 of this.pendingRequests.values()) {
|
|
22874
|
-
pending2.reject(error);
|
|
22875
|
-
}
|
|
22876
|
-
this.pendingRequests.clear();
|
|
22877
|
-
});
|
|
22878
|
-
}
|
|
22879
22853
|
const id = this.nextRequestId++;
|
|
22880
22854
|
const pending = promiseWithResolvers();
|
|
22881
22855
|
this.pendingRequests.set(id, pending);
|
|
22882
|
-
|
|
22856
|
+
const worker = this.workers[this.nextWorkerIndex];
|
|
22857
|
+
this.nextWorkerIndex = (this.nextWorkerIndex + 1) % this.workers.length;
|
|
22858
|
+
worker.postMessage({ id, color, alpha }, { transfer: [color, alpha] });
|
|
22883
22859
|
return pending.promise;
|
|
22884
22860
|
}
|
|
22885
22861
|
close() {
|
|
22886
|
-
this.
|
|
22887
|
-
|
|
22888
|
-
|
|
22889
|
-
this.
|
|
22890
|
-
this.worker = null;
|
|
22862
|
+
for (const worker of this.workers) {
|
|
22863
|
+
worker.terminate();
|
|
22864
|
+
}
|
|
22865
|
+
this.workers.length = 0;
|
|
22891
22866
|
const error = new Error("Color/alpha merger closed.");
|
|
22892
22867
|
for (const pending of this.pendingRequests.values()) {
|
|
22893
22868
|
pending.reject(error);
|
|
@@ -22895,8 +22870,6 @@ var Mediabunny = (() => {
|
|
|
22895
22870
|
this.pendingRequests.clear();
|
|
22896
22871
|
}
|
|
22897
22872
|
};
|
|
22898
|
-
_ColorAlphaMerger.forceCpu = true;
|
|
22899
|
-
var ColorAlphaMerger = _ColorAlphaMerger;
|
|
22900
22873
|
var colorAlphaMergerWorkerCode = () => {
|
|
22901
22874
|
let cpuAlphaBuffer = null;
|
|
22902
22875
|
let cpuColorBuffer = null;
|
|
@@ -22930,18 +22903,18 @@ var Mediabunny = (() => {
|
|
|
22930
22903
|
`CPU color/alpha merging requires the alpha frame to have the same bit depth as the color frame (color: '${format}', alpha: '${alphaFormat}').`
|
|
22931
22904
|
);
|
|
22932
22905
|
}
|
|
22933
|
-
const width = color.codedWidth;
|
|
22934
|
-
const height = color.codedHeight;
|
|
22935
22906
|
if (format === "RGBX" || format === "RGBA" || format === "BGRX" || format === "BGRA") {
|
|
22936
|
-
return await mergeInterleavedRgba(color, alpha,
|
|
22907
|
+
return await mergeInterleavedRgba(color, alpha, format);
|
|
22937
22908
|
} else if (format === "I420" || format === "I420P10" || format === "I420P12" || format === "I422" || format === "I422P10" || format === "I422P12" || format === "I444" || format === "I444P10" || format === "I444P12") {
|
|
22938
|
-
return await mergePlanarYuv(color, alpha,
|
|
22909
|
+
return await mergePlanarYuv(color, alpha, format);
|
|
22939
22910
|
} else if (format === "NV12") {
|
|
22940
|
-
return await mergeNv12(color, alpha
|
|
22911
|
+
return await mergeNv12(color, alpha);
|
|
22941
22912
|
}
|
|
22942
22913
|
throw new Error(`CPU color/alpha merging does not support format '${format}'.`);
|
|
22943
22914
|
};
|
|
22944
|
-
const mergeInterleavedRgba = async (color, alpha,
|
|
22915
|
+
const mergeInterleavedRgba = async (color, alpha, format) => {
|
|
22916
|
+
const width = color.visibleRect?.width ?? color.codedWidth;
|
|
22917
|
+
const height = color.visibleRect?.height ?? color.codedHeight;
|
|
22945
22918
|
const pixelCount = width * height;
|
|
22946
22919
|
const output = new Uint8Array(pixelCount * 4);
|
|
22947
22920
|
await color.copyTo(output);
|
|
@@ -22960,7 +22933,9 @@ var Mediabunny = (() => {
|
|
|
22960
22933
|
};
|
|
22961
22934
|
return new VideoFrame(output, init);
|
|
22962
22935
|
};
|
|
22963
|
-
const mergePlanarYuv = async (color, alpha,
|
|
22936
|
+
const mergePlanarYuv = async (color, alpha, format) => {
|
|
22937
|
+
const width = color.visibleRect?.width ?? color.codedWidth;
|
|
22938
|
+
const height = color.visibleRect?.height ?? color.codedHeight;
|
|
22964
22939
|
const is10 = format.includes("P10");
|
|
22965
22940
|
const is12 = format.includes("P12");
|
|
22966
22941
|
const bytesPerSample = is10 || is12 ? 2 : 1;
|
|
@@ -22998,7 +22973,9 @@ var Mediabunny = (() => {
|
|
|
22998
22973
|
};
|
|
22999
22974
|
return new VideoFrame(output, init);
|
|
23000
22975
|
};
|
|
23001
|
-
const mergeNv12 = async (color, alpha
|
|
22976
|
+
const mergeNv12 = async (color, alpha) => {
|
|
22977
|
+
const width = color.visibleRect?.width ?? color.codedWidth;
|
|
22978
|
+
const height = color.visibleRect?.height ?? color.codedHeight;
|
|
23002
22979
|
const ySize = width * height;
|
|
23003
22980
|
const chromaW = Math.ceil(width / 2);
|
|
23004
22981
|
const chromaH = Math.ceil(height / 2);
|
|
@@ -23361,7 +23338,10 @@ var Mediabunny = (() => {
|
|
|
23361
23338
|
}
|
|
23362
23339
|
sampleHandler(sample);
|
|
23363
23340
|
};
|
|
23364
|
-
|
|
23341
|
+
this.customDecoder.onError = (error) => {
|
|
23342
|
+
onError(error);
|
|
23343
|
+
};
|
|
23344
|
+
void this.customDecoderCallSerializer.call(() => this.customDecoder.init()).catch((error) => onError(error));
|
|
23365
23345
|
} else {
|
|
23366
23346
|
const stack = new Error("Decoding error").stack;
|
|
23367
23347
|
this.decoder = new AudioDecoder({
|
|
@@ -23391,7 +23371,7 @@ var Mediabunny = (() => {
|
|
|
23391
23371
|
decode(packet) {
|
|
23392
23372
|
if (this.customDecoder) {
|
|
23393
23373
|
this.customDecoderQueueSize++;
|
|
23394
|
-
void this.customDecoderCallSerializer.call(() => this.customDecoder.decode(packet)).
|
|
23374
|
+
void this.customDecoderCallSerializer.call(() => this.customDecoder.decode(packet)).catch((error) => this.onError(error)).finally(() => this.customDecoderQueueSize--);
|
|
23395
23375
|
} else {
|
|
23396
23376
|
assert(this.decoder);
|
|
23397
23377
|
this.expectedFirstTimestamp ??= packet.timestamp;
|
|
@@ -27129,7 +27109,7 @@ var Mediabunny = (() => {
|
|
|
27129
27109
|
i16(65535)
|
|
27130
27110
|
// Pre-defined
|
|
27131
27111
|
], [
|
|
27132
|
-
VIDEO_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec](trackData),
|
|
27112
|
+
VIDEO_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec]?.(trackData) ?? null,
|
|
27133
27113
|
pasp(trackData),
|
|
27134
27114
|
colorSpaceIsComplete(trackData.info.decoderConfig.colorSpace) ? colr(trackData) : null
|
|
27135
27115
|
]);
|
|
@@ -28124,6 +28104,8 @@ var Mediabunny = (() => {
|
|
|
28124
28104
|
return "vp09";
|
|
28125
28105
|
case "av1":
|
|
28126
28106
|
return "av01";
|
|
28107
|
+
case "prores":
|
|
28108
|
+
return fullCodecString;
|
|
28127
28109
|
}
|
|
28128
28110
|
};
|
|
28129
28111
|
var VIDEO_CODEC_TO_CONFIGURATION_BOX = {
|
|
@@ -28131,7 +28113,8 @@ var Mediabunny = (() => {
|
|
|
28131
28113
|
hevc: hvcC,
|
|
28132
28114
|
vp8: vpcC,
|
|
28133
28115
|
vp9: vpcC,
|
|
28134
|
-
av1: av1C
|
|
28116
|
+
av1: av1C,
|
|
28117
|
+
prores: null
|
|
28135
28118
|
};
|
|
28136
28119
|
var audioCodecToBoxName = (codec, isQuickTime) => {
|
|
28137
28120
|
switch (codec) {
|
|
@@ -30088,6 +30071,7 @@ var Mediabunny = (() => {
|
|
|
30088
30071
|
{ id: 156 /* FlagLacing */, data: 0 },
|
|
30089
30072
|
{ id: 2274716 /* Language */, data: trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE },
|
|
30090
30073
|
{ id: 134 /* CodecID */, data: codecId },
|
|
30074
|
+
trackData.codecPrivate ? { id: 25506 /* CodecPrivate */, data: toUint8Array(trackData.codecPrivate) } : null,
|
|
30091
30075
|
{ id: 22186 /* CodecDelay */, data: 0 },
|
|
30092
30076
|
{ id: 22203 /* SeekPreRoll */, data: seekPreRollNs },
|
|
30093
30077
|
trackData.track.metadata.name !== void 0 ? { id: 21358 /* Name */, data: new EBMLUnicodeString(trackData.track.metadata.name) } : null,
|
|
@@ -30100,10 +30084,6 @@ var Mediabunny = (() => {
|
|
|
30100
30084
|
videoSpecificTrackInfo(trackData) {
|
|
30101
30085
|
const { frameRate, rotation } = trackData.track.metadata;
|
|
30102
30086
|
const elements = [
|
|
30103
|
-
trackData.info.decoderConfig.description ? {
|
|
30104
|
-
id: 25506 /* CodecPrivate */,
|
|
30105
|
-
data: toUint8Array(trackData.info.decoderConfig.description)
|
|
30106
|
-
} : null,
|
|
30107
30087
|
frameRate ? {
|
|
30108
30088
|
id: 2352003 /* DefaultDuration */,
|
|
30109
30089
|
data: 1e9 / frameRate
|
|
@@ -30163,10 +30143,6 @@ var Mediabunny = (() => {
|
|
|
30163
30143
|
audioSpecificTrackInfo(trackData) {
|
|
30164
30144
|
const pcmInfo = PCM_AUDIO_CODECS.includes(trackData.track.source._codec) ? parsePcmCodec(trackData.track.source._codec) : null;
|
|
30165
30145
|
return [
|
|
30166
|
-
trackData.info.decoderConfig.description ? {
|
|
30167
|
-
id: 25506 /* CodecPrivate */,
|
|
30168
|
-
data: toUint8Array(trackData.info.decoderConfig.description)
|
|
30169
|
-
} : null,
|
|
30170
30146
|
{ id: 225 /* Audio */, data: [
|
|
30171
30147
|
{ id: 181 /* SamplingFrequency */, data: new EBMLFloat32(trackData.info.sampleRate) },
|
|
30172
30148
|
{ id: 159 /* Channels */, data: trackData.info.numberOfChannels },
|
|
@@ -30174,10 +30150,9 @@ var Mediabunny = (() => {
|
|
|
30174
30150
|
] }
|
|
30175
30151
|
];
|
|
30176
30152
|
}
|
|
30153
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
30177
30154
|
subtitleSpecificTrackInfo(trackData) {
|
|
30178
|
-
return [
|
|
30179
|
-
{ id: 25506 /* CodecPrivate */, data: textEncoder.encode(trackData.info.config.description) }
|
|
30180
|
-
];
|
|
30155
|
+
return [];
|
|
30181
30156
|
}
|
|
30182
30157
|
maybeCreateTags() {
|
|
30183
30158
|
const simpleTags = [];
|
|
@@ -30466,22 +30441,19 @@ var Mediabunny = (() => {
|
|
|
30466
30441
|
},
|
|
30467
30442
|
chunkQueue: [],
|
|
30468
30443
|
lastWrittenMsTimestamp: null,
|
|
30444
|
+
codecPrivate: meta.decoderConfig.description ?? null,
|
|
30469
30445
|
closed: false
|
|
30470
30446
|
};
|
|
30471
30447
|
if (track.source._codec === "vp9") {
|
|
30472
|
-
newTrackData.
|
|
30473
|
-
|
|
30474
|
-
|
|
30475
|
-
generateVp9CodecConfigurationFromCodecString(newTrackData.info.decoderConfig.codec)
|
|
30476
|
-
)
|
|
30477
|
-
};
|
|
30448
|
+
newTrackData.codecPrivate = new Uint8Array(
|
|
30449
|
+
generateVp9CodecConfigurationFromCodecString(newTrackData.info.decoderConfig.codec)
|
|
30450
|
+
);
|
|
30478
30451
|
} else if (track.source._codec === "av1") {
|
|
30479
|
-
newTrackData.
|
|
30480
|
-
|
|
30481
|
-
|
|
30482
|
-
|
|
30483
|
-
|
|
30484
|
-
};
|
|
30452
|
+
newTrackData.codecPrivate = new Uint8Array(
|
|
30453
|
+
generateAv1CodecConfigurationFromCodecString(newTrackData.info.decoderConfig.codec)
|
|
30454
|
+
);
|
|
30455
|
+
} else if (track.source._codec === "prores") {
|
|
30456
|
+
newTrackData.codecPrivate = textEncoder.encode(meta.decoderConfig.codec);
|
|
30485
30457
|
}
|
|
30486
30458
|
this.trackDatas.push(newTrackData);
|
|
30487
30459
|
this.trackDatas.sort((a, b) => a.track.id - b.track.id);
|
|
@@ -30530,6 +30502,7 @@ var Mediabunny = (() => {
|
|
|
30530
30502
|
},
|
|
30531
30503
|
chunkQueue: [],
|
|
30532
30504
|
lastWrittenMsTimestamp: null,
|
|
30505
|
+
codecPrivate: decoderConfig.description ?? null,
|
|
30533
30506
|
closed: false
|
|
30534
30507
|
};
|
|
30535
30508
|
this.trackDatas.push(newTrackData);
|
|
@@ -30555,6 +30528,7 @@ var Mediabunny = (() => {
|
|
|
30555
30528
|
},
|
|
30556
30529
|
chunkQueue: [],
|
|
30557
30530
|
lastWrittenMsTimestamp: null,
|
|
30531
|
+
codecPrivate: textEncoder.encode(meta.config.description),
|
|
30558
30532
|
closed: false
|
|
30559
30533
|
};
|
|
30560
30534
|
this.trackDatas.push(newTrackData);
|
|
@@ -32628,8 +32602,15 @@ ${cue.notes ?? ""}`;
|
|
|
32628
32602
|
* So, we keep track of the encoder error and throw it as soon as we get the chance.
|
|
32629
32603
|
*/
|
|
32630
32604
|
this.error = null;
|
|
32631
|
-
this.
|
|
32605
|
+
this.errorSet = false;
|
|
32632
32606
|
this.lastMuxerPromise = Promise.resolve();
|
|
32607
|
+
this.closed = false;
|
|
32608
|
+
}
|
|
32609
|
+
setError(error) {
|
|
32610
|
+
if (!this.errorSet) {
|
|
32611
|
+
this.error = error;
|
|
32612
|
+
this.errorSet = true;
|
|
32613
|
+
}
|
|
32633
32614
|
}
|
|
32634
32615
|
async add(videoSample, shouldClose, encodeOptions) {
|
|
32635
32616
|
const originalSample = videoSample;
|
|
@@ -32780,7 +32761,8 @@ ${cue.notes ?? ""}`;
|
|
|
32780
32761
|
if (this.customEncoder) {
|
|
32781
32762
|
this.customEncoderQueueSize++;
|
|
32782
32763
|
const clonedSample = sampleToEncode.clone();
|
|
32783
|
-
const promise = this.customEncoderCallSerializer.call(() => this.customEncoder.encode(clonedSample, finalEncodeOptions)).
|
|
32764
|
+
const promise = this.customEncoderCallSerializer.call(() => this.customEncoder.encode(clonedSample, finalEncodeOptions)).catch((error) => this.setError(error)).finally(() => {
|
|
32765
|
+
this.customEncoderQueueSize--;
|
|
32784
32766
|
clonedSample.close();
|
|
32785
32767
|
});
|
|
32786
32768
|
if (this.customEncoderQueueSize >= 4) {
|
|
@@ -32824,12 +32806,10 @@ ${cue.notes ?? ""}`;
|
|
|
32824
32806
|
this.encoder.encode(videoFrame, finalEncodeOptions);
|
|
32825
32807
|
videoFrame.close();
|
|
32826
32808
|
} else {
|
|
32827
|
-
const width = videoFrame.displayWidth;
|
|
32828
|
-
const height = videoFrame.displayHeight;
|
|
32829
32809
|
if (!this.splitter) {
|
|
32830
|
-
this.splitter = new ColorAlphaSplitter(
|
|
32810
|
+
this.splitter = new ColorAlphaSplitter();
|
|
32831
32811
|
}
|
|
32832
|
-
const { colorFrame, alphaFrame } = await this.splitter.
|
|
32812
|
+
const { colorFrame, alphaFrame } = await this.splitter.split(videoFrame);
|
|
32833
32813
|
this.alphaFrameQueue.push(alphaFrame);
|
|
32834
32814
|
this.encoder.encode(colorFrame, finalEncodeOptions);
|
|
32835
32815
|
colorFrame.close();
|
|
@@ -32893,9 +32873,12 @@ ${cue.notes ?? ""}`;
|
|
|
32893
32873
|
maybeEnsureIsKeyPacket(this.source._connectedTrack, packet);
|
|
32894
32874
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
|
32895
32875
|
this.lastMuxerPromise = this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta).catch((error) => {
|
|
32896
|
-
this.error
|
|
32876
|
+
this.setError(error);
|
|
32897
32877
|
});
|
|
32898
32878
|
};
|
|
32879
|
+
this.customEncoder.onError = (error) => {
|
|
32880
|
+
this.setError(error);
|
|
32881
|
+
};
|
|
32899
32882
|
await this.customEncoder.init();
|
|
32900
32883
|
} else {
|
|
32901
32884
|
if (typeof VideoEncoder === "undefined") {
|
|
@@ -32953,7 +32936,7 @@ ${cue.notes ?? ""}`;
|
|
|
32953
32936
|
maybeEnsureIsKeyPacket(this.source._connectedTrack, packet);
|
|
32954
32937
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
|
32955
32938
|
this.lastMuxerPromise = this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta).catch((error) => {
|
|
32956
|
-
this.error
|
|
32939
|
+
this.setError(error);
|
|
32957
32940
|
});
|
|
32958
32941
|
this.emittedEncoderPackets++;
|
|
32959
32942
|
};
|
|
@@ -32987,7 +32970,7 @@ ${cue.notes ?? ""}`;
|
|
|
32987
32970
|
},
|
|
32988
32971
|
error: (error) => {
|
|
32989
32972
|
error.stack = stack;
|
|
32990
|
-
this.error
|
|
32973
|
+
this.setError(error);
|
|
32991
32974
|
}
|
|
32992
32975
|
});
|
|
32993
32976
|
this.encoder.configure(encoderConfig);
|
|
@@ -33011,7 +32994,7 @@ ${cue.notes ?? ""}`;
|
|
|
33011
32994
|
},
|
|
33012
32995
|
error: (error) => {
|
|
33013
32996
|
error.stack = stack2;
|
|
33014
|
-
this.error
|
|
32997
|
+
this.setError(error);
|
|
33015
32998
|
}
|
|
33016
32999
|
});
|
|
33017
33000
|
this.alphaEncoder.configure(encoderConfig);
|
|
@@ -33065,274 +33048,28 @@ ${cue.notes ?? ""}`;
|
|
|
33065
33048
|
}
|
|
33066
33049
|
}
|
|
33067
33050
|
checkForEncoderError() {
|
|
33068
|
-
if (this.
|
|
33051
|
+
if (this.errorSet) {
|
|
33069
33052
|
throw this.error;
|
|
33070
33053
|
}
|
|
33071
33054
|
}
|
|
33072
33055
|
};
|
|
33073
|
-
var
|
|
33074
|
-
var
|
|
33075
|
-
constructor(
|
|
33076
|
-
this.canvas = null;
|
|
33077
|
-
this.gl = null;
|
|
33078
|
-
this.colorProgram = null;
|
|
33079
|
-
this.alphaProgram = null;
|
|
33080
|
-
this.vao = null;
|
|
33081
|
-
this.sourceTexture = null;
|
|
33082
|
-
this.alphaResolutionLocation = null;
|
|
33056
|
+
var splitterWorkerUrl = null;
|
|
33057
|
+
var ColorAlphaSplitter = class {
|
|
33058
|
+
constructor() {
|
|
33083
33059
|
this.worker = null;
|
|
33084
33060
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
33085
33061
|
this.nextRequestId = 0;
|
|
33086
|
-
const canMakeCanvas = typeof OffscreenCanvas !== "undefined" || typeof document !== "undefined" && typeof document.createElement === "function";
|
|
33087
|
-
if (!_ColorAlphaSplitter.forceCpu && canMakeCanvas && !splitterGpuUnavailable) {
|
|
33088
|
-
try {
|
|
33089
|
-
if (typeof OffscreenCanvas !== "undefined") {
|
|
33090
|
-
this.canvas = new OffscreenCanvas(initialWidth, initialHeight);
|
|
33091
|
-
} else {
|
|
33092
|
-
this.canvas = document.createElement("canvas");
|
|
33093
|
-
this.canvas.width = initialWidth;
|
|
33094
|
-
this.canvas.height = initialHeight;
|
|
33095
|
-
}
|
|
33096
|
-
const gl = this.canvas.getContext("webgl2", {
|
|
33097
|
-
alpha: true
|
|
33098
|
-
// Needed due to the YUV thing we do for alpha
|
|
33099
|
-
});
|
|
33100
|
-
if (!gl) {
|
|
33101
|
-
throw new Error("Couldn't acquire WebGL 2 context.");
|
|
33102
|
-
}
|
|
33103
|
-
this.gl = gl;
|
|
33104
|
-
this.colorProgram = this.createColorProgram();
|
|
33105
|
-
this.alphaProgram = this.createAlphaProgram();
|
|
33106
|
-
this.vao = this.createVAO();
|
|
33107
|
-
this.sourceTexture = this.createTexture();
|
|
33108
|
-
this.alphaResolutionLocation = this.gl.getUniformLocation(this.alphaProgram, "u_resolution");
|
|
33109
|
-
this.gl.useProgram(this.colorProgram);
|
|
33110
|
-
this.gl.uniform1i(this.gl.getUniformLocation(this.colorProgram, "u_sourceTexture"), 0);
|
|
33111
|
-
this.gl.useProgram(this.alphaProgram);
|
|
33112
|
-
this.gl.uniform1i(this.gl.getUniformLocation(this.alphaProgram, "u_sourceTexture"), 0);
|
|
33113
|
-
} catch (error) {
|
|
33114
|
-
this.gl = null;
|
|
33115
|
-
this.canvas = null;
|
|
33116
|
-
splitterGpuUnavailable = true;
|
|
33117
|
-
Logging._warn("Falling back to CPU for color/alpha splitting.", error);
|
|
33118
|
-
}
|
|
33119
|
-
}
|
|
33120
33062
|
}
|
|
33121
|
-
|
|
33122
|
-
if (this.gl) {
|
|
33123
|
-
return this.updateGpu(sourceFrame);
|
|
33124
|
-
} else {
|
|
33125
|
-
return this.updateCpu(sourceFrame);
|
|
33126
|
-
}
|
|
33127
|
-
}
|
|
33128
|
-
updateGpu(sourceFrame) {
|
|
33129
|
-
assert(this.gl);
|
|
33130
|
-
assert(this.canvas);
|
|
33131
|
-
if (sourceFrame.displayWidth !== this.canvas.width || sourceFrame.displayHeight !== this.canvas.height) {
|
|
33132
|
-
this.canvas.width = sourceFrame.displayWidth;
|
|
33133
|
-
this.canvas.height = sourceFrame.displayHeight;
|
|
33134
|
-
}
|
|
33135
|
-
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
33136
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, this.sourceTexture);
|
|
33137
|
-
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, sourceFrame);
|
|
33138
|
-
const colorFrame = this.runColorProgram(sourceFrame);
|
|
33139
|
-
const alphaFrame = this.runAlphaProgram(sourceFrame);
|
|
33140
|
-
sourceFrame.close();
|
|
33141
|
-
return { colorFrame, alphaFrame };
|
|
33142
|
-
}
|
|
33143
|
-
createVertexShader() {
|
|
33144
|
-
assert(this.gl);
|
|
33145
|
-
return this.createShader(this.gl.VERTEX_SHADER, `#version 300 es
|
|
33146
|
-
in vec2 a_position;
|
|
33147
|
-
in vec2 a_texCoord;
|
|
33148
|
-
out vec2 v_texCoord;
|
|
33149
|
-
|
|
33150
|
-
void main() {
|
|
33151
|
-
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
33152
|
-
v_texCoord = a_texCoord;
|
|
33153
|
-
}
|
|
33154
|
-
`);
|
|
33155
|
-
}
|
|
33156
|
-
createColorProgram() {
|
|
33157
|
-
assert(this.gl);
|
|
33158
|
-
const vertexShader = this.createVertexShader();
|
|
33159
|
-
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, `#version 300 es
|
|
33160
|
-
precision highp float;
|
|
33161
|
-
|
|
33162
|
-
uniform sampler2D u_sourceTexture;
|
|
33163
|
-
in vec2 v_texCoord;
|
|
33164
|
-
out vec4 fragColor;
|
|
33165
|
-
|
|
33166
|
-
void main() {
|
|
33167
|
-
vec4 source = texture(u_sourceTexture, v_texCoord);
|
|
33168
|
-
fragColor = vec4(source.rgb, 1.0);
|
|
33169
|
-
}
|
|
33170
|
-
`);
|
|
33171
|
-
const program = this.gl.createProgram();
|
|
33172
|
-
this.gl.attachShader(program, vertexShader);
|
|
33173
|
-
this.gl.attachShader(program, fragmentShader);
|
|
33174
|
-
this.gl.linkProgram(program);
|
|
33175
|
-
return program;
|
|
33176
|
-
}
|
|
33177
|
-
createAlphaProgram() {
|
|
33178
|
-
assert(this.gl);
|
|
33179
|
-
const vertexShader = this.createVertexShader();
|
|
33180
|
-
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, `#version 300 es
|
|
33181
|
-
precision highp float;
|
|
33182
|
-
|
|
33183
|
-
uniform sampler2D u_sourceTexture;
|
|
33184
|
-
uniform vec2 u_resolution; // The width and height of the canvas
|
|
33185
|
-
in vec2 v_texCoord;
|
|
33186
|
-
out vec4 fragColor;
|
|
33187
|
-
|
|
33188
|
-
// This function determines the value for a single byte in the YUV stream
|
|
33189
|
-
float getByteValue(float byteOffset) {
|
|
33190
|
-
float width = u_resolution.x;
|
|
33191
|
-
float height = u_resolution.y;
|
|
33192
|
-
|
|
33193
|
-
float yPlaneSize = width * height;
|
|
33194
|
-
|
|
33195
|
-
if (byteOffset < yPlaneSize) {
|
|
33196
|
-
// This byte is in the luma plane. Find the corresponding pixel coordinates to sample from
|
|
33197
|
-
float y = floor(byteOffset / width);
|
|
33198
|
-
float x = mod(byteOffset, width);
|
|
33199
|
-
|
|
33200
|
-
// Add 0.5 to sample the center of the texel
|
|
33201
|
-
vec2 sampleCoord = (vec2(x, y) + 0.5) / u_resolution;
|
|
33202
|
-
|
|
33203
|
-
// The luma value is the alpha from the source texture
|
|
33204
|
-
return texture(u_sourceTexture, sampleCoord).a;
|
|
33205
|
-
} else {
|
|
33206
|
-
// Write a fixed value for chroma and beyond
|
|
33207
|
-
return 128.0 / 255.0;
|
|
33208
|
-
}
|
|
33209
|
-
}
|
|
33210
|
-
|
|
33211
|
-
void main() {
|
|
33212
|
-
// Each fragment writes 4 bytes (R, G, B, A)
|
|
33213
|
-
float pixelIndex = floor(gl_FragCoord.y) * u_resolution.x + floor(gl_FragCoord.x);
|
|
33214
|
-
float baseByteOffset = pixelIndex * 4.0;
|
|
33215
|
-
|
|
33216
|
-
vec4 result;
|
|
33217
|
-
for (int i = 0; i < 4; i++) {
|
|
33218
|
-
float currentByteOffset = baseByteOffset + float(i);
|
|
33219
|
-
result[i] = getByteValue(currentByteOffset);
|
|
33220
|
-
}
|
|
33221
|
-
|
|
33222
|
-
fragColor = result;
|
|
33223
|
-
}
|
|
33224
|
-
`);
|
|
33225
|
-
const program = this.gl.createProgram();
|
|
33226
|
-
this.gl.attachShader(program, vertexShader);
|
|
33227
|
-
this.gl.attachShader(program, fragmentShader);
|
|
33228
|
-
this.gl.linkProgram(program);
|
|
33229
|
-
return program;
|
|
33230
|
-
}
|
|
33231
|
-
createShader(type, source) {
|
|
33232
|
-
assert(this.gl);
|
|
33233
|
-
const shader = this.gl.createShader(type);
|
|
33234
|
-
this.gl.shaderSource(shader, source);
|
|
33235
|
-
this.gl.compileShader(shader);
|
|
33236
|
-
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
|
|
33237
|
-
Logging._error("Shader compile error:", this.gl.getShaderInfoLog(shader));
|
|
33238
|
-
}
|
|
33239
|
-
return shader;
|
|
33240
|
-
}
|
|
33241
|
-
createVAO() {
|
|
33242
|
-
assert(this.gl);
|
|
33243
|
-
assert(this.colorProgram);
|
|
33244
|
-
const vao = this.gl.createVertexArray();
|
|
33245
|
-
this.gl.bindVertexArray(vao);
|
|
33246
|
-
const vertices = new Float32Array([
|
|
33247
|
-
-1,
|
|
33248
|
-
-1,
|
|
33249
|
-
0,
|
|
33250
|
-
1,
|
|
33251
|
-
1,
|
|
33252
|
-
-1,
|
|
33253
|
-
1,
|
|
33254
|
-
1,
|
|
33255
|
-
-1,
|
|
33256
|
-
1,
|
|
33257
|
-
0,
|
|
33258
|
-
0,
|
|
33259
|
-
1,
|
|
33260
|
-
1,
|
|
33261
|
-
1,
|
|
33262
|
-
0
|
|
33263
|
-
]);
|
|
33264
|
-
const buffer = this.gl.createBuffer();
|
|
33265
|
-
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
|
|
33266
|
-
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW);
|
|
33267
|
-
const positionLocation = this.gl.getAttribLocation(this.colorProgram, "a_position");
|
|
33268
|
-
const texCoordLocation = this.gl.getAttribLocation(this.colorProgram, "a_texCoord");
|
|
33269
|
-
this.gl.enableVertexAttribArray(positionLocation);
|
|
33270
|
-
this.gl.vertexAttribPointer(positionLocation, 2, this.gl.FLOAT, false, 16, 0);
|
|
33271
|
-
this.gl.enableVertexAttribArray(texCoordLocation);
|
|
33272
|
-
this.gl.vertexAttribPointer(texCoordLocation, 2, this.gl.FLOAT, false, 16, 8);
|
|
33273
|
-
return vao;
|
|
33274
|
-
}
|
|
33275
|
-
createTexture() {
|
|
33276
|
-
assert(this.gl);
|
|
33277
|
-
const texture = this.gl.createTexture();
|
|
33278
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
33279
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
33280
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
33281
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
|
33282
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
|
|
33283
|
-
return texture;
|
|
33284
|
-
}
|
|
33285
|
-
runColorProgram(sourceFrame) {
|
|
33286
|
-
assert(this.gl);
|
|
33287
|
-
assert(this.canvas);
|
|
33288
|
-
this.gl.useProgram(this.colorProgram);
|
|
33289
|
-
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
33290
|
-
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
33291
|
-
this.gl.bindVertexArray(this.vao);
|
|
33292
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
33293
|
-
return new VideoFrame(this.canvas, {
|
|
33294
|
-
timestamp: sourceFrame.timestamp,
|
|
33295
|
-
duration: sourceFrame.duration ?? void 0,
|
|
33296
|
-
alpha: "discard"
|
|
33297
|
-
});
|
|
33298
|
-
}
|
|
33299
|
-
runAlphaProgram(sourceFrame) {
|
|
33300
|
-
assert(this.gl);
|
|
33301
|
-
assert(this.canvas);
|
|
33302
|
-
this.gl.useProgram(this.alphaProgram);
|
|
33303
|
-
this.gl.uniform2f(this.alphaResolutionLocation, this.canvas.width, this.canvas.height);
|
|
33304
|
-
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
33305
|
-
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
33306
|
-
this.gl.bindVertexArray(this.vao);
|
|
33307
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
33308
|
-
const { width, height } = this.canvas;
|
|
33309
|
-
const chromaSamples = Math.ceil(width / 2) * Math.ceil(height / 2);
|
|
33310
|
-
const yuvSize = width * height + chromaSamples * 2;
|
|
33311
|
-
const requiredHeight = Math.ceil(yuvSize / (width * 4));
|
|
33312
|
-
let yuv = new Uint8Array(4 * width * requiredHeight);
|
|
33313
|
-
this.gl.readPixels(0, 0, width, requiredHeight, this.gl.RGBA, this.gl.UNSIGNED_BYTE, yuv);
|
|
33314
|
-
yuv = yuv.subarray(0, yuvSize);
|
|
33315
|
-
assert(yuv[width * height] === 128);
|
|
33316
|
-
assert(yuv[yuv.length - 1] === 128);
|
|
33317
|
-
const init = {
|
|
33318
|
-
format: "I420",
|
|
33319
|
-
codedWidth: width,
|
|
33320
|
-
codedHeight: height,
|
|
33321
|
-
timestamp: sourceFrame.timestamp,
|
|
33322
|
-
duration: sourceFrame.duration ?? void 0,
|
|
33323
|
-
transfer: [yuv.buffer]
|
|
33324
|
-
};
|
|
33325
|
-
return new VideoFrame(yuv, init);
|
|
33326
|
-
}
|
|
33327
|
-
updateCpu(sourceFrame) {
|
|
33063
|
+
split(sourceFrame) {
|
|
33328
33064
|
if (!this.worker) {
|
|
33329
|
-
|
|
33330
|
-
|
|
33331
|
-
|
|
33332
|
-
|
|
33333
|
-
|
|
33334
|
-
|
|
33335
|
-
|
|
33065
|
+
if (!splitterWorkerUrl) {
|
|
33066
|
+
const blob = new Blob(
|
|
33067
|
+
[`(${colorAlphaSplitterWorkerCode.toString()})()`],
|
|
33068
|
+
{ type: "application/javascript" }
|
|
33069
|
+
);
|
|
33070
|
+
splitterWorkerUrl = URL.createObjectURL(blob);
|
|
33071
|
+
}
|
|
33072
|
+
this.worker = new Worker(splitterWorkerUrl);
|
|
33336
33073
|
this.worker.addEventListener("message", (event) => {
|
|
33337
33074
|
const data = event.data;
|
|
33338
33075
|
const pending2 = this.pendingRequests.get(data.id);
|
|
@@ -33361,9 +33098,6 @@ ${cue.notes ?? ""}`;
|
|
|
33361
33098
|
return pending.promise;
|
|
33362
33099
|
}
|
|
33363
33100
|
close() {
|
|
33364
|
-
this.gl?.getExtension("WEBGL_lose_context")?.loseContext();
|
|
33365
|
-
this.gl = null;
|
|
33366
|
-
this.canvas = null;
|
|
33367
33101
|
this.worker?.terminate();
|
|
33368
33102
|
this.worker = null;
|
|
33369
33103
|
const error = new Error("Color/alpha splitter closed.");
|
|
@@ -33373,8 +33107,6 @@ ${cue.notes ?? ""}`;
|
|
|
33373
33107
|
this.pendingRequests.clear();
|
|
33374
33108
|
}
|
|
33375
33109
|
};
|
|
33376
|
-
_ColorAlphaSplitter.forceCpu = true;
|
|
33377
|
-
var ColorAlphaSplitter = _ColorAlphaSplitter;
|
|
33378
33110
|
var colorAlphaSplitterWorkerCode = () => {
|
|
33379
33111
|
let cpuSourceBuffer = null;
|
|
33380
33112
|
let chain = Promise.resolve();
|
|
@@ -33396,21 +33128,21 @@ ${cue.notes ?? ""}`;
|
|
|
33396
33128
|
if (!format) {
|
|
33397
33129
|
throw new Error("CPU color/alpha splitting requires a known VideoFrame format.");
|
|
33398
33130
|
}
|
|
33399
|
-
const width = sourceFrame.codedWidth;
|
|
33400
|
-
const height = sourceFrame.codedHeight;
|
|
33401
33131
|
const sourceSize = sourceFrame.allocationSize();
|
|
33402
33132
|
if (!cpuSourceBuffer || cpuSourceBuffer.byteLength !== sourceSize) {
|
|
33403
33133
|
cpuSourceBuffer = new Uint8Array(sourceSize);
|
|
33404
33134
|
}
|
|
33405
33135
|
await sourceFrame.copyTo(cpuSourceBuffer);
|
|
33406
33136
|
if (format === "RGBA" || format === "BGRA") {
|
|
33407
|
-
return splitInterleavedRgba(cpuSourceBuffer,
|
|
33137
|
+
return splitInterleavedRgba(cpuSourceBuffer, format, sourceFrame);
|
|
33408
33138
|
} else if (format === "I420A" || format === "I420AP10" || format === "I420AP12" || format === "I422A" || format === "I422AP10" || format === "I422AP12" || format === "I444A" || format === "I444AP10" || format === "I444AP12") {
|
|
33409
|
-
return splitPlanarYuvA(cpuSourceBuffer,
|
|
33139
|
+
return splitPlanarYuvA(cpuSourceBuffer, format, sourceFrame);
|
|
33410
33140
|
}
|
|
33411
33141
|
throw new Error(`CPU color/alpha splitting does not support format '${format}'.`);
|
|
33412
33142
|
};
|
|
33413
|
-
const splitInterleavedRgba = (source,
|
|
33143
|
+
const splitInterleavedRgba = (source, format, sourceFrame) => {
|
|
33144
|
+
const width = sourceFrame.visibleRect?.width ?? sourceFrame.codedWidth;
|
|
33145
|
+
const height = sourceFrame.visibleRect?.height ?? sourceFrame.codedHeight;
|
|
33414
33146
|
const pixelCount = width * height;
|
|
33415
33147
|
const chromaW = Math.ceil(width / 2);
|
|
33416
33148
|
const chromaH = Math.ceil(height / 2);
|
|
@@ -33439,7 +33171,9 @@ ${cue.notes ?? ""}`;
|
|
|
33439
33171
|
const alphaFrame = new VideoFrame(alphaBuffer, alphaInit);
|
|
33440
33172
|
return { colorFrame, alphaFrame };
|
|
33441
33173
|
};
|
|
33442
|
-
const splitPlanarYuvA = (source,
|
|
33174
|
+
const splitPlanarYuvA = (source, format, sourceFrame) => {
|
|
33175
|
+
const width = sourceFrame.visibleRect?.width ?? sourceFrame.codedWidth;
|
|
33176
|
+
const height = sourceFrame.visibleRect?.height ?? sourceFrame.codedHeight;
|
|
33443
33177
|
const is10 = format.includes("P10");
|
|
33444
33178
|
const is12 = format.includes("P12");
|
|
33445
33179
|
const bytesPerSample = is10 || is12 ? 2 : 1;
|
|
@@ -33904,9 +33638,16 @@ ${cue.notes ?? ""}`;
|
|
|
33904
33638
|
* So, we keep track of the encoder error and throw it as soon as we get the chance.
|
|
33905
33639
|
*/
|
|
33906
33640
|
this.error = null;
|
|
33641
|
+
this.errorSet = false;
|
|
33907
33642
|
this.lastMuxerPromise = Promise.resolve();
|
|
33908
33643
|
this.closed = false;
|
|
33909
33644
|
}
|
|
33645
|
+
setError(error) {
|
|
33646
|
+
if (!this.errorSet) {
|
|
33647
|
+
this.error = error;
|
|
33648
|
+
this.errorSet = true;
|
|
33649
|
+
}
|
|
33650
|
+
}
|
|
33910
33651
|
async add(audioSample, shouldClose) {
|
|
33911
33652
|
try {
|
|
33912
33653
|
this.checkForEncoderError();
|
|
@@ -34028,7 +33769,8 @@ ${cue.notes ?? ""}`;
|
|
|
34028
33769
|
if (this.customEncoder) {
|
|
34029
33770
|
this.customEncoderQueueSize++;
|
|
34030
33771
|
const clonedSample = audioSample.clone();
|
|
34031
|
-
const promise = this.customEncoderCallSerializer.call(() => this.customEncoder.encode(clonedSample)).
|
|
33772
|
+
const promise = this.customEncoderCallSerializer.call(() => this.customEncoder.encode(clonedSample)).catch((error) => this.setError(error)).finally(() => {
|
|
33773
|
+
this.customEncoderQueueSize--;
|
|
34032
33774
|
clonedSample.close();
|
|
34033
33775
|
});
|
|
34034
33776
|
if (this.customEncoderQueueSize >= 4) {
|
|
@@ -34134,9 +33876,12 @@ ${cue.notes ?? ""}`;
|
|
|
34134
33876
|
}
|
|
34135
33877
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
|
34136
33878
|
this.lastMuxerPromise = this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta).catch((error) => {
|
|
34137
|
-
this.error
|
|
33879
|
+
this.setError(error);
|
|
34138
33880
|
});
|
|
34139
33881
|
};
|
|
33882
|
+
this.customEncoder.onError = (error) => {
|
|
33883
|
+
this.setError(error);
|
|
33884
|
+
};
|
|
34140
33885
|
await this.customEncoder.init();
|
|
34141
33886
|
} else if (PCM_AUDIO_CODECS.includes(this.encodingConfig.codec)) {
|
|
34142
33887
|
this.initPcmEncoder();
|
|
@@ -34179,12 +33924,12 @@ ${cue.notes ?? ""}`;
|
|
|
34179
33924
|
});
|
|
34180
33925
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
|
34181
33926
|
this.lastMuxerPromise = this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta).catch((error) => {
|
|
34182
|
-
this.error
|
|
33927
|
+
this.setError(error);
|
|
34183
33928
|
});
|
|
34184
33929
|
},
|
|
34185
33930
|
error: (error) => {
|
|
34186
33931
|
error.stack = stack;
|
|
34187
|
-
this.error
|
|
33932
|
+
this.setError(error);
|
|
34188
33933
|
}
|
|
34189
33934
|
});
|
|
34190
33935
|
this.encoder.configure(encoderConfig);
|
|
@@ -34325,7 +34070,7 @@ ${cue.notes ?? ""}`;
|
|
|
34325
34070
|
}
|
|
34326
34071
|
}
|
|
34327
34072
|
checkForEncoderError() {
|
|
34328
|
-
if (this.
|
|
34073
|
+
if (this.errorSet) {
|
|
34329
34074
|
throw this.error;
|
|
34330
34075
|
}
|
|
34331
34076
|
}
|
|
@@ -34685,12 +34430,14 @@ ${cue.notes ?? ""}`;
|
|
|
34685
34430
|
/** @internal */
|
|
34686
34431
|
this._error = null;
|
|
34687
34432
|
/** @internal */
|
|
34433
|
+
this._errorSet = false;
|
|
34434
|
+
/** @internal */
|
|
34688
34435
|
this._lastMuxerPromise = Promise.resolve();
|
|
34689
34436
|
this._parser = new SubtitleParser({
|
|
34690
34437
|
codec,
|
|
34691
34438
|
output: (cue, metadata) => {
|
|
34692
34439
|
this._lastMuxerPromise = this._connectedTrack.output._muxer.addSubtitleCue(this._connectedTrack, cue, metadata).catch((error) => {
|
|
34693
|
-
this.
|
|
34440
|
+
this._setError(error);
|
|
34694
34441
|
});
|
|
34695
34442
|
}
|
|
34696
34443
|
});
|
|
@@ -34712,8 +34459,15 @@ ${cue.notes ?? ""}`;
|
|
|
34712
34459
|
return this._lastMuxerPromise;
|
|
34713
34460
|
}
|
|
34714
34461
|
/** @internal */
|
|
34462
|
+
_setError(error) {
|
|
34463
|
+
if (!this._errorSet) {
|
|
34464
|
+
this._error = error;
|
|
34465
|
+
this._errorSet = true;
|
|
34466
|
+
}
|
|
34467
|
+
}
|
|
34468
|
+
/** @internal */
|
|
34715
34469
|
_checkForError() {
|
|
34716
|
-
if (this.
|
|
34470
|
+
if (this._errorSet) {
|
|
34717
34471
|
throw this._error;
|
|
34718
34472
|
}
|
|
34719
34473
|
}
|
|
@@ -37739,7 +37493,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37739
37493
|
let numberOfChannels = trackOptions.numberOfChannels ?? originalNumberOfChannels;
|
|
37740
37494
|
let sampleRate = trackOptions.sampleRate ?? originalSampleRate;
|
|
37741
37495
|
const needsTrimming = firstTimestamp < this._startTimestamp;
|
|
37742
|
-
|
|
37496
|
+
let needsPadding = firstTimestamp > this._startTimestamp && !this.output.format.supportsTimestampedMediaData;
|
|
37743
37497
|
let audioCodecs = this.output.format.getSupportedAudioCodecs();
|
|
37744
37498
|
if (!trackOptions.forceTranscode && !trackOptions.bitrate && numberOfChannels === originalNumberOfChannels && sampleRate === originalSampleRate && !needsTrimming && !needsPadding && audioCodecs.includes(sourceCodec) && (!trackOptions.codec || trackOptions.codec === sourceCodec) && !trackOptions.process && trackOptions.sampleFormat === void 0) {
|
|
37745
37499
|
const source = new EncodedAudioPacketSource(sourceCodec);
|
|
@@ -37835,24 +37589,32 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37835
37589
|
audioSource = source;
|
|
37836
37590
|
this._trackPromises.push((async () => {
|
|
37837
37591
|
await this._started;
|
|
37838
|
-
if (needsPadding) {
|
|
37839
|
-
const paddingLength = firstTimestamp - this._startTimestamp;
|
|
37840
|
-
const paddingLengthSamples = Math.round(paddingLength * originalSampleRate);
|
|
37841
|
-
const silentSample = new AudioSample({
|
|
37842
|
-
data: new Float32Array(paddingLengthSamples * originalNumberOfChannels),
|
|
37843
|
-
format: "f32-planar",
|
|
37844
|
-
numberOfChannels: originalNumberOfChannels,
|
|
37845
|
-
sampleRate: originalSampleRate,
|
|
37846
|
-
timestamp: 0
|
|
37847
|
-
});
|
|
37848
|
-
await this._registerAudioSample(silentSample, source, outputTrackId, () => lastSampleTimestamp);
|
|
37849
|
-
}
|
|
37850
37592
|
const sink = new AudioSampleSink(track);
|
|
37851
37593
|
for await (let sample of sink.samples(this._startTimestamp, this._endTimestamp)) {
|
|
37852
37594
|
if (this._canceled) {
|
|
37853
37595
|
sample.close();
|
|
37854
37596
|
return;
|
|
37855
37597
|
}
|
|
37598
|
+
if (needsPadding) {
|
|
37599
|
+
const paddingLength = firstTimestamp - this._startTimestamp;
|
|
37600
|
+
const paddingLengthSamples = Math.round(paddingLength * originalSampleRate);
|
|
37601
|
+
const bytesPerSample = getBytesPerSample(sample.format);
|
|
37602
|
+
const data = new Uint8Array(bytesPerSample * paddingLengthSamples * originalNumberOfChannels);
|
|
37603
|
+
if (sample.format === "u8" || sample.format === "u8-planar") {
|
|
37604
|
+
data.fill(2 ** 7);
|
|
37605
|
+
}
|
|
37606
|
+
const silentSample = new AudioSample({
|
|
37607
|
+
data,
|
|
37608
|
+
// Use the same format the decoder is spitting out. This avoids feeding changing sample
|
|
37609
|
+
// formats to the audio encoder.
|
|
37610
|
+
format: sample.format,
|
|
37611
|
+
numberOfChannels: originalNumberOfChannels,
|
|
37612
|
+
sampleRate: originalSampleRate,
|
|
37613
|
+
timestamp: 0
|
|
37614
|
+
});
|
|
37615
|
+
await this._registerAudioSample(silentSample, source, outputTrackId, () => lastSampleTimestamp);
|
|
37616
|
+
needsPadding = false;
|
|
37617
|
+
}
|
|
37856
37618
|
let startFrame = 0;
|
|
37857
37619
|
let endFrame = sample.numberOfFrames;
|
|
37858
37620
|
if (sample.timestamp < this._startTimestamp) {
|