@mediabunny/server 1.54.0 → 1.55.2
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-server.cjs +48 -10
- package/dist/bundles/mediabunny-server.min.cjs +2 -2
- package/dist/bundles/mediabunny-server.min.mjs +2 -2
- package/dist/bundles/mediabunny-server.mjs +48 -10
- package/dist/modules/src/audio-decoder.d.ts.map +1 -1
- package/dist/modules/src/audio-decoder.js +2 -1
- package/dist/modules/src/audio-encoder.d.ts.map +1 -1
- package/dist/modules/src/audio-encoder.js +19 -5
- package/dist/modules/src/misc.d.ts +5 -0
- package/dist/modules/src/misc.d.ts.map +1 -1
- package/dist/modules/src/misc.js +19 -1
- package/dist/modules/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/audio-decoder.ts +2 -1
- package/src/audio-encoder.ts +23 -7
- package/src/misc.ts +19 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mediabunny/server",
|
|
3
3
|
"author": "Vanilagy",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.55.2",
|
|
5
5
|
"description": "Adds full video and audio decoder and encoder support to Mediabunny for use in server-side environments (Node, Bun, Deno). Based on NodeAV.",
|
|
6
6
|
"main": "./dist/bundles/mediabunny-server.cjs",
|
|
7
7
|
"module": "./dist/bundles/mediabunny-server.mjs",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"node-av": "^6.0.0",
|
|
38
|
-
"@mediabunny/prores": "^1.
|
|
38
|
+
"@mediabunny/prores": "^1.55.2"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"mediabunny": "^1.45.0"
|
package/src/audio-decoder.ts
CHANGED
package/src/audio-encoder.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
EncodedPacket,
|
|
16
16
|
} from 'mediabunny';
|
|
17
17
|
import * as NodeAv from 'node-av';
|
|
18
|
-
import { CODEC_TO_CODEC_ID, getChannelLayout } from './misc';
|
|
18
|
+
import { CODEC_TO_CODEC_ID, getChannelLayout, getDtsChannelLayout } from './misc';
|
|
19
19
|
import { assert, toUint8Array } from '../../../src/misc';
|
|
20
20
|
import { copyAudioSampleToAvFrame, AvFrameAudioSampleResource } from './audio-sample';
|
|
21
21
|
import {
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
buildAdtsHeaderTemplate,
|
|
24
24
|
parseAacAudioSpecificConfig,
|
|
25
25
|
} from '../../../shared/aac-misc';
|
|
26
|
+
import { DTS_CHANNEL_COUNTS, DTS_SAMPLE_RATES, dtsBitrateFits } from '../../../shared/dts-misc';
|
|
26
27
|
|
|
27
28
|
const AAC_SAMPLE_RATES
|
|
28
29
|
= [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
|
|
@@ -72,6 +73,10 @@ export class NodeAvAudioEncoder extends CustomAudioEncoder {
|
|
|
72
73
|
) || (
|
|
73
74
|
codec === 'eac3' && numberOfChannels >= 1 && numberOfChannels <= 16
|
|
74
75
|
&& AC3_SAMPLE_RATES.includes(sampleRate)
|
|
76
|
+
) || (
|
|
77
|
+
codec === 'dts' && DTS_CHANNEL_COUNTS.includes(numberOfChannels)
|
|
78
|
+
&& DTS_SAMPLE_RATES.includes(sampleRate)
|
|
79
|
+
&& dtsBitrateFits(resolveBitrate(config, codec), sampleRate, numberOfChannels)
|
|
75
80
|
);
|
|
76
81
|
}
|
|
77
82
|
|
|
@@ -107,21 +112,26 @@ export class NodeAvAudioEncoder extends CustomAudioEncoder {
|
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
codecContext.sampleRate = this.config.sampleRate;
|
|
110
|
-
codecContext.channelLayout =
|
|
115
|
+
codecContext.channelLayout = this.codec === 'dts'
|
|
116
|
+
? getDtsChannelLayout(this.config.numberOfChannels)
|
|
117
|
+
: getChannelLayout(this.config.numberOfChannels);
|
|
111
118
|
codecContext.codecType = NodeAv.AVMEDIA_TYPE_AUDIO;
|
|
112
119
|
codecContext.codecId = CODEC_TO_CODEC_ID[this.codec]!;
|
|
113
120
|
codecContext.sampleFormat = sampleFormat;
|
|
114
121
|
codecContext.timeBase = new NodeAv.Rational(1, this.config.sampleRate);
|
|
115
|
-
codecContext.bitRate = BigInt(
|
|
116
|
-
this.config.bitrate ?? new Quality('medium')._toAudioBitrate(this.codec) ?? 0,
|
|
117
|
-
);
|
|
122
|
+
codecContext.bitRate = BigInt(resolveBitrate(this.config, this.codec));
|
|
118
123
|
|
|
119
124
|
if (this.config.bitrateMode === 'constant') {
|
|
120
125
|
codecContext.rcMinRate = codecContext.bitRate;
|
|
121
126
|
codecContext.rcMaxRate = codecContext.bitRate;
|
|
122
127
|
}
|
|
123
128
|
|
|
124
|
-
|
|
129
|
+
// libav's DTS encoder is marked experimental, so it refuses to open at the default compliance level
|
|
130
|
+
const options = this.codec === 'dts'
|
|
131
|
+
? NodeAv.Dictionary.fromObject({ strict: -2 })
|
|
132
|
+
: null;
|
|
133
|
+
|
|
134
|
+
const ret = await codecContext.open2(this.avCodec, options);
|
|
125
135
|
NodeAv.FFmpegError.throwIfError(ret, 'Open codec context');
|
|
126
136
|
|
|
127
137
|
this.codecContext = codecContext;
|
|
@@ -172,7 +182,9 @@ export class NodeAvAudioEncoder extends CustomAudioEncoder {
|
|
|
172
182
|
this.resampler = new NodeAv.SoftwareResampleContext();
|
|
173
183
|
this.resamplerInputSampleRate = this.frame.sampleRate;
|
|
174
184
|
|
|
175
|
-
|
|
185
|
+
// Resample straight to whatever layout the encoder was opened with, since not every codec accepts
|
|
186
|
+
// the layout that getChannelLayout hands out for a given channel count
|
|
187
|
+
const outLayout = this.codecContext.channelLayout;
|
|
176
188
|
const inLayout = getChannelLayout(this.frame.channels);
|
|
177
189
|
|
|
178
190
|
const ret = this.resampler.allocSetOpts2(
|
|
@@ -400,3 +412,7 @@ export class NodeAvAudioEncoder extends CustomAudioEncoder {
|
|
|
400
412
|
this.resampler?.free();
|
|
401
413
|
}
|
|
402
414
|
}
|
|
415
|
+
|
|
416
|
+
const resolveBitrate = (config: AudioEncoderConfig, codec: AudioCodec) => {
|
|
417
|
+
return config.bitrate ?? new Quality('medium')._toAudioBitrate(codec) ?? 0;
|
|
418
|
+
};
|
package/src/misc.ts
CHANGED
|
@@ -25,6 +25,7 @@ export const CODEC_TO_CODEC_ID: Partial<Record<MediaCodec, NodeAv.AVCodecID>> =
|
|
|
25
25
|
flac: NodeAv.AV_CODEC_ID_FLAC,
|
|
26
26
|
ac3: NodeAv.AV_CODEC_ID_AC3,
|
|
27
27
|
eac3: NodeAv.AV_CODEC_ID_EAC3,
|
|
28
|
+
dts: NodeAv.AV_CODEC_ID_DTS,
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
let cachedHardwareContext: NodeAv.HardwareContext | null | undefined = undefined;
|
|
@@ -267,3 +268,21 @@ export const getChannelLayout = (numChannels: number): NodeAv.ChannelLayout => {
|
|
|
267
268
|
default: return { nbChannels: numChannels, order: NodeAv.AV_CHANNEL_ORDER_UNSPEC, mask: 0n };
|
|
268
269
|
}
|
|
269
270
|
};
|
|
271
|
+
|
|
272
|
+
/** FL + FR + SL + SR, which libav has no constant for. */
|
|
273
|
+
const QUAD_SIDE_MASK = 0x603n;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* DTS insists on the side-based surround layouts and rejects the back-based ones that {@link getChannelLayout}
|
|
277
|
+
* hands out, so it gets its own mapping.
|
|
278
|
+
*/
|
|
279
|
+
export const getDtsChannelLayout = (numChannels: number): NodeAv.ChannelLayout => {
|
|
280
|
+
switch (numChannels) {
|
|
281
|
+
case 1: return NodeAv.AV_CHANNEL_LAYOUT_MONO;
|
|
282
|
+
case 2: return NodeAv.AV_CHANNEL_LAYOUT_STEREO;
|
|
283
|
+
case 4: return { nbChannels: 4, order: NodeAv.AV_CHANNEL_ORDER_NATIVE, mask: QUAD_SIDE_MASK };
|
|
284
|
+
case 5: return NodeAv.AV_CHANNEL_LAYOUT_5POINT0;
|
|
285
|
+
case 6: return NodeAv.AV_CHANNEL_LAYOUT_5POINT1;
|
|
286
|
+
default: return { nbChannels: numChannels, order: NodeAv.AV_CHANNEL_ORDER_UNSPEC, mask: 0n };
|
|
287
|
+
}
|
|
288
|
+
};
|