webcodecs-node 0.2.2 → 0.3.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 +4 -0
- package/dist/__tests__/AudioDecoder.test.js +3 -3
- package/dist/__tests__/AudioDecoder.test.js.map +1 -1
- package/dist/__tests__/ImageDecoder.wpt.test.d.ts +8 -0
- package/dist/__tests__/ImageDecoder.wpt.test.d.ts.map +1 -0
- package/dist/__tests__/ImageDecoder.wpt.test.js +135 -0
- package/dist/__tests__/ImageDecoder.wpt.test.js.map +1 -0
- package/dist/__tests__/NodeAvDecoder.test.d.ts +2 -0
- package/dist/__tests__/NodeAvDecoder.test.d.ts.map +1 -0
- package/dist/__tests__/NodeAvDecoder.test.js +199 -0
- package/dist/__tests__/NodeAvDecoder.test.js.map +1 -0
- package/dist/__tests__/NodeAvEncoder.test.d.ts +2 -0
- package/dist/__tests__/NodeAvEncoder.test.d.ts.map +1 -0
- package/dist/__tests__/NodeAvEncoder.test.js +176 -0
- package/dist/__tests__/NodeAvEncoder.test.js.map +1 -0
- package/dist/__tests__/VideoFrame.test.js.map +1 -1
- package/dist/backends/index.d.ts +3 -0
- package/dist/backends/index.d.ts.map +1 -0
- package/dist/backends/index.js +2 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/types.d.ts +165 -0
- package/dist/backends/types.d.ts.map +1 -0
- package/dist/backends/types.js +25 -0
- package/dist/backends/types.js.map +1 -0
- package/dist/core/AudioData.d.ts +1 -1
- package/dist/core/AudioData.d.ts.map +1 -1
- package/dist/core/AudioData.js +13 -9
- package/dist/core/AudioData.js.map +1 -1
- package/dist/core/VideoFrame.d.ts +25 -10
- package/dist/core/VideoFrame.d.ts.map +1 -1
- package/dist/core/VideoFrame.js +115 -65
- package/dist/core/VideoFrame.js.map +1 -1
- package/dist/decoders/AudioDecoder.d.ts +6 -12
- package/dist/decoders/AudioDecoder.d.ts.map +1 -1
- package/dist/decoders/AudioDecoder.js +57 -147
- package/dist/decoders/AudioDecoder.js.map +1 -1
- package/dist/decoders/ImageDecoder.d.ts +1 -0
- package/dist/decoders/ImageDecoder.d.ts.map +1 -1
- package/dist/decoders/ImageDecoder.js +59 -0
- package/dist/decoders/ImageDecoder.js.map +1 -1
- package/dist/decoders/VideoDecoder.d.ts +6 -13
- package/dist/decoders/VideoDecoder.d.ts.map +1 -1
- package/dist/decoders/VideoDecoder.js +49 -130
- package/dist/decoders/VideoDecoder.js.map +1 -1
- package/dist/demos/demo-conversion.js +2 -2
- package/dist/demos/demo-conversion.js.map +1 -1
- package/dist/demos/demo-four-corners.d.ts +6 -0
- package/dist/demos/demo-four-corners.d.ts.map +1 -0
- package/dist/demos/demo-four-corners.js +218 -0
- package/dist/demos/demo-four-corners.js.map +1 -0
- package/dist/demos/demo-samples.js +228 -64
- package/dist/demos/demo-samples.js.map +1 -1
- package/dist/encoders/AudioEncoder.d.ts +6 -13
- package/dist/encoders/AudioEncoder.d.ts.map +1 -1
- package/dist/encoders/AudioEncoder.js +81 -213
- package/dist/encoders/AudioEncoder.js.map +1 -1
- package/dist/encoders/VideoEncoder.d.ts +5 -14
- package/dist/encoders/VideoEncoder.d.ts.map +1 -1
- package/dist/encoders/VideoEncoder.js +39 -159
- package/dist/encoders/VideoEncoder.js.map +1 -1
- package/dist/formats/conversions/frame-converter.d.ts +17 -0
- package/dist/formats/conversions/frame-converter.d.ts.map +1 -1
- package/dist/formats/conversions/frame-converter.js +127 -0
- package/dist/formats/conversions/frame-converter.js.map +1 -1
- package/dist/formats/conversions/index.d.ts +1 -0
- package/dist/formats/conversions/index.d.ts.map +1 -1
- package/dist/formats/conversions/index.js +2 -0
- package/dist/formats/conversions/index.js.map +1 -1
- package/dist/hardware/detection.d.ts +1 -1
- package/dist/hardware/detection.d.ts.map +1 -1
- package/dist/hardware/detection.js +54 -27
- package/dist/hardware/detection.js.map +1 -1
- package/dist/mediabunny/FFmpegAudioDecoder.d.ts +2 -16
- package/dist/mediabunny/FFmpegAudioDecoder.d.ts.map +1 -1
- package/dist/mediabunny/FFmpegAudioDecoder.js +59 -184
- package/dist/mediabunny/FFmpegAudioDecoder.js.map +1 -1
- package/dist/mediabunny/FFmpegAudioEncoder.d.ts +4 -38
- package/dist/mediabunny/FFmpegAudioEncoder.d.ts.map +1 -1
- package/dist/mediabunny/FFmpegAudioEncoder.js +64 -328
- package/dist/mediabunny/FFmpegAudioEncoder.js.map +1 -1
- package/dist/mediabunny/FFmpegVideoDecoder.d.ts +2 -36
- package/dist/mediabunny/FFmpegVideoDecoder.d.ts.map +1 -1
- package/dist/mediabunny/FFmpegVideoDecoder.js +37 -278
- package/dist/mediabunny/FFmpegVideoDecoder.js.map +1 -1
- package/dist/mediabunny/FFmpegVideoEncoder.d.ts +6 -35
- package/dist/mediabunny/FFmpegVideoEncoder.d.ts.map +1 -1
- package/dist/mediabunny/FFmpegVideoEncoder.js +46 -334
- package/dist/mediabunny/FFmpegVideoEncoder.js.map +1 -1
- package/dist/node-av/HardwarePipeline.d.ts +36 -0
- package/dist/node-av/HardwarePipeline.d.ts.map +1 -0
- package/dist/node-av/HardwarePipeline.js +243 -0
- package/dist/node-av/HardwarePipeline.js.map +1 -0
- package/dist/node-av/NodeAvAudioDecoder.d.ts +46 -0
- package/dist/node-av/NodeAvAudioDecoder.d.ts.map +1 -0
- package/dist/node-av/NodeAvAudioDecoder.js +343 -0
- package/dist/node-av/NodeAvAudioDecoder.js.map +1 -0
- package/dist/node-av/NodeAvAudioEncoder.d.ts +44 -0
- package/dist/node-av/NodeAvAudioEncoder.d.ts.map +1 -0
- package/dist/node-av/NodeAvAudioEncoder.js +385 -0
- package/dist/node-av/NodeAvAudioEncoder.js.map +1 -0
- package/dist/node-av/NodeAvImageDecoder.d.ts +95 -0
- package/dist/node-av/NodeAvImageDecoder.d.ts.map +1 -0
- package/dist/node-av/NodeAvImageDecoder.js +287 -0
- package/dist/node-av/NodeAvImageDecoder.js.map +1 -0
- package/dist/node-av/NodeAvVideoDecoder.d.ts +43 -0
- package/dist/node-av/NodeAvVideoDecoder.d.ts.map +1 -0
- package/dist/node-av/NodeAvVideoDecoder.js +361 -0
- package/dist/node-av/NodeAvVideoDecoder.js.map +1 -0
- package/dist/node-av/NodeAvVideoEncoder.d.ts +44 -0
- package/dist/node-av/NodeAvVideoEncoder.d.ts.map +1 -0
- package/dist/node-av/NodeAvVideoEncoder.js +397 -0
- package/dist/node-av/NodeAvVideoEncoder.js.map +1 -0
- package/dist/utils/event-target.d.ts +42 -0
- package/dist/utils/event-target.d.ts.map +1 -0
- package/dist/utils/event-target.js +96 -0
- package/dist/utils/event-target.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +14 -6
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Hardware acceleration detection
|
|
3
3
|
*
|
|
4
4
|
* Detects available hardware acceleration methods, encoders, and decoders
|
|
5
|
-
*
|
|
5
|
+
* using node-av native bindings for better performance.
|
|
6
6
|
*/
|
|
7
7
|
import type { HardwareAccelerationMethod, HardwareCapabilities } from './types.js';
|
|
8
8
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detection.d.ts","sourceRoot":"","sources":["../../src/hardware/detection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,0BAA0B,EAC1B,oBAAoB,EACrB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"detection.d.ts","sourceRoot":"","sources":["../../src/hardware/detection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,0BAA0B,EAC1B,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAqIpB;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAEhF;AAED;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,oBAAoB,CAKrE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAE/E;AAED,wBAAgB,qBAAqB,IAAI,0BAA0B,EAAE,CAEpE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAE3D;AAED,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAE3D;AAED,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED;;GAEG;AACH,wBAAsB,8BAA8B,IAAI,OAAO,CAAC,MAAM,CAAC,CAgCtE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
|
|
@@ -2,30 +2,31 @@
|
|
|
2
2
|
* Hardware acceleration detection
|
|
3
3
|
*
|
|
4
4
|
* Detects available hardware acceleration methods, encoders, and decoders
|
|
5
|
-
*
|
|
5
|
+
* using node-av native bindings for better performance.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { HardwareContext } from 'node-av/api';
|
|
8
8
|
import { createLogger } from '../utils/logger.js';
|
|
9
9
|
import { HARDWARE_ENCODERS, HARDWARE_DECODERS } from './types.js';
|
|
10
10
|
const logger = createLogger('HardwareAcceleration');
|
|
11
11
|
// Cached capabilities
|
|
12
12
|
let cachedCapabilities = null;
|
|
13
|
+
// Map node-av device types to our HardwareAccelerationMethod
|
|
14
|
+
const DEVICE_TYPE_MAP = {
|
|
15
|
+
'vaapi': 'vaapi',
|
|
16
|
+
'cuda': 'cuda',
|
|
17
|
+
'qsv': 'qsv',
|
|
18
|
+
'videotoolbox': 'videotoolbox',
|
|
19
|
+
'drm': 'drm',
|
|
20
|
+
'v4l2m2m': 'v4l2m2m',
|
|
21
|
+
};
|
|
13
22
|
function collectHwaccels() {
|
|
14
23
|
try {
|
|
15
|
-
const
|
|
16
|
-
const lines = output.split('\n');
|
|
24
|
+
const available = HardwareContext.listAvailable();
|
|
17
25
|
const methods = [];
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
if (startParsing && line.trim()) {
|
|
25
|
-
const method = line.trim();
|
|
26
|
-
if (['vaapi', 'cuda', 'qsv', 'videotoolbox', 'drm', 'v4l2m2m'].includes(method)) {
|
|
27
|
-
methods.push(method);
|
|
28
|
-
}
|
|
26
|
+
for (const deviceType of available) {
|
|
27
|
+
const mapped = DEVICE_TYPE_MAP[deviceType];
|
|
28
|
+
if (mapped) {
|
|
29
|
+
methods.push(mapped);
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
return methods;
|
|
@@ -36,34 +37,60 @@ function collectHwaccels() {
|
|
|
36
37
|
}
|
|
37
38
|
function collectEncoders() {
|
|
38
39
|
try {
|
|
39
|
-
const output = execSync('ffmpeg -encoders 2>&1', { encoding: 'utf8' });
|
|
40
40
|
const encoders = [];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
const hw = HardwareContext.auto();
|
|
42
|
+
if (hw) {
|
|
43
|
+
const supportedCodecs = hw.findSupportedCodecs();
|
|
44
|
+
// Filter for encoder codecs (typically ending with the hwaccel suffix)
|
|
45
|
+
for (const codec of supportedCodecs) {
|
|
46
|
+
encoders.push(codec);
|
|
47
|
+
}
|
|
48
|
+
hw.dispose();
|
|
49
|
+
}
|
|
50
|
+
// Also include standard software encoders
|
|
51
|
+
const softwareEncoders = [
|
|
52
|
+
'libx264', 'libx265', 'libvpx', 'libvpx-vp9',
|
|
53
|
+
'libaom-av1', 'libsvtav1', 'aac', 'libopus',
|
|
54
|
+
];
|
|
55
|
+
for (const enc of softwareEncoders) {
|
|
56
|
+
if (!encoders.includes(enc)) {
|
|
57
|
+
encoders.push(enc);
|
|
45
58
|
}
|
|
46
59
|
}
|
|
47
60
|
return encoders;
|
|
48
61
|
}
|
|
49
62
|
catch {
|
|
50
|
-
|
|
63
|
+
// Return software encoders as fallback
|
|
64
|
+
return ['libx264', 'libx265', 'libvpx', 'libvpx-vp9', 'libaom-av1'];
|
|
51
65
|
}
|
|
52
66
|
}
|
|
53
67
|
function collectDecoders() {
|
|
54
68
|
try {
|
|
55
|
-
const output = execSync('ffmpeg -decoders 2>&1', { encoding: 'utf8' });
|
|
56
69
|
const decoders = [];
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
70
|
+
const hw = HardwareContext.auto();
|
|
71
|
+
if (hw) {
|
|
72
|
+
const supportedCodecs = hw.findSupportedCodecs();
|
|
73
|
+
// Hardware decoders from node-av
|
|
74
|
+
for (const codec of supportedCodecs) {
|
|
75
|
+
decoders.push(codec);
|
|
76
|
+
}
|
|
77
|
+
hw.dispose();
|
|
78
|
+
}
|
|
79
|
+
// Also include standard software decoders
|
|
80
|
+
const softwareDecoders = [
|
|
81
|
+
'h264', 'hevc', 'vp8', 'vp9', 'av1',
|
|
82
|
+
'aac', 'opus', 'mp3', 'flac',
|
|
83
|
+
];
|
|
84
|
+
for (const dec of softwareDecoders) {
|
|
85
|
+
if (!decoders.includes(dec)) {
|
|
86
|
+
decoders.push(dec);
|
|
61
87
|
}
|
|
62
88
|
}
|
|
63
89
|
return decoders;
|
|
64
90
|
}
|
|
65
91
|
catch {
|
|
66
|
-
|
|
92
|
+
// Return software decoders as fallback
|
|
93
|
+
return ['h264', 'hevc', 'vp8', 'vp9', 'av1'];
|
|
67
94
|
}
|
|
68
95
|
}
|
|
69
96
|
function buildCapabilities() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/hardware/detection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/hardware/detection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKlD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,MAAM,GAAG,YAAY,CAAC,sBAAsB,CAAC,CAAC;AAEpD,sBAAsB;AACtB,IAAI,kBAAkB,GAAgC,IAAI,CAAC;AAE3D,6DAA6D;AAC7D,MAAM,eAAe,GAA+C;IAClE,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,KAAK;IACZ,cAAc,EAAE,cAAc;IAC9B,KAAK,EAAE,KAAK;IACZ,SAAS,EAAE,SAAS;CACrB,CAAC;AAEF,SAAS,eAAe;IACtB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,eAAe,CAAC,aAAa,EAAE,CAAC;QAClD,MAAM,OAAO,GAAiC,EAAE,CAAC;QAEjD,KAAK,MAAM,UAAU,IAAI,SAAS,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;YAC3C,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;QAElC,IAAI,EAAE,EAAE,CAAC;YACP,MAAM,eAAe,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC;YACjD,uEAAuE;YACvE,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;gBACpC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;YACD,EAAE,CAAC,OAAO,EAAE,CAAC;QACf,CAAC;QAED,0CAA0C;QAC1C,MAAM,gBAAgB,GAAG;YACvB,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY;YAC5C,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS;SAC5C,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;QACvC,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;IACtE,CAAC;AACH,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;QAElC,IAAI,EAAE,EAAE,CAAC;YACP,MAAM,eAAe,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC;YACjD,iCAAiC;YACjC,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;gBACpC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;YACD,EAAE,CAAC,OAAO,EAAE,CAAC;QACf,CAAC;QAED,0CAA0C;QAC1C,MAAM,gBAAgB,GAAG;YACvB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;YACnC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;SAC7B,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;QACvC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB;IACxB,MAAM,YAAY,GAAyB;QACzC,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,KAAK;KAChB,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;QACnC,YAAY,CAAC,OAAO,GAAG,QAAQ,CAAC;QAEhC,MAAM,iBAAiB,GAAG,eAAe,EAAE,CAAC;QAC5C,YAAY,CAAC,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpD,GAAG,GAAG;YACN,SAAS,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;SAChD,CAAC,CAAC,CAAC;QAEJ,MAAM,iBAAiB,GAAG,eAAe,EAAE,CAAC;QAC5C,YAAY,CAAC,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpD,GAAG,GAAG;YACN,SAAS,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;SAChD,CAAC,CAAC,CAAC;QAEJ,YAAY,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC7B,kBAAkB,GAAG,YAAY,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,OAAO,8BAA8B,EAAE,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,8BAA8B;IAC5C,IAAI,kBAAkB,EAAE,QAAQ,EAAE,CAAC;QACjC,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,OAAO,iBAAiB,EAAE,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B;IAClD,MAAM,YAAY,GAAG,MAAM,0BAA0B,EAAE,CAAC;IAExD,MAAM,KAAK,GAAa;QACtB,gCAAgC;QAChC,cAAc,YAAY,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;QAC1F,EAAE;QACF,8BAA8B;KAC/B,CAAC;IAEF,MAAM,iBAAiB,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACzE,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAE3C,MAAM,iBAAiB,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACzE,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,kBAAkB,GAAG,IAAI,CAAC;AAC5B,CAAC"}
|
|
@@ -1,34 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FFmpeg-backed AudioDecoder for Mediabunny
|
|
3
3
|
*
|
|
4
|
-
* Implements Mediabunny's CustomAudioDecoder interface using
|
|
4
|
+
* Implements Mediabunny's CustomAudioDecoder interface using node-av native bindings.
|
|
5
5
|
*/
|
|
6
6
|
import { CustomAudioDecoder, EncodedPacket, AudioCodec } from 'mediabunny';
|
|
7
7
|
export declare class FFmpegAudioDecoder extends CustomAudioDecoder {
|
|
8
|
-
private
|
|
9
|
-
private accumulatedData;
|
|
8
|
+
private backend;
|
|
10
9
|
private frameIndex;
|
|
11
10
|
private resolveFlush;
|
|
12
|
-
private aacConfig;
|
|
13
11
|
private baseTimestamp;
|
|
14
12
|
private hasBaseTimestamp;
|
|
15
13
|
static supports(codec: AudioCodec, _config: AudioDecoderConfig): boolean;
|
|
16
14
|
init(): Promise<void>;
|
|
17
|
-
/**
|
|
18
|
-
* Parse AAC AudioSpecificConfig from description buffer
|
|
19
|
-
*/
|
|
20
|
-
private parseAacAudioSpecificConfig;
|
|
21
15
|
decode(packet: EncodedPacket): Promise<void>;
|
|
22
|
-
/**
|
|
23
|
-
* Wrap raw AAC frame with ADTS header (7 bytes)
|
|
24
|
-
*/
|
|
25
|
-
private wrapWithAdtsHeader;
|
|
26
16
|
flush(): Promise<void>;
|
|
27
17
|
close(): Promise<void>;
|
|
28
|
-
/**
|
|
29
|
-
* Emit decoded audio samples
|
|
30
|
-
*/
|
|
31
|
-
private emitDecodedSamples;
|
|
32
18
|
/**
|
|
33
19
|
* Emit an AudioSample via Mediabunny callback
|
|
34
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FFmpegAudioDecoder.d.ts","sourceRoot":"","sources":["../../src/mediabunny/FFmpegAudioDecoder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"FFmpegAudioDecoder.d.ts","sourceRoot":"","sources":["../../src/mediabunny/FFmpegAudioDecoder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,kBAAkB,EAElB,aAAa,EACb,UAAU,EACX,MAAM,YAAY,CAAC;AA0BpB,qBAAa,kBAAmB,SAAQ,kBAAkB;IACxD,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,YAAY,CAA6B;IAEjD,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,gBAAgB,CAAkB;IAE1C,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO;IAIlE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA4CrB,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAe5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B;;OAEG;IACH,OAAO,CAAC,eAAe;CAsBxB"}
|
|
@@ -1,135 +1,81 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FFmpeg-backed AudioDecoder for Mediabunny
|
|
3
3
|
*
|
|
4
|
-
* Implements Mediabunny's CustomAudioDecoder interface using
|
|
4
|
+
* Implements Mediabunny's CustomAudioDecoder interface using node-av native bindings.
|
|
5
5
|
*/
|
|
6
|
-
import { spawn } from 'child_process';
|
|
7
6
|
import { CustomAudioDecoder, AudioSample, } from 'mediabunny';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'pcm-
|
|
17
|
-
'pcm-
|
|
18
|
-
'pcm-
|
|
19
|
-
'pcm-
|
|
20
|
-
'pcm-
|
|
21
|
-
'pcm-
|
|
22
|
-
'pcm-
|
|
23
|
-
'pcm-
|
|
24
|
-
'pcm-
|
|
25
|
-
'pcm-
|
|
26
|
-
'pcm-
|
|
27
|
-
'
|
|
28
|
-
'
|
|
7
|
+
import { NodeAvAudioDecoder } from '../node-av/NodeAvAudioDecoder.js';
|
|
8
|
+
// Map Mediabunny codec to internal codec name
|
|
9
|
+
const CODEC_NAME_MAP = {
|
|
10
|
+
'aac': 'aac',
|
|
11
|
+
'opus': 'opus',
|
|
12
|
+
'mp3': 'mp3',
|
|
13
|
+
'flac': 'flac',
|
|
14
|
+
'vorbis': 'vorbis',
|
|
15
|
+
'pcm-s16': 'pcm-s16',
|
|
16
|
+
'pcm-s16be': 'pcm-s16',
|
|
17
|
+
'pcm-s24': 'pcm-s16',
|
|
18
|
+
'pcm-s24be': 'pcm-s16',
|
|
19
|
+
'pcm-s32': 'pcm-s16',
|
|
20
|
+
'pcm-s32be': 'pcm-s16',
|
|
21
|
+
'pcm-f32': 'pcm-f32',
|
|
22
|
+
'pcm-f32be': 'pcm-f32',
|
|
23
|
+
'pcm-f64': 'pcm-f32',
|
|
24
|
+
'pcm-f64be': 'pcm-f32',
|
|
25
|
+
'pcm-u8': 'pcm-s16',
|
|
26
|
+
'pcm-s8': 'pcm-s16',
|
|
27
|
+
'ulaw': 'pcm-s16',
|
|
28
|
+
'alaw': 'pcm-s16',
|
|
29
29
|
};
|
|
30
|
-
// AAC frequency table for ADTS header
|
|
31
|
-
const AAC_FREQUENCIES = [
|
|
32
|
-
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
|
|
33
|
-
16000, 12000, 11025, 8000, 7350
|
|
34
|
-
];
|
|
35
30
|
export class FFmpegAudioDecoder extends CustomAudioDecoder {
|
|
36
|
-
|
|
37
|
-
accumulatedData = Buffer.alloc(0);
|
|
31
|
+
backend = null;
|
|
38
32
|
frameIndex = 0;
|
|
39
33
|
resolveFlush = null;
|
|
40
|
-
aacConfig = null;
|
|
41
34
|
// Track base timestamp from first input packet
|
|
42
35
|
baseTimestamp = 0;
|
|
43
36
|
hasBaseTimestamp = false;
|
|
44
37
|
static supports(codec, _config) {
|
|
45
|
-
return codec in
|
|
38
|
+
return codec in CODEC_NAME_MAP;
|
|
46
39
|
}
|
|
47
40
|
async init() {
|
|
48
|
-
const codecInfo = CODEC_MAP[this.codec] || { decoder: 'aac', format: 'aac' };
|
|
49
41
|
const sampleRate = this.config.sampleRate ?? 44100;
|
|
50
42
|
const numberOfChannels = this.config.numberOfChannels ?? 2;
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
43
|
+
// Create node-av backend
|
|
44
|
+
this.backend = new NodeAvAudioDecoder();
|
|
45
|
+
const codecName = CODEC_NAME_MAP[this.codec] || 'aac';
|
|
46
|
+
// Convert description to ArrayBufferView if present
|
|
47
|
+
let description;
|
|
48
|
+
if (this.config.description) {
|
|
49
|
+
if (this.config.description instanceof ArrayBuffer) {
|
|
50
|
+
description = new Uint8Array(this.config.description);
|
|
51
|
+
}
|
|
52
|
+
else if (ArrayBuffer.isView(this.config.description)) {
|
|
53
|
+
description = this.config.description;
|
|
54
|
+
}
|
|
63
55
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
'-f', inputFormat,
|
|
71
|
-
'-i', 'pipe:0',
|
|
72
|
-
// Output: raw PCM f32le
|
|
73
|
-
'-f', 'f32le',
|
|
74
|
-
'-ar', String(sampleRate),
|
|
75
|
-
'-ac', String(numberOfChannels),
|
|
76
|
-
'pipe:1',
|
|
77
|
-
];
|
|
78
|
-
this.process = spawn('ffmpeg', args, {
|
|
79
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
56
|
+
this.backend.startDecoder({
|
|
57
|
+
codec: codecName,
|
|
58
|
+
sampleRate,
|
|
59
|
+
numberOfChannels,
|
|
60
|
+
description,
|
|
61
|
+
outputFormat: 'f32',
|
|
80
62
|
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.
|
|
63
|
+
// Listen for decoded frames
|
|
64
|
+
this.backend.on('frame', (frame) => {
|
|
65
|
+
this.emitAudioSample(frame.data, frame.numberOfFrames);
|
|
84
66
|
});
|
|
85
|
-
this.
|
|
86
|
-
|
|
87
|
-
// Ignore common warnings, but log real errors for debugging
|
|
88
|
-
if (!msg.includes('Discarding') && !msg.includes('Last message repeated')) {
|
|
89
|
-
console.error('FFmpeg audio decoder:', msg);
|
|
90
|
-
}
|
|
67
|
+
this.backend.on('error', (err) => {
|
|
68
|
+
console.error('[FFmpegAudioDecoder] Backend error:', err.message);
|
|
91
69
|
});
|
|
92
|
-
this.
|
|
93
|
-
// Emit any remaining samples
|
|
94
|
-
if (this.accumulatedData.length > 0) {
|
|
95
|
-
this.emitAudioSample(this.accumulatedData);
|
|
96
|
-
this.accumulatedData = Buffer.alloc(0);
|
|
97
|
-
}
|
|
70
|
+
this.backend.on('close', () => {
|
|
98
71
|
if (this.resolveFlush) {
|
|
99
72
|
this.resolveFlush();
|
|
100
73
|
this.resolveFlush = null;
|
|
101
74
|
}
|
|
102
75
|
});
|
|
103
|
-
this.process.stdin?.on('error', () => {
|
|
104
|
-
// Ignore EPIPE errors
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Parse AAC AudioSpecificConfig from description buffer
|
|
109
|
-
*/
|
|
110
|
-
parseAacAudioSpecificConfig(description) {
|
|
111
|
-
let data;
|
|
112
|
-
if (description instanceof ArrayBuffer) {
|
|
113
|
-
data = new Uint8Array(description);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
data = new Uint8Array(description.buffer, description.byteOffset, description.byteLength);
|
|
117
|
-
}
|
|
118
|
-
if (data.length < 2) {
|
|
119
|
-
// Default config
|
|
120
|
-
return { objectType: 2, frequencyIndex: 4, channelConfig: 2 };
|
|
121
|
-
}
|
|
122
|
-
// Parse AudioSpecificConfig
|
|
123
|
-
// 5 bits: objectType
|
|
124
|
-
// 4 bits: frequencyIndex
|
|
125
|
-
// 4 bits: channelConfiguration
|
|
126
|
-
const objectType = (data[0] >> 3) & 0x1f;
|
|
127
|
-
const frequencyIndex = ((data[0] & 0x07) << 1) | ((data[1] >> 7) & 0x01);
|
|
128
|
-
const channelConfig = (data[1] >> 3) & 0x0f;
|
|
129
|
-
return { objectType, frequencyIndex, channelConfig };
|
|
130
76
|
}
|
|
131
77
|
async decode(packet) {
|
|
132
|
-
if (!this.
|
|
78
|
+
if (!this.backend?.isHealthy) {
|
|
133
79
|
throw new Error('Decoder not initialized');
|
|
134
80
|
}
|
|
135
81
|
// Capture the base timestamp from the first packet
|
|
@@ -137,65 +83,14 @@ export class FFmpegAudioDecoder extends CustomAudioDecoder {
|
|
|
137
83
|
this.baseTimestamp = packet.timestamp;
|
|
138
84
|
this.hasBaseTimestamp = true;
|
|
139
85
|
}
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
const adtsFrame = this.wrapWithAdtsHeader(packet.data);
|
|
143
|
-
this.process.stdin.write(adtsFrame);
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
// Write encoded data directly to FFmpeg
|
|
147
|
-
this.process.stdin.write(Buffer.from(packet.data));
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Wrap raw AAC frame with ADTS header (7 bytes)
|
|
152
|
-
*/
|
|
153
|
-
wrapWithAdtsHeader(rawAac) {
|
|
154
|
-
if (!this.aacConfig) {
|
|
155
|
-
return Buffer.from(rawAac);
|
|
156
|
-
}
|
|
157
|
-
const frameLength = rawAac.length + 7; // 7-byte ADTS header
|
|
158
|
-
const header = Buffer.alloc(7);
|
|
159
|
-
// ADTS header structure (7 bytes, no CRC):
|
|
160
|
-
// Syncword: 12 bits (0xFFF)
|
|
161
|
-
// ID: 1 bit (0 = MPEG-4, 1 = MPEG-2)
|
|
162
|
-
// Layer: 2 bits (always 0)
|
|
163
|
-
// Protection absent: 1 bit (1 = no CRC)
|
|
164
|
-
// Profile: 2 bits (objectType - 1)
|
|
165
|
-
// Sampling frequency index: 4 bits
|
|
166
|
-
// Private bit: 1 bit (0)
|
|
167
|
-
// Channel configuration: 3 bits
|
|
168
|
-
// Original/copy: 1 bit (0)
|
|
169
|
-
// Home: 1 bit (0)
|
|
170
|
-
// Copyright ID bit: 1 bit (0)
|
|
171
|
-
// Copyright ID start: 1 bit (0)
|
|
172
|
-
// Frame length: 13 bits
|
|
173
|
-
// Buffer fullness: 11 bits (0x7FF = variable)
|
|
174
|
-
// Number of AAC frames - 1: 2 bits (0 = 1 frame)
|
|
175
|
-
const profile = this.aacConfig.objectType - 1; // Profile is objectType - 1
|
|
176
|
-
const freqIdx = this.aacConfig.frequencyIndex;
|
|
177
|
-
const chanCfg = this.aacConfig.channelConfig;
|
|
178
|
-
// Byte 0: Syncword high (0xFF)
|
|
179
|
-
header[0] = 0xff;
|
|
180
|
-
// Byte 1: Syncword low (0xF) + ID (0) + Layer (00) + Protection absent (1)
|
|
181
|
-
header[1] = 0xf1; // 0xF0 | 0x01
|
|
182
|
-
// Byte 2: Profile (2 bits) + Frequency index (4 bits) + Private (1 bit) + Channel config high (1 bit)
|
|
183
|
-
header[2] = ((profile & 0x03) << 6) | ((freqIdx & 0x0f) << 2) | ((chanCfg >> 2) & 0x01);
|
|
184
|
-
// Byte 3: Channel config low (2 bits) + Original (1 bit) + Home (1 bit) + Copyright ID (1 bit) + Copyright start (1 bit) + Frame length high (2 bits)
|
|
185
|
-
header[3] = ((chanCfg & 0x03) << 6) | ((frameLength >> 11) & 0x03);
|
|
186
|
-
// Byte 4: Frame length middle (8 bits)
|
|
187
|
-
header[4] = (frameLength >> 3) & 0xff;
|
|
188
|
-
// Byte 5: Frame length low (3 bits) + Buffer fullness high (5 bits)
|
|
189
|
-
header[5] = ((frameLength & 0x07) << 5) | 0x1f; // Buffer fullness = 0x7FF
|
|
190
|
-
// Byte 6: Buffer fullness low (6 bits) + Number of frames - 1 (2 bits)
|
|
191
|
-
header[6] = 0xfc; // (0x3F << 2) | 0x00
|
|
192
|
-
return Buffer.concat([header, Buffer.from(rawAac)]);
|
|
86
|
+
// Write encoded data to backend
|
|
87
|
+
this.backend.write(Buffer.from(packet.data));
|
|
193
88
|
}
|
|
194
89
|
async flush() {
|
|
195
90
|
return new Promise((resolve) => {
|
|
196
91
|
this.resolveFlush = resolve;
|
|
197
|
-
if (this.
|
|
198
|
-
this.
|
|
92
|
+
if (this.backend) {
|
|
93
|
+
this.backend.end();
|
|
199
94
|
}
|
|
200
95
|
else {
|
|
201
96
|
resolve();
|
|
@@ -203,39 +98,19 @@ export class FFmpegAudioDecoder extends CustomAudioDecoder {
|
|
|
203
98
|
});
|
|
204
99
|
}
|
|
205
100
|
async close() {
|
|
206
|
-
if (this.
|
|
207
|
-
this.
|
|
208
|
-
this.
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Emit decoded audio samples
|
|
213
|
-
*/
|
|
214
|
-
emitDecodedSamples() {
|
|
215
|
-
const sampleRate = this.config.sampleRate ?? 44100;
|
|
216
|
-
const numberOfChannels = this.config.numberOfChannels ?? 2;
|
|
217
|
-
// Calculate chunk size (emit ~20ms chunks)
|
|
218
|
-
const samplesPerChunk = Math.floor(sampleRate * 0.02); // 20ms
|
|
219
|
-
const bytesPerSample = 4; // f32
|
|
220
|
-
const bytesPerChunk = samplesPerChunk * numberOfChannels * bytesPerSample;
|
|
221
|
-
while (this.accumulatedData.length >= bytesPerChunk) {
|
|
222
|
-
const chunkData = Buffer.from(this.accumulatedData.subarray(0, bytesPerChunk));
|
|
223
|
-
this.accumulatedData = this.accumulatedData.subarray(bytesPerChunk);
|
|
224
|
-
this.emitAudioSample(chunkData);
|
|
101
|
+
if (this.backend) {
|
|
102
|
+
this.backend.kill();
|
|
103
|
+
this.backend = null;
|
|
225
104
|
}
|
|
226
105
|
}
|
|
227
106
|
/**
|
|
228
107
|
* Emit an AudioSample via Mediabunny callback
|
|
229
108
|
*/
|
|
230
|
-
emitAudioSample(data) {
|
|
231
|
-
if (data.length === 0)
|
|
109
|
+
emitAudioSample(data, numberOfFrames) {
|
|
110
|
+
if (data.length === 0 || numberOfFrames === 0)
|
|
232
111
|
return;
|
|
233
112
|
const sampleRate = this.config.sampleRate ?? 44100;
|
|
234
113
|
const numberOfChannels = this.config.numberOfChannels ?? 2;
|
|
235
|
-
const bytesPerSample = 4; // f32
|
|
236
|
-
const numberOfFrames = Math.floor(data.length / (numberOfChannels * bytesPerSample));
|
|
237
|
-
if (numberOfFrames === 0)
|
|
238
|
-
return;
|
|
239
114
|
// Calculate timestamp in seconds, preserving base timestamp from input
|
|
240
115
|
const offsetSeconds = this.frameIndex / sampleRate;
|
|
241
116
|
const timestampSeconds = this.baseTimestamp + offsetSeconds;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FFmpegAudioDecoder.js","sourceRoot":"","sources":["../../src/mediabunny/FFmpegAudioDecoder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"FFmpegAudioDecoder.js","sourceRoot":"","sources":["../../src/mediabunny/FFmpegAudioDecoder.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FFmpeg-backed AudioEncoder for Mediabunny
|
|
3
3
|
*
|
|
4
|
-
* Implements Mediabunny's CustomAudioEncoder interface using
|
|
4
|
+
* Implements Mediabunny's CustomAudioEncoder interface using node-av native bindings.
|
|
5
5
|
*/
|
|
6
6
|
import { CustomAudioEncoder, AudioSample, AudioCodec } from 'mediabunny';
|
|
7
7
|
export declare class FFmpegAudioEncoder extends CustomAudioEncoder {
|
|
8
|
-
private
|
|
9
|
-
private accumulatedData;
|
|
8
|
+
private backend;
|
|
10
9
|
private frameIndex;
|
|
11
10
|
private resolveFlush;
|
|
12
|
-
private ffmpegCodec;
|
|
13
11
|
private metadataEmitted;
|
|
14
12
|
private codecDescription;
|
|
15
|
-
private audioOutputFormat;
|
|
16
13
|
static supports(codec: AudioCodec, _config: AudioEncoderConfig): boolean;
|
|
17
14
|
init(): Promise<void>;
|
|
18
15
|
encode(audioSample: AudioSample): Promise<void>;
|
|
@@ -23,42 +20,13 @@ export declare class FFmpegAudioEncoder extends CustomAudioEncoder {
|
|
|
23
20
|
*/
|
|
24
21
|
private getSampleData;
|
|
25
22
|
/**
|
|
26
|
-
*
|
|
27
|
-
*/
|
|
28
|
-
private parseEncodedFrames;
|
|
29
|
-
/**
|
|
30
|
-
* Find the end of an audio frame
|
|
31
|
-
*/
|
|
32
|
-
private findFrameEnd;
|
|
33
|
-
private findADTSFrame;
|
|
34
|
-
private findMP3Frame;
|
|
35
|
-
/**
|
|
36
|
-
* Parse Ogg pages and extract individual Opus packets
|
|
37
|
-
* Ogg page structure:
|
|
38
|
-
* - 4 bytes: "OggS" magic
|
|
39
|
-
* - 1 byte: version
|
|
40
|
-
* - 1 byte: header type
|
|
41
|
-
* - 8 bytes: granule position
|
|
42
|
-
* - 4 bytes: serial number
|
|
43
|
-
* - 4 bytes: page sequence number
|
|
44
|
-
* - 4 bytes: checksum
|
|
45
|
-
* - 1 byte: number of segments
|
|
46
|
-
* - N bytes: segment table (one byte per segment)
|
|
47
|
-
* - data: concatenated segments
|
|
48
|
-
*/
|
|
49
|
-
private findOggPage;
|
|
50
|
-
/**
|
|
51
|
-
* Extract individual Opus packets from Ogg page segments
|
|
23
|
+
* Get the number of samples per frame based on codec
|
|
52
24
|
*/
|
|
53
|
-
private
|
|
25
|
+
private getFrameSamples;
|
|
54
26
|
/**
|
|
55
27
|
* Emit an encoded packet via Mediabunny callback
|
|
56
28
|
*/
|
|
57
29
|
private emitPacket;
|
|
58
|
-
/**
|
|
59
|
-
* Get the number of samples per frame based on codec
|
|
60
|
-
*/
|
|
61
|
-
private getFrameSamples;
|
|
62
30
|
/**
|
|
63
31
|
* Get codec string for the output format
|
|
64
32
|
*/
|
|
@@ -69,9 +37,7 @@ export declare class FFmpegAudioEncoder extends CustomAudioEncoder {
|
|
|
69
37
|
private buildOpusDescription;
|
|
70
38
|
/**
|
|
71
39
|
* Build AAC AudioSpecificConfig for decoder config description
|
|
72
|
-
* ISO 14496-3 section 1.6.2.1
|
|
73
40
|
*/
|
|
74
41
|
private buildAacDescription;
|
|
75
|
-
private stripAdtsHeader;
|
|
76
42
|
}
|
|
77
43
|
//# sourceMappingURL=FFmpegAudioEncoder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FFmpegAudioEncoder.d.ts","sourceRoot":"","sources":["../../src/mediabunny/FFmpegAudioEncoder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"FFmpegAudioEncoder.d.ts","sourceRoot":"","sources":["../../src/mediabunny/FFmpegAudioEncoder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,kBAAkB,EAClB,WAAW,EAEX,UAAU,EACX,MAAM,YAAY,CAAC;AA2BpB,qBAAa,kBAAmB,SAAQ,kBAAkB;IACxD,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,gBAAgB,CAA2B;IAEnD,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO;IAIlE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BrB,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B;;OAEG;YACW,aAAa;IAiC3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;OAEG;IACH,OAAO,CAAC,UAAU;IAyClB;;OAEG;IACH,OAAO,CAAC,cAAc;IAiBtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAM5B"}
|