@mediabunny/server 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/README.md +37 -1
- package/dist/bundles/mediabunny-server.cjs +183 -15
- package/dist/bundles/mediabunny-server.min.cjs +2 -2
- package/dist/bundles/mediabunny-server.min.mjs +2 -2
- package/dist/bundles/mediabunny-server.mjs +184 -15
- package/dist/modules/src/index.d.ts.map +1 -1
- package/dist/modules/src/index.js +3 -1
- package/dist/modules/src/misc.d.ts.map +1 -1
- package/dist/modules/src/misc.js +1 -0
- package/dist/modules/src/video-encoder.d.ts.map +1 -1
- package/dist/modules/src/video-encoder.js +58 -6
- package/dist/modules/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/index.ts +4 -1
- package/src/misc.ts +1 -0
- package/src/video-encoder.ts +67 -7
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// packages/server/src/index.ts
|
|
10
10
|
import {
|
|
11
11
|
AudioSample as AudioSample4,
|
|
12
|
+
Logging as Logging2,
|
|
12
13
|
registerDecoder,
|
|
13
14
|
registerEncoder,
|
|
14
15
|
registerVideoSampleTransformer,
|
|
@@ -28,6 +29,7 @@ var CODEC_TO_CODEC_ID = {
|
|
|
28
29
|
vp8: NodeAv.AV_CODEC_ID_VP8,
|
|
29
30
|
vp9: NodeAv.AV_CODEC_ID_VP9,
|
|
30
31
|
av1: NodeAv.AV_CODEC_ID_AV1,
|
|
32
|
+
prores: NodeAv.AV_CODEC_ID_PRORES,
|
|
31
33
|
aac: NodeAv.AV_CODEC_ID_AAC,
|
|
32
34
|
opus: NodeAv.AV_CODEC_ID_OPUS,
|
|
33
35
|
mp3: NodeAv.AV_CODEC_ID_MP3,
|
|
@@ -343,6 +345,56 @@ var getChannelLayout = (numChannels) => {
|
|
|
343
345
|
}
|
|
344
346
|
};
|
|
345
347
|
|
|
348
|
+
// src/logging.ts
|
|
349
|
+
var _Logging = class _Logging {
|
|
350
|
+
constructor() {
|
|
351
|
+
}
|
|
352
|
+
/** The current log level. Defaults to {@link LogLevel.Info}. */
|
|
353
|
+
static get level() {
|
|
354
|
+
return _Logging._level;
|
|
355
|
+
}
|
|
356
|
+
static set level(value) {
|
|
357
|
+
if (value !== 0 /* Silent */ && value !== 1 /* Errors */ && value !== 2 /* Warnings */ && value !== 3 /* Info */) {
|
|
358
|
+
throw new TypeError("Invalid log level. Use one of the values of the LogLevel enum.");
|
|
359
|
+
}
|
|
360
|
+
_Logging._level = value;
|
|
361
|
+
}
|
|
362
|
+
/** @internal */
|
|
363
|
+
static get _emitter() {
|
|
364
|
+
return _Logging._emitterInstance ??= new EventEmitter();
|
|
365
|
+
}
|
|
366
|
+
/** Registers a listener for a log event. Returns a function that, when called, removes the listener again. */
|
|
367
|
+
static on(event, listener, options) {
|
|
368
|
+
return _Logging._emitter.on(event, listener, options);
|
|
369
|
+
}
|
|
370
|
+
/** @internal */
|
|
371
|
+
static _error(...args) {
|
|
372
|
+
_Logging._emitter._emit("error", args);
|
|
373
|
+
if (_Logging._level >= 1 /* Errors */) {
|
|
374
|
+
console.error(...args);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/** @internal */
|
|
378
|
+
static _warn(...args) {
|
|
379
|
+
_Logging._emitter._emit("warn", args);
|
|
380
|
+
if (_Logging._level >= 2 /* Warnings */) {
|
|
381
|
+
console.warn(...args);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/** @internal */
|
|
385
|
+
static _info(...args) {
|
|
386
|
+
_Logging._emitter._emit("info", args);
|
|
387
|
+
if (_Logging._level >= 3 /* Info */) {
|
|
388
|
+
console.info(...args);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
/** @internal */
|
|
393
|
+
_Logging._level = 3 /* Info */;
|
|
394
|
+
/** @internal */
|
|
395
|
+
_Logging._emitterInstance = null;
|
|
396
|
+
var Logging = _Logging;
|
|
397
|
+
|
|
346
398
|
// src/misc.ts
|
|
347
399
|
function assert(x) {
|
|
348
400
|
if (!x) {
|
|
@@ -450,6 +502,9 @@ var binarySearchLessOrEqual = (arr, key, valueGetter) => {
|
|
|
450
502
|
}
|
|
451
503
|
return ans;
|
|
452
504
|
};
|
|
505
|
+
var assertNever = (x) => {
|
|
506
|
+
throw new Error(`Unexpected value: ${x}`);
|
|
507
|
+
};
|
|
453
508
|
var SECOND_TO_MICROSECOND_FACTOR = 1e6 * (1 + Number.EPSILON);
|
|
454
509
|
var simplifyRational = (rational) => {
|
|
455
510
|
assert(Number.isInteger(rational.num));
|
|
@@ -468,6 +523,41 @@ var simplifyRational = (rational) => {
|
|
|
468
523
|
den: rational.den / gcd
|
|
469
524
|
};
|
|
470
525
|
};
|
|
526
|
+
var EventEmitter = class {
|
|
527
|
+
constructor() {
|
|
528
|
+
/** @internal */
|
|
529
|
+
this._listeners = /* @__PURE__ */ new Map();
|
|
530
|
+
}
|
|
531
|
+
/** Registers a listener for the given event. Returns a function that, when called, removes the listener again. */
|
|
532
|
+
on(event, listener, options) {
|
|
533
|
+
if (!this._listeners.has(event)) {
|
|
534
|
+
this._listeners.set(event, /* @__PURE__ */ new Set());
|
|
535
|
+
}
|
|
536
|
+
const entry = { fn: listener, once: options?.once ?? false };
|
|
537
|
+
this._listeners.get(event).add(entry);
|
|
538
|
+
return () => {
|
|
539
|
+
this._listeners.get(event)?.delete(entry);
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
/** @internal */
|
|
543
|
+
_emit(...args) {
|
|
544
|
+
const [event, data] = args;
|
|
545
|
+
const listeners = this._listeners.get(event);
|
|
546
|
+
if (!listeners) {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
for (const entry of listeners) {
|
|
550
|
+
try {
|
|
551
|
+
entry.fn(data);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
console.error(error);
|
|
554
|
+
}
|
|
555
|
+
if (entry.once) {
|
|
556
|
+
listeners.delete(entry);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
};
|
|
471
561
|
|
|
472
562
|
// packages/server/src/video-sample.ts
|
|
473
563
|
import {
|
|
@@ -1072,8 +1162,31 @@ var VP9_LEVEL_TABLE = [
|
|
|
1072
1162
|
];
|
|
1073
1163
|
var VP9_DEFAULT_SUFFIX = ".01.01.01.01.00";
|
|
1074
1164
|
var AV1_DEFAULT_SUFFIX = ".0.110.01.01.01.0";
|
|
1165
|
+
var PRORES_FOURCCS = [
|
|
1166
|
+
"ap4x",
|
|
1167
|
+
// ProRes 4444 XQ
|
|
1168
|
+
"ap4h",
|
|
1169
|
+
// ProRes 4444
|
|
1170
|
+
"apch",
|
|
1171
|
+
// ProRes 422 High Quality
|
|
1172
|
+
"apcn",
|
|
1173
|
+
// ProRes 422 Standard Definition
|
|
1174
|
+
"apcs",
|
|
1175
|
+
// ProRes 422 LT
|
|
1176
|
+
"apco"
|
|
1177
|
+
// ProRes 422 Proxy
|
|
1178
|
+
];
|
|
1075
1179
|
var extractVideoCodecString = (trackInfo) => {
|
|
1076
|
-
const {
|
|
1180
|
+
const {
|
|
1181
|
+
codec,
|
|
1182
|
+
codecDescription,
|
|
1183
|
+
colorSpace,
|
|
1184
|
+
avcCodecInfo,
|
|
1185
|
+
hevcCodecInfo,
|
|
1186
|
+
vp9CodecInfo,
|
|
1187
|
+
av1CodecInfo,
|
|
1188
|
+
proresFormat
|
|
1189
|
+
} = trackInfo;
|
|
1077
1190
|
if (codec === "avc") {
|
|
1078
1191
|
assert(trackInfo.avcType !== null);
|
|
1079
1192
|
if (avcCodecInfo) {
|
|
@@ -1193,9 +1306,14 @@ var extractVideoCodecString = (trackInfo) => {
|
|
|
1193
1306
|
string = string.slice(0, -AV1_DEFAULT_SUFFIX.length);
|
|
1194
1307
|
}
|
|
1195
1308
|
return string;
|
|
1309
|
+
} else if (codec === "prores") {
|
|
1310
|
+
return proresFormat ?? "apch";
|
|
1311
|
+
} else if (codec !== null) {
|
|
1312
|
+
assertNever(codec);
|
|
1196
1313
|
}
|
|
1197
1314
|
throw new TypeError(`Unhandled codec '${codec}'.`);
|
|
1198
1315
|
};
|
|
1316
|
+
var VALID_VIDEO_CODEC_STRING_PREFIXES = ["avc1", "avc3", "hev1", "hvc1", "vp8", "vp09", "av01", ...PRORES_FOURCCS];
|
|
1199
1317
|
|
|
1200
1318
|
// src/codec-data.ts
|
|
1201
1319
|
var iterateNalUnitsInAnnexB = function* (packetData) {
|
|
@@ -1291,7 +1409,7 @@ var extractAvcDecoderConfigurationRecord = (packetData) => {
|
|
|
1291
1409
|
sequenceParameterSetExt: hasExtendedData ? spsExtUnits : null
|
|
1292
1410
|
};
|
|
1293
1411
|
} catch (error) {
|
|
1294
|
-
|
|
1412
|
+
Logging._error("Error building AVC Decoder Configuration Record:", error);
|
|
1295
1413
|
return null;
|
|
1296
1414
|
}
|
|
1297
1415
|
};
|
|
@@ -1565,7 +1683,7 @@ var parseAvcSps = (sps) => {
|
|
|
1565
1683
|
maxDecFrameBuffering
|
|
1566
1684
|
};
|
|
1567
1685
|
} catch (error) {
|
|
1568
|
-
|
|
1686
|
+
Logging._error("Error parsing AVC SPS:", error);
|
|
1569
1687
|
return null;
|
|
1570
1688
|
}
|
|
1571
1689
|
};
|
|
@@ -1709,7 +1827,7 @@ var parseHevcSps = (sps) => {
|
|
|
1709
1827
|
minSpatialSegmentationIdc
|
|
1710
1828
|
};
|
|
1711
1829
|
} catch (error) {
|
|
1712
|
-
|
|
1830
|
+
Logging._error("Error parsing HEVC SPS:", error);
|
|
1713
1831
|
return null;
|
|
1714
1832
|
}
|
|
1715
1833
|
};
|
|
@@ -1820,7 +1938,7 @@ var extractHevcDecoderConfigurationRecord = (packetData) => {
|
|
|
1820
1938
|
};
|
|
1821
1939
|
return record;
|
|
1822
1940
|
} catch (error) {
|
|
1823
|
-
|
|
1941
|
+
Logging._error("Error building HEVC Decoder Configuration Record:", error);
|
|
1824
1942
|
return null;
|
|
1825
1943
|
}
|
|
1826
1944
|
};
|
|
@@ -2494,6 +2612,14 @@ var AC3_REGISTRATION_DESCRIPTOR = new Uint8Array([5, 4, 65, 67, 45, 51]);
|
|
|
2494
2612
|
var EAC3_REGISTRATION_DESCRIPTOR = new Uint8Array([5, 4, 69, 65, 67, 51]);
|
|
2495
2613
|
|
|
2496
2614
|
// packages/server/src/video-encoder.ts
|
|
2615
|
+
var PRORES_FOURCC_TO_PROFILE = {
|
|
2616
|
+
apco: NodeAv4.AV_PROFILE_PRORES_PROXY,
|
|
2617
|
+
apcs: NodeAv4.AV_PROFILE_PRORES_LT,
|
|
2618
|
+
apcn: NodeAv4.AV_PROFILE_PRORES_STANDARD,
|
|
2619
|
+
apch: NodeAv4.AV_PROFILE_PRORES_HQ,
|
|
2620
|
+
ap4h: NodeAv4.AV_PROFILE_PRORES_4444,
|
|
2621
|
+
ap4x: NodeAv4.AV_PROFILE_PRORES_XQ
|
|
2622
|
+
};
|
|
2497
2623
|
var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
2498
2624
|
constructor() {
|
|
2499
2625
|
super(...arguments);
|
|
@@ -2507,7 +2633,7 @@ var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
|
2507
2633
|
this.preciseTimings = [];
|
|
2508
2634
|
}
|
|
2509
2635
|
static supports(codec, config) {
|
|
2510
|
-
return (codec === "avc" || codec === "hevc" || codec === "vp8" || codec === "vp9" || codec === "av1") && config.bitrateMode !== "quantizer";
|
|
2636
|
+
return (codec === "avc" || codec === "hevc" || codec === "vp8" || codec === "vp9" || codec === "av1" || codec === "prores") && config.bitrateMode !== "quantizer";
|
|
2511
2637
|
}
|
|
2512
2638
|
async init() {
|
|
2513
2639
|
this.frame = new NodeAv4.Frame();
|
|
@@ -2517,13 +2643,22 @@ var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
|
2517
2643
|
this.packet.alloc();
|
|
2518
2644
|
const codecId = CODEC_TO_CODEC_ID[this.codec];
|
|
2519
2645
|
assert(codecId !== void 0);
|
|
2646
|
+
const getSoftwareCodec = () => {
|
|
2647
|
+
if (this.codec === "prores") {
|
|
2648
|
+
const proresKs = NodeAv4.Codec.findEncoderByName(NodeAv4.FF_ENCODER_PRORES_KS);
|
|
2649
|
+
if (proresKs) {
|
|
2650
|
+
return proresKs;
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
return NodeAv4.Codec.findEncoder(codecId);
|
|
2654
|
+
};
|
|
2520
2655
|
let codec = null;
|
|
2521
2656
|
if (this.codec === "vp9" && this.config.alpha === "keep") {
|
|
2522
2657
|
codec = NodeAv4.Codec.findEncoderByName(NodeAv4.FF_ENCODER_LIBVPX_VP9) ?? NodeAv4.Codec.findEncoder(codecId);
|
|
2523
2658
|
} else if (this.config.hardwareAcceleration === "prefer-software") {
|
|
2524
|
-
codec =
|
|
2659
|
+
codec = getSoftwareCodec();
|
|
2525
2660
|
} else {
|
|
2526
|
-
codec = await getHardwareEncoderCodec(codecId) ??
|
|
2661
|
+
codec = await getHardwareEncoderCodec(codecId) ?? getSoftwareCodec();
|
|
2527
2662
|
}
|
|
2528
2663
|
if (!codec) {
|
|
2529
2664
|
throw new Error(`Unable to obtain libav codec for '${this.codec}'.`);
|
|
@@ -2540,8 +2675,15 @@ var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
|
2540
2675
|
if (!this.avCodec.pixelFormats.includes(NodeAv4.AV_PIX_FMT_YUV420P)) {
|
|
2541
2676
|
pixelFormat = this.avCodec.pixelFormats[0];
|
|
2542
2677
|
}
|
|
2543
|
-
if (this.config.alpha === "keep"
|
|
2544
|
-
|
|
2678
|
+
if (this.config.alpha === "keep") {
|
|
2679
|
+
if (this.avCodec.pixelFormats.includes(NodeAv4.AV_PIX_FMT_YUVA420P)) {
|
|
2680
|
+
pixelFormat = NodeAv4.AV_PIX_FMT_YUVA420P;
|
|
2681
|
+
} else {
|
|
2682
|
+
pixelFormat = NodeAv4.avcodecFindBestPixFmtOfList(
|
|
2683
|
+
this.avCodec.pixelFormats,
|
|
2684
|
+
NodeAv4.AV_PIX_FMT_YUVA444P12LE
|
|
2685
|
+
);
|
|
2686
|
+
}
|
|
2545
2687
|
}
|
|
2546
2688
|
}
|
|
2547
2689
|
const pixelAspectRatio = simplifyRational({
|
|
@@ -2594,6 +2736,11 @@ var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
|
2594
2736
|
codecContext.setOption("preset", "12");
|
|
2595
2737
|
}
|
|
2596
2738
|
}
|
|
2739
|
+
if (this.codec === "prores") {
|
|
2740
|
+
const profile = PRORES_FOURCC_TO_PROFILE[this.config.codec];
|
|
2741
|
+
assert(profile !== void 0);
|
|
2742
|
+
codecContext.setOption("profile", String(profile));
|
|
2743
|
+
}
|
|
2597
2744
|
const ret = await codecContext.open2();
|
|
2598
2745
|
NodeAv4.FFmpegError.throwIfError(ret, "Open codec context");
|
|
2599
2746
|
this.codecContext = codecContext;
|
|
@@ -2744,7 +2891,8 @@ var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
|
2744
2891
|
avcCodecInfo: null,
|
|
2745
2892
|
hevcCodecInfo: null,
|
|
2746
2893
|
vp9CodecInfo: null,
|
|
2747
|
-
av1CodecInfo: null
|
|
2894
|
+
av1CodecInfo: null,
|
|
2895
|
+
proresFormat: null
|
|
2748
2896
|
});
|
|
2749
2897
|
if (!expectsAnnexB) {
|
|
2750
2898
|
decoderConfigDescription = serializedRecord;
|
|
@@ -2797,7 +2945,8 @@ var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
|
2797
2945
|
avcCodecInfo: null,
|
|
2798
2946
|
hevcCodecInfo: null,
|
|
2799
2947
|
vp9CodecInfo: null,
|
|
2800
|
-
av1CodecInfo: null
|
|
2948
|
+
av1CodecInfo: null,
|
|
2949
|
+
proresFormat: null
|
|
2801
2950
|
});
|
|
2802
2951
|
}
|
|
2803
2952
|
} else if (this.codec === "vp9") {
|
|
@@ -2813,7 +2962,8 @@ var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
|
2813
2962
|
avcCodecInfo: null,
|
|
2814
2963
|
hevcCodecInfo: null,
|
|
2815
2964
|
vp9CodecInfo,
|
|
2816
|
-
av1CodecInfo: null
|
|
2965
|
+
av1CodecInfo: null,
|
|
2966
|
+
proresFormat: null
|
|
2817
2967
|
});
|
|
2818
2968
|
}
|
|
2819
2969
|
} else if (this.codec === "av1") {
|
|
@@ -2829,7 +2979,24 @@ var NodeAvVideoEncoder = class extends CustomVideoEncoder {
|
|
|
2829
2979
|
avcCodecInfo: null,
|
|
2830
2980
|
hevcCodecInfo: null,
|
|
2831
2981
|
vp9CodecInfo: null,
|
|
2832
|
-
av1CodecInfo
|
|
2982
|
+
av1CodecInfo,
|
|
2983
|
+
proresFormat: null
|
|
2984
|
+
});
|
|
2985
|
+
}
|
|
2986
|
+
} else if (this.codec === "prores") {
|
|
2987
|
+
if (!this.packetEmitted) {
|
|
2988
|
+
decoderConfigCodecString = extractVideoCodecString({
|
|
2989
|
+
width: this.config.width,
|
|
2990
|
+
height: this.config.height,
|
|
2991
|
+
codec: "prores",
|
|
2992
|
+
codecDescription: null,
|
|
2993
|
+
colorSpace: null,
|
|
2994
|
+
avcType: null,
|
|
2995
|
+
avcCodecInfo: null,
|
|
2996
|
+
hevcCodecInfo: null,
|
|
2997
|
+
vp9CodecInfo: null,
|
|
2998
|
+
av1CodecInfo: null,
|
|
2999
|
+
proresFormat: this.config.codec
|
|
2833
3000
|
});
|
|
2834
3001
|
}
|
|
2835
3002
|
} else {
|
|
@@ -3323,9 +3490,10 @@ var NodeAvAudioEncoder = class extends CustomAudioEncoder {
|
|
|
3323
3490
|
};
|
|
3324
3491
|
|
|
3325
3492
|
// packages/server/src/index.ts
|
|
3493
|
+
import { registerProresDecoder } from "@mediabunny/prores";
|
|
3326
3494
|
var SERVER_LOADED_SYMBOL = Symbol.for("@mediabunny/server loaded");
|
|
3327
3495
|
if (globalThis[SERVER_LOADED_SYMBOL]) {
|
|
3328
|
-
|
|
3496
|
+
Logging2._error(
|
|
3329
3497
|
"[WARNING]\n@mediabunny/server was loaded twice. This will likely cause the package not to work correctly. Check if multiple dependencies are importing different versions of @mediabunny/server, or if something is being bundled incorrectly."
|
|
3330
3498
|
);
|
|
3331
3499
|
}
|
|
@@ -3348,6 +3516,7 @@ var registerMediabunnyServer = (options = {}) => {
|
|
|
3348
3516
|
_serverOptions = options;
|
|
3349
3517
|
NodeAv8.Log.setLevel(NodeAv8.AV_LOG_ERROR);
|
|
3350
3518
|
registerDecoder(NodeAvVideoDecoder);
|
|
3519
|
+
registerProresDecoder();
|
|
3351
3520
|
registerEncoder(NodeAvVideoEncoder);
|
|
3352
3521
|
registerDecoder(NodeAvAudioDecoder);
|
|
3353
3522
|
registerEncoder(NodeAvAudioEncoder);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,WAAW,EAEX,YAAY,EAIZ,WAAW,EACX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAsBlC;;;;GAIG;AACH,KAAK,uBAAuB,GAAG;IAC9B;;;;;;;OAOG;IACH,eAAe,CAAC,EACb,MAAM,CAAC,eAAe,GACtB,IAAI,GACJ,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,KAAK,YAAY,CAAC,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;CAChF,CAAC;AAKF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GAAI,UAAS,uBAA4B,SAkC7E,CAAC;AAEF,YAAY,EAAE,uBAAuB,EAAE,CAAC;AAExC,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,GAAU,QAAQ,WAAW,GAAG,WAAW,EAAE,OAAO,MAAM,CAAC,KAAK,kBAqCrF,CAAC"}
|
|
@@ -49,9 +49,10 @@ const audio_decoder_1 = require("./audio-decoder");
|
|
|
49
49
|
const audio_encoder_1 = require("./audio-encoder");
|
|
50
50
|
const video_sample_1 = require("./video-sample");
|
|
51
51
|
const audio_sample_1 = require("./audio-sample");
|
|
52
|
+
const prores_1 = require("@mediabunny/prores");
|
|
52
53
|
const SERVER_LOADED_SYMBOL = Symbol.for('@mediabunny/server loaded');
|
|
53
54
|
if (globalThis[SERVER_LOADED_SYMBOL]) {
|
|
54
|
-
|
|
55
|
+
mediabunny_1.Logging._error('[WARNING]\n@mediabunny/server was loaded twice.'
|
|
55
56
|
+ ' This will likely cause the package not to work correctly.'
|
|
56
57
|
+ ' Check if multiple dependencies are importing different versions of @mediabunny/server,'
|
|
57
58
|
+ ' or if something is being bundled incorrectly.');
|
|
@@ -91,6 +92,7 @@ const registerMediabunnyServer = (options = {}) => {
|
|
|
91
92
|
NodeAv.Log.setLevel(NodeAv.AV_LOG_ERROR);
|
|
92
93
|
// Video
|
|
93
94
|
(0, mediabunny_1.registerDecoder)(video_decoder_1.NodeAvVideoDecoder);
|
|
95
|
+
(0, prores_1.registerProresDecoder)(); // Faster than FFmpeg, so we use it
|
|
94
96
|
(0, mediabunny_1.registerEncoder)(video_encoder_1.NodeAvVideoEncoder);
|
|
95
97
|
// Audio
|
|
96
98
|
(0, mediabunny_1.registerDecoder)(audio_decoder_1.NodeAvAudioDecoder);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../../src/misc.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAGlC,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../../src/misc.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAGlC,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,CAe3E,CAAC;AAGF,eAAO,MAAM,kBAAkB,QAAO,MAAM,CAAC,eAAe,GAAG,IAU9D,CAAC;AAYF,eAAO,MAAM,uBAAuB,GAAU,SAAS,MAAM,CAAC,SAAS,KAAG,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAapG,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAAU,SAAS,MAAM,CAAC,SAAS,KAAG,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAapG,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,mCAUlD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,WAAW,MAAM,qEAUpD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,UAAU,MAAM,gDAW1D,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,UAAU,MAAM,4EAW5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,+BAUnD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,oEAUrD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,mBAAmB,MAAM,CAAC,aAAa,KAAG,sBAAsB,GAAG,IAqChG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,aAAa,sBAAsB,yBA+BlE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,oBAAoB,MAAM,CAAC,cAAc,KAAG,iBAAiB,GAAG,IAanG,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,cAAc,iBAAiB,KAAG,MAAM,CAAC,cAa9E,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,KAAG,MAAM,CAAC,aAS7D,CAAC"}
|
package/dist/modules/src/misc.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video-encoder.d.ts","sourceRoot":"","sources":["../../../src/video-encoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,kBAAkB,EAClB,KAAK,YAAY,EAEjB,UAAU,EACV,WAAW,EAGX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"video-encoder.d.ts","sourceRoot":"","sources":["../../../src/video-encoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,kBAAkB,EAClB,KAAK,YAAY,EAEjB,UAAU,EACV,WAAW,EAGX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAmClC,qBAAa,kBAAmB,SAAQ,kBAAkB;IACzD,KAAK,EAAG,MAAM,CAAC,KAAK,CAAC;IACrB,MAAM,EAAG,MAAM,CAAC,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAQ;IAChD,MAAM,EAAE,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAQ;IAClD,QAAQ,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAQ;IACrC,OAAO,EAAG,MAAM,CAAC,KAAK,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IACjC,aAAa,UAAS;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGpC,cAAc,EAAE;QACf,oBAAoB,EAAE,MAAM,CAAC;QAC7B,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,OAAO,CAAC;KACzB,EAAE,CAAM;WAEO,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO;IAO1E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAyCrB,kBAAkB;IAqGlB,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwHzF,aAAa,CAAC,GAAG,EAAE,MAAM;IA8PnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC;CAO3B"}
|
|
@@ -48,6 +48,14 @@ const video_sample_1 = require("./video-sample");
|
|
|
48
48
|
const codec_data_1 = require("../../../src/codec-data");
|
|
49
49
|
const codec_1 = require("../../../src/codec");
|
|
50
50
|
const misc_2 = require("../../../src/misc");
|
|
51
|
+
const PRORES_FOURCC_TO_PROFILE = {
|
|
52
|
+
apco: NodeAv.AV_PROFILE_PRORES_PROXY,
|
|
53
|
+
apcs: NodeAv.AV_PROFILE_PRORES_LT,
|
|
54
|
+
apcn: NodeAv.AV_PROFILE_PRORES_STANDARD,
|
|
55
|
+
apch: NodeAv.AV_PROFILE_PRORES_HQ,
|
|
56
|
+
ap4h: NodeAv.AV_PROFILE_PRORES_4444,
|
|
57
|
+
ap4x: NodeAv.AV_PROFILE_PRORES_XQ,
|
|
58
|
+
};
|
|
51
59
|
class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
52
60
|
constructor() {
|
|
53
61
|
super(...arguments);
|
|
@@ -61,8 +69,8 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
|
61
69
|
this.preciseTimings = [];
|
|
62
70
|
}
|
|
63
71
|
static supports(codec, config) {
|
|
64
|
-
return (codec === 'avc' || codec === 'hevc' || codec === 'vp8' || codec === 'vp9' || codec === 'av1'
|
|
65
|
-
&& config.bitrateMode !== 'quantizer';
|
|
72
|
+
return (codec === 'avc' || codec === 'hevc' || codec === 'vp8' || codec === 'vp9' || codec === 'av1'
|
|
73
|
+
|| codec === 'prores') && config.bitrateMode !== 'quantizer';
|
|
66
74
|
}
|
|
67
75
|
async init() {
|
|
68
76
|
this.frame = new NodeAv.Frame();
|
|
@@ -72,15 +80,25 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
|
72
80
|
this.packet.alloc();
|
|
73
81
|
const codecId = misc_1.CODEC_TO_CODEC_ID[this.codec];
|
|
74
82
|
(0, misc_2.assert)(codecId !== undefined);
|
|
83
|
+
const getSoftwareCodec = () => {
|
|
84
|
+
if (this.codec === 'prores') {
|
|
85
|
+
// Prefer prores_ks for ProRes
|
|
86
|
+
const proresKs = NodeAv.Codec.findEncoderByName(NodeAv.FF_ENCODER_PRORES_KS);
|
|
87
|
+
if (proresKs) {
|
|
88
|
+
return proresKs;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return NodeAv.Codec.findEncoder(codecId);
|
|
92
|
+
};
|
|
75
93
|
let codec = null;
|
|
76
94
|
if (this.codec === 'vp9' && this.config.alpha === 'keep') {
|
|
77
95
|
codec = NodeAv.Codec.findEncoderByName(NodeAv.FF_ENCODER_LIBVPX_VP9) ?? NodeAv.Codec.findEncoder(codecId);
|
|
78
96
|
}
|
|
79
97
|
else if (this.config.hardwareAcceleration === 'prefer-software') {
|
|
80
|
-
codec =
|
|
98
|
+
codec = getSoftwareCodec();
|
|
81
99
|
}
|
|
82
100
|
else {
|
|
83
|
-
codec = (await (0, misc_1.getHardwareEncoderCodec)(codecId)) ??
|
|
101
|
+
codec = (await (0, misc_1.getHardwareEncoderCodec)(codecId)) ?? getSoftwareCodec();
|
|
84
102
|
}
|
|
85
103
|
if (!codec) {
|
|
86
104
|
throw new Error(`Unable to obtain libav codec for '${this.codec}'.`);
|
|
@@ -97,8 +115,15 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
|
97
115
|
if (!this.avCodec.pixelFormats.includes(NodeAv.AV_PIX_FMT_YUV420P)) {
|
|
98
116
|
pixelFormat = this.avCodec.pixelFormats[0];
|
|
99
117
|
}
|
|
100
|
-
if (this.config.alpha === 'keep'
|
|
101
|
-
|
|
118
|
+
if (this.config.alpha === 'keep') {
|
|
119
|
+
if (this.avCodec.pixelFormats.includes(NodeAv.AV_PIX_FMT_YUVA420P)) {
|
|
120
|
+
pixelFormat = NodeAv.AV_PIX_FMT_YUVA420P;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// Let FFmpeg pick the best alpha-capable format it supports, minimizing data loss versus a
|
|
124
|
+
// high-quality YUVA source
|
|
125
|
+
pixelFormat = NodeAv.avcodecFindBestPixFmtOfList(this.avCodec.pixelFormats, NodeAv.AV_PIX_FMT_YUVA444P12LE);
|
|
126
|
+
}
|
|
102
127
|
}
|
|
103
128
|
}
|
|
104
129
|
const pixelAspectRatio = (0, misc_2.simplifyRational)({
|
|
@@ -157,6 +182,12 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
|
157
182
|
codecContext.setOption('preset', '12');
|
|
158
183
|
}
|
|
159
184
|
}
|
|
185
|
+
if (this.codec === 'prores') {
|
|
186
|
+
// Pick the encoder profile from the requested ProRes four-character code
|
|
187
|
+
const profile = PRORES_FOURCC_TO_PROFILE[this.config.codec];
|
|
188
|
+
(0, misc_2.assert)(profile !== undefined);
|
|
189
|
+
codecContext.setOption('profile', String(profile));
|
|
190
|
+
}
|
|
160
191
|
const ret = await codecContext.open2();
|
|
161
192
|
NodeAv.FFmpegError.throwIfError(ret, 'Open codec context');
|
|
162
193
|
this.codecContext = codecContext;
|
|
@@ -318,6 +349,7 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
|
318
349
|
hevcCodecInfo: null,
|
|
319
350
|
vp9CodecInfo: null,
|
|
320
351
|
av1CodecInfo: null,
|
|
352
|
+
proresFormat: null,
|
|
321
353
|
});
|
|
322
354
|
if (!expectsAnnexB) {
|
|
323
355
|
decoderConfigDescription = serializedRecord;
|
|
@@ -377,6 +409,7 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
|
377
409
|
hevcCodecInfo: null,
|
|
378
410
|
vp9CodecInfo: null,
|
|
379
411
|
av1CodecInfo: null,
|
|
412
|
+
proresFormat: null,
|
|
380
413
|
});
|
|
381
414
|
}
|
|
382
415
|
}
|
|
@@ -394,6 +427,7 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
|
394
427
|
hevcCodecInfo: null,
|
|
395
428
|
vp9CodecInfo,
|
|
396
429
|
av1CodecInfo: null,
|
|
430
|
+
proresFormat: null,
|
|
397
431
|
});
|
|
398
432
|
}
|
|
399
433
|
}
|
|
@@ -411,6 +445,24 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
|
|
|
411
445
|
hevcCodecInfo: null,
|
|
412
446
|
vp9CodecInfo: null,
|
|
413
447
|
av1CodecInfo,
|
|
448
|
+
proresFormat: null,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
else if (this.codec === 'prores') {
|
|
453
|
+
if (!this.packetEmitted) {
|
|
454
|
+
decoderConfigCodecString = (0, codec_1.extractVideoCodecString)({
|
|
455
|
+
width: this.config.width,
|
|
456
|
+
height: this.config.height,
|
|
457
|
+
codec: 'prores',
|
|
458
|
+
codecDescription: null,
|
|
459
|
+
colorSpace: null,
|
|
460
|
+
avcType: null,
|
|
461
|
+
avcCodecInfo: null,
|
|
462
|
+
hevcCodecInfo: null,
|
|
463
|
+
vp9CodecInfo: null,
|
|
464
|
+
av1CodecInfo: null,
|
|
465
|
+
proresFormat: this.config.codec,
|
|
414
466
|
});
|
|
415
467
|
}
|
|
416
468
|
}
|