mediabunny 1.26.0 → 1.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/bundles/mediabunny.cjs +314 -39
- package/dist/bundles/mediabunny.min.cjs +7 -7
- package/dist/bundles/mediabunny.min.mjs +7 -7
- package/dist/bundles/mediabunny.mjs +314 -39
- package/dist/mediabunny.d.ts +60 -10
- package/dist/modules/src/codec-data.d.ts +4 -2
- package/dist/modules/src/codec-data.d.ts.map +1 -1
- package/dist/modules/src/codec-data.js +47 -20
- package/dist/modules/src/conversion.d.ts +5 -0
- package/dist/modules/src/conversion.d.ts.map +1 -1
- package/dist/modules/src/conversion.js +6 -0
- package/dist/modules/src/index.d.ts +1 -1
- package/dist/modules/src/index.d.ts.map +1 -1
- package/dist/modules/src/index.js +1 -1
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-muxer.js +7 -4
- package/dist/modules/src/media-sink.d.ts.map +1 -1
- package/dist/modules/src/media-sink.js +28 -9
- package/dist/modules/src/sample.d.ts +52 -10
- package/dist/modules/src/sample.d.ts.map +1 -1
- package/dist/modules/src/sample.js +257 -13
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/codec-data.ts +52 -20
- package/src/conversion.ts +15 -0
- package/src/index.ts +3 -0
- package/src/isobmff/isobmff-muxer.ts +8 -4
- package/src/media-sink.ts +36 -9
- package/src/sample.ts +344 -20
package/README.md
CHANGED
|
@@ -17,7 +17,10 @@ Mediabunny is a JavaScript library for reading, writing, and converting media fi
|
|
|
17
17
|
|
|
18
18
|
<div align="center">
|
|
19
19
|
<a href="https://remotion.dev/" target="_blank" rel="sponsored">
|
|
20
|
-
<
|
|
20
|
+
<picture>
|
|
21
|
+
<source srcset="./docs/public/sponsors/remotion-dark.png" media="(prefers-color-scheme: dark)">
|
|
22
|
+
<img src="./docs/public/sponsors/remotion-light.png" width="60" height="60" alt="Remotion">
|
|
23
|
+
</picture>
|
|
21
24
|
</a>
|
|
22
25
|
|
|
23
26
|
<a href="https://www.gling.ai/" target="_blank" rel="sponsored">
|
|
@@ -128,7 +128,9 @@ var Mediabunny = (() => {
|
|
|
128
128
|
TextSubtitleSource: () => TextSubtitleSource,
|
|
129
129
|
UrlSource: () => UrlSource,
|
|
130
130
|
VIDEO_CODECS: () => VIDEO_CODECS,
|
|
131
|
+
VIDEO_SAMPLE_PIXEL_FORMATS: () => VIDEO_SAMPLE_PIXEL_FORMATS,
|
|
131
132
|
VideoSample: () => VideoSample,
|
|
133
|
+
VideoSampleColorSpace: () => VideoSampleColorSpace,
|
|
132
134
|
VideoSampleSink: () => VideoSampleSink,
|
|
133
135
|
VideoSampleSource: () => VideoSampleSource,
|
|
134
136
|
VideoSource: () => VideoSource,
|
|
@@ -1930,27 +1932,44 @@ var Mediabunny = (() => {
|
|
|
1930
1932
|
}
|
|
1931
1933
|
return new Uint8Array(result);
|
|
1932
1934
|
};
|
|
1933
|
-
var
|
|
1934
|
-
|
|
1935
|
-
const
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
}
|
|
1939
|
-
let totalSize = 0;
|
|
1935
|
+
var ANNEX_B_START_CODE = new Uint8Array([0, 0, 0, 1]);
|
|
1936
|
+
var concatNalUnitsInAnnexB = (nalUnits) => {
|
|
1937
|
+
const totalLength = nalUnits.reduce((a, b) => a + ANNEX_B_START_CODE.byteLength + b.byteLength, 0);
|
|
1938
|
+
const result = new Uint8Array(totalLength);
|
|
1939
|
+
let offset = 0;
|
|
1940
1940
|
for (const nalUnit of nalUnits) {
|
|
1941
|
-
|
|
1941
|
+
result.set(ANNEX_B_START_CODE, offset);
|
|
1942
|
+
offset += ANNEX_B_START_CODE.byteLength;
|
|
1943
|
+
result.set(nalUnit, offset);
|
|
1944
|
+
offset += nalUnit.byteLength;
|
|
1942
1945
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1946
|
+
return result;
|
|
1947
|
+
};
|
|
1948
|
+
var concatNalUnitsInLengthPrefixed = (nalUnits, lengthSize) => {
|
|
1949
|
+
const totalLength = nalUnits.reduce((a, b) => a + lengthSize + b.byteLength, 0);
|
|
1950
|
+
const result = new Uint8Array(totalLength);
|
|
1945
1951
|
let offset = 0;
|
|
1946
1952
|
for (const nalUnit of nalUnits) {
|
|
1947
|
-
const
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1953
|
+
const dataView = new DataView(result.buffer, result.byteOffset, result.byteLength);
|
|
1954
|
+
switch (lengthSize) {
|
|
1955
|
+
case 1:
|
|
1956
|
+
dataView.setUint8(offset, nalUnit.byteLength);
|
|
1957
|
+
break;
|
|
1958
|
+
case 2:
|
|
1959
|
+
dataView.setUint16(offset, nalUnit.byteLength, false);
|
|
1960
|
+
break;
|
|
1961
|
+
case 3:
|
|
1962
|
+
setUint24(dataView, offset, nalUnit.byteLength, false);
|
|
1963
|
+
break;
|
|
1964
|
+
case 4:
|
|
1965
|
+
dataView.setUint32(offset, nalUnit.byteLength, false);
|
|
1966
|
+
break;
|
|
1967
|
+
}
|
|
1968
|
+
offset += lengthSize;
|
|
1969
|
+
result.set(nalUnit, offset);
|
|
1951
1970
|
offset += nalUnit.byteLength;
|
|
1952
1971
|
}
|
|
1953
|
-
return
|
|
1972
|
+
return result;
|
|
1954
1973
|
};
|
|
1955
1974
|
var extractAvcNalUnits = (packetData, decoderConfig) => {
|
|
1956
1975
|
if (decoderConfig.description) {
|
|
@@ -1962,6 +1981,16 @@ var Mediabunny = (() => {
|
|
|
1962
1981
|
return findNalUnitsInAnnexB(packetData);
|
|
1963
1982
|
}
|
|
1964
1983
|
};
|
|
1984
|
+
var concatAvcNalUnits = (nalUnits, decoderConfig) => {
|
|
1985
|
+
if (decoderConfig.description) {
|
|
1986
|
+
const bytes2 = toUint8Array(decoderConfig.description);
|
|
1987
|
+
const lengthSizeMinusOne = bytes2[4] & 3;
|
|
1988
|
+
const lengthSize = lengthSizeMinusOne + 1;
|
|
1989
|
+
return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize);
|
|
1990
|
+
} else {
|
|
1991
|
+
return concatNalUnitsInAnnexB(nalUnits);
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1965
1994
|
var extractNalUnitTypeForAvc = (data) => {
|
|
1966
1995
|
return data[0] & 31;
|
|
1967
1996
|
};
|
|
@@ -3834,6 +3863,43 @@ var Mediabunny = (() => {
|
|
|
3834
3863
|
}
|
|
3835
3864
|
});
|
|
3836
3865
|
}
|
|
3866
|
+
var VIDEO_SAMPLE_PIXEL_FORMATS = [
|
|
3867
|
+
// 4:2:0 Y, U, V
|
|
3868
|
+
"I420",
|
|
3869
|
+
"I420P10",
|
|
3870
|
+
"I420P12",
|
|
3871
|
+
// 4:2:0 Y, U, V, A
|
|
3872
|
+
"I420A",
|
|
3873
|
+
"I420AP10",
|
|
3874
|
+
"I420AP12",
|
|
3875
|
+
// 4:2:2 Y, U, V
|
|
3876
|
+
"I422",
|
|
3877
|
+
"I422P10",
|
|
3878
|
+
"I422P12",
|
|
3879
|
+
// 4:2:2 Y, U, V, A
|
|
3880
|
+
"I422A",
|
|
3881
|
+
"I422AP10",
|
|
3882
|
+
"I422AP12",
|
|
3883
|
+
// 4:4:4 Y, U, V
|
|
3884
|
+
"I444",
|
|
3885
|
+
"I444P10",
|
|
3886
|
+
"I444P12",
|
|
3887
|
+
// 4:4:4 Y, U, V, A
|
|
3888
|
+
"I444A",
|
|
3889
|
+
"I444AP10",
|
|
3890
|
+
"I444AP12",
|
|
3891
|
+
// 4:2:0 Y, UV
|
|
3892
|
+
"NV12",
|
|
3893
|
+
// 4:4:4 RGBA
|
|
3894
|
+
"RGBA",
|
|
3895
|
+
// 4:4:4 RGBX (opaque)
|
|
3896
|
+
"RGBX",
|
|
3897
|
+
// 4:4:4 BGRA
|
|
3898
|
+
"BGRA",
|
|
3899
|
+
// 4:4:4 BGRX (opaque)
|
|
3900
|
+
"BGRX"
|
|
3901
|
+
];
|
|
3902
|
+
var VIDEO_SAMPLE_PIXEL_FORMATS_SET = new Set(VIDEO_SAMPLE_PIXEL_FORMATS);
|
|
3837
3903
|
var VideoSample = class _VideoSample {
|
|
3838
3904
|
constructor(data, init) {
|
|
3839
3905
|
/** @internal */
|
|
@@ -3842,8 +3908,8 @@ var Mediabunny = (() => {
|
|
|
3842
3908
|
if (!init || typeof init !== "object") {
|
|
3843
3909
|
throw new TypeError("init must be an object.");
|
|
3844
3910
|
}
|
|
3845
|
-
if (
|
|
3846
|
-
throw new TypeError("init.format must be
|
|
3911
|
+
if (init.format === void 0 || !VIDEO_SAMPLE_PIXEL_FORMATS_SET.has(init.format)) {
|
|
3912
|
+
throw new TypeError("init.format must be one of: " + VIDEO_SAMPLE_PIXEL_FORMATS.join(", "));
|
|
3847
3913
|
}
|
|
3848
3914
|
if (!Number.isInteger(init.codedWidth) || init.codedWidth <= 0) {
|
|
3849
3915
|
throw new TypeError("init.codedWidth must be a positive integer.");
|
|
@@ -3861,13 +3927,14 @@ var Mediabunny = (() => {
|
|
|
3861
3927
|
throw new TypeError("init.duration, when provided, must be a non-negative number.");
|
|
3862
3928
|
}
|
|
3863
3929
|
this._data = toUint8Array(data).slice();
|
|
3930
|
+
this._layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight);
|
|
3864
3931
|
this.format = init.format;
|
|
3865
3932
|
this.codedWidth = init.codedWidth;
|
|
3866
3933
|
this.codedHeight = init.codedHeight;
|
|
3867
3934
|
this.rotation = init.rotation ?? 0;
|
|
3868
3935
|
this.timestamp = init.timestamp;
|
|
3869
3936
|
this.duration = init.duration ?? 0;
|
|
3870
|
-
this.colorSpace = new
|
|
3937
|
+
this.colorSpace = new VideoSampleColorSpace(init.colorSpace);
|
|
3871
3938
|
} else if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) {
|
|
3872
3939
|
if (init?.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) {
|
|
3873
3940
|
throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");
|
|
@@ -3879,13 +3946,14 @@ var Mediabunny = (() => {
|
|
|
3879
3946
|
throw new TypeError("init.duration, when provided, must be a non-negative number.");
|
|
3880
3947
|
}
|
|
3881
3948
|
this._data = data;
|
|
3949
|
+
this._layout = null;
|
|
3882
3950
|
this.format = data.format;
|
|
3883
3951
|
this.codedWidth = data.displayWidth;
|
|
3884
3952
|
this.codedHeight = data.displayHeight;
|
|
3885
3953
|
this.rotation = init?.rotation ?? 0;
|
|
3886
3954
|
this.timestamp = init?.timestamp ?? data.timestamp / 1e6;
|
|
3887
3955
|
this.duration = init?.duration ?? (data.duration ?? 0) / 1e6;
|
|
3888
|
-
this.colorSpace = data.colorSpace;
|
|
3956
|
+
this.colorSpace = new VideoSampleColorSpace(data.colorSpace);
|
|
3889
3957
|
} else if (typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement || typeof SVGImageElement !== "undefined" && data instanceof SVGImageElement || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas) {
|
|
3890
3958
|
if (!init || typeof init !== "object") {
|
|
3891
3959
|
throw new TypeError("init must be an object.");
|
|
@@ -3933,13 +4001,14 @@ var Mediabunny = (() => {
|
|
|
3933
4001
|
assert(context);
|
|
3934
4002
|
context.drawImage(data, 0, 0);
|
|
3935
4003
|
this._data = canvas;
|
|
4004
|
+
this._layout = null;
|
|
3936
4005
|
this.format = "RGBX";
|
|
3937
4006
|
this.codedWidth = width;
|
|
3938
4007
|
this.codedHeight = height;
|
|
3939
4008
|
this.rotation = init.rotation ?? 0;
|
|
3940
4009
|
this.timestamp = init.timestamp;
|
|
3941
4010
|
this.duration = init.duration ?? 0;
|
|
3942
|
-
this.colorSpace = new
|
|
4011
|
+
this.colorSpace = new VideoSampleColorSpace({
|
|
3943
4012
|
matrix: "rgb",
|
|
3944
4013
|
primaries: "bt709",
|
|
3945
4014
|
transfer: "iec61966-2-1",
|
|
@@ -3986,8 +4055,10 @@ var Mediabunny = (() => {
|
|
|
3986
4055
|
rotation: this.rotation
|
|
3987
4056
|
});
|
|
3988
4057
|
} else if (this._data instanceof Uint8Array) {
|
|
3989
|
-
|
|
4058
|
+
assert(this._layout);
|
|
4059
|
+
return new _VideoSample(this._data, {
|
|
3990
4060
|
format: this.format,
|
|
4061
|
+
layout: this._layout,
|
|
3991
4062
|
codedWidth: this.codedWidth,
|
|
3992
4063
|
codedHeight: this.codedHeight,
|
|
3993
4064
|
timestamp: this.timestamp,
|
|
@@ -4023,34 +4094,71 @@ var Mediabunny = (() => {
|
|
|
4023
4094
|
}
|
|
4024
4095
|
this._closed = true;
|
|
4025
4096
|
}
|
|
4026
|
-
/**
|
|
4027
|
-
|
|
4097
|
+
/**
|
|
4098
|
+
* Returns the number of bytes required to hold this video sample's pixel data. Throws if `format` is `null`;
|
|
4099
|
+
* specify an explicit RGB format in the options in this case.
|
|
4100
|
+
*/
|
|
4101
|
+
allocationSize(options = {}) {
|
|
4102
|
+
validateVideoFrameCopyToOptions(options);
|
|
4028
4103
|
if (this._closed) {
|
|
4029
4104
|
throw new Error("VideoSample is closed.");
|
|
4030
4105
|
}
|
|
4106
|
+
if ((options.format ?? this.format) === null) {
|
|
4107
|
+
throw new Error(
|
|
4108
|
+
"Cannot get allocation size when format is null. Please manually provide an RGB pixel format in the options instead."
|
|
4109
|
+
);
|
|
4110
|
+
}
|
|
4031
4111
|
assert(this._data !== null);
|
|
4112
|
+
if (!isVideoFrame(this._data)) {
|
|
4113
|
+
if (options.colorSpace || options.format && options.format !== this.format || options.layout || options.rect) {
|
|
4114
|
+
const videoFrame = this.toVideoFrame();
|
|
4115
|
+
const size = videoFrame.allocationSize(options);
|
|
4116
|
+
videoFrame.close();
|
|
4117
|
+
return size;
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4032
4120
|
if (isVideoFrame(this._data)) {
|
|
4033
|
-
return this._data.allocationSize();
|
|
4121
|
+
return this._data.allocationSize(options);
|
|
4034
4122
|
} else if (this._data instanceof Uint8Array) {
|
|
4035
4123
|
return this._data.byteLength;
|
|
4036
4124
|
} else {
|
|
4037
4125
|
return this.codedWidth * this.codedHeight * 4;
|
|
4038
4126
|
}
|
|
4039
4127
|
}
|
|
4040
|
-
/**
|
|
4041
|
-
|
|
4128
|
+
/**
|
|
4129
|
+
* Copies this video sample's pixel data to an ArrayBuffer or ArrayBufferView. Throws if `format` is `null`;
|
|
4130
|
+
* specify an explicit RGB format in the options in this case.
|
|
4131
|
+
* @returns The byte layout of the planes of the copied data.
|
|
4132
|
+
*/
|
|
4133
|
+
async copyTo(destination, options = {}) {
|
|
4042
4134
|
if (!isAllowSharedBufferSource(destination)) {
|
|
4043
4135
|
throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");
|
|
4044
4136
|
}
|
|
4137
|
+
validateVideoFrameCopyToOptions(options);
|
|
4045
4138
|
if (this._closed) {
|
|
4046
4139
|
throw new Error("VideoSample is closed.");
|
|
4047
4140
|
}
|
|
4141
|
+
if ((options.format ?? this.format) === null) {
|
|
4142
|
+
throw new Error(
|
|
4143
|
+
"Cannot copy video sample data when format is null. Please manually provide an RGB pixel format in the options instead."
|
|
4144
|
+
);
|
|
4145
|
+
}
|
|
4048
4146
|
assert(this._data !== null);
|
|
4147
|
+
if (!isVideoFrame(this._data)) {
|
|
4148
|
+
if (options.colorSpace || options.format && options.format !== this.format || options.layout || options.rect) {
|
|
4149
|
+
const videoFrame = this.toVideoFrame();
|
|
4150
|
+
const layout = await videoFrame.copyTo(destination, options);
|
|
4151
|
+
videoFrame.close();
|
|
4152
|
+
return layout;
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
4049
4155
|
if (isVideoFrame(this._data)) {
|
|
4050
|
-
|
|
4156
|
+
return this._data.copyTo(destination, options);
|
|
4051
4157
|
} else if (this._data instanceof Uint8Array) {
|
|
4158
|
+
assert(this._layout);
|
|
4052
4159
|
const dest = toUint8Array(destination);
|
|
4053
4160
|
dest.set(this._data);
|
|
4161
|
+
return this._layout;
|
|
4054
4162
|
} else {
|
|
4055
4163
|
const canvas = this._data;
|
|
4056
4164
|
const context = canvas.getContext("2d");
|
|
@@ -4058,6 +4166,10 @@ var Mediabunny = (() => {
|
|
|
4058
4166
|
const imageData = context.getImageData(0, 0, this.codedWidth, this.codedHeight);
|
|
4059
4167
|
const dest = toUint8Array(destination);
|
|
4060
4168
|
dest.set(imageData.data);
|
|
4169
|
+
return [{
|
|
4170
|
+
offset: 0,
|
|
4171
|
+
stride: 4 * this.codedWidth
|
|
4172
|
+
}];
|
|
4061
4173
|
}
|
|
4062
4174
|
}
|
|
4063
4175
|
/**
|
|
@@ -4303,6 +4415,24 @@ var Mediabunny = (() => {
|
|
|
4303
4415
|
this.close();
|
|
4304
4416
|
}
|
|
4305
4417
|
};
|
|
4418
|
+
var VideoSampleColorSpace = class {
|
|
4419
|
+
/** Creates a new VideoSampleColorSpace. */
|
|
4420
|
+
constructor(init) {
|
|
4421
|
+
this.primaries = init?.primaries ?? null;
|
|
4422
|
+
this.transfer = init?.transfer ?? null;
|
|
4423
|
+
this.matrix = init?.matrix ?? null;
|
|
4424
|
+
this.fullRange = init?.fullRange ?? null;
|
|
4425
|
+
}
|
|
4426
|
+
/** Serializes the color space to a JSON object. */
|
|
4427
|
+
toJSON() {
|
|
4428
|
+
return {
|
|
4429
|
+
primaries: this.primaries,
|
|
4430
|
+
transfer: this.transfer,
|
|
4431
|
+
matrix: this.matrix,
|
|
4432
|
+
fullRange: this.fullRange
|
|
4433
|
+
};
|
|
4434
|
+
}
|
|
4435
|
+
};
|
|
4306
4436
|
var isVideoFrame = (x) => {
|
|
4307
4437
|
return typeof VideoFrame !== "undefined" && x instanceof VideoFrame;
|
|
4308
4438
|
};
|
|
@@ -4331,6 +4461,128 @@ var Mediabunny = (() => {
|
|
|
4331
4461
|
throw new TypeError(prefix + "crop.height must be a non-negative integer.");
|
|
4332
4462
|
}
|
|
4333
4463
|
};
|
|
4464
|
+
var validateVideoFrameCopyToOptions = (options) => {
|
|
4465
|
+
if (!options || typeof options !== "object") {
|
|
4466
|
+
throw new TypeError("options must be an object.");
|
|
4467
|
+
}
|
|
4468
|
+
if (options.colorSpace !== void 0 && !["display-p3", "srgb"].includes(options.colorSpace)) {
|
|
4469
|
+
throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");
|
|
4470
|
+
}
|
|
4471
|
+
if (options.format !== void 0 && typeof options.format !== "string") {
|
|
4472
|
+
throw new TypeError("options.format, when provided, must be a string.");
|
|
4473
|
+
}
|
|
4474
|
+
if (options.layout !== void 0) {
|
|
4475
|
+
if (!Array.isArray(options.layout)) {
|
|
4476
|
+
throw new TypeError("options.layout, when provided, must be an array.");
|
|
4477
|
+
}
|
|
4478
|
+
for (const plane of options.layout) {
|
|
4479
|
+
if (!plane || typeof plane !== "object") {
|
|
4480
|
+
throw new TypeError("Each entry in options.layout must be an object.");
|
|
4481
|
+
}
|
|
4482
|
+
if (!Number.isInteger(plane.offset) || plane.offset < 0) {
|
|
4483
|
+
throw new TypeError("plane.offset must be a non-negative integer.");
|
|
4484
|
+
}
|
|
4485
|
+
if (!Number.isInteger(plane.stride) || plane.stride < 0) {
|
|
4486
|
+
throw new TypeError("plane.stride must be a non-negative integer.");
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
if (options.rect !== void 0) {
|
|
4491
|
+
if (!options.rect || typeof options.rect !== "object") {
|
|
4492
|
+
throw new TypeError("options.rect, when provided, must be an object.");
|
|
4493
|
+
}
|
|
4494
|
+
if (options.rect.x !== void 0 && (!Number.isInteger(options.rect.x) || options.rect.x < 0)) {
|
|
4495
|
+
throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");
|
|
4496
|
+
}
|
|
4497
|
+
if (options.rect.y !== void 0 && (!Number.isInteger(options.rect.y) || options.rect.y < 0)) {
|
|
4498
|
+
throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");
|
|
4499
|
+
}
|
|
4500
|
+
if (options.rect.width !== void 0 && (!Number.isInteger(options.rect.width) || options.rect.width < 0)) {
|
|
4501
|
+
throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");
|
|
4502
|
+
}
|
|
4503
|
+
if (options.rect.height !== void 0 && (!Number.isInteger(options.rect.height) || options.rect.height < 0)) {
|
|
4504
|
+
throw new TypeError("options.rect.height, when provided, must be a non-negative integer.");
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
};
|
|
4508
|
+
var createDefaultPlaneLayout = (format, codedWidth, codedHeight) => {
|
|
4509
|
+
const planes = getPlaneConfigs(format);
|
|
4510
|
+
const layouts = [];
|
|
4511
|
+
let currentOffset = 0;
|
|
4512
|
+
for (const plane of planes) {
|
|
4513
|
+
const planeWidth = Math.ceil(codedWidth / plane.widthDivisor);
|
|
4514
|
+
const planeHeight = Math.ceil(codedHeight / plane.heightDivisor);
|
|
4515
|
+
const stride = planeWidth * plane.sampleBytes;
|
|
4516
|
+
const planeSize = stride * planeHeight;
|
|
4517
|
+
layouts.push({
|
|
4518
|
+
offset: currentOffset,
|
|
4519
|
+
stride
|
|
4520
|
+
});
|
|
4521
|
+
currentOffset += planeSize;
|
|
4522
|
+
}
|
|
4523
|
+
return layouts;
|
|
4524
|
+
};
|
|
4525
|
+
var getPlaneConfigs = (format) => {
|
|
4526
|
+
const yuv = (yBytes, uvBytes, subX, subY, hasAlpha) => {
|
|
4527
|
+
const configs = [
|
|
4528
|
+
{ sampleBytes: yBytes, widthDivisor: 1, heightDivisor: 1 },
|
|
4529
|
+
{ sampleBytes: uvBytes, widthDivisor: subX, heightDivisor: subY },
|
|
4530
|
+
{ sampleBytes: uvBytes, widthDivisor: subX, heightDivisor: subY }
|
|
4531
|
+
];
|
|
4532
|
+
if (hasAlpha) {
|
|
4533
|
+
configs.push({ sampleBytes: yBytes, widthDivisor: 1, heightDivisor: 1 });
|
|
4534
|
+
}
|
|
4535
|
+
return configs;
|
|
4536
|
+
};
|
|
4537
|
+
switch (format) {
|
|
4538
|
+
case "I420":
|
|
4539
|
+
return yuv(1, 1, 2, 2, false);
|
|
4540
|
+
case "I420P10":
|
|
4541
|
+
case "I420P12":
|
|
4542
|
+
return yuv(2, 2, 2, 2, false);
|
|
4543
|
+
case "I420A":
|
|
4544
|
+
return yuv(1, 1, 2, 2, true);
|
|
4545
|
+
case "I420AP10":
|
|
4546
|
+
case "I420AP12":
|
|
4547
|
+
return yuv(2, 2, 2, 2, true);
|
|
4548
|
+
case "I422":
|
|
4549
|
+
return yuv(1, 1, 2, 1, false);
|
|
4550
|
+
case "I422P10":
|
|
4551
|
+
case "I422P12":
|
|
4552
|
+
return yuv(2, 2, 2, 1, false);
|
|
4553
|
+
case "I422A":
|
|
4554
|
+
return yuv(1, 1, 2, 1, true);
|
|
4555
|
+
case "I422AP10":
|
|
4556
|
+
case "I422AP12":
|
|
4557
|
+
return yuv(2, 2, 2, 1, true);
|
|
4558
|
+
case "I444":
|
|
4559
|
+
return yuv(1, 1, 1, 1, false);
|
|
4560
|
+
case "I444P10":
|
|
4561
|
+
case "I444P12":
|
|
4562
|
+
return yuv(2, 2, 1, 1, false);
|
|
4563
|
+
case "I444A":
|
|
4564
|
+
return yuv(1, 1, 1, 1, true);
|
|
4565
|
+
case "I444AP10":
|
|
4566
|
+
case "I444AP12":
|
|
4567
|
+
return yuv(2, 2, 1, 1, true);
|
|
4568
|
+
case "NV12":
|
|
4569
|
+
return [
|
|
4570
|
+
{ sampleBytes: 1, widthDivisor: 1, heightDivisor: 1 },
|
|
4571
|
+
{ sampleBytes: 2, widthDivisor: 2, heightDivisor: 2 }
|
|
4572
|
+
// Interleaved U and V
|
|
4573
|
+
];
|
|
4574
|
+
case "RGBA":
|
|
4575
|
+
case "RGBX":
|
|
4576
|
+
case "BGRA":
|
|
4577
|
+
case "BGRX":
|
|
4578
|
+
return [
|
|
4579
|
+
{ sampleBytes: 4, widthDivisor: 1, heightDivisor: 1 }
|
|
4580
|
+
];
|
|
4581
|
+
default:
|
|
4582
|
+
assertNever(format);
|
|
4583
|
+
assert(false);
|
|
4584
|
+
}
|
|
4585
|
+
};
|
|
4334
4586
|
var AUDIO_SAMPLE_FORMATS = /* @__PURE__ */ new Set(
|
|
4335
4587
|
["f32", "f32-planar", "s16", "s16-planar", "s32", "s32-planar", "u8", "u8-planar"]
|
|
4336
4588
|
);
|
|
@@ -5086,7 +5338,6 @@ var Mediabunny = (() => {
|
|
|
5086
5338
|
let terminated = false;
|
|
5087
5339
|
let outOfBandError = null;
|
|
5088
5340
|
(async () => {
|
|
5089
|
-
const decoderError = new Error();
|
|
5090
5341
|
const decoder = await this._createDecoder((sample) => {
|
|
5091
5342
|
onQueueDequeue();
|
|
5092
5343
|
if (sample.timestamp >= endTimestamp) {
|
|
@@ -5115,7 +5366,6 @@ var Mediabunny = (() => {
|
|
|
5115
5366
|
}
|
|
5116
5367
|
}, (error) => {
|
|
5117
5368
|
if (!outOfBandError) {
|
|
5118
|
-
error.stack = decoderError.stack;
|
|
5119
5369
|
outOfBandError = error;
|
|
5120
5370
|
onQueueNotEmpty();
|
|
5121
5371
|
}
|
|
@@ -5225,7 +5475,6 @@ var Mediabunny = (() => {
|
|
|
5225
5475
|
({ promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers());
|
|
5226
5476
|
};
|
|
5227
5477
|
(async () => {
|
|
5228
|
-
const decoderError = new Error();
|
|
5229
5478
|
const decoder = await this._createDecoder((sample) => {
|
|
5230
5479
|
onQueueDequeue();
|
|
5231
5480
|
if (terminated) {
|
|
@@ -5246,7 +5495,6 @@ var Mediabunny = (() => {
|
|
|
5246
5495
|
}
|
|
5247
5496
|
}, (error) => {
|
|
5248
5497
|
if (!outOfBandError) {
|
|
5249
|
-
error.stack = decoderError.stack;
|
|
5250
5498
|
outOfBandError = error;
|
|
5251
5499
|
onQueueNotEmpty();
|
|
5252
5500
|
}
|
|
@@ -5436,6 +5684,7 @@ var Mediabunny = (() => {
|
|
|
5436
5684
|
}
|
|
5437
5685
|
}
|
|
5438
5686
|
}
|
|
5687
|
+
const stack = new Error("Decoding error").stack;
|
|
5439
5688
|
this.decoder = new VideoDecoder({
|
|
5440
5689
|
output: (frame) => {
|
|
5441
5690
|
try {
|
|
@@ -5444,7 +5693,10 @@ var Mediabunny = (() => {
|
|
|
5444
5693
|
this.onError(error);
|
|
5445
5694
|
}
|
|
5446
5695
|
},
|
|
5447
|
-
error:
|
|
5696
|
+
error: (error) => {
|
|
5697
|
+
error.stack = stack;
|
|
5698
|
+
this.onError(error);
|
|
5699
|
+
}
|
|
5448
5700
|
});
|
|
5449
5701
|
this.decoder.configure(this.decoderConfig);
|
|
5450
5702
|
}
|
|
@@ -5467,7 +5719,6 @@ var Mediabunny = (() => {
|
|
|
5467
5719
|
}
|
|
5468
5720
|
this.raslSkipped = true;
|
|
5469
5721
|
}
|
|
5470
|
-
this.currentPacketIndex++;
|
|
5471
5722
|
if (this.customDecoder) {
|
|
5472
5723
|
this.customDecoderQueueSize++;
|
|
5473
5724
|
void this.customDecoderCallSerializer.call(() => this.customDecoder.decode(packet)).then(() => this.customDecoderQueueSize--);
|
|
@@ -5476,9 +5727,19 @@ var Mediabunny = (() => {
|
|
|
5476
5727
|
if (!isWebKit()) {
|
|
5477
5728
|
insertSorted(this.inputTimestamps, packet.timestamp, (x) => x);
|
|
5478
5729
|
}
|
|
5730
|
+
if (isChromium() && this.currentPacketIndex === 0 && this.codec === "avc") {
|
|
5731
|
+
const nalUnits = extractAvcNalUnits(packet.data, this.decoderConfig);
|
|
5732
|
+
const filteredNalUnits = nalUnits.filter((x) => {
|
|
5733
|
+
const type = extractNalUnitTypeForAvc(x);
|
|
5734
|
+
return !(type >= 20 && type <= 31);
|
|
5735
|
+
});
|
|
5736
|
+
const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig);
|
|
5737
|
+
packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration);
|
|
5738
|
+
}
|
|
5479
5739
|
this.decoder.decode(packet.toEncodedVideoChunk());
|
|
5480
5740
|
this.decodeAlphaData(packet);
|
|
5481
5741
|
}
|
|
5742
|
+
this.currentPacketIndex++;
|
|
5482
5743
|
}
|
|
5483
5744
|
decodeAlphaData(packet) {
|
|
5484
5745
|
if (!packet.sideData.alpha || this.mergerCreationFailed) {
|
|
@@ -5517,6 +5778,7 @@ var Mediabunny = (() => {
|
|
|
5517
5778
|
}
|
|
5518
5779
|
}
|
|
5519
5780
|
};
|
|
5781
|
+
const stack = new Error("Decoding error").stack;
|
|
5520
5782
|
this.alphaDecoder = new VideoDecoder({
|
|
5521
5783
|
output: (frame) => {
|
|
5522
5784
|
try {
|
|
@@ -5525,7 +5787,10 @@ var Mediabunny = (() => {
|
|
|
5525
5787
|
this.onError(error);
|
|
5526
5788
|
}
|
|
5527
5789
|
},
|
|
5528
|
-
error:
|
|
5790
|
+
error: (error) => {
|
|
5791
|
+
error.stack = stack;
|
|
5792
|
+
this.onError(error);
|
|
5793
|
+
}
|
|
5529
5794
|
});
|
|
5530
5795
|
this.alphaDecoder.configure(this.decoderConfig);
|
|
5531
5796
|
}
|
|
@@ -6029,6 +6294,7 @@ var Mediabunny = (() => {
|
|
|
6029
6294
|
};
|
|
6030
6295
|
void this.customDecoderCallSerializer.call(() => this.customDecoder.init());
|
|
6031
6296
|
} else {
|
|
6297
|
+
const stack = new Error("Decoding error").stack;
|
|
6032
6298
|
this.decoder = new AudioDecoder({
|
|
6033
6299
|
output: (data) => {
|
|
6034
6300
|
try {
|
|
@@ -6037,7 +6303,10 @@ var Mediabunny = (() => {
|
|
|
6037
6303
|
this.onError(error);
|
|
6038
6304
|
}
|
|
6039
6305
|
},
|
|
6040
|
-
error:
|
|
6306
|
+
error: (error) => {
|
|
6307
|
+
error.stack = stack;
|
|
6308
|
+
this.onError(error);
|
|
6309
|
+
}
|
|
6041
6310
|
});
|
|
6042
6311
|
this.decoder.configure(decoderConfig);
|
|
6043
6312
|
}
|
|
@@ -19297,13 +19566,13 @@ var Mediabunny = (() => {
|
|
|
19297
19566
|
const trackData = this.getVideoTrackData(track, packet, meta);
|
|
19298
19567
|
let packetData = packet.data;
|
|
19299
19568
|
if (trackData.info.requiresAnnexBTransformation) {
|
|
19300
|
-
const
|
|
19301
|
-
if (
|
|
19569
|
+
const nalUnits = findNalUnitsInAnnexB(packetData);
|
|
19570
|
+
if (nalUnits.length === 0) {
|
|
19302
19571
|
throw new Error(
|
|
19303
19572
|
"Failed to transform packet data. Make sure all packets are provided in Annex B format, as specified in ITU-T-REC-H.264 and ITU-T-REC-H.265."
|
|
19304
19573
|
);
|
|
19305
19574
|
}
|
|
19306
|
-
packetData =
|
|
19575
|
+
packetData = concatNalUnitsInLengthPrefixed(nalUnits, 4);
|
|
19307
19576
|
}
|
|
19308
19577
|
const timestamp = this.validateAndNormalizeTimestamp(
|
|
19309
19578
|
trackData.track,
|
|
@@ -24525,6 +24794,11 @@ ${cue.notes ?? ""}`;
|
|
|
24525
24794
|
if (videoOptions?.processedHeight !== void 0 && (!Number.isInteger(videoOptions.processedHeight) || videoOptions.processedHeight <= 0)) {
|
|
24526
24795
|
throw new TypeError("options.video.processedHeight, when provided, must be a positive integer.");
|
|
24527
24796
|
}
|
|
24797
|
+
if (videoOptions?.hardwareAcceleration !== void 0 && !["no-preference", "prefer-hardware", "prefer-software"].includes(videoOptions.hardwareAcceleration)) {
|
|
24798
|
+
throw new TypeError(
|
|
24799
|
+
"options.video.hardwareAcceleration, when provided, must be 'no-preference', 'prefer-hardware' or 'prefer-software'."
|
|
24800
|
+
);
|
|
24801
|
+
}
|
|
24528
24802
|
};
|
|
24529
24803
|
var validateAudioOptions = (audioOptions) => {
|
|
24530
24804
|
if (audioOptions !== void 0 && (!audioOptions || typeof audioOptions !== "object")) {
|
|
@@ -24953,7 +25227,8 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
24953
25227
|
bitrate,
|
|
24954
25228
|
keyFrameInterval: trackOptions.keyFrameInterval,
|
|
24955
25229
|
sizeChangeBehavior: trackOptions.fit ?? "passThrough",
|
|
24956
|
-
alpha
|
|
25230
|
+
alpha,
|
|
25231
|
+
hardwareAcceleration: trackOptions.hardwareAcceleration
|
|
24957
25232
|
};
|
|
24958
25233
|
const source = new VideoSampleSource(encodingConfig);
|
|
24959
25234
|
videoSource = source;
|