mediabunny 1.48.1 → 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 +503 -657
- package/dist/bundles/mediabunny.min.cjs +18 -104
- package/dist/bundles/mediabunny.min.mjs +18 -104
- package/dist/bundles/mediabunny.mjs +503 -657
- package/dist/bundles/mediabunny.node.cjs +503 -657
- package/dist/mediabunny.d.ts +68 -6
- package/dist/modules/src/codec-data.d.ts.map +1 -1
- package/dist/modules/src/codec-data.js +12 -6
- package/dist/modules/src/codec.d.ts +6 -3
- 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 +27 -17
- 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/custom-coder.js +5 -4
- 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/flac/flac-demuxer.d.ts.map +1 -1
- package/dist/modules/src/flac/flac-demuxer.js +23 -1
- package/dist/modules/src/hls/hls-muxer.d.ts.map +1 -1
- package/dist/modules/src/hls/hls-muxer.js +4 -3
- package/dist/modules/src/id3.d.ts +0 -1
- package/dist/modules/src/id3.d.ts.map +1 -1
- package/dist/modules/src/id3.js +12 -12
- package/dist/modules/src/index.d.ts +1 -0
- package/dist/modules/src/index.d.ts.map +1 -1
- package/dist/modules/src/index.js +3 -1
- package/dist/modules/src/input-format.d.ts.map +1 -1
- package/dist/modules/src/input-format.js +15 -1
- package/dist/modules/src/input-track.d.ts.map +1 -1
- package/dist/modules/src/input-track.js +3 -2
- 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 +26 -19
- package/dist/modules/src/logging.d.ts +57 -0
- package/dist/modules/src/logging.d.ts.map +1 -0
- package/dist/modules/src/logging.js +84 -0
- package/dist/modules/src/matroska/ebml.d.ts +4 -4
- 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 +21 -4
- 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 -245
- 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 +69 -289
- package/dist/modules/src/metadata.d.ts +4 -2
- package/dist/modules/src/metadata.d.ts.map +1 -1
- package/dist/modules/src/misc.d.ts +1 -1
- package/dist/modules/src/misc.d.ts.map +1 -1
- package/dist/modules/src/misc.js +5 -2
- package/dist/modules/src/mpeg-ts/mpeg-ts-demuxer.d.ts.map +1 -1
- package/dist/modules/src/mpeg-ts/mpeg-ts-demuxer.js +3 -1
- package/dist/modules/src/output.d.ts.map +1 -1
- package/dist/modules/src/output.js +5 -4
- 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 +20 -10
- package/dist/modules/src/source.d.ts.map +1 -1
- package/dist/modules/src/source.js +4 -4
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/dist/modules/src/wave/wave-muxer.d.ts.map +1 -1
- package/dist/modules/src/wave/wave-muxer.js +2 -1
- package/package.json +2 -2
- package/src/codec-data.ts +11 -6
- package/src/codec.ts +76 -5
- package/src/conversion.ts +31 -18
- package/src/custom-coder.ts +13 -4
- package/src/decode.ts +1 -1
- package/src/encode.ts +10 -8
- package/src/flac/flac-demuxer.ts +28 -2
- package/src/hls/hls-muxer.ts +4 -3
- package/src/id3.ts +14 -14
- package/src/index.ts +8 -1
- package/src/input-format.ts +17 -1
- package/src/input-track.ts +3 -2
- package/src/isobmff/isobmff-boxes.ts +7 -2
- package/src/isobmff/isobmff-demuxer.ts +29 -18
- package/src/logging.ts +120 -0
- package/src/matroska/ebml.ts +1 -0
- package/src/matroska/matroska-demuxer.ts +26 -2
- package/src/matroska/matroska-muxer.ts +18 -27
- package/src/media-sink.ts +171 -306
- package/src/media-source.ts +82 -353
- package/src/metadata.ts +4 -2
- package/src/misc.ts +5 -2
- package/src/mpeg-ts/mpeg-ts-demuxer.ts +3 -1
- package/src/output.ts +5 -4
- package/src/sample.ts +24 -12
- package/src/source.ts +4 -4
- package/src/wave/wave-muxer.ts +2 -1
|
@@ -145,6 +145,8 @@ var Mediabunny = (() => {
|
|
|
145
145
|
InputVideoTrack: () => InputVideoTrack,
|
|
146
146
|
IsobmffInputFormat: () => IsobmffInputFormat,
|
|
147
147
|
IsobmffOutputFormat: () => IsobmffOutputFormat2,
|
|
148
|
+
LogLevel: () => LogLevel,
|
|
149
|
+
Logging: () => Logging,
|
|
148
150
|
MATROSKA: () => MATROSKA,
|
|
149
151
|
MP3: () => MP3,
|
|
150
152
|
MP4: () => MP4,
|
|
@@ -640,7 +642,7 @@ var Mediabunny = (() => {
|
|
|
640
642
|
if (retryDelayInSeconds === null) {
|
|
641
643
|
throw error;
|
|
642
644
|
}
|
|
643
|
-
|
|
645
|
+
Logging._error("Retrying failed fetch. Error:", error);
|
|
644
646
|
if (!Number.isFinite(retryDelayInSeconds) || retryDelayInSeconds < 0) {
|
|
645
647
|
throw new TypeError("Retry delay must be a non-negative finite number.");
|
|
646
648
|
}
|
|
@@ -1038,7 +1040,7 @@ var Mediabunny = (() => {
|
|
|
1038
1040
|
/** @internal */
|
|
1039
1041
|
this._listeners = /* @__PURE__ */ new Map();
|
|
1040
1042
|
}
|
|
1041
|
-
/** Registers a listener for the given event. */
|
|
1043
|
+
/** Registers a listener for the given event. Returns a function that, when called, removes the listener again. */
|
|
1042
1044
|
on(event, listener, options) {
|
|
1043
1045
|
if (!this._listeners.has(event)) {
|
|
1044
1046
|
this._listeners.set(event, /* @__PURE__ */ new Set());
|
|
@@ -1112,6 +1114,63 @@ var Mediabunny = (() => {
|
|
|
1112
1114
|
return value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype && Object.values(value).every((x) => typeof x === "string");
|
|
1113
1115
|
};
|
|
1114
1116
|
|
|
1117
|
+
// src/logging.ts
|
|
1118
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
1119
|
+
LogLevel2[LogLevel2["Silent"] = 0] = "Silent";
|
|
1120
|
+
LogLevel2[LogLevel2["Errors"] = 1] = "Errors";
|
|
1121
|
+
LogLevel2[LogLevel2["Warnings"] = 2] = "Warnings";
|
|
1122
|
+
LogLevel2[LogLevel2["Info"] = 3] = "Info";
|
|
1123
|
+
return LogLevel2;
|
|
1124
|
+
})(LogLevel || {});
|
|
1125
|
+
var _Logging = class _Logging {
|
|
1126
|
+
constructor() {
|
|
1127
|
+
}
|
|
1128
|
+
/** The current log level. Defaults to {@link LogLevel.Info}. */
|
|
1129
|
+
static get level() {
|
|
1130
|
+
return _Logging._level;
|
|
1131
|
+
}
|
|
1132
|
+
static set level(value) {
|
|
1133
|
+
if (value !== 0 /* Silent */ && value !== 1 /* Errors */ && value !== 2 /* Warnings */ && value !== 3 /* Info */) {
|
|
1134
|
+
throw new TypeError("Invalid log level. Use one of the values of the LogLevel enum.");
|
|
1135
|
+
}
|
|
1136
|
+
_Logging._level = value;
|
|
1137
|
+
}
|
|
1138
|
+
/** @internal */
|
|
1139
|
+
static get _emitter() {
|
|
1140
|
+
return _Logging._emitterInstance ??= new EventEmitter();
|
|
1141
|
+
}
|
|
1142
|
+
/** Registers a listener for a log event. Returns a function that, when called, removes the listener again. */
|
|
1143
|
+
static on(event, listener, options) {
|
|
1144
|
+
return _Logging._emitter.on(event, listener, options);
|
|
1145
|
+
}
|
|
1146
|
+
/** @internal */
|
|
1147
|
+
static _error(...args) {
|
|
1148
|
+
_Logging._emitter._emit("error", args);
|
|
1149
|
+
if (_Logging._level >= 1 /* Errors */) {
|
|
1150
|
+
console.error(...args);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
/** @internal */
|
|
1154
|
+
static _warn(...args) {
|
|
1155
|
+
_Logging._emitter._emit("warn", args);
|
|
1156
|
+
if (_Logging._level >= 2 /* Warnings */) {
|
|
1157
|
+
console.warn(...args);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
/** @internal */
|
|
1161
|
+
static _info(...args) {
|
|
1162
|
+
_Logging._emitter._emit("info", args);
|
|
1163
|
+
if (_Logging._level >= 3 /* Info */) {
|
|
1164
|
+
console.info(...args);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
/** @internal */
|
|
1169
|
+
_Logging._level = 3 /* Info */;
|
|
1170
|
+
/** @internal */
|
|
1171
|
+
_Logging._emitterInstance = null;
|
|
1172
|
+
var Logging = _Logging;
|
|
1173
|
+
|
|
1115
1174
|
// src/metadata.ts
|
|
1116
1175
|
var RichImageData = class {
|
|
1117
1176
|
/** Creates a new {@link RichImageData}. */
|
|
@@ -1439,7 +1498,8 @@ var Mediabunny = (() => {
|
|
|
1439
1498
|
"hevc",
|
|
1440
1499
|
"vp9",
|
|
1441
1500
|
"av1",
|
|
1442
|
-
"vp8"
|
|
1501
|
+
"vp8",
|
|
1502
|
+
"prores"
|
|
1443
1503
|
];
|
|
1444
1504
|
var PCM_AUDIO_CODECS = [
|
|
1445
1505
|
"pcm-s16",
|
|
@@ -1640,7 +1700,35 @@ var Mediabunny = (() => {
|
|
|
1640
1700
|
];
|
|
1641
1701
|
var VP9_DEFAULT_SUFFIX = ".01.01.01.01.00";
|
|
1642
1702
|
var AV1_DEFAULT_SUFFIX = ".0.110.01.01.01.0";
|
|
1643
|
-
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) => {
|
|
1644
1732
|
if (codec === "avc") {
|
|
1645
1733
|
const profileIndication = 100;
|
|
1646
1734
|
const totalMacroblocks = Math.ceil(width / 16) * Math.ceil(height / 16);
|
|
@@ -1681,8 +1769,24 @@ var Mediabunny = (() => {
|
|
|
1681
1769
|
const level = levelInfo.level.toString().padStart(2, "0");
|
|
1682
1770
|
const bitDepth = "08";
|
|
1683
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);
|
|
1684
1788
|
}
|
|
1685
|
-
throw new TypeError(`Unhandled codec '${codec}'.`);
|
|
1789
|
+
throw new TypeError(`Unhandled codec '${String(codec)}'.`);
|
|
1686
1790
|
};
|
|
1687
1791
|
var generateVp9CodecConfigurationFromCodecString = (codecString) => {
|
|
1688
1792
|
const parts = codecString.split(".");
|
|
@@ -1728,7 +1832,16 @@ var Mediabunny = (() => {
|
|
|
1728
1832
|
return [firstByte, secondByte, thirdByte, fourthByte];
|
|
1729
1833
|
};
|
|
1730
1834
|
var extractVideoCodecString = (trackInfo) => {
|
|
1731
|
-
const {
|
|
1835
|
+
const {
|
|
1836
|
+
codec,
|
|
1837
|
+
codecDescription,
|
|
1838
|
+
colorSpace,
|
|
1839
|
+
avcCodecInfo,
|
|
1840
|
+
hevcCodecInfo,
|
|
1841
|
+
vp9CodecInfo,
|
|
1842
|
+
av1CodecInfo,
|
|
1843
|
+
proresFormat
|
|
1844
|
+
} = trackInfo;
|
|
1732
1845
|
if (codec === "avc") {
|
|
1733
1846
|
assert(trackInfo.avcType !== null);
|
|
1734
1847
|
if (avcCodecInfo) {
|
|
@@ -1848,6 +1961,10 @@ var Mediabunny = (() => {
|
|
|
1848
1961
|
string = string.slice(0, -AV1_DEFAULT_SUFFIX.length);
|
|
1849
1962
|
}
|
|
1850
1963
|
return string;
|
|
1964
|
+
} else if (codec === "prores") {
|
|
1965
|
+
return proresFormat ?? "apch";
|
|
1966
|
+
} else if (codec !== null) {
|
|
1967
|
+
assertNever(codec);
|
|
1851
1968
|
}
|
|
1852
1969
|
throw new TypeError(`Unhandled codec '${codec}'.`);
|
|
1853
1970
|
};
|
|
@@ -1977,6 +2094,8 @@ var Mediabunny = (() => {
|
|
|
1977
2094
|
return "vp9";
|
|
1978
2095
|
} else if (codecString.startsWith("av01")) {
|
|
1979
2096
|
return "av1";
|
|
2097
|
+
} else if (PRORES_FOURCCS.includes(codecString)) {
|
|
2098
|
+
return "prores";
|
|
1980
2099
|
}
|
|
1981
2100
|
if (codecString === "mp3" || codecString === "mp4a.69" || codecString === "mp4a.6B" || codecString === "mp4a.6b" || codecString === "mp4a.40.34") {
|
|
1982
2101
|
return "mp3";
|
|
@@ -2039,7 +2158,7 @@ var Mediabunny = (() => {
|
|
|
2039
2158
|
}
|
|
2040
2159
|
return {};
|
|
2041
2160
|
};
|
|
2042
|
-
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];
|
|
2043
2162
|
var AVC_CODEC_STRING_REGEX = /^(avc1|avc3)\.[0-9a-fA-F]{6}$/;
|
|
2044
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}$/;
|
|
2045
2164
|
var VP9_CODEC_STRING_REGEX = /^vp09(?:\.\d{2}){3}(?:(?:\.\d{2}){5})?$/;
|
|
@@ -2156,6 +2275,12 @@ var Mediabunny = (() => {
|
|
|
2156
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/.'
|
|
2157
2276
|
);
|
|
2158
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
|
+
}
|
|
2159
2284
|
}
|
|
2160
2285
|
};
|
|
2161
2286
|
var VALID_AUDIO_CODEC_STRING_PREFIXES = [
|
|
@@ -2735,7 +2860,7 @@ var Mediabunny = (() => {
|
|
|
2735
2860
|
sequenceParameterSetExt: hasExtendedData ? spsExtUnits : null
|
|
2736
2861
|
};
|
|
2737
2862
|
} catch (error) {
|
|
2738
|
-
|
|
2863
|
+
Logging._error("Error building AVC Decoder Configuration Record:", error);
|
|
2739
2864
|
return null;
|
|
2740
2865
|
}
|
|
2741
2866
|
};
|
|
@@ -2841,7 +2966,7 @@ var Mediabunny = (() => {
|
|
|
2841
2966
|
}
|
|
2842
2967
|
return record;
|
|
2843
2968
|
} catch (error) {
|
|
2844
|
-
|
|
2969
|
+
Logging._error("Error deserializing AVC Decoder Configuration Record:", error);
|
|
2845
2970
|
return null;
|
|
2846
2971
|
}
|
|
2847
2972
|
};
|
|
@@ -3070,7 +3195,7 @@ var Mediabunny = (() => {
|
|
|
3070
3195
|
maxDecFrameBuffering
|
|
3071
3196
|
};
|
|
3072
3197
|
} catch (error) {
|
|
3073
|
-
|
|
3198
|
+
Logging._error("Error parsing AVC SPS:", error);
|
|
3074
3199
|
return null;
|
|
3075
3200
|
}
|
|
3076
3201
|
};
|
|
@@ -3234,7 +3359,7 @@ var Mediabunny = (() => {
|
|
|
3234
3359
|
minSpatialSegmentationIdc
|
|
3235
3360
|
};
|
|
3236
3361
|
} catch (error) {
|
|
3237
|
-
|
|
3362
|
+
Logging._error("Error parsing HEVC SPS:", error);
|
|
3238
3363
|
return null;
|
|
3239
3364
|
}
|
|
3240
3365
|
};
|
|
@@ -3345,7 +3470,7 @@ var Mediabunny = (() => {
|
|
|
3345
3470
|
};
|
|
3346
3471
|
return record;
|
|
3347
3472
|
} catch (error) {
|
|
3348
|
-
|
|
3473
|
+
Logging._error("Error building HEVC Decoder Configuration Record:", error);
|
|
3349
3474
|
return null;
|
|
3350
3475
|
}
|
|
3351
3476
|
};
|
|
@@ -3693,7 +3818,7 @@ var Mediabunny = (() => {
|
|
|
3693
3818
|
arrays
|
|
3694
3819
|
};
|
|
3695
3820
|
} catch (error) {
|
|
3696
|
-
|
|
3821
|
+
Logging._error("Error deserializing HEVC Decoder Configuration Record:", error);
|
|
3697
3822
|
return null;
|
|
3698
3823
|
}
|
|
3699
3824
|
};
|
|
@@ -4279,6 +4404,11 @@ var Mediabunny = (() => {
|
|
|
4279
4404
|
return null;
|
|
4280
4405
|
}
|
|
4281
4406
|
;
|
|
4407
|
+
case "prores":
|
|
4408
|
+
{
|
|
4409
|
+
return "key";
|
|
4410
|
+
}
|
|
4411
|
+
;
|
|
4282
4412
|
default:
|
|
4283
4413
|
{
|
|
4284
4414
|
assertNever(codec);
|
|
@@ -5877,7 +6007,7 @@ var Mediabunny = (() => {
|
|
|
5877
6007
|
continue;
|
|
5878
6008
|
}
|
|
5879
6009
|
if (relevantEntryFound) {
|
|
5880
|
-
|
|
6010
|
+
Logging._warn(
|
|
5881
6011
|
"Unsupported edit list: multiple edits are not currently supported. Only using first edit."
|
|
5882
6012
|
);
|
|
5883
6013
|
break;
|
|
@@ -5887,7 +6017,7 @@ var Mediabunny = (() => {
|
|
|
5887
6017
|
continue;
|
|
5888
6018
|
}
|
|
5889
6019
|
if (mediaRate !== 1) {
|
|
5890
|
-
|
|
6020
|
+
Logging._warn("Unsupported edit list entry: media rate must be 1.");
|
|
5891
6021
|
break;
|
|
5892
6022
|
}
|
|
5893
6023
|
track.editListPreviousSegmentDurations = previousSegmentDurations;
|
|
@@ -5950,7 +6080,8 @@ var Mediabunny = (() => {
|
|
|
5950
6080
|
avcCodecInfo: null,
|
|
5951
6081
|
hevcCodecInfo: null,
|
|
5952
6082
|
vp9CodecInfo: null,
|
|
5953
|
-
av1CodecInfo: null
|
|
6083
|
+
av1CodecInfo: null,
|
|
6084
|
+
proresFormat: null
|
|
5954
6085
|
};
|
|
5955
6086
|
} else if (handlerType === "soun") {
|
|
5956
6087
|
track.info = {
|
|
@@ -6025,10 +6156,13 @@ var Mediabunny = (() => {
|
|
|
6025
6156
|
track.info.codec = "vp9";
|
|
6026
6157
|
} else if (codecName === "av01") {
|
|
6027
6158
|
track.info.codec = "av1";
|
|
6159
|
+
} else if (PRORES_FOURCCS.includes(lowercaseBoxName)) {
|
|
6160
|
+
track.info.codec = "prores";
|
|
6161
|
+
track.info.proresFormat = lowercaseBoxName;
|
|
6028
6162
|
} else if (codecName === null) {
|
|
6029
|
-
|
|
6163
|
+
Logging._warn(`Unknown encrypted video codec due to missing frma box.`);
|
|
6030
6164
|
} else {
|
|
6031
|
-
|
|
6165
|
+
Logging._warn(`Unsupported video codec (sample entry type '${sampleBoxInfo.name}').`);
|
|
6032
6166
|
}
|
|
6033
6167
|
} else {
|
|
6034
6168
|
slice.skip(6 * 1 + 2);
|
|
@@ -6085,7 +6219,7 @@ var Mediabunny = (() => {
|
|
|
6085
6219
|
} else if (sampleSize === 16) {
|
|
6086
6220
|
track.info.codec = track.info.pcmLittleEndian ? "pcm-s16" : "pcm-s16be";
|
|
6087
6221
|
} else {
|
|
6088
|
-
|
|
6222
|
+
Logging._warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`);
|
|
6089
6223
|
track.info.codec = null;
|
|
6090
6224
|
}
|
|
6091
6225
|
} else if (codecName === "sowt") {
|
|
@@ -6094,7 +6228,7 @@ var Mediabunny = (() => {
|
|
|
6094
6228
|
} else if (sampleSize === 16) {
|
|
6095
6229
|
track.info.codec = "pcm-s16";
|
|
6096
6230
|
} else {
|
|
6097
|
-
|
|
6231
|
+
Logging._warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`);
|
|
6098
6232
|
track.info.codec = null;
|
|
6099
6233
|
}
|
|
6100
6234
|
} else if (codecName === "raw ") {
|
|
@@ -6117,7 +6251,7 @@ var Mediabunny = (() => {
|
|
|
6117
6251
|
} else if (pcmSampleSize === 32) {
|
|
6118
6252
|
track.info.codec = "pcm-s32";
|
|
6119
6253
|
} else {
|
|
6120
|
-
|
|
6254
|
+
Logging._warn(`Invalid ipcm sample size ${pcmSampleSize}.`);
|
|
6121
6255
|
track.info.codec = null;
|
|
6122
6256
|
}
|
|
6123
6257
|
} else {
|
|
@@ -6128,7 +6262,7 @@ var Mediabunny = (() => {
|
|
|
6128
6262
|
} else if (pcmSampleSize === 32) {
|
|
6129
6263
|
track.info.codec = "pcm-s32be";
|
|
6130
6264
|
} else {
|
|
6131
|
-
|
|
6265
|
+
Logging._warn(`Invalid ipcm sample size ${pcmSampleSize}.`);
|
|
6132
6266
|
track.info.codec = null;
|
|
6133
6267
|
}
|
|
6134
6268
|
}
|
|
@@ -6140,7 +6274,7 @@ var Mediabunny = (() => {
|
|
|
6140
6274
|
} else if (pcmSampleSize === 64) {
|
|
6141
6275
|
track.info.codec = "pcm-f64";
|
|
6142
6276
|
} else {
|
|
6143
|
-
|
|
6277
|
+
Logging._warn(`Invalid fpcm sample size ${pcmSampleSize}.`);
|
|
6144
6278
|
track.info.codec = null;
|
|
6145
6279
|
}
|
|
6146
6280
|
} else {
|
|
@@ -6149,7 +6283,7 @@ var Mediabunny = (() => {
|
|
|
6149
6283
|
} else if (pcmSampleSize === 64) {
|
|
6150
6284
|
track.info.codec = "pcm-f64be";
|
|
6151
6285
|
} else {
|
|
6152
|
-
|
|
6286
|
+
Logging._warn(`Invalid fpcm sample size ${pcmSampleSize}.`);
|
|
6153
6287
|
track.info.codec = null;
|
|
6154
6288
|
}
|
|
6155
6289
|
}
|
|
@@ -6182,12 +6316,12 @@ var Mediabunny = (() => {
|
|
|
6182
6316
|
}
|
|
6183
6317
|
}
|
|
6184
6318
|
if (track.info.codec === null) {
|
|
6185
|
-
|
|
6319
|
+
Logging._warn("Unsupported PCM format.");
|
|
6186
6320
|
}
|
|
6187
6321
|
} else if (codecName === null) {
|
|
6188
|
-
|
|
6322
|
+
Logging._warn(`Unknown encrypted audio codec due to missing frma box.`);
|
|
6189
6323
|
} else {
|
|
6190
|
-
|
|
6324
|
+
Logging._warn(`Unsupported audio codec (sample entry type '${sampleBoxInfo.name}').`);
|
|
6191
6325
|
}
|
|
6192
6326
|
}
|
|
6193
6327
|
slice.filePos = sampleBoxStartPos + sampleBoxInfo.totalSize;
|
|
@@ -6226,7 +6360,7 @@ var Mediabunny = (() => {
|
|
|
6226
6360
|
defaultSkipByteBlock: null
|
|
6227
6361
|
};
|
|
6228
6362
|
} else {
|
|
6229
|
-
|
|
6363
|
+
Logging._warn(`Unsupported encryption scheme '${schemeType}'.`);
|
|
6230
6364
|
}
|
|
6231
6365
|
}
|
|
6232
6366
|
;
|
|
@@ -6439,7 +6573,7 @@ var Mediabunny = (() => {
|
|
|
6439
6573
|
} else if (objectTypeIndication === 221) {
|
|
6440
6574
|
track.info.codec = "vorbis";
|
|
6441
6575
|
} else {
|
|
6442
|
-
|
|
6576
|
+
Logging._warn(
|
|
6443
6577
|
`Unsupported audio codec (objectTypeIndication ${objectTypeIndication}) - discarding track.`
|
|
6444
6578
|
);
|
|
6445
6579
|
}
|
|
@@ -6593,7 +6727,7 @@ var Mediabunny = (() => {
|
|
|
6593
6727
|
const bytes2 = readBytes(slice, boxInfo.contentSize);
|
|
6594
6728
|
const config = parseEac3Config(bytes2);
|
|
6595
6729
|
if (!config) {
|
|
6596
|
-
|
|
6730
|
+
Logging._warn("Invalid dec3 box contents, ignoring.");
|
|
6597
6731
|
break;
|
|
6598
6732
|
}
|
|
6599
6733
|
const sampleRate = getEac3SampleRate(config);
|
|
@@ -7152,7 +7286,7 @@ var Mediabunny = (() => {
|
|
|
7152
7286
|
break;
|
|
7153
7287
|
}
|
|
7154
7288
|
if (entryCount > 1) {
|
|
7155
|
-
|
|
7289
|
+
Logging._warn("Multiple saio entries are not supported; using the first offset only.");
|
|
7156
7290
|
}
|
|
7157
7291
|
let offset = version === 0 ? readU32Be(slice) : Number(readU64Be(slice));
|
|
7158
7292
|
if (this.currentFragment) {
|
|
@@ -7987,7 +8121,7 @@ var Mediabunny = (() => {
|
|
|
7987
8121
|
};
|
|
7988
8122
|
}
|
|
7989
8123
|
async canBeTransparent() {
|
|
7990
|
-
return
|
|
8124
|
+
return this.internalTrack.info.codec === "prores" && (this.internalTrack.info.proresFormat === "ap4h" || this.internalTrack.info.proresFormat === "ap4x");
|
|
7991
8125
|
}
|
|
7992
8126
|
async getDecoderConfig() {
|
|
7993
8127
|
if (!this.internalTrack.info.codec) {
|
|
@@ -8882,6 +9016,7 @@ var Mediabunny = (() => {
|
|
|
8882
9016
|
"vp8": "V_VP8",
|
|
8883
9017
|
"vp9": "V_VP9",
|
|
8884
9018
|
"av1": "V_AV1",
|
|
9019
|
+
"prores": "V_PRORES",
|
|
8885
9020
|
"aac": "A_AAC",
|
|
8886
9021
|
"mp3": "A_MPEG/L3",
|
|
8887
9022
|
"opus": "A_OPUS",
|
|
@@ -9509,7 +9644,7 @@ var Mediabunny = (() => {
|
|
|
9509
9644
|
if (this.currentTrack.decodingInstructions.some((instruction) => {
|
|
9510
9645
|
return instruction.data?.type !== "decompress" || instruction.scope !== 1 /* Block */ || instruction.data.algorithm !== 3 /* HeaderStripping */;
|
|
9511
9646
|
})) {
|
|
9512
|
-
|
|
9647
|
+
Logging._warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`);
|
|
9513
9648
|
this.currentTrack = null;
|
|
9514
9649
|
}
|
|
9515
9650
|
if (this.currentTrack && this.currentTrack.id !== -1 && this.currentTrack.codecId && this.currentTrack.info) {
|
|
@@ -9545,6 +9680,13 @@ var Mediabunny = (() => {
|
|
|
9545
9680
|
this.currentTrack.info.codec = "vp9";
|
|
9546
9681
|
} else if (codecIdWithoutSuffix === CODEC_STRING_MAP.av1) {
|
|
9547
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
|
+
}
|
|
9548
9690
|
}
|
|
9549
9691
|
const videoTrack = this.currentTrack;
|
|
9550
9692
|
this.currentTrack.trackBacking = new MatroskaVideoTrackBacking(videoTrack);
|
|
@@ -9636,7 +9778,8 @@ var Mediabunny = (() => {
|
|
|
9636
9778
|
codec: null,
|
|
9637
9779
|
codecDescription: null,
|
|
9638
9780
|
colorSpace: null,
|
|
9639
|
-
alphaMode: false
|
|
9781
|
+
alphaMode: false,
|
|
9782
|
+
proresFormat: null
|
|
9640
9783
|
};
|
|
9641
9784
|
} else if (type === 2) {
|
|
9642
9785
|
this.currentTrack.info = {
|
|
@@ -10819,7 +10962,7 @@ var Mediabunny = (() => {
|
|
|
10819
10962
|
};
|
|
10820
10963
|
}
|
|
10821
10964
|
async canBeTransparent() {
|
|
10822
|
-
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");
|
|
10823
10966
|
}
|
|
10824
10967
|
async getDecoderConfig() {
|
|
10825
10968
|
if (!this.internalTrack.info.codec) {
|
|
@@ -10843,7 +10986,8 @@ var Mediabunny = (() => {
|
|
|
10843
10986
|
avcCodecInfo: this.internalTrack.info.codec === "avc" && firstPacket ? extractAvcDecoderConfigurationRecord(firstPacket.data) : null,
|
|
10844
10987
|
hevcCodecInfo: this.internalTrack.info.codec === "hevc" && firstPacket ? extractHevcDecoderConfigurationRecord(firstPacket.data) : null,
|
|
10845
10988
|
vp9CodecInfo: this.internalTrack.info.codec === "vp9" && firstPacket ? extractVp9CodecInfoFromPacket(firstPacket.data) : null,
|
|
10846
|
-
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
|
|
10847
10991
|
}),
|
|
10848
10992
|
codedWidth: this.internalTrack.info.width,
|
|
10849
10993
|
codedHeight: this.internalTrack.info.height,
|
|
@@ -13024,8 +13168,26 @@ var Mediabunny = (() => {
|
|
|
13024
13168
|
return "audio/flac";
|
|
13025
13169
|
}
|
|
13026
13170
|
async readMetadata() {
|
|
13027
|
-
let currentPos = 4;
|
|
13028
13171
|
return this.metadataPromise ??= (async () => {
|
|
13172
|
+
let currentPos = 0;
|
|
13173
|
+
while (true) {
|
|
13174
|
+
let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE);
|
|
13175
|
+
if (headerSlice instanceof Promise) headerSlice = await headerSlice;
|
|
13176
|
+
if (!headerSlice) {
|
|
13177
|
+
this.lastSampleLoaded = true;
|
|
13178
|
+
return;
|
|
13179
|
+
}
|
|
13180
|
+
const id3V2Header = readId3V2Header(headerSlice);
|
|
13181
|
+
if (!id3V2Header) {
|
|
13182
|
+
break;
|
|
13183
|
+
}
|
|
13184
|
+
let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size);
|
|
13185
|
+
if (contentSlice instanceof Promise) contentSlice = await contentSlice;
|
|
13186
|
+
assert(contentSlice);
|
|
13187
|
+
parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags);
|
|
13188
|
+
currentPos = headerSlice.filePos + id3V2Header.size;
|
|
13189
|
+
}
|
|
13190
|
+
currentPos += 4;
|
|
13029
13191
|
while (this.reader.fileSize === null || currentPos < this.reader.fileSize) {
|
|
13030
13192
|
let sizeSlice = this.reader.requestSlice(currentPos, 4);
|
|
13031
13193
|
if (sizeSlice instanceof Promise) sizeSlice = await sizeSlice;
|
|
@@ -13707,7 +13869,7 @@ var Mediabunny = (() => {
|
|
|
13707
13869
|
break;
|
|
13708
13870
|
default: {
|
|
13709
13871
|
if (!ignoredStreamTypes.has(streamType)) {
|
|
13710
|
-
|
|
13872
|
+
Logging._warn(
|
|
13711
13873
|
`Note: MPEG-TS streams with stream_type 0x${streamType.toString(16)} are not currently supported.`
|
|
13712
13874
|
);
|
|
13713
13875
|
ignoredStreamTypes.add(streamType);
|
|
@@ -13845,7 +14007,8 @@ var Mediabunny = (() => {
|
|
|
13845
14007
|
avcCodecInfo: elementaryStream.info.avcCodecInfo,
|
|
13846
14008
|
hevcCodecInfo: elementaryStream.info.hevcCodecInfo,
|
|
13847
14009
|
vp9CodecInfo: null,
|
|
13848
|
-
av1CodecInfo: null
|
|
14010
|
+
av1CodecInfo: null,
|
|
14011
|
+
proresFormat: null
|
|
13849
14012
|
}),
|
|
13850
14013
|
codedWidth: elementaryStream.info.width,
|
|
13851
14014
|
codedHeight: elementaryStream.info.height,
|
|
@@ -16026,7 +16189,7 @@ var Mediabunny = (() => {
|
|
|
16026
16189
|
}
|
|
16027
16190
|
const isOnline = typeof navigator !== "undefined" && typeof navigator.onLine === "boolean" ? navigator.onLine : true;
|
|
16028
16191
|
if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) {
|
|
16029
|
-
|
|
16192
|
+
Logging._warn(
|
|
16030
16193
|
`Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option.`
|
|
16031
16194
|
);
|
|
16032
16195
|
return null;
|
|
@@ -16200,8 +16363,7 @@ var Mediabunny = (() => {
|
|
|
16200
16363
|
);
|
|
16201
16364
|
if (url2.origin !== "null" && !(url2.pathname.endsWith(".m3u8") || url2.pathname.endsWith(".m3u"))) {
|
|
16202
16365
|
if (!warnedOrigins.has(url2.origin)) {
|
|
16203
|
-
|
|
16204
|
-
console.warn(
|
|
16366
|
+
Logging._warn(
|
|
16205
16367
|
`HTTP server (origin ${url2.origin}) did not respond to a range request with 206 Partial Content, meaning the entire resource will now be downloaded. To enable efficient media file streaming across a network, please make sure your server supports range requests.`
|
|
16206
16368
|
);
|
|
16207
16369
|
warnedOrigins.add(url2.origin);
|
|
@@ -16239,7 +16401,7 @@ var Mediabunny = (() => {
|
|
|
16239
16401
|
}
|
|
16240
16402
|
const retryDelayInSeconds = this._getRetryDelay(1, error, this._url);
|
|
16241
16403
|
if (retryDelayInSeconds !== null) {
|
|
16242
|
-
|
|
16404
|
+
Logging._error("Error while reading response stream. Attempting to resume.", error);
|
|
16243
16405
|
await wait(1e3 * retryDelayInSeconds);
|
|
16244
16406
|
break;
|
|
16245
16407
|
} else {
|
|
@@ -18747,7 +18909,18 @@ var Mediabunny = (() => {
|
|
|
18747
18909
|
var FlacInputFormat = class extends InputFormat {
|
|
18748
18910
|
/** @internal */
|
|
18749
18911
|
async _canReadInput(input) {
|
|
18750
|
-
let
|
|
18912
|
+
let currentPos = 0;
|
|
18913
|
+
while (true) {
|
|
18914
|
+
let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE);
|
|
18915
|
+
if (slice2 instanceof Promise) slice2 = await slice2;
|
|
18916
|
+
if (!slice2) break;
|
|
18917
|
+
const id3V2Header = readId3V2Header(slice2);
|
|
18918
|
+
if (!id3V2Header) {
|
|
18919
|
+
break;
|
|
18920
|
+
}
|
|
18921
|
+
currentPos = slice2.filePos + id3V2Header.size;
|
|
18922
|
+
}
|
|
18923
|
+
let slice = input._reader.requestSlice(currentPos, 4);
|
|
18751
18924
|
if (slice instanceof Promise) slice = await slice;
|
|
18752
18925
|
if (!slice) return false;
|
|
18753
18926
|
return readAscii(slice, 4) === "fLaC";
|
|
@@ -18977,7 +19150,7 @@ var Mediabunny = (() => {
|
|
|
18977
19150
|
...options,
|
|
18978
19151
|
codedWidth: options.codedWidth ?? 1280,
|
|
18979
19152
|
codedHeight: options.codedHeight ?? 720,
|
|
18980
|
-
codec: options.codec ?? buildVideoCodecString(codec, 1280, 720, 1e6)
|
|
19153
|
+
codec: options.codec ?? buildVideoCodecString(codec, 1280, 720, 1e6, false)
|
|
18981
19154
|
};
|
|
18982
19155
|
resolvedOptions.description ??= guessDescriptionForVideo(resolvedOptions);
|
|
18983
19156
|
const key = JSON.stringify(resolvedOptions);
|
|
@@ -19063,7 +19236,7 @@ var Mediabunny = (() => {
|
|
|
19063
19236
|
const now = performance.now();
|
|
19064
19237
|
if (value.type === "video") {
|
|
19065
19238
|
if (now - lastVideoGcErrorLog >= 1e3) {
|
|
19066
|
-
|
|
19239
|
+
Logging._error(
|
|
19067
19240
|
`A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them.`
|
|
19068
19241
|
);
|
|
19069
19242
|
lastVideoGcErrorLog = now;
|
|
@@ -19073,7 +19246,7 @@ var Mediabunny = (() => {
|
|
|
19073
19246
|
}
|
|
19074
19247
|
} else {
|
|
19075
19248
|
if (now - lastAudioGcErrorLog >= 1e3) {
|
|
19076
|
-
|
|
19249
|
+
Logging._error(
|
|
19077
19250
|
`An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them.`
|
|
19078
19251
|
);
|
|
19079
19252
|
lastAudioGcErrorLog = now;
|
|
@@ -19185,12 +19358,11 @@ var Mediabunny = (() => {
|
|
|
19185
19358
|
"init.displayWidth and init.displayHeight must be either both provided or both omitted."
|
|
19186
19359
|
);
|
|
19187
19360
|
}
|
|
19188
|
-
this._data = init._doNotCopy ? toUint8Array(data) : toUint8Array(data).slice();
|
|
19189
|
-
this._layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight);
|
|
19190
19361
|
this.format = init.format;
|
|
19191
19362
|
this.rotation = init.rotation ?? 0;
|
|
19192
19363
|
this.timestamp = init.timestamp;
|
|
19193
19364
|
this.duration = init.duration ?? 0;
|
|
19365
|
+
const layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight);
|
|
19194
19366
|
let colorSpaceInit = init.colorSpace ?? null;
|
|
19195
19367
|
if (colorSpaceInit === null) {
|
|
19196
19368
|
if (this.format === "RGBA" || this.format === "RGBX" || this.format === "BGRA" || this.format === "BGRX") {
|
|
@@ -19209,7 +19381,6 @@ var Mediabunny = (() => {
|
|
|
19209
19381
|
};
|
|
19210
19382
|
}
|
|
19211
19383
|
}
|
|
19212
|
-
this.colorSpace = new VideoSampleColorSpace(colorSpaceInit);
|
|
19213
19384
|
this.visibleRect = {
|
|
19214
19385
|
left: init.visibleRect?.left ?? 0,
|
|
19215
19386
|
top: init.visibleRect?.top ?? 0,
|
|
@@ -19223,6 +19394,9 @@ var Mediabunny = (() => {
|
|
|
19223
19394
|
this.squarePixelWidth = this.visibleRect.width;
|
|
19224
19395
|
this.squarePixelHeight = this.visibleRect.height;
|
|
19225
19396
|
}
|
|
19397
|
+
this._data = init._doNotCopy ? toUint8Array(data) : toUint8Array(data).slice();
|
|
19398
|
+
this._layout = layout;
|
|
19399
|
+
this.colorSpace = new VideoSampleColorSpace(colorSpaceInit);
|
|
19226
19400
|
} else if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) {
|
|
19227
19401
|
if (init?.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) {
|
|
19228
19402
|
throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");
|
|
@@ -19681,6 +19855,7 @@ var Mediabunny = (() => {
|
|
|
19681
19855
|
timestamp: this.microsecondTimestamp,
|
|
19682
19856
|
duration: this.microsecondDuration,
|
|
19683
19857
|
colorSpace: this.colorSpace,
|
|
19858
|
+
visibleRect: this.visibleRect,
|
|
19684
19859
|
displayWidth: this.squarePixelWidth,
|
|
19685
19860
|
// Not display* since we're not passing rotation
|
|
19686
19861
|
displayHeight: this.squarePixelHeight
|
|
@@ -19692,13 +19867,18 @@ var Mediabunny = (() => {
|
|
|
19692
19867
|
// Drag 0 duration to undefined, glitches some codecs
|
|
19693
19868
|
});
|
|
19694
19869
|
} else if (this._data instanceof Uint8Array) {
|
|
19870
|
+
assert(this._layout);
|
|
19695
19871
|
return new VideoFrame(this._data, {
|
|
19696
19872
|
format: this.format,
|
|
19697
19873
|
codedWidth: this.codedWidth,
|
|
19874
|
+
// This is technically wrong! codedWidth is a lie technically. But, since
|
|
19698
19875
|
codedHeight: this.codedHeight,
|
|
19876
|
+
// we pass the layout (which contains the true coded width), we're good.
|
|
19877
|
+
layout: this._layout,
|
|
19699
19878
|
timestamp: this.microsecondTimestamp,
|
|
19700
19879
|
duration: this.microsecondDuration || void 0,
|
|
19701
19880
|
colorSpace: this.colorSpace,
|
|
19881
|
+
visibleRect: this.visibleRect,
|
|
19702
19882
|
displayWidth: this.squarePixelWidth,
|
|
19703
19883
|
// Not display* since we're not passing rotation
|
|
19704
19884
|
displayHeight: this.squarePixelHeight
|
|
@@ -21216,7 +21396,8 @@ var Mediabunny = (() => {
|
|
|
21216
21396
|
options.codec,
|
|
21217
21397
|
options.width,
|
|
21218
21398
|
options.height,
|
|
21219
|
-
resolvedBitrate
|
|
21399
|
+
resolvedBitrate,
|
|
21400
|
+
options.alpha === "keep"
|
|
21220
21401
|
),
|
|
21221
21402
|
width: options.width,
|
|
21222
21403
|
height: options.height,
|
|
@@ -21313,6 +21494,10 @@ var Mediabunny = (() => {
|
|
|
21313
21494
|
/** @internal */
|
|
21314
21495
|
_toVideoBitrate(codec, width, height) {
|
|
21315
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;
|
|
21316
21501
|
const codecEfficiencyFactors = {
|
|
21317
21502
|
avc: 1,
|
|
21318
21503
|
// H.264/AVC (baseline)
|
|
@@ -21322,13 +21507,11 @@ var Mediabunny = (() => {
|
|
|
21322
21507
|
// Similar to HEVC
|
|
21323
21508
|
av1: 0.4,
|
|
21324
21509
|
// ~60% more efficient than AVC
|
|
21325
|
-
vp8: 1.2
|
|
21510
|
+
vp8: 1.2,
|
|
21326
21511
|
// Slightly less efficient than AVC
|
|
21512
|
+
prores: 22e7 / referenceBitrate
|
|
21513
|
+
// Apple ProRes white paper claims 220 Mbps for 1080p 422 HQ @30Hz
|
|
21327
21514
|
};
|
|
21328
|
-
const referencePixels = 1920 * 1080;
|
|
21329
|
-
const referenceBitrate = 3e6;
|
|
21330
|
-
const scaleFactor = Math.pow(pixels / referencePixels, 0.95);
|
|
21331
|
-
const baseBitrate = referenceBitrate * scaleFactor;
|
|
21332
21515
|
const codecAdjustedBitrate = baseBitrate * codecEfficiencyFactors[codec];
|
|
21333
21516
|
const finalBitrate = codecAdjustedBitrate * this._factor;
|
|
21334
21517
|
return Math.ceil(finalBitrate / 1e3) * 1e3;
|
|
@@ -21621,7 +21804,7 @@ var Mediabunny = (() => {
|
|
|
21621
21804
|
if (decoder.prototype instanceof CustomVideoDecoder) {
|
|
21622
21805
|
const casted = decoder;
|
|
21623
21806
|
if (customVideoDecoders.includes(casted)) {
|
|
21624
|
-
|
|
21807
|
+
Logging._warn("Video decoder already registered.");
|
|
21625
21808
|
return;
|
|
21626
21809
|
}
|
|
21627
21810
|
customVideoDecoders.push(casted);
|
|
@@ -21629,7 +21812,7 @@ var Mediabunny = (() => {
|
|
|
21629
21812
|
} else if (decoder.prototype instanceof CustomAudioDecoder) {
|
|
21630
21813
|
const casted = decoder;
|
|
21631
21814
|
if (customAudioDecoders.includes(casted)) {
|
|
21632
|
-
|
|
21815
|
+
Logging._warn("Audio decoder already registered.");
|
|
21633
21816
|
return;
|
|
21634
21817
|
}
|
|
21635
21818
|
customAudioDecoders.push(casted);
|
|
@@ -21642,7 +21825,7 @@ var Mediabunny = (() => {
|
|
|
21642
21825
|
if (encoder.prototype instanceof CustomVideoEncoder) {
|
|
21643
21826
|
const casted = encoder;
|
|
21644
21827
|
if (customVideoEncoders.includes(casted)) {
|
|
21645
|
-
|
|
21828
|
+
Logging._warn("Video encoder already registered.");
|
|
21646
21829
|
return;
|
|
21647
21830
|
}
|
|
21648
21831
|
customVideoEncoders.push(casted);
|
|
@@ -21650,7 +21833,7 @@ var Mediabunny = (() => {
|
|
|
21650
21833
|
} else if (encoder.prototype instanceof CustomAudioEncoder) {
|
|
21651
21834
|
const casted = encoder;
|
|
21652
21835
|
if (customAudioEncoders.includes(casted)) {
|
|
21653
|
-
|
|
21836
|
+
Logging._warn("Audio encoder already registered.");
|
|
21654
21837
|
return;
|
|
21655
21838
|
}
|
|
21656
21839
|
customAudioEncoders.push(casted);
|
|
@@ -21922,6 +22105,7 @@ var Mediabunny = (() => {
|
|
|
21922
22105
|
let ended = false;
|
|
21923
22106
|
let terminated = false;
|
|
21924
22107
|
let outOfBandError = null;
|
|
22108
|
+
let hasOutOfBandError = false;
|
|
21925
22109
|
const timestamps = [];
|
|
21926
22110
|
const maxQueueSize = () => Math.max(2, timestamps.length);
|
|
21927
22111
|
(async () => {
|
|
@@ -21943,8 +22127,9 @@ var Mediabunny = (() => {
|
|
|
21943
22127
|
ended = true;
|
|
21944
22128
|
onQueueNotEmpty();
|
|
21945
22129
|
})().catch((error) => {
|
|
21946
|
-
if (!
|
|
22130
|
+
if (!hasOutOfBandError) {
|
|
21947
22131
|
outOfBandError = error;
|
|
22132
|
+
hasOutOfBandError = true;
|
|
21948
22133
|
onQueueNotEmpty();
|
|
21949
22134
|
}
|
|
21950
22135
|
});
|
|
@@ -21956,7 +22141,7 @@ var Mediabunny = (() => {
|
|
|
21956
22141
|
throw new InputDisposedError();
|
|
21957
22142
|
} else if (terminated) {
|
|
21958
22143
|
return { value: void 0, done: true };
|
|
21959
|
-
} else if (
|
|
22144
|
+
} else if (hasOutOfBandError) {
|
|
21960
22145
|
throw outOfBandError;
|
|
21961
22146
|
} else if (packetQueue.length > 0) {
|
|
21962
22147
|
const value = packetQueue.shift();
|
|
@@ -22009,6 +22194,7 @@ var Mediabunny = (() => {
|
|
|
22009
22194
|
let ended = false;
|
|
22010
22195
|
let terminated = false;
|
|
22011
22196
|
let outOfBandError = null;
|
|
22197
|
+
let hasOutOfBandError = false;
|
|
22012
22198
|
const packetRetrievalOptions = {
|
|
22013
22199
|
...options,
|
|
22014
22200
|
verifyKeyPackets: true,
|
|
@@ -22042,8 +22228,9 @@ var Mediabunny = (() => {
|
|
|
22042
22228
|
({ promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers());
|
|
22043
22229
|
}
|
|
22044
22230
|
}, (error) => {
|
|
22045
|
-
if (!
|
|
22231
|
+
if (!hasOutOfBandError) {
|
|
22046
22232
|
outOfBandError = error;
|
|
22233
|
+
hasOutOfBandError = true;
|
|
22047
22234
|
onQueueNotEmpty();
|
|
22048
22235
|
}
|
|
22049
22236
|
});
|
|
@@ -22078,8 +22265,9 @@ var Mediabunny = (() => {
|
|
|
22078
22265
|
decoderIsFlushed = true;
|
|
22079
22266
|
onQueueNotEmpty();
|
|
22080
22267
|
})().catch((error) => {
|
|
22081
|
-
if (!
|
|
22268
|
+
if (!hasOutOfBandError) {
|
|
22082
22269
|
outOfBandError = error;
|
|
22270
|
+
hasOutOfBandError = true;
|
|
22083
22271
|
onQueueNotEmpty();
|
|
22084
22272
|
}
|
|
22085
22273
|
});
|
|
@@ -22098,7 +22286,7 @@ var Mediabunny = (() => {
|
|
|
22098
22286
|
throw new InputDisposedError();
|
|
22099
22287
|
} else if (terminated) {
|
|
22100
22288
|
return { value: void 0, done: true };
|
|
22101
|
-
} else if (
|
|
22289
|
+
} else if (hasOutOfBandError) {
|
|
22102
22290
|
closeSamples();
|
|
22103
22291
|
throw outOfBandError;
|
|
22104
22292
|
} else if (sampleQueue.length > 0) {
|
|
@@ -22139,6 +22327,7 @@ var Mediabunny = (() => {
|
|
|
22139
22327
|
let decoderIsFlushed = false;
|
|
22140
22328
|
let terminated = false;
|
|
22141
22329
|
let outOfBandError = null;
|
|
22330
|
+
let hasOutOfBandError = false;
|
|
22142
22331
|
const pushToQueue = (sample) => {
|
|
22143
22332
|
sampleQueue.push(sample);
|
|
22144
22333
|
onQueueNotEmpty();
|
|
@@ -22169,8 +22358,9 @@ var Mediabunny = (() => {
|
|
|
22169
22358
|
sample.close();
|
|
22170
22359
|
}
|
|
22171
22360
|
}, (error) => {
|
|
22172
|
-
if (!
|
|
22361
|
+
if (!hasOutOfBandError) {
|
|
22173
22362
|
outOfBandError = error;
|
|
22363
|
+
hasOutOfBandError = true;
|
|
22174
22364
|
onQueueNotEmpty();
|
|
22175
22365
|
}
|
|
22176
22366
|
});
|
|
@@ -22240,8 +22430,9 @@ var Mediabunny = (() => {
|
|
|
22240
22430
|
decoderIsFlushed = true;
|
|
22241
22431
|
onQueueNotEmpty();
|
|
22242
22432
|
})().catch((error) => {
|
|
22243
|
-
if (!
|
|
22433
|
+
if (!hasOutOfBandError) {
|
|
22244
22434
|
outOfBandError = error;
|
|
22435
|
+
hasOutOfBandError = true;
|
|
22245
22436
|
onQueueNotEmpty();
|
|
22246
22437
|
}
|
|
22247
22438
|
});
|
|
@@ -22259,7 +22450,7 @@ var Mediabunny = (() => {
|
|
|
22259
22450
|
throw new InputDisposedError();
|
|
22260
22451
|
} else if (terminated) {
|
|
22261
22452
|
return { value: void 0, done: true };
|
|
22262
|
-
} else if (
|
|
22453
|
+
} else if (hasOutOfBandError) {
|
|
22263
22454
|
closeSamples();
|
|
22264
22455
|
throw outOfBandError;
|
|
22265
22456
|
} else if (sampleQueue.length > 0) {
|
|
@@ -22324,7 +22515,8 @@ var Mediabunny = (() => {
|
|
|
22324
22515
|
this.currentAlphaPacketIndex = 0;
|
|
22325
22516
|
this.alphaRaslSkipped = false;
|
|
22326
22517
|
// For HEVC stuff
|
|
22327
|
-
this.
|
|
22518
|
+
this.finalSamples = [];
|
|
22519
|
+
this.mergeAlphaPromises = [];
|
|
22328
22520
|
const MatchingCustomDecoder = customVideoDecoders.find((x) => x.supports(codec, decoderConfig));
|
|
22329
22521
|
if (MatchingCustomDecoder) {
|
|
22330
22522
|
this.customDecoder = new MatchingCustomDecoder();
|
|
@@ -22336,18 +22528,19 @@ var Mediabunny = (() => {
|
|
|
22336
22528
|
}
|
|
22337
22529
|
this.finalizeAndEmitSample(sample);
|
|
22338
22530
|
};
|
|
22339
|
-
|
|
22531
|
+
this.customDecoder.onError = (error) => {
|
|
22532
|
+
onError(error);
|
|
22533
|
+
};
|
|
22534
|
+
void this.customDecoderCallSerializer.call(() => this.customDecoder.init()).catch((error) => onError(error));
|
|
22340
22535
|
} else {
|
|
22341
22536
|
const colorHandler = (frame) => {
|
|
22342
|
-
this.
|
|
22343
|
-
|
|
22344
|
-
|
|
22345
|
-
|
|
22346
|
-
|
|
22347
|
-
|
|
22348
|
-
|
|
22349
|
-
}
|
|
22350
|
-
}).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
|
+
}
|
|
22351
22544
|
};
|
|
22352
22545
|
if (codec === "avc" && this.decoderConfig.description && isChromium()) {
|
|
22353
22546
|
const record = deserializeAvcDecoderConfigurationRecord(toUint8Array(this.decoderConfig.description));
|
|
@@ -22398,7 +22591,7 @@ var Mediabunny = (() => {
|
|
|
22398
22591
|
}
|
|
22399
22592
|
if (this.customDecoder) {
|
|
22400
22593
|
this.customDecoderQueueSize++;
|
|
22401
|
-
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--);
|
|
22402
22595
|
} else {
|
|
22403
22596
|
assert(this.decoder);
|
|
22404
22597
|
if (!isWebKit()) {
|
|
@@ -22440,27 +22633,25 @@ var Mediabunny = (() => {
|
|
|
22440
22633
|
}
|
|
22441
22634
|
if (!this.alphaDecoder) {
|
|
22442
22635
|
const alphaHandler = (frame) => {
|
|
22443
|
-
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();
|
|
22444
22646
|
if (this.colorQueue.length > 0) {
|
|
22445
22647
|
const colorFrame = this.colorQueue.shift();
|
|
22446
22648
|
assert(colorFrame !== void 0);
|
|
22447
|
-
|
|
22649
|
+
void this.mergeAlpha(colorFrame, null);
|
|
22448
22650
|
} else {
|
|
22449
|
-
this.alphaQueue.push(
|
|
22450
|
-
}
|
|
22451
|
-
this.decodedAlphaChunkCount++;
|
|
22452
|
-
while (this.nullAlphaFrameQueue.length > 0 && this.nullAlphaFrameQueue[0] === this.decodedAlphaChunkCount) {
|
|
22453
|
-
this.nullAlphaFrameQueue.shift();
|
|
22454
|
-
if (this.colorQueue.length > 0) {
|
|
22455
|
-
const colorFrame = this.colorQueue.shift();
|
|
22456
|
-
assert(colorFrame !== void 0);
|
|
22457
|
-
await this.mergeAlpha(colorFrame, null);
|
|
22458
|
-
} else {
|
|
22459
|
-
this.alphaQueue.push(null);
|
|
22460
|
-
}
|
|
22651
|
+
this.alphaQueue.push(null);
|
|
22461
22652
|
}
|
|
22462
|
-
|
|
22463
|
-
|
|
22653
|
+
}
|
|
22654
|
+
this.alphaDecoderQueueSize--;
|
|
22464
22655
|
};
|
|
22465
22656
|
const stack = new Error("Decoding error").stack;
|
|
22466
22657
|
this.alphaDecoder = new VideoDecoder({
|
|
@@ -22543,15 +22734,29 @@ var Mediabunny = (() => {
|
|
|
22543
22734
|
this.onSample(sample);
|
|
22544
22735
|
}
|
|
22545
22736
|
async mergeAlpha(color, alpha) {
|
|
22546
|
-
|
|
22547
|
-
|
|
22548
|
-
|
|
22549
|
-
|
|
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();
|
|
22550
22759
|
}
|
|
22551
|
-
assert(this.merger);
|
|
22552
|
-
const finalFrame = await this.merger.update(color, alpha);
|
|
22553
|
-
const finalSample = new VideoSample(finalFrame);
|
|
22554
|
-
this.sampleHandler(finalSample);
|
|
22555
22760
|
}
|
|
22556
22761
|
async flush() {
|
|
22557
22762
|
if (this.customDecoder) {
|
|
@@ -22562,7 +22767,7 @@ var Mediabunny = (() => {
|
|
|
22562
22767
|
this.decoder.flush(),
|
|
22563
22768
|
this.alphaDecoder?.flush()
|
|
22564
22769
|
]);
|
|
22565
|
-
await this.
|
|
22770
|
+
await Promise.all(this.mergeAlphaPromises);
|
|
22566
22771
|
this.colorQueue.forEach((x) => x.close());
|
|
22567
22772
|
this.colorQueue.length = 0;
|
|
22568
22773
|
this.alphaQueue.forEach((x) => x?.close());
|
|
@@ -22602,205 +22807,62 @@ var Mediabunny = (() => {
|
|
|
22602
22807
|
this.sampleQueue.length = 0;
|
|
22603
22808
|
}
|
|
22604
22809
|
};
|
|
22605
|
-
var
|
|
22606
|
-
var
|
|
22810
|
+
var mergerWorkerUrl = null;
|
|
22811
|
+
var ColorAlphaMerger = class {
|
|
22607
22812
|
constructor() {
|
|
22608
|
-
this.
|
|
22609
|
-
this.
|
|
22610
|
-
this.program = null;
|
|
22611
|
-
this.vao = null;
|
|
22612
|
-
this.colorTexture = null;
|
|
22613
|
-
this.alphaTexture = null;
|
|
22614
|
-
this.worker = null;
|
|
22813
|
+
this.workers = [];
|
|
22814
|
+
this.nextWorkerIndex = 0;
|
|
22615
22815
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
22616
22816
|
this.nextRequestId = 0;
|
|
22617
|
-
|
|
22618
|
-
|
|
22619
|
-
|
|
22620
|
-
|
|
22621
|
-
|
|
22622
|
-
|
|
22623
|
-
|
|
22624
|
-
|
|
22625
|
-
|
|
22626
|
-
|
|
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
|
+
}
|
|
22627
22842
|
});
|
|
22628
|
-
|
|
22629
|
-
|
|
22630
|
-
|
|
22631
|
-
|
|
22632
|
-
|
|
22633
|
-
|
|
22634
|
-
|
|
22635
|
-
this.
|
|
22636
|
-
this.gl.useProgram(this.program);
|
|
22637
|
-
this.gl.uniform1i(this.gl.getUniformLocation(this.program, "u_colorTexture"), 0);
|
|
22638
|
-
this.gl.uniform1i(this.gl.getUniformLocation(this.program, "u_alphaTexture"), 1);
|
|
22639
|
-
} catch (error) {
|
|
22640
|
-
this.gl = null;
|
|
22641
|
-
this.canvas = null;
|
|
22642
|
-
mergerGpuUnavailable = true;
|
|
22643
|
-
console.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);
|
|
22644
22851
|
}
|
|
22645
22852
|
}
|
|
22646
|
-
}
|
|
22647
|
-
async update(color, alpha) {
|
|
22648
|
-
if (this.gl) {
|
|
22649
|
-
return this.updateGpu(color, alpha);
|
|
22650
|
-
} else {
|
|
22651
|
-
return this.updateCpu(color, alpha);
|
|
22652
|
-
}
|
|
22653
|
-
}
|
|
22654
|
-
createProgram() {
|
|
22655
|
-
assert(this.gl);
|
|
22656
|
-
const vertexShader = this.createShader(this.gl.VERTEX_SHADER, `#version 300 es
|
|
22657
|
-
in vec2 a_position;
|
|
22658
|
-
in vec2 a_texCoord;
|
|
22659
|
-
out vec2 v_texCoord;
|
|
22660
|
-
|
|
22661
|
-
void main() {
|
|
22662
|
-
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
22663
|
-
v_texCoord = a_texCoord;
|
|
22664
|
-
}
|
|
22665
|
-
`);
|
|
22666
|
-
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, `#version 300 es
|
|
22667
|
-
precision highp float;
|
|
22668
|
-
|
|
22669
|
-
uniform sampler2D u_colorTexture;
|
|
22670
|
-
uniform sampler2D u_alphaTexture;
|
|
22671
|
-
in vec2 v_texCoord;
|
|
22672
|
-
out vec4 fragColor;
|
|
22673
|
-
|
|
22674
|
-
void main() {
|
|
22675
|
-
vec3 color = texture(u_colorTexture, v_texCoord).rgb;
|
|
22676
|
-
float alpha = texture(u_alphaTexture, v_texCoord).r;
|
|
22677
|
-
fragColor = vec4(color, alpha);
|
|
22678
|
-
}
|
|
22679
|
-
`);
|
|
22680
|
-
const program = this.gl.createProgram();
|
|
22681
|
-
this.gl.attachShader(program, vertexShader);
|
|
22682
|
-
this.gl.attachShader(program, fragmentShader);
|
|
22683
|
-
this.gl.linkProgram(program);
|
|
22684
|
-
return program;
|
|
22685
|
-
}
|
|
22686
|
-
createShader(type, source) {
|
|
22687
|
-
assert(this.gl);
|
|
22688
|
-
const shader = this.gl.createShader(type);
|
|
22689
|
-
this.gl.shaderSource(shader, source);
|
|
22690
|
-
this.gl.compileShader(shader);
|
|
22691
|
-
return shader;
|
|
22692
|
-
}
|
|
22693
|
-
createVAO() {
|
|
22694
|
-
assert(this.gl);
|
|
22695
|
-
assert(this.program);
|
|
22696
|
-
const vao = this.gl.createVertexArray();
|
|
22697
|
-
this.gl.bindVertexArray(vao);
|
|
22698
|
-
const vertices = new Float32Array([
|
|
22699
|
-
-1,
|
|
22700
|
-
-1,
|
|
22701
|
-
0,
|
|
22702
|
-
1,
|
|
22703
|
-
1,
|
|
22704
|
-
-1,
|
|
22705
|
-
1,
|
|
22706
|
-
1,
|
|
22707
|
-
-1,
|
|
22708
|
-
1,
|
|
22709
|
-
0,
|
|
22710
|
-
0,
|
|
22711
|
-
1,
|
|
22712
|
-
1,
|
|
22713
|
-
1,
|
|
22714
|
-
0
|
|
22715
|
-
]);
|
|
22716
|
-
const buffer = this.gl.createBuffer();
|
|
22717
|
-
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
|
|
22718
|
-
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW);
|
|
22719
|
-
const positionLocation = this.gl.getAttribLocation(this.program, "a_position");
|
|
22720
|
-
const texCoordLocation = this.gl.getAttribLocation(this.program, "a_texCoord");
|
|
22721
|
-
this.gl.enableVertexAttribArray(positionLocation);
|
|
22722
|
-
this.gl.vertexAttribPointer(positionLocation, 2, this.gl.FLOAT, false, 16, 0);
|
|
22723
|
-
this.gl.enableVertexAttribArray(texCoordLocation);
|
|
22724
|
-
this.gl.vertexAttribPointer(texCoordLocation, 2, this.gl.FLOAT, false, 16, 8);
|
|
22725
|
-
return vao;
|
|
22726
|
-
}
|
|
22727
|
-
createTexture() {
|
|
22728
|
-
assert(this.gl);
|
|
22729
|
-
const texture = this.gl.createTexture();
|
|
22730
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
22731
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
22732
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
22733
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
|
22734
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
|
|
22735
|
-
return texture;
|
|
22736
|
-
}
|
|
22737
|
-
updateGpu(color, alpha) {
|
|
22738
|
-
assert(this.gl);
|
|
22739
|
-
assert(this.canvas);
|
|
22740
|
-
if (color.displayWidth !== this.canvas.width || color.displayHeight !== this.canvas.height) {
|
|
22741
|
-
this.canvas.width = color.displayWidth;
|
|
22742
|
-
this.canvas.height = color.displayHeight;
|
|
22743
|
-
}
|
|
22744
|
-
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
22745
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, this.colorTexture);
|
|
22746
|
-
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, color);
|
|
22747
|
-
this.gl.activeTexture(this.gl.TEXTURE1);
|
|
22748
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, this.alphaTexture);
|
|
22749
|
-
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, alpha);
|
|
22750
|
-
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
22751
|
-
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
22752
|
-
this.gl.bindVertexArray(this.vao);
|
|
22753
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
22754
|
-
const finalFrame = new VideoFrame(this.canvas, {
|
|
22755
|
-
timestamp: color.timestamp,
|
|
22756
|
-
duration: color.duration ?? void 0
|
|
22757
|
-
});
|
|
22758
|
-
color.close();
|
|
22759
|
-
alpha.close();
|
|
22760
|
-
return finalFrame;
|
|
22761
|
-
}
|
|
22762
|
-
updateCpu(color, alpha) {
|
|
22763
|
-
if (!this.worker) {
|
|
22764
|
-
const blob = new Blob(
|
|
22765
|
-
[`(${colorAlphaMergerWorkerCode.toString()})()`],
|
|
22766
|
-
{ type: "application/javascript" }
|
|
22767
|
-
);
|
|
22768
|
-
const url2 = URL.createObjectURL(blob);
|
|
22769
|
-
this.worker = new Worker(url2);
|
|
22770
|
-
URL.revokeObjectURL(url2);
|
|
22771
|
-
this.worker.addEventListener("message", (event) => {
|
|
22772
|
-
const data = event.data;
|
|
22773
|
-
const pending2 = this.pendingRequests.get(data.id);
|
|
22774
|
-
if (!pending2) {
|
|
22775
|
-
return;
|
|
22776
|
-
}
|
|
22777
|
-
this.pendingRequests.delete(data.id);
|
|
22778
|
-
if ("error" in data) {
|
|
22779
|
-
pending2.reject(new Error(data.error));
|
|
22780
|
-
} else {
|
|
22781
|
-
pending2.resolve(data.frame);
|
|
22782
|
-
}
|
|
22783
|
-
});
|
|
22784
|
-
this.worker.addEventListener("error", (event) => {
|
|
22785
|
-
const error = new Error(event.message || "Color/alpha merge worker error.");
|
|
22786
|
-
for (const pending2 of this.pendingRequests.values()) {
|
|
22787
|
-
pending2.reject(error);
|
|
22788
|
-
}
|
|
22789
|
-
this.pendingRequests.clear();
|
|
22790
|
-
});
|
|
22791
|
-
}
|
|
22792
22853
|
const id = this.nextRequestId++;
|
|
22793
22854
|
const pending = promiseWithResolvers();
|
|
22794
22855
|
this.pendingRequests.set(id, pending);
|
|
22795
|
-
|
|
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] });
|
|
22796
22859
|
return pending.promise;
|
|
22797
22860
|
}
|
|
22798
22861
|
close() {
|
|
22799
|
-
this.
|
|
22800
|
-
|
|
22801
|
-
|
|
22802
|
-
this.
|
|
22803
|
-
this.worker = null;
|
|
22862
|
+
for (const worker of this.workers) {
|
|
22863
|
+
worker.terminate();
|
|
22864
|
+
}
|
|
22865
|
+
this.workers.length = 0;
|
|
22804
22866
|
const error = new Error("Color/alpha merger closed.");
|
|
22805
22867
|
for (const pending of this.pendingRequests.values()) {
|
|
22806
22868
|
pending.reject(error);
|
|
@@ -22808,8 +22870,6 @@ var Mediabunny = (() => {
|
|
|
22808
22870
|
this.pendingRequests.clear();
|
|
22809
22871
|
}
|
|
22810
22872
|
};
|
|
22811
|
-
_ColorAlphaMerger.forceCpu = true;
|
|
22812
|
-
var ColorAlphaMerger = _ColorAlphaMerger;
|
|
22813
22873
|
var colorAlphaMergerWorkerCode = () => {
|
|
22814
22874
|
let cpuAlphaBuffer = null;
|
|
22815
22875
|
let cpuColorBuffer = null;
|
|
@@ -22843,18 +22903,18 @@ var Mediabunny = (() => {
|
|
|
22843
22903
|
`CPU color/alpha merging requires the alpha frame to have the same bit depth as the color frame (color: '${format}', alpha: '${alphaFormat}').`
|
|
22844
22904
|
);
|
|
22845
22905
|
}
|
|
22846
|
-
const width = color.codedWidth;
|
|
22847
|
-
const height = color.codedHeight;
|
|
22848
22906
|
if (format === "RGBX" || format === "RGBA" || format === "BGRX" || format === "BGRA") {
|
|
22849
|
-
return await mergeInterleavedRgba(color, alpha,
|
|
22907
|
+
return await mergeInterleavedRgba(color, alpha, format);
|
|
22850
22908
|
} else if (format === "I420" || format === "I420P10" || format === "I420P12" || format === "I422" || format === "I422P10" || format === "I422P12" || format === "I444" || format === "I444P10" || format === "I444P12") {
|
|
22851
|
-
return await mergePlanarYuv(color, alpha,
|
|
22909
|
+
return await mergePlanarYuv(color, alpha, format);
|
|
22852
22910
|
} else if (format === "NV12") {
|
|
22853
|
-
return await mergeNv12(color, alpha
|
|
22911
|
+
return await mergeNv12(color, alpha);
|
|
22854
22912
|
}
|
|
22855
22913
|
throw new Error(`CPU color/alpha merging does not support format '${format}'.`);
|
|
22856
22914
|
};
|
|
22857
|
-
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;
|
|
22858
22918
|
const pixelCount = width * height;
|
|
22859
22919
|
const output = new Uint8Array(pixelCount * 4);
|
|
22860
22920
|
await color.copyTo(output);
|
|
@@ -22873,7 +22933,9 @@ var Mediabunny = (() => {
|
|
|
22873
22933
|
};
|
|
22874
22934
|
return new VideoFrame(output, init);
|
|
22875
22935
|
};
|
|
22876
|
-
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;
|
|
22877
22939
|
const is10 = format.includes("P10");
|
|
22878
22940
|
const is12 = format.includes("P12");
|
|
22879
22941
|
const bytesPerSample = is10 || is12 ? 2 : 1;
|
|
@@ -22911,7 +22973,9 @@ var Mediabunny = (() => {
|
|
|
22911
22973
|
};
|
|
22912
22974
|
return new VideoFrame(output, init);
|
|
22913
22975
|
};
|
|
22914
|
-
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;
|
|
22915
22979
|
const ySize = width * height;
|
|
22916
22980
|
const chromaW = Math.ceil(width / 2);
|
|
22917
22981
|
const chromaH = Math.ceil(height / 2);
|
|
@@ -23274,7 +23338,10 @@ var Mediabunny = (() => {
|
|
|
23274
23338
|
}
|
|
23275
23339
|
sampleHandler(sample);
|
|
23276
23340
|
};
|
|
23277
|
-
|
|
23341
|
+
this.customDecoder.onError = (error) => {
|
|
23342
|
+
onError(error);
|
|
23343
|
+
};
|
|
23344
|
+
void this.customDecoderCallSerializer.call(() => this.customDecoder.init()).catch((error) => onError(error));
|
|
23278
23345
|
} else {
|
|
23279
23346
|
const stack = new Error("Decoding error").stack;
|
|
23280
23347
|
this.decoder = new AudioDecoder({
|
|
@@ -23304,7 +23371,7 @@ var Mediabunny = (() => {
|
|
|
23304
23371
|
decode(packet) {
|
|
23305
23372
|
if (this.customDecoder) {
|
|
23306
23373
|
this.customDecoderQueueSize++;
|
|
23307
|
-
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--);
|
|
23308
23375
|
} else {
|
|
23309
23376
|
assert(this.decoder);
|
|
23310
23377
|
this.expectedFirstTimestamp ??= packet.timestamp;
|
|
@@ -24180,7 +24247,7 @@ var Mediabunny = (() => {
|
|
|
24180
24247
|
const support = await VideoDecoder.isConfigSupported(decoderConfig);
|
|
24181
24248
|
return support.supported === true;
|
|
24182
24249
|
} catch (error) {
|
|
24183
|
-
|
|
24250
|
+
Logging._error("Error during decodability check:", error);
|
|
24184
24251
|
return false;
|
|
24185
24252
|
}
|
|
24186
24253
|
}
|
|
@@ -24282,7 +24349,7 @@ var Mediabunny = (() => {
|
|
|
24282
24349
|
return support.supported === true;
|
|
24283
24350
|
}
|
|
24284
24351
|
} catch (error) {
|
|
24285
|
-
|
|
24352
|
+
Logging._error("Error during decodability check:", error);
|
|
24286
24353
|
return false;
|
|
24287
24354
|
}
|
|
24288
24355
|
}
|
|
@@ -25323,19 +25390,20 @@ var Mediabunny = (() => {
|
|
|
25323
25390
|
slice.filePos = startPos;
|
|
25324
25391
|
return null;
|
|
25325
25392
|
}
|
|
25326
|
-
|
|
25393
|
+
let size = decodeSynchsafe(sizeRaw);
|
|
25394
|
+
if (flags & 16 /* Footer */) {
|
|
25395
|
+
size += ID3_V2_HEADER_SIZE;
|
|
25396
|
+
}
|
|
25327
25397
|
return { majorVersion, revision, flags, size };
|
|
25328
25398
|
};
|
|
25329
25399
|
var parseId3V2Tag = (slice, header, tags) => {
|
|
25330
25400
|
if (![2, 3, 4].includes(header.majorVersion)) {
|
|
25331
|
-
|
|
25401
|
+
Logging._warn(`Unsupported ID3v2 major version: ${header.majorVersion}`);
|
|
25332
25402
|
return;
|
|
25333
25403
|
}
|
|
25334
|
-
const
|
|
25404
|
+
const dataSize = header.flags & 16 /* Footer */ ? header.size - ID3_V2_HEADER_SIZE : header.size;
|
|
25405
|
+
const bytes2 = readBytes(slice, dataSize);
|
|
25335
25406
|
const reader = new Id3V2Reader(header, bytes2);
|
|
25336
|
-
if (header.flags & 16 /* Footer */) {
|
|
25337
|
-
reader.removeFooter();
|
|
25338
|
-
}
|
|
25339
25407
|
if (header.flags & 128 /* Unsynchronisation */ && header.majorVersion === 3) {
|
|
25340
25408
|
reader.ununsynchronizeAll();
|
|
25341
25409
|
}
|
|
@@ -25366,12 +25434,12 @@ var Mediabunny = (() => {
|
|
|
25366
25434
|
frameUnsynchronized = !!(frame.flags & 1 << 1) || !!(header.flags & 128 /* Unsynchronisation */);
|
|
25367
25435
|
}
|
|
25368
25436
|
if (frameEncrypted) {
|
|
25369
|
-
|
|
25437
|
+
Logging._warn(`Skipping encrypted ID3v2 frame ${frame.id}`);
|
|
25370
25438
|
reader.pos = frameEndPos;
|
|
25371
25439
|
continue;
|
|
25372
25440
|
}
|
|
25373
25441
|
if (frameCompressed) {
|
|
25374
|
-
|
|
25442
|
+
Logging._warn(`Skipping compressed ID3v2 frame ${frame.id}`);
|
|
25375
25443
|
reader.pos = frameEndPos;
|
|
25376
25444
|
continue;
|
|
25377
25445
|
}
|
|
@@ -25607,10 +25675,6 @@ var Mediabunny = (() => {
|
|
|
25607
25675
|
this.bytes.set(after, before.length + newBytes.length);
|
|
25608
25676
|
this.view = new DataView(this.bytes.buffer);
|
|
25609
25677
|
}
|
|
25610
|
-
removeFooter() {
|
|
25611
|
-
this.bytes = this.bytes.subarray(0, this.bytes.length - ID3_V2_HEADER_SIZE);
|
|
25612
|
-
this.view = new DataView(this.bytes.buffer);
|
|
25613
|
-
}
|
|
25614
25678
|
readBytes(length) {
|
|
25615
25679
|
const slice = this.bytes.subarray(this.pos, this.pos + length);
|
|
25616
25680
|
this.pos += length;
|
|
@@ -27045,7 +27109,7 @@ var Mediabunny = (() => {
|
|
|
27045
27109
|
i16(65535)
|
|
27046
27110
|
// Pre-defined
|
|
27047
27111
|
], [
|
|
27048
|
-
VIDEO_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec](trackData),
|
|
27112
|
+
VIDEO_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec]?.(trackData) ?? null,
|
|
27049
27113
|
pasp(trackData),
|
|
27050
27114
|
colorSpaceIsComplete(trackData.info.decoderConfig.colorSpace) ? colr(trackData) : null
|
|
27051
27115
|
]);
|
|
@@ -28040,6 +28104,8 @@ var Mediabunny = (() => {
|
|
|
28040
28104
|
return "vp09";
|
|
28041
28105
|
case "av1":
|
|
28042
28106
|
return "av01";
|
|
28107
|
+
case "prores":
|
|
28108
|
+
return fullCodecString;
|
|
28043
28109
|
}
|
|
28044
28110
|
};
|
|
28045
28111
|
var VIDEO_CODEC_TO_CONFIGURATION_BOX = {
|
|
@@ -28047,7 +28113,8 @@ var Mediabunny = (() => {
|
|
|
28047
28113
|
hevc: hvcC,
|
|
28048
28114
|
vp8: vpcC,
|
|
28049
28115
|
vp9: vpcC,
|
|
28050
|
-
av1: av1C
|
|
28116
|
+
av1: av1C,
|
|
28117
|
+
prores: null
|
|
28051
28118
|
};
|
|
28052
28119
|
var audioCodecToBoxName = (codec, isQuickTime) => {
|
|
28053
28120
|
switch (codec) {
|
|
@@ -30004,6 +30071,7 @@ var Mediabunny = (() => {
|
|
|
30004
30071
|
{ id: 156 /* FlagLacing */, data: 0 },
|
|
30005
30072
|
{ id: 2274716 /* Language */, data: trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE },
|
|
30006
30073
|
{ id: 134 /* CodecID */, data: codecId },
|
|
30074
|
+
trackData.codecPrivate ? { id: 25506 /* CodecPrivate */, data: toUint8Array(trackData.codecPrivate) } : null,
|
|
30007
30075
|
{ id: 22186 /* CodecDelay */, data: 0 },
|
|
30008
30076
|
{ id: 22203 /* SeekPreRoll */, data: seekPreRollNs },
|
|
30009
30077
|
trackData.track.metadata.name !== void 0 ? { id: 21358 /* Name */, data: new EBMLUnicodeString(trackData.track.metadata.name) } : null,
|
|
@@ -30016,10 +30084,6 @@ var Mediabunny = (() => {
|
|
|
30016
30084
|
videoSpecificTrackInfo(trackData) {
|
|
30017
30085
|
const { frameRate, rotation } = trackData.track.metadata;
|
|
30018
30086
|
const elements = [
|
|
30019
|
-
trackData.info.decoderConfig.description ? {
|
|
30020
|
-
id: 25506 /* CodecPrivate */,
|
|
30021
|
-
data: toUint8Array(trackData.info.decoderConfig.description)
|
|
30022
|
-
} : null,
|
|
30023
30087
|
frameRate ? {
|
|
30024
30088
|
id: 2352003 /* DefaultDuration */,
|
|
30025
30089
|
data: 1e9 / frameRate
|
|
@@ -30079,10 +30143,6 @@ var Mediabunny = (() => {
|
|
|
30079
30143
|
audioSpecificTrackInfo(trackData) {
|
|
30080
30144
|
const pcmInfo = PCM_AUDIO_CODECS.includes(trackData.track.source._codec) ? parsePcmCodec(trackData.track.source._codec) : null;
|
|
30081
30145
|
return [
|
|
30082
|
-
trackData.info.decoderConfig.description ? {
|
|
30083
|
-
id: 25506 /* CodecPrivate */,
|
|
30084
|
-
data: toUint8Array(trackData.info.decoderConfig.description)
|
|
30085
|
-
} : null,
|
|
30086
30146
|
{ id: 225 /* Audio */, data: [
|
|
30087
30147
|
{ id: 181 /* SamplingFrequency */, data: new EBMLFloat32(trackData.info.sampleRate) },
|
|
30088
30148
|
{ id: 159 /* Channels */, data: trackData.info.numberOfChannels },
|
|
@@ -30090,10 +30150,9 @@ var Mediabunny = (() => {
|
|
|
30090
30150
|
] }
|
|
30091
30151
|
];
|
|
30092
30152
|
}
|
|
30153
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
30093
30154
|
subtitleSpecificTrackInfo(trackData) {
|
|
30094
|
-
return [
|
|
30095
|
-
{ id: 25506 /* CodecPrivate */, data: textEncoder.encode(trackData.info.config.description) }
|
|
30096
|
-
];
|
|
30155
|
+
return [];
|
|
30097
30156
|
}
|
|
30098
30157
|
maybeCreateTags() {
|
|
30099
30158
|
const simpleTags = [];
|
|
@@ -30382,22 +30441,19 @@ var Mediabunny = (() => {
|
|
|
30382
30441
|
},
|
|
30383
30442
|
chunkQueue: [],
|
|
30384
30443
|
lastWrittenMsTimestamp: null,
|
|
30444
|
+
codecPrivate: meta.decoderConfig.description ?? null,
|
|
30385
30445
|
closed: false
|
|
30386
30446
|
};
|
|
30387
30447
|
if (track.source._codec === "vp9") {
|
|
30388
|
-
newTrackData.
|
|
30389
|
-
|
|
30390
|
-
|
|
30391
|
-
generateVp9CodecConfigurationFromCodecString(newTrackData.info.decoderConfig.codec)
|
|
30392
|
-
)
|
|
30393
|
-
};
|
|
30448
|
+
newTrackData.codecPrivate = new Uint8Array(
|
|
30449
|
+
generateVp9CodecConfigurationFromCodecString(newTrackData.info.decoderConfig.codec)
|
|
30450
|
+
);
|
|
30394
30451
|
} else if (track.source._codec === "av1") {
|
|
30395
|
-
newTrackData.
|
|
30396
|
-
|
|
30397
|
-
|
|
30398
|
-
|
|
30399
|
-
|
|
30400
|
-
};
|
|
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);
|
|
30401
30457
|
}
|
|
30402
30458
|
this.trackDatas.push(newTrackData);
|
|
30403
30459
|
this.trackDatas.sort((a, b) => a.track.id - b.track.id);
|
|
@@ -30446,6 +30502,7 @@ var Mediabunny = (() => {
|
|
|
30446
30502
|
},
|
|
30447
30503
|
chunkQueue: [],
|
|
30448
30504
|
lastWrittenMsTimestamp: null,
|
|
30505
|
+
codecPrivate: decoderConfig.description ?? null,
|
|
30449
30506
|
closed: false
|
|
30450
30507
|
};
|
|
30451
30508
|
this.trackDatas.push(newTrackData);
|
|
@@ -30471,6 +30528,7 @@ var Mediabunny = (() => {
|
|
|
30471
30528
|
},
|
|
30472
30529
|
chunkQueue: [],
|
|
30473
30530
|
lastWrittenMsTimestamp: null,
|
|
30531
|
+
codecPrivate: textEncoder.encode(meta.config.description),
|
|
30474
30532
|
closed: false
|
|
30475
30533
|
};
|
|
30476
30534
|
this.trackDatas.push(newTrackData);
|
|
@@ -32066,7 +32124,7 @@ ${cue.notes ?? ""}`;
|
|
|
32066
32124
|
const writtenTags = /* @__PURE__ */ new Set();
|
|
32067
32125
|
const writeInfoTag = (tag, value) => {
|
|
32068
32126
|
if (!isIso88591Compatible(value)) {
|
|
32069
|
-
|
|
32127
|
+
Logging._warn(`Didn't write tag '${tag}' because '${value}' is not ISO 8859-1-compatible.`);
|
|
32070
32128
|
return;
|
|
32071
32129
|
}
|
|
32072
32130
|
const size = value.length + 1;
|
|
@@ -32544,8 +32602,15 @@ ${cue.notes ?? ""}`;
|
|
|
32544
32602
|
* So, we keep track of the encoder error and throw it as soon as we get the chance.
|
|
32545
32603
|
*/
|
|
32546
32604
|
this.error = null;
|
|
32547
|
-
this.
|
|
32605
|
+
this.errorSet = false;
|
|
32548
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
|
+
}
|
|
32549
32614
|
}
|
|
32550
32615
|
async add(videoSample, shouldClose, encodeOptions) {
|
|
32551
32616
|
const originalSample = videoSample;
|
|
@@ -32696,7 +32761,8 @@ ${cue.notes ?? ""}`;
|
|
|
32696
32761
|
if (this.customEncoder) {
|
|
32697
32762
|
this.customEncoderQueueSize++;
|
|
32698
32763
|
const clonedSample = sampleToEncode.clone();
|
|
32699
|
-
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--;
|
|
32700
32766
|
clonedSample.close();
|
|
32701
32767
|
});
|
|
32702
32768
|
if (this.customEncoderQueueSize >= 4) {
|
|
@@ -32740,12 +32806,10 @@ ${cue.notes ?? ""}`;
|
|
|
32740
32806
|
this.encoder.encode(videoFrame, finalEncodeOptions);
|
|
32741
32807
|
videoFrame.close();
|
|
32742
32808
|
} else {
|
|
32743
|
-
const width = videoFrame.displayWidth;
|
|
32744
|
-
const height = videoFrame.displayHeight;
|
|
32745
32809
|
if (!this.splitter) {
|
|
32746
|
-
this.splitter = new ColorAlphaSplitter(
|
|
32810
|
+
this.splitter = new ColorAlphaSplitter();
|
|
32747
32811
|
}
|
|
32748
|
-
const { colorFrame, alphaFrame } = await this.splitter.
|
|
32812
|
+
const { colorFrame, alphaFrame } = await this.splitter.split(videoFrame);
|
|
32749
32813
|
this.alphaFrameQueue.push(alphaFrame);
|
|
32750
32814
|
this.encoder.encode(colorFrame, finalEncodeOptions);
|
|
32751
32815
|
colorFrame.close();
|
|
@@ -32809,9 +32873,12 @@ ${cue.notes ?? ""}`;
|
|
|
32809
32873
|
maybeEnsureIsKeyPacket(this.source._connectedTrack, packet);
|
|
32810
32874
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
|
32811
32875
|
this.lastMuxerPromise = this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta).catch((error) => {
|
|
32812
|
-
this.error
|
|
32876
|
+
this.setError(error);
|
|
32813
32877
|
});
|
|
32814
32878
|
};
|
|
32879
|
+
this.customEncoder.onError = (error) => {
|
|
32880
|
+
this.setError(error);
|
|
32881
|
+
};
|
|
32815
32882
|
await this.customEncoder.init();
|
|
32816
32883
|
} else {
|
|
32817
32884
|
if (typeof VideoEncoder === "undefined") {
|
|
@@ -32869,7 +32936,7 @@ ${cue.notes ?? ""}`;
|
|
|
32869
32936
|
maybeEnsureIsKeyPacket(this.source._connectedTrack, packet);
|
|
32870
32937
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
|
32871
32938
|
this.lastMuxerPromise = this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta).catch((error) => {
|
|
32872
|
-
this.error
|
|
32939
|
+
this.setError(error);
|
|
32873
32940
|
});
|
|
32874
32941
|
this.emittedEncoderPackets++;
|
|
32875
32942
|
};
|
|
@@ -32903,7 +32970,7 @@ ${cue.notes ?? ""}`;
|
|
|
32903
32970
|
},
|
|
32904
32971
|
error: (error) => {
|
|
32905
32972
|
error.stack = stack;
|
|
32906
|
-
this.error
|
|
32973
|
+
this.setError(error);
|
|
32907
32974
|
}
|
|
32908
32975
|
});
|
|
32909
32976
|
this.encoder.configure(encoderConfig);
|
|
@@ -32927,7 +32994,7 @@ ${cue.notes ?? ""}`;
|
|
|
32927
32994
|
},
|
|
32928
32995
|
error: (error) => {
|
|
32929
32996
|
error.stack = stack2;
|
|
32930
|
-
this.error
|
|
32997
|
+
this.setError(error);
|
|
32931
32998
|
}
|
|
32932
32999
|
});
|
|
32933
33000
|
this.alphaEncoder.configure(encoderConfig);
|
|
@@ -32981,274 +33048,28 @@ ${cue.notes ?? ""}`;
|
|
|
32981
33048
|
}
|
|
32982
33049
|
}
|
|
32983
33050
|
checkForEncoderError() {
|
|
32984
|
-
if (this.
|
|
33051
|
+
if (this.errorSet) {
|
|
32985
33052
|
throw this.error;
|
|
32986
33053
|
}
|
|
32987
33054
|
}
|
|
32988
33055
|
};
|
|
32989
|
-
var
|
|
32990
|
-
var
|
|
32991
|
-
constructor(
|
|
32992
|
-
this.canvas = null;
|
|
32993
|
-
this.gl = null;
|
|
32994
|
-
this.colorProgram = null;
|
|
32995
|
-
this.alphaProgram = null;
|
|
32996
|
-
this.vao = null;
|
|
32997
|
-
this.sourceTexture = null;
|
|
32998
|
-
this.alphaResolutionLocation = null;
|
|
33056
|
+
var splitterWorkerUrl = null;
|
|
33057
|
+
var ColorAlphaSplitter = class {
|
|
33058
|
+
constructor() {
|
|
32999
33059
|
this.worker = null;
|
|
33000
33060
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
33001
33061
|
this.nextRequestId = 0;
|
|
33002
|
-
const canMakeCanvas = typeof OffscreenCanvas !== "undefined" || typeof document !== "undefined" && typeof document.createElement === "function";
|
|
33003
|
-
if (!_ColorAlphaSplitter.forceCpu && canMakeCanvas && !splitterGpuUnavailable) {
|
|
33004
|
-
try {
|
|
33005
|
-
if (typeof OffscreenCanvas !== "undefined") {
|
|
33006
|
-
this.canvas = new OffscreenCanvas(initialWidth, initialHeight);
|
|
33007
|
-
} else {
|
|
33008
|
-
this.canvas = document.createElement("canvas");
|
|
33009
|
-
this.canvas.width = initialWidth;
|
|
33010
|
-
this.canvas.height = initialHeight;
|
|
33011
|
-
}
|
|
33012
|
-
const gl = this.canvas.getContext("webgl2", {
|
|
33013
|
-
alpha: true
|
|
33014
|
-
// Needed due to the YUV thing we do for alpha
|
|
33015
|
-
});
|
|
33016
|
-
if (!gl) {
|
|
33017
|
-
throw new Error("Couldn't acquire WebGL 2 context.");
|
|
33018
|
-
}
|
|
33019
|
-
this.gl = gl;
|
|
33020
|
-
this.colorProgram = this.createColorProgram();
|
|
33021
|
-
this.alphaProgram = this.createAlphaProgram();
|
|
33022
|
-
this.vao = this.createVAO();
|
|
33023
|
-
this.sourceTexture = this.createTexture();
|
|
33024
|
-
this.alphaResolutionLocation = this.gl.getUniformLocation(this.alphaProgram, "u_resolution");
|
|
33025
|
-
this.gl.useProgram(this.colorProgram);
|
|
33026
|
-
this.gl.uniform1i(this.gl.getUniformLocation(this.colorProgram, "u_sourceTexture"), 0);
|
|
33027
|
-
this.gl.useProgram(this.alphaProgram);
|
|
33028
|
-
this.gl.uniform1i(this.gl.getUniformLocation(this.alphaProgram, "u_sourceTexture"), 0);
|
|
33029
|
-
} catch (error) {
|
|
33030
|
-
this.gl = null;
|
|
33031
|
-
this.canvas = null;
|
|
33032
|
-
splitterGpuUnavailable = true;
|
|
33033
|
-
console.warn("Falling back to CPU for color/alpha splitting.", error);
|
|
33034
|
-
}
|
|
33035
|
-
}
|
|
33036
|
-
}
|
|
33037
|
-
async update(sourceFrame) {
|
|
33038
|
-
if (this.gl) {
|
|
33039
|
-
return this.updateGpu(sourceFrame);
|
|
33040
|
-
} else {
|
|
33041
|
-
return this.updateCpu(sourceFrame);
|
|
33042
|
-
}
|
|
33043
|
-
}
|
|
33044
|
-
updateGpu(sourceFrame) {
|
|
33045
|
-
assert(this.gl);
|
|
33046
|
-
assert(this.canvas);
|
|
33047
|
-
if (sourceFrame.displayWidth !== this.canvas.width || sourceFrame.displayHeight !== this.canvas.height) {
|
|
33048
|
-
this.canvas.width = sourceFrame.displayWidth;
|
|
33049
|
-
this.canvas.height = sourceFrame.displayHeight;
|
|
33050
|
-
}
|
|
33051
|
-
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
33052
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, this.sourceTexture);
|
|
33053
|
-
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, sourceFrame);
|
|
33054
|
-
const colorFrame = this.runColorProgram(sourceFrame);
|
|
33055
|
-
const alphaFrame = this.runAlphaProgram(sourceFrame);
|
|
33056
|
-
sourceFrame.close();
|
|
33057
|
-
return { colorFrame, alphaFrame };
|
|
33058
|
-
}
|
|
33059
|
-
createVertexShader() {
|
|
33060
|
-
assert(this.gl);
|
|
33061
|
-
return this.createShader(this.gl.VERTEX_SHADER, `#version 300 es
|
|
33062
|
-
in vec2 a_position;
|
|
33063
|
-
in vec2 a_texCoord;
|
|
33064
|
-
out vec2 v_texCoord;
|
|
33065
|
-
|
|
33066
|
-
void main() {
|
|
33067
|
-
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
33068
|
-
v_texCoord = a_texCoord;
|
|
33069
|
-
}
|
|
33070
|
-
`);
|
|
33071
|
-
}
|
|
33072
|
-
createColorProgram() {
|
|
33073
|
-
assert(this.gl);
|
|
33074
|
-
const vertexShader = this.createVertexShader();
|
|
33075
|
-
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, `#version 300 es
|
|
33076
|
-
precision highp float;
|
|
33077
|
-
|
|
33078
|
-
uniform sampler2D u_sourceTexture;
|
|
33079
|
-
in vec2 v_texCoord;
|
|
33080
|
-
out vec4 fragColor;
|
|
33081
|
-
|
|
33082
|
-
void main() {
|
|
33083
|
-
vec4 source = texture(u_sourceTexture, v_texCoord);
|
|
33084
|
-
fragColor = vec4(source.rgb, 1.0);
|
|
33085
|
-
}
|
|
33086
|
-
`);
|
|
33087
|
-
const program = this.gl.createProgram();
|
|
33088
|
-
this.gl.attachShader(program, vertexShader);
|
|
33089
|
-
this.gl.attachShader(program, fragmentShader);
|
|
33090
|
-
this.gl.linkProgram(program);
|
|
33091
|
-
return program;
|
|
33092
|
-
}
|
|
33093
|
-
createAlphaProgram() {
|
|
33094
|
-
assert(this.gl);
|
|
33095
|
-
const vertexShader = this.createVertexShader();
|
|
33096
|
-
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, `#version 300 es
|
|
33097
|
-
precision highp float;
|
|
33098
|
-
|
|
33099
|
-
uniform sampler2D u_sourceTexture;
|
|
33100
|
-
uniform vec2 u_resolution; // The width and height of the canvas
|
|
33101
|
-
in vec2 v_texCoord;
|
|
33102
|
-
out vec4 fragColor;
|
|
33103
|
-
|
|
33104
|
-
// This function determines the value for a single byte in the YUV stream
|
|
33105
|
-
float getByteValue(float byteOffset) {
|
|
33106
|
-
float width = u_resolution.x;
|
|
33107
|
-
float height = u_resolution.y;
|
|
33108
|
-
|
|
33109
|
-
float yPlaneSize = width * height;
|
|
33110
|
-
|
|
33111
|
-
if (byteOffset < yPlaneSize) {
|
|
33112
|
-
// This byte is in the luma plane. Find the corresponding pixel coordinates to sample from
|
|
33113
|
-
float y = floor(byteOffset / width);
|
|
33114
|
-
float x = mod(byteOffset, width);
|
|
33115
|
-
|
|
33116
|
-
// Add 0.5 to sample the center of the texel
|
|
33117
|
-
vec2 sampleCoord = (vec2(x, y) + 0.5) / u_resolution;
|
|
33118
|
-
|
|
33119
|
-
// The luma value is the alpha from the source texture
|
|
33120
|
-
return texture(u_sourceTexture, sampleCoord).a;
|
|
33121
|
-
} else {
|
|
33122
|
-
// Write a fixed value for chroma and beyond
|
|
33123
|
-
return 128.0 / 255.0;
|
|
33124
|
-
}
|
|
33125
|
-
}
|
|
33126
|
-
|
|
33127
|
-
void main() {
|
|
33128
|
-
// Each fragment writes 4 bytes (R, G, B, A)
|
|
33129
|
-
float pixelIndex = floor(gl_FragCoord.y) * u_resolution.x + floor(gl_FragCoord.x);
|
|
33130
|
-
float baseByteOffset = pixelIndex * 4.0;
|
|
33131
|
-
|
|
33132
|
-
vec4 result;
|
|
33133
|
-
for (int i = 0; i < 4; i++) {
|
|
33134
|
-
float currentByteOffset = baseByteOffset + float(i);
|
|
33135
|
-
result[i] = getByteValue(currentByteOffset);
|
|
33136
|
-
}
|
|
33137
|
-
|
|
33138
|
-
fragColor = result;
|
|
33139
|
-
}
|
|
33140
|
-
`);
|
|
33141
|
-
const program = this.gl.createProgram();
|
|
33142
|
-
this.gl.attachShader(program, vertexShader);
|
|
33143
|
-
this.gl.attachShader(program, fragmentShader);
|
|
33144
|
-
this.gl.linkProgram(program);
|
|
33145
|
-
return program;
|
|
33146
|
-
}
|
|
33147
|
-
createShader(type, source) {
|
|
33148
|
-
assert(this.gl);
|
|
33149
|
-
const shader = this.gl.createShader(type);
|
|
33150
|
-
this.gl.shaderSource(shader, source);
|
|
33151
|
-
this.gl.compileShader(shader);
|
|
33152
|
-
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
|
|
33153
|
-
console.error("Shader compile error:", this.gl.getShaderInfoLog(shader));
|
|
33154
|
-
}
|
|
33155
|
-
return shader;
|
|
33156
|
-
}
|
|
33157
|
-
createVAO() {
|
|
33158
|
-
assert(this.gl);
|
|
33159
|
-
assert(this.colorProgram);
|
|
33160
|
-
const vao = this.gl.createVertexArray();
|
|
33161
|
-
this.gl.bindVertexArray(vao);
|
|
33162
|
-
const vertices = new Float32Array([
|
|
33163
|
-
-1,
|
|
33164
|
-
-1,
|
|
33165
|
-
0,
|
|
33166
|
-
1,
|
|
33167
|
-
1,
|
|
33168
|
-
-1,
|
|
33169
|
-
1,
|
|
33170
|
-
1,
|
|
33171
|
-
-1,
|
|
33172
|
-
1,
|
|
33173
|
-
0,
|
|
33174
|
-
0,
|
|
33175
|
-
1,
|
|
33176
|
-
1,
|
|
33177
|
-
1,
|
|
33178
|
-
0
|
|
33179
|
-
]);
|
|
33180
|
-
const buffer = this.gl.createBuffer();
|
|
33181
|
-
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
|
|
33182
|
-
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW);
|
|
33183
|
-
const positionLocation = this.gl.getAttribLocation(this.colorProgram, "a_position");
|
|
33184
|
-
const texCoordLocation = this.gl.getAttribLocation(this.colorProgram, "a_texCoord");
|
|
33185
|
-
this.gl.enableVertexAttribArray(positionLocation);
|
|
33186
|
-
this.gl.vertexAttribPointer(positionLocation, 2, this.gl.FLOAT, false, 16, 0);
|
|
33187
|
-
this.gl.enableVertexAttribArray(texCoordLocation);
|
|
33188
|
-
this.gl.vertexAttribPointer(texCoordLocation, 2, this.gl.FLOAT, false, 16, 8);
|
|
33189
|
-
return vao;
|
|
33190
|
-
}
|
|
33191
|
-
createTexture() {
|
|
33192
|
-
assert(this.gl);
|
|
33193
|
-
const texture = this.gl.createTexture();
|
|
33194
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
33195
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
33196
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
33197
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
|
33198
|
-
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
|
|
33199
|
-
return texture;
|
|
33200
|
-
}
|
|
33201
|
-
runColorProgram(sourceFrame) {
|
|
33202
|
-
assert(this.gl);
|
|
33203
|
-
assert(this.canvas);
|
|
33204
|
-
this.gl.useProgram(this.colorProgram);
|
|
33205
|
-
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
33206
|
-
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
33207
|
-
this.gl.bindVertexArray(this.vao);
|
|
33208
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
33209
|
-
return new VideoFrame(this.canvas, {
|
|
33210
|
-
timestamp: sourceFrame.timestamp,
|
|
33211
|
-
duration: sourceFrame.duration ?? void 0,
|
|
33212
|
-
alpha: "discard"
|
|
33213
|
-
});
|
|
33214
|
-
}
|
|
33215
|
-
runAlphaProgram(sourceFrame) {
|
|
33216
|
-
assert(this.gl);
|
|
33217
|
-
assert(this.canvas);
|
|
33218
|
-
this.gl.useProgram(this.alphaProgram);
|
|
33219
|
-
this.gl.uniform2f(this.alphaResolutionLocation, this.canvas.width, this.canvas.height);
|
|
33220
|
-
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
33221
|
-
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
33222
|
-
this.gl.bindVertexArray(this.vao);
|
|
33223
|
-
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
|
|
33224
|
-
const { width, height } = this.canvas;
|
|
33225
|
-
const chromaSamples = Math.ceil(width / 2) * Math.ceil(height / 2);
|
|
33226
|
-
const yuvSize = width * height + chromaSamples * 2;
|
|
33227
|
-
const requiredHeight = Math.ceil(yuvSize / (width * 4));
|
|
33228
|
-
let yuv = new Uint8Array(4 * width * requiredHeight);
|
|
33229
|
-
this.gl.readPixels(0, 0, width, requiredHeight, this.gl.RGBA, this.gl.UNSIGNED_BYTE, yuv);
|
|
33230
|
-
yuv = yuv.subarray(0, yuvSize);
|
|
33231
|
-
assert(yuv[width * height] === 128);
|
|
33232
|
-
assert(yuv[yuv.length - 1] === 128);
|
|
33233
|
-
const init = {
|
|
33234
|
-
format: "I420",
|
|
33235
|
-
codedWidth: width,
|
|
33236
|
-
codedHeight: height,
|
|
33237
|
-
timestamp: sourceFrame.timestamp,
|
|
33238
|
-
duration: sourceFrame.duration ?? void 0,
|
|
33239
|
-
transfer: [yuv.buffer]
|
|
33240
|
-
};
|
|
33241
|
-
return new VideoFrame(yuv, init);
|
|
33242
33062
|
}
|
|
33243
|
-
|
|
33063
|
+
split(sourceFrame) {
|
|
33244
33064
|
if (!this.worker) {
|
|
33245
|
-
|
|
33246
|
-
|
|
33247
|
-
|
|
33248
|
-
|
|
33249
|
-
|
|
33250
|
-
|
|
33251
|
-
|
|
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);
|
|
33252
33073
|
this.worker.addEventListener("message", (event) => {
|
|
33253
33074
|
const data = event.data;
|
|
33254
33075
|
const pending2 = this.pendingRequests.get(data.id);
|
|
@@ -33277,9 +33098,6 @@ ${cue.notes ?? ""}`;
|
|
|
33277
33098
|
return pending.promise;
|
|
33278
33099
|
}
|
|
33279
33100
|
close() {
|
|
33280
|
-
this.gl?.getExtension("WEBGL_lose_context")?.loseContext();
|
|
33281
|
-
this.gl = null;
|
|
33282
|
-
this.canvas = null;
|
|
33283
33101
|
this.worker?.terminate();
|
|
33284
33102
|
this.worker = null;
|
|
33285
33103
|
const error = new Error("Color/alpha splitter closed.");
|
|
@@ -33289,8 +33107,6 @@ ${cue.notes ?? ""}`;
|
|
|
33289
33107
|
this.pendingRequests.clear();
|
|
33290
33108
|
}
|
|
33291
33109
|
};
|
|
33292
|
-
_ColorAlphaSplitter.forceCpu = true;
|
|
33293
|
-
var ColorAlphaSplitter = _ColorAlphaSplitter;
|
|
33294
33110
|
var colorAlphaSplitterWorkerCode = () => {
|
|
33295
33111
|
let cpuSourceBuffer = null;
|
|
33296
33112
|
let chain = Promise.resolve();
|
|
@@ -33312,21 +33128,21 @@ ${cue.notes ?? ""}`;
|
|
|
33312
33128
|
if (!format) {
|
|
33313
33129
|
throw new Error("CPU color/alpha splitting requires a known VideoFrame format.");
|
|
33314
33130
|
}
|
|
33315
|
-
const width = sourceFrame.codedWidth;
|
|
33316
|
-
const height = sourceFrame.codedHeight;
|
|
33317
33131
|
const sourceSize = sourceFrame.allocationSize();
|
|
33318
33132
|
if (!cpuSourceBuffer || cpuSourceBuffer.byteLength !== sourceSize) {
|
|
33319
33133
|
cpuSourceBuffer = new Uint8Array(sourceSize);
|
|
33320
33134
|
}
|
|
33321
33135
|
await sourceFrame.copyTo(cpuSourceBuffer);
|
|
33322
33136
|
if (format === "RGBA" || format === "BGRA") {
|
|
33323
|
-
return splitInterleavedRgba(cpuSourceBuffer,
|
|
33137
|
+
return splitInterleavedRgba(cpuSourceBuffer, format, sourceFrame);
|
|
33324
33138
|
} else if (format === "I420A" || format === "I420AP10" || format === "I420AP12" || format === "I422A" || format === "I422AP10" || format === "I422AP12" || format === "I444A" || format === "I444AP10" || format === "I444AP12") {
|
|
33325
|
-
return splitPlanarYuvA(cpuSourceBuffer,
|
|
33139
|
+
return splitPlanarYuvA(cpuSourceBuffer, format, sourceFrame);
|
|
33326
33140
|
}
|
|
33327
33141
|
throw new Error(`CPU color/alpha splitting does not support format '${format}'.`);
|
|
33328
33142
|
};
|
|
33329
|
-
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;
|
|
33330
33146
|
const pixelCount = width * height;
|
|
33331
33147
|
const chromaW = Math.ceil(width / 2);
|
|
33332
33148
|
const chromaH = Math.ceil(height / 2);
|
|
@@ -33355,7 +33171,9 @@ ${cue.notes ?? ""}`;
|
|
|
33355
33171
|
const alphaFrame = new VideoFrame(alphaBuffer, alphaInit);
|
|
33356
33172
|
return { colorFrame, alphaFrame };
|
|
33357
33173
|
};
|
|
33358
|
-
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;
|
|
33359
33177
|
const is10 = format.includes("P10");
|
|
33360
33178
|
const is12 = format.includes("P12");
|
|
33361
33179
|
const bytesPerSample = is10 || is12 ? 2 : 1;
|
|
@@ -33540,7 +33358,7 @@ ${cue.notes ?? ""}`;
|
|
|
33540
33358
|
/** @internal */
|
|
33541
33359
|
async _start() {
|
|
33542
33360
|
if (!this._errorPromiseAccessed) {
|
|
33543
|
-
|
|
33361
|
+
Logging._warn(
|
|
33544
33362
|
"Make sure not to ignore the `errorPromise` field on MediaStreamVideoTrackSource, so that any internal errors get bubbled up properly."
|
|
33545
33363
|
);
|
|
33546
33364
|
}
|
|
@@ -33820,9 +33638,16 @@ ${cue.notes ?? ""}`;
|
|
|
33820
33638
|
* So, we keep track of the encoder error and throw it as soon as we get the chance.
|
|
33821
33639
|
*/
|
|
33822
33640
|
this.error = null;
|
|
33641
|
+
this.errorSet = false;
|
|
33823
33642
|
this.lastMuxerPromise = Promise.resolve();
|
|
33824
33643
|
this.closed = false;
|
|
33825
33644
|
}
|
|
33645
|
+
setError(error) {
|
|
33646
|
+
if (!this.errorSet) {
|
|
33647
|
+
this.error = error;
|
|
33648
|
+
this.errorSet = true;
|
|
33649
|
+
}
|
|
33650
|
+
}
|
|
33826
33651
|
async add(audioSample, shouldClose) {
|
|
33827
33652
|
try {
|
|
33828
33653
|
this.checkForEncoderError();
|
|
@@ -33944,7 +33769,8 @@ ${cue.notes ?? ""}`;
|
|
|
33944
33769
|
if (this.customEncoder) {
|
|
33945
33770
|
this.customEncoderQueueSize++;
|
|
33946
33771
|
const clonedSample = audioSample.clone();
|
|
33947
|
-
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--;
|
|
33948
33774
|
clonedSample.close();
|
|
33949
33775
|
});
|
|
33950
33776
|
if (this.customEncoderQueueSize >= 4) {
|
|
@@ -34050,9 +33876,12 @@ ${cue.notes ?? ""}`;
|
|
|
34050
33876
|
}
|
|
34051
33877
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
|
34052
33878
|
this.lastMuxerPromise = this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta).catch((error) => {
|
|
34053
|
-
this.error
|
|
33879
|
+
this.setError(error);
|
|
34054
33880
|
});
|
|
34055
33881
|
};
|
|
33882
|
+
this.customEncoder.onError = (error) => {
|
|
33883
|
+
this.setError(error);
|
|
33884
|
+
};
|
|
34056
33885
|
await this.customEncoder.init();
|
|
34057
33886
|
} else if (PCM_AUDIO_CODECS.includes(this.encodingConfig.codec)) {
|
|
34058
33887
|
this.initPcmEncoder();
|
|
@@ -34095,12 +33924,12 @@ ${cue.notes ?? ""}`;
|
|
|
34095
33924
|
});
|
|
34096
33925
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
|
34097
33926
|
this.lastMuxerPromise = this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta).catch((error) => {
|
|
34098
|
-
this.error
|
|
33927
|
+
this.setError(error);
|
|
34099
33928
|
});
|
|
34100
33929
|
},
|
|
34101
33930
|
error: (error) => {
|
|
34102
33931
|
error.stack = stack;
|
|
34103
|
-
this.error
|
|
33932
|
+
this.setError(error);
|
|
34104
33933
|
}
|
|
34105
33934
|
});
|
|
34106
33935
|
this.encoder.configure(encoderConfig);
|
|
@@ -34241,7 +34070,7 @@ ${cue.notes ?? ""}`;
|
|
|
34241
34070
|
}
|
|
34242
34071
|
}
|
|
34243
34072
|
checkForEncoderError() {
|
|
34244
|
-
if (this.
|
|
34073
|
+
if (this.errorSet) {
|
|
34245
34074
|
throw this.error;
|
|
34246
34075
|
}
|
|
34247
34076
|
}
|
|
@@ -34357,7 +34186,7 @@ ${cue.notes ?? ""}`;
|
|
|
34357
34186
|
/** @internal */
|
|
34358
34187
|
async _start() {
|
|
34359
34188
|
if (!this._errorPromiseAccessed) {
|
|
34360
|
-
|
|
34189
|
+
Logging._warn(
|
|
34361
34190
|
"Make sure not to ignore the `errorPromise` field on MediaStreamAudioTrackSource, so that any internal errors get bubbled up properly."
|
|
34362
34191
|
);
|
|
34363
34192
|
}
|
|
@@ -34601,12 +34430,14 @@ ${cue.notes ?? ""}`;
|
|
|
34601
34430
|
/** @internal */
|
|
34602
34431
|
this._error = null;
|
|
34603
34432
|
/** @internal */
|
|
34433
|
+
this._errorSet = false;
|
|
34434
|
+
/** @internal */
|
|
34604
34435
|
this._lastMuxerPromise = Promise.resolve();
|
|
34605
34436
|
this._parser = new SubtitleParser({
|
|
34606
34437
|
codec,
|
|
34607
34438
|
output: (cue, metadata) => {
|
|
34608
34439
|
this._lastMuxerPromise = this._connectedTrack.output._muxer.addSubtitleCue(this._connectedTrack, cue, metadata).catch((error) => {
|
|
34609
|
-
this.
|
|
34440
|
+
this._setError(error);
|
|
34610
34441
|
});
|
|
34611
34442
|
}
|
|
34612
34443
|
});
|
|
@@ -34628,8 +34459,15 @@ ${cue.notes ?? ""}`;
|
|
|
34628
34459
|
return this._lastMuxerPromise;
|
|
34629
34460
|
}
|
|
34630
34461
|
/** @internal */
|
|
34462
|
+
_setError(error) {
|
|
34463
|
+
if (!this._errorSet) {
|
|
34464
|
+
this._error = error;
|
|
34465
|
+
this._errorSet = true;
|
|
34466
|
+
}
|
|
34467
|
+
}
|
|
34468
|
+
/** @internal */
|
|
34631
34469
|
_checkForError() {
|
|
34632
|
-
if (this.
|
|
34470
|
+
if (this._errorSet) {
|
|
34633
34471
|
throw this._error;
|
|
34634
34472
|
}
|
|
34635
34473
|
}
|
|
@@ -34692,7 +34530,7 @@ ${cue.notes ?? ""}`;
|
|
|
34692
34530
|
}
|
|
34693
34531
|
if (track.type === otherTrack.type) {
|
|
34694
34532
|
if (!illegalPairingDetected) {
|
|
34695
|
-
|
|
34533
|
+
Logging._warn(
|
|
34696
34534
|
`Illegal pairing of two ${track.type} tracks detected, which is not possible in HLS; treating them as unpaired.`
|
|
34697
34535
|
);
|
|
34698
34536
|
illegalPairingDetected = true;
|
|
@@ -34701,7 +34539,7 @@ ${cue.notes ?? ""}`;
|
|
|
34701
34539
|
}
|
|
34702
34540
|
if (track.isVideoTrack() && track.metadata.hasOnlyKeyPackets || otherTrack.isVideoTrack() && otherTrack.metadata.hasOnlyKeyPackets) {
|
|
34703
34541
|
if (!keyPacketsOnlyPairingWarned) {
|
|
34704
|
-
|
|
34542
|
+
Logging._warn(
|
|
34705
34543
|
`A key-packets-only video track is pairable with another track, which is not possible in HLS; treating them as unpaired.`
|
|
34706
34544
|
);
|
|
34707
34545
|
keyPacketsOnlyPairingWarned = true;
|
|
@@ -35555,7 +35393,7 @@ ${cue.notes ?? ""}`;
|
|
|
35555
35393
|
groupIdTrackCount++;
|
|
35556
35394
|
masterPlaylistText += `#EXT-X-MEDIA:TYPE=${type.toUpperCase()},GROUP-ID="${decl.groupId}"`;
|
|
35557
35395
|
if (name !== null && /[\n\r"]/.test(name)) {
|
|
35558
|
-
|
|
35396
|
+
Logging._warn(
|
|
35559
35397
|
"Dropping track name since it includes a line feed, carriage return, or double quote character, which are not allowed in HLS playlist attributes."
|
|
35560
35398
|
);
|
|
35561
35399
|
name = null;
|
|
@@ -36789,7 +36627,7 @@ ${cue.notes ?? ""}`;
|
|
|
36789
36627
|
throw new Error("Output has been canceled.");
|
|
36790
36628
|
}
|
|
36791
36629
|
if (this._startPromise) {
|
|
36792
|
-
|
|
36630
|
+
Logging._warn("Output has already been started.");
|
|
36793
36631
|
return this._startPromise;
|
|
36794
36632
|
}
|
|
36795
36633
|
return this._startPromise = (async () => {
|
|
@@ -36820,11 +36658,11 @@ ${cue.notes ?? ""}`;
|
|
|
36820
36658
|
*/
|
|
36821
36659
|
async cancel() {
|
|
36822
36660
|
if (this._cancelPromise) {
|
|
36823
|
-
|
|
36661
|
+
Logging._warn("Output has already been canceled.");
|
|
36824
36662
|
return this._cancelPromise;
|
|
36825
36663
|
} else if (this.state === "finalizing" || this.state === "finalized") {
|
|
36826
36664
|
if (this.state === "finalized") {
|
|
36827
|
-
|
|
36665
|
+
Logging._warn("Output has already been finalized.");
|
|
36828
36666
|
}
|
|
36829
36667
|
return;
|
|
36830
36668
|
}
|
|
@@ -36853,7 +36691,7 @@ ${cue.notes ?? ""}`;
|
|
|
36853
36691
|
throw new Error("Cannot finalize after canceling.");
|
|
36854
36692
|
}
|
|
36855
36693
|
if (this._finalizePromise) {
|
|
36856
|
-
|
|
36694
|
+
Logging._warn("Output has already been finalized.");
|
|
36857
36695
|
return this._finalizePromise;
|
|
36858
36696
|
}
|
|
36859
36697
|
return this._finalizePromise = (async () => {
|
|
@@ -37301,7 +37139,7 @@ ${cue.notes ?? ""}`;
|
|
|
37301
37139
|
warnElements.push(this._getInvalidityExplanation().join(""));
|
|
37302
37140
|
}
|
|
37303
37141
|
if (warnElements.length > 0) {
|
|
37304
|
-
|
|
37142
|
+
Logging._warn(...warnElements);
|
|
37305
37143
|
}
|
|
37306
37144
|
}
|
|
37307
37145
|
}
|
|
@@ -37434,7 +37272,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37434
37272
|
return;
|
|
37435
37273
|
}
|
|
37436
37274
|
if (this._canceled) {
|
|
37437
|
-
|
|
37275
|
+
Logging._warn("Conversion already canceled.");
|
|
37438
37276
|
return;
|
|
37439
37277
|
}
|
|
37440
37278
|
this._canceled = true;
|
|
@@ -37565,7 +37403,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37565
37403
|
firstSample.close();
|
|
37566
37404
|
await tempOutput.finalize();
|
|
37567
37405
|
} catch (error) {
|
|
37568
|
-
|
|
37406
|
+
Logging._info("Error when probing encoder support. Falling back to rerender path.", error);
|
|
37569
37407
|
needsRerender = true;
|
|
37570
37408
|
void tempOutput.cancel();
|
|
37571
37409
|
}
|
|
@@ -37655,7 +37493,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37655
37493
|
let numberOfChannels = trackOptions.numberOfChannels ?? originalNumberOfChannels;
|
|
37656
37494
|
let sampleRate = trackOptions.sampleRate ?? originalSampleRate;
|
|
37657
37495
|
const needsTrimming = firstTimestamp < this._startTimestamp;
|
|
37658
|
-
|
|
37496
|
+
let needsPadding = firstTimestamp > this._startTimestamp && !this.output.format.supportsTimestampedMediaData;
|
|
37659
37497
|
let audioCodecs = this.output.format.getSupportedAudioCodecs();
|
|
37660
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) {
|
|
37661
37499
|
const source = new EncodedAudioPacketSource(sourceCodec);
|
|
@@ -37751,24 +37589,32 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37751
37589
|
audioSource = source;
|
|
37752
37590
|
this._trackPromises.push((async () => {
|
|
37753
37591
|
await this._started;
|
|
37754
|
-
if (needsPadding) {
|
|
37755
|
-
const paddingLength = firstTimestamp - this._startTimestamp;
|
|
37756
|
-
const paddingLengthSamples = Math.round(paddingLength * originalSampleRate);
|
|
37757
|
-
const silentSample = new AudioSample({
|
|
37758
|
-
data: new Float32Array(paddingLengthSamples * originalNumberOfChannels),
|
|
37759
|
-
format: "f32-planar",
|
|
37760
|
-
numberOfChannels: originalNumberOfChannels,
|
|
37761
|
-
sampleRate: originalSampleRate,
|
|
37762
|
-
timestamp: 0
|
|
37763
|
-
});
|
|
37764
|
-
await this._registerAudioSample(silentSample, source, outputTrackId, () => lastSampleTimestamp);
|
|
37765
|
-
}
|
|
37766
37592
|
const sink = new AudioSampleSink(track);
|
|
37767
37593
|
for await (let sample of sink.samples(this._startTimestamp, this._endTimestamp)) {
|
|
37768
37594
|
if (this._canceled) {
|
|
37769
37595
|
sample.close();
|
|
37770
37596
|
return;
|
|
37771
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
|
+
}
|
|
37772
37618
|
let startFrame = 0;
|
|
37773
37619
|
let endFrame = sample.numberOfFrames;
|
|
37774
37620
|
if (sample.timestamp < this._startTimestamp) {
|
|
@@ -37897,7 +37743,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37897
37743
|
// src/index.ts
|
|
37898
37744
|
var MEDIABUNNY_LOADED_SYMBOL = Symbol.for("mediabunny loaded");
|
|
37899
37745
|
if (globalThis[MEDIABUNNY_LOADED_SYMBOL]) {
|
|
37900
|
-
|
|
37746
|
+
Logging._error(
|
|
37901
37747
|
"[WARNING]\nMediabunny was loaded twice. This will likely cause Mediabunny not to work correctly. Check if multiple dependencies are importing different versions of Mediabunny, or if something is being bundled incorrectly."
|
|
37902
37748
|
);
|
|
37903
37749
|
}
|