node-av 5.1.0 → 5.1.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 +17 -1
- package/dist/api/hardware.js +3 -4
- package/dist/api/hardware.js.map +1 -1
- package/dist/api/rtp-stream.js +0 -6
- package/dist/api/rtp-stream.js.map +1 -1
- package/dist/ffmpeg/index.js +3 -4
- package/dist/ffmpeg/index.js.map +1 -1
- package/dist/lib/binding.js +3 -4
- package/dist/lib/binding.js.map +1 -1
- package/dist/utils/electron.d.ts +49 -0
- package/dist/utils/electron.js +63 -0
- package/dist/utils/electron.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +27 -12
- package/benchmarks/cases/latency.ts +0 -361
- package/benchmarks/cases/memory.ts +0 -260
- package/benchmarks/cases/transcode.ts +0 -271
- package/benchmarks/index.ts +0 -264
- package/benchmarks/regen-report.ts +0 -22
- package/benchmarks/results/.gitkeep +0 -2
- package/benchmarks/runner.ts +0 -247
- package/benchmarks/utils/ffmpeg-cli.ts +0 -363
- package/benchmarks/utils/measure.ts +0 -275
- package/benchmarks/utils/report.ts +0 -405
- package/binding.gyp +0 -166
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Transcode Speed Benchmark Tests
|
|
3
|
-
*
|
|
4
|
-
* Compares transcoding performance between FFmpeg CLI and node-av
|
|
5
|
-
* for various codec configurations.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { dirname, join, resolve } from 'node:path';
|
|
9
|
-
import { fileURLToPath } from 'node:url';
|
|
10
|
-
|
|
11
|
-
import { Decoder, Demuxer, Encoder, HardwareContext, Muxer, pipeline } from '../../src/api/index.js';
|
|
12
|
-
import { FF_ENCODER_LIBX264, FF_ENCODER_LIBX265 } from '../../src/constants/encoders.js';
|
|
13
|
-
import { runner } from '../runner.js';
|
|
14
|
-
import { FFmpegArgs } from '../utils/ffmpeg-cli.js';
|
|
15
|
-
|
|
16
|
-
import type { BenchmarkConfig } from '../runner.js';
|
|
17
|
-
|
|
18
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
-
const __dirname = dirname(__filename);
|
|
20
|
-
|
|
21
|
-
// Default paths
|
|
22
|
-
const testDataDir = resolve(__dirname, '../../testdata');
|
|
23
|
-
const resultsDir = resolve(__dirname, '../results');
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Default benchmark configuration
|
|
27
|
-
*/
|
|
28
|
-
const defaultConfig = {
|
|
29
|
-
iterations: 5,
|
|
30
|
-
warmupIterations: 1,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Software H.264 Transcode Benchmark
|
|
35
|
-
*/
|
|
36
|
-
export async function benchmarkSWH264(inputFile?: string, outputFile?: string): Promise<void> {
|
|
37
|
-
const input = inputFile ?? join(testDataDir, 'video.mp4');
|
|
38
|
-
const output = outputFile ?? join(resultsDir, 'sw-h264-output.mp4');
|
|
39
|
-
|
|
40
|
-
const config: BenchmarkConfig = {
|
|
41
|
-
name: 'SW H.264 Transcode',
|
|
42
|
-
description: 'Software H.264 encoding with libx264 (CPU)',
|
|
43
|
-
category: 'transcode',
|
|
44
|
-
inputFile: input,
|
|
45
|
-
outputFile: output,
|
|
46
|
-
...defaultConfig,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const ffmpegOptions = {
|
|
50
|
-
input,
|
|
51
|
-
output,
|
|
52
|
-
args: FFmpegArgs.swH264(23),
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const nodeAVFn = async () => {
|
|
56
|
-
await using demuxer = await Demuxer.open(input);
|
|
57
|
-
const videoStream = demuxer.video();
|
|
58
|
-
if (!videoStream) throw new Error('No video stream found');
|
|
59
|
-
|
|
60
|
-
const decoder = await Decoder.create(videoStream);
|
|
61
|
-
const encoder = await Encoder.create(FF_ENCODER_LIBX264, {
|
|
62
|
-
decoder,
|
|
63
|
-
options: { preset: 'medium', crf: 23 },
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
await using muxer = await Muxer.open(output);
|
|
67
|
-
|
|
68
|
-
const control = pipeline(demuxer, decoder, encoder, muxer);
|
|
69
|
-
await control.completion;
|
|
70
|
-
|
|
71
|
-
// Get frame count from codec context
|
|
72
|
-
const ctx = encoder.getCodecContext();
|
|
73
|
-
return { framesProcessed: ctx?.frameNumber };
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
await runner.runBenchmark(config, ffmpegOptions, nodeAVFn);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Software H.265/HEVC Transcode Benchmark
|
|
81
|
-
*/
|
|
82
|
-
export async function benchmarkSWH265(inputFile?: string, outputFile?: string): Promise<void> {
|
|
83
|
-
const input = inputFile ?? join(testDataDir, 'video.mp4');
|
|
84
|
-
const output = outputFile ?? join(resultsDir, 'sw-h265-output.mp4');
|
|
85
|
-
|
|
86
|
-
const config: BenchmarkConfig = {
|
|
87
|
-
name: 'SW H.265 Transcode',
|
|
88
|
-
description: 'Software H.265/HEVC encoding with libx265 (CPU)',
|
|
89
|
-
category: 'transcode',
|
|
90
|
-
inputFile: input,
|
|
91
|
-
outputFile: output,
|
|
92
|
-
...defaultConfig,
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const ffmpegOptions = {
|
|
96
|
-
input,
|
|
97
|
-
output,
|
|
98
|
-
args: FFmpegArgs.swH265(28),
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const nodeAVFn = async () => {
|
|
102
|
-
await using demuxer = await Demuxer.open(input);
|
|
103
|
-
const videoStream = demuxer.video();
|
|
104
|
-
if (!videoStream) throw new Error('No video stream found');
|
|
105
|
-
|
|
106
|
-
const decoder = await Decoder.create(videoStream);
|
|
107
|
-
const encoder = await Encoder.create(FF_ENCODER_LIBX265, {
|
|
108
|
-
decoder,
|
|
109
|
-
options: { preset: 'medium', crf: 28 },
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
await using muxer = await Muxer.open(output);
|
|
113
|
-
|
|
114
|
-
const control = pipeline(demuxer, decoder, encoder, muxer);
|
|
115
|
-
await control.completion;
|
|
116
|
-
|
|
117
|
-
// Get frame count from codec context
|
|
118
|
-
const ctx = encoder.getCodecContext();
|
|
119
|
-
return { framesProcessed: ctx?.frameNumber };
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
await runner.runBenchmark(config, ffmpegOptions, nodeAVFn);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Hardware H.264 Transcode Benchmark (platform-dependent)
|
|
127
|
-
*/
|
|
128
|
-
export async function benchmarkHWH264(inputFile?: string, outputFile?: string): Promise<void> {
|
|
129
|
-
const input = inputFile ?? join(testDataDir, 'video.mp4');
|
|
130
|
-
const output = outputFile ?? join(resultsDir, 'hw-h264-output.mp4');
|
|
131
|
-
|
|
132
|
-
// Check hardware availability
|
|
133
|
-
const hw = HardwareContext.auto();
|
|
134
|
-
if (!hw) {
|
|
135
|
-
console.log('⚠️ Skipping HW H.264 benchmark: No hardware acceleration available');
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const hwEncoderCodec = hw.getEncoderCodec('h264');
|
|
140
|
-
if (!hwEncoderCodec) {
|
|
141
|
-
console.log('⚠️ Skipping HW H.264 benchmark: No hardware H.264 encoder available');
|
|
142
|
-
hw.dispose();
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Determine FFmpeg hardware encoder based on platform
|
|
147
|
-
let ffmpegArgs: string[];
|
|
148
|
-
const platform = process.platform;
|
|
149
|
-
|
|
150
|
-
if (platform === 'darwin') {
|
|
151
|
-
ffmpegArgs = FFmpegArgs.hwH264VideoToolbox();
|
|
152
|
-
} else if (platform === 'linux') {
|
|
153
|
-
// Try VAAPI first, then NVENC
|
|
154
|
-
ffmpegArgs = FFmpegArgs.hwH264Vaapi();
|
|
155
|
-
} else if (platform === 'win32') {
|
|
156
|
-
ffmpegArgs = FFmpegArgs.hwH264Nvenc();
|
|
157
|
-
} else {
|
|
158
|
-
console.log('⚠️ Skipping HW H.264 benchmark: Unknown platform');
|
|
159
|
-
hw.dispose();
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const config: BenchmarkConfig = {
|
|
164
|
-
name: 'HW H.264 Transcode',
|
|
165
|
-
description: `Hardware H.264 encoding (${hw.deviceTypeName})`,
|
|
166
|
-
category: 'transcode',
|
|
167
|
-
inputFile: input,
|
|
168
|
-
outputFile: output,
|
|
169
|
-
...defaultConfig,
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const ffmpegOptions = {
|
|
173
|
-
input,
|
|
174
|
-
output,
|
|
175
|
-
args: ffmpegArgs,
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
const nodeAVFn = async () => {
|
|
179
|
-
await using demuxer = await Demuxer.open(input);
|
|
180
|
-
const videoStream = demuxer.video();
|
|
181
|
-
if (!videoStream) throw new Error('No video stream found');
|
|
182
|
-
|
|
183
|
-
const decoder = await Decoder.create(videoStream, { hardware: hw });
|
|
184
|
-
const encoder = await Encoder.create(hwEncoderCodec, {
|
|
185
|
-
decoder,
|
|
186
|
-
bitrate: '2M',
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
await using muxer = await Muxer.open(output);
|
|
190
|
-
|
|
191
|
-
const control = pipeline(demuxer, decoder, encoder, muxer);
|
|
192
|
-
await control.completion;
|
|
193
|
-
|
|
194
|
-
// Get frame count from codec context
|
|
195
|
-
const ctx = encoder.getCodecContext();
|
|
196
|
-
return { framesProcessed: ctx?.frameNumber };
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
await runner.runBenchmark(config, ffmpegOptions, nodeAVFn);
|
|
201
|
-
} finally {
|
|
202
|
-
hw.dispose();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Stream Copy (Remux) Benchmark
|
|
208
|
-
*/
|
|
209
|
-
export async function benchmarkStreamCopy(inputFile?: string, outputFile?: string): Promise<void> {
|
|
210
|
-
const input = inputFile ?? join(testDataDir, 'video.mp4');
|
|
211
|
-
const output = outputFile ?? join(resultsDir, 'stream-copy-output.mp4');
|
|
212
|
-
|
|
213
|
-
const config: BenchmarkConfig = {
|
|
214
|
-
name: 'Stream Copy (Remux)',
|
|
215
|
-
description: 'Copy streams without re-encoding',
|
|
216
|
-
category: 'transcode',
|
|
217
|
-
inputFile: input,
|
|
218
|
-
outputFile: output,
|
|
219
|
-
...defaultConfig,
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
const ffmpegOptions = {
|
|
223
|
-
input,
|
|
224
|
-
output,
|
|
225
|
-
args: FFmpegArgs.streamCopy(),
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
const nodeAVFn = async () => {
|
|
229
|
-
await using demuxer = await Demuxer.open(input);
|
|
230
|
-
await using muxer = await Muxer.open(output);
|
|
231
|
-
|
|
232
|
-
// Add streams from demuxer to muxer (required for stream copy)
|
|
233
|
-
const streamMap = new Map<number, number>();
|
|
234
|
-
for (const stream of demuxer.streams) {
|
|
235
|
-
const outIndex = muxer.addStream(stream);
|
|
236
|
-
streamMap.set(stream.index, outIndex);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Manual packet copy to count packets
|
|
240
|
-
let packetCount = 0;
|
|
241
|
-
for await (const packet of demuxer.packets()) {
|
|
242
|
-
if (!packet) break;
|
|
243
|
-
const outIndex = streamMap.get(packet.streamIndex);
|
|
244
|
-
if (outIndex !== undefined) {
|
|
245
|
-
await muxer.writePacket(packet, outIndex);
|
|
246
|
-
packetCount++;
|
|
247
|
-
}
|
|
248
|
-
packet.free();
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return { framesProcessed: packetCount };
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
await runner.runBenchmark(config, ffmpegOptions, nodeAVFn);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Run all transcode benchmarks
|
|
259
|
-
*/
|
|
260
|
-
export async function runAllTranscodeBenchmarks(inputFile?: string): Promise<void> {
|
|
261
|
-
console.log('\n🎬 Running Transcode Speed Benchmarks\n');
|
|
262
|
-
console.log('='.repeat(60));
|
|
263
|
-
|
|
264
|
-
await benchmarkSWH264(inputFile);
|
|
265
|
-
await benchmarkSWH265(inputFile);
|
|
266
|
-
await benchmarkHWH264(inputFile);
|
|
267
|
-
await benchmarkStreamCopy(inputFile);
|
|
268
|
-
|
|
269
|
-
console.log('\n' + '='.repeat(60));
|
|
270
|
-
console.log('Transcode benchmarks completed\n');
|
|
271
|
-
}
|
package/benchmarks/index.ts
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env tsx
|
|
2
|
-
/**
|
|
3
|
-
* node-av Benchmark CLI
|
|
4
|
-
*
|
|
5
|
-
* Comprehensive benchmark suite comparing node-av with FFmpeg CLI.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* npm run benchmark # Run all benchmarks
|
|
9
|
-
* npm run benchmark -- --help # Show help
|
|
10
|
-
* npm run benchmark -- transcode # Run only transcode benchmarks
|
|
11
|
-
* npm run benchmark -- memory # Run only memory benchmarks
|
|
12
|
-
* npm run benchmark -- latency # Run only latency benchmarks
|
|
13
|
-
* npm run benchmark -- -i file1.mp4 -i file2.mp4 # Multiple inputs
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
17
|
-
import { mkdir } from 'node:fs/promises';
|
|
18
|
-
import { basename, dirname, join, resolve } from 'node:path';
|
|
19
|
-
import { fileURLToPath } from 'node:url';
|
|
20
|
-
|
|
21
|
-
import { measureAllLatencies } from './cases/latency.js';
|
|
22
|
-
import { runAllMemoryBenchmarks } from './cases/memory.js';
|
|
23
|
-
import { runAllTranscodeBenchmarks } from './cases/transcode.js';
|
|
24
|
-
import { runner } from './runner.js';
|
|
25
|
-
import { createInputFileInfo, getSystemInfo, saveResultsJSON, writeReport } from './utils/report.js';
|
|
26
|
-
|
|
27
|
-
import type { BenchmarkReport, InputFileInfo } from './utils/report.js';
|
|
28
|
-
|
|
29
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
30
|
-
const __dirname = dirname(__filename);
|
|
31
|
-
|
|
32
|
-
// Default paths
|
|
33
|
-
const testDataDir = resolve(__dirname, '../testdata');
|
|
34
|
-
const resultsDir = resolve(__dirname, 'results');
|
|
35
|
-
const defaultInputFile = join(testDataDir, 'video.mp4');
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Parse command line arguments
|
|
39
|
-
*/
|
|
40
|
-
function parseArgs(): { category?: string; inputFiles: string[]; help: boolean; noReport: boolean; iterations?: number; pattern?: string } {
|
|
41
|
-
const args = process.argv.slice(2);
|
|
42
|
-
let category: string | undefined;
|
|
43
|
-
const inputFiles: string[] = [];
|
|
44
|
-
let help = false;
|
|
45
|
-
let noReport = false;
|
|
46
|
-
let iterations: number | undefined;
|
|
47
|
-
let pattern: string | undefined;
|
|
48
|
-
|
|
49
|
-
for (let i = 0; i < args.length; i++) {
|
|
50
|
-
const arg = args[i];
|
|
51
|
-
|
|
52
|
-
if (arg === '--help' || arg === '-h') {
|
|
53
|
-
help = true;
|
|
54
|
-
} else if (arg === '--no-report') {
|
|
55
|
-
noReport = true;
|
|
56
|
-
} else if (arg === '--input' || arg === '-i') {
|
|
57
|
-
inputFiles.push(args[++i]);
|
|
58
|
-
} else if (arg === '--pattern' || arg === '-p') {
|
|
59
|
-
pattern = args[++i];
|
|
60
|
-
} else if (arg === '--iterations' || arg === '-n') {
|
|
61
|
-
iterations = parseInt(args[++i], 10);
|
|
62
|
-
} else if (!arg.startsWith('-')) {
|
|
63
|
-
category = arg;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return { category, inputFiles, help, noReport, iterations, pattern };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Expand glob pattern to file list
|
|
72
|
-
*/
|
|
73
|
-
function expandPattern(pattern: string): string[] {
|
|
74
|
-
const dir = dirname(pattern);
|
|
75
|
-
const filePattern = basename(pattern).replace('*', '.*');
|
|
76
|
-
const regex = new RegExp(`^${filePattern}$`);
|
|
77
|
-
|
|
78
|
-
if (!existsSync(dir)) return [];
|
|
79
|
-
|
|
80
|
-
return readdirSync(dir)
|
|
81
|
-
.filter((file) => regex.test(file))
|
|
82
|
-
.map((file) => join(dir, file))
|
|
83
|
-
.sort();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Print help message
|
|
88
|
-
*/
|
|
89
|
-
function printHelp(): void {
|
|
90
|
-
console.log(`
|
|
91
|
-
node-av Benchmark Suite
|
|
92
|
-
========================
|
|
93
|
-
|
|
94
|
-
Usage:
|
|
95
|
-
npm run benchmark [options] [category]
|
|
96
|
-
|
|
97
|
-
Categories:
|
|
98
|
-
transcode Run transcode speed benchmarks
|
|
99
|
-
memory Run memory usage benchmarks
|
|
100
|
-
latency Run latency benchmarks
|
|
101
|
-
all Run all benchmarks (default)
|
|
102
|
-
|
|
103
|
-
Options:
|
|
104
|
-
-h, --help Show this help message
|
|
105
|
-
-i, --input FILE Use custom input file (can be repeated for multiple files)
|
|
106
|
-
-p, --pattern PAT Use glob pattern to match input files
|
|
107
|
-
-n, --iterations N Number of iterations per benchmark (default: 5)
|
|
108
|
-
--no-report Skip generating BENCHMARK.md report
|
|
109
|
-
|
|
110
|
-
Examples:
|
|
111
|
-
npm run benchmark # Run all benchmarks with default input
|
|
112
|
-
npm run benchmark transcode # Run only transcode benchmarks
|
|
113
|
-
npm run benchmark -- -i input.mp4 # Use custom input file
|
|
114
|
-
npm run benchmark -- -i h264.mp4 -i hevc.mp4 # Multiple input files
|
|
115
|
-
npm run benchmark -- -p "testdata/bbb-4k-*" # Match pattern
|
|
116
|
-
npm run benchmark -- -n 10 # Run 10 iterations
|
|
117
|
-
npm run benchmark -- --no-report # Skip report generation
|
|
118
|
-
`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Main benchmark runner
|
|
123
|
-
*/
|
|
124
|
-
async function main(): Promise<void> {
|
|
125
|
-
const { category, inputFiles, help, noReport, pattern } = parseArgs();
|
|
126
|
-
|
|
127
|
-
if (help) {
|
|
128
|
-
printHelp();
|
|
129
|
-
process.exit(0);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Resolve input files
|
|
133
|
-
let inputs: string[] = [];
|
|
134
|
-
|
|
135
|
-
if (pattern) {
|
|
136
|
-
inputs = expandPattern(pattern);
|
|
137
|
-
if (inputs.length === 0) {
|
|
138
|
-
console.error(`Error: No files matched pattern: ${pattern}`);
|
|
139
|
-
process.exit(1);
|
|
140
|
-
}
|
|
141
|
-
} else if (inputFiles.length > 0) {
|
|
142
|
-
inputs = inputFiles;
|
|
143
|
-
} else {
|
|
144
|
-
inputs = [defaultInputFile];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Validate all input files exist
|
|
148
|
-
for (const input of inputs) {
|
|
149
|
-
if (!existsSync(input)) {
|
|
150
|
-
console.error(`Error: Input file not found: ${input}`);
|
|
151
|
-
console.error('Please provide a valid input file with --input or ensure testdata/video.mp4 exists.');
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Ensure results directory exists
|
|
157
|
-
if (!existsSync(resultsDir)) {
|
|
158
|
-
await mkdir(resultsDir, { recursive: true });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
console.log(`
|
|
162
|
-
╔═══════════════════════════════════════════════════════════════╗
|
|
163
|
-
║ node-av Benchmark Suite ║
|
|
164
|
-
╚═══════════════════════════════════════════════════════════════╝
|
|
165
|
-
`);
|
|
166
|
-
|
|
167
|
-
// Print system info
|
|
168
|
-
console.log('Gathering system information...\n');
|
|
169
|
-
const systemInfo = await getSystemInfo();
|
|
170
|
-
|
|
171
|
-
console.log(`System: ${systemInfo.os} ${systemInfo.osVersion} (${systemInfo.arch})`);
|
|
172
|
-
console.log(`CPU: ${systemInfo.cpu} (${systemInfo.cpuCores} cores)`);
|
|
173
|
-
console.log(`RAM: ${systemInfo.ram}`);
|
|
174
|
-
if (systemInfo.gpu) {
|
|
175
|
-
console.log(`GPU: ${systemInfo.gpu}`);
|
|
176
|
-
}
|
|
177
|
-
console.log(`Node.js: ${systemInfo.nodeVersion}`);
|
|
178
|
-
console.log(`FFmpeg: ${systemInfo.ffmpegVersion}`);
|
|
179
|
-
console.log(`node-av: ${systemInfo.nodeAVVersion}`);
|
|
180
|
-
console.log(`Input files: ${inputs.length}`);
|
|
181
|
-
for (const input of inputs) {
|
|
182
|
-
console.log(` - ${basename(input)}`);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Get input file info for all files
|
|
186
|
-
const inputFileInfos: InputFileInfo[] = [];
|
|
187
|
-
for (const input of inputs) {
|
|
188
|
-
const info = await createInputFileInfo(input);
|
|
189
|
-
inputFileInfos.push(info);
|
|
190
|
-
console.log(`\n${basename(input)}:`);
|
|
191
|
-
if (info.duration > 0) {
|
|
192
|
-
console.log(` Duration: ${info.duration.toFixed(1)}s`);
|
|
193
|
-
if (info.resolution) {
|
|
194
|
-
console.log(` Resolution: ${info.resolution}`);
|
|
195
|
-
}
|
|
196
|
-
if (info.codec) {
|
|
197
|
-
console.log(` Codec: ${info.codec}`);
|
|
198
|
-
}
|
|
199
|
-
if (info.fps) {
|
|
200
|
-
console.log(` FPS: ${info.fps.toFixed(1)}`);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Run benchmarks based on category for each input file
|
|
206
|
-
const categoryLower = category?.toLowerCase() ?? 'all';
|
|
207
|
-
let latencyMetrics;
|
|
208
|
-
|
|
209
|
-
for (const input of inputs) {
|
|
210
|
-
console.log(`\n${'='.repeat(60)}`);
|
|
211
|
-
console.log(`📁 Benchmarking: ${basename(input)}`);
|
|
212
|
-
console.log('='.repeat(60));
|
|
213
|
-
|
|
214
|
-
switch (categoryLower) {
|
|
215
|
-
case 'transcode':
|
|
216
|
-
await runAllTranscodeBenchmarks(input);
|
|
217
|
-
break;
|
|
218
|
-
case 'memory':
|
|
219
|
-
await runAllMemoryBenchmarks(input);
|
|
220
|
-
break;
|
|
221
|
-
case 'latency':
|
|
222
|
-
latencyMetrics = await measureAllLatencies(input, 10);
|
|
223
|
-
break;
|
|
224
|
-
case 'all':
|
|
225
|
-
default:
|
|
226
|
-
await runAllTranscodeBenchmarks(input);
|
|
227
|
-
await runAllMemoryBenchmarks(input);
|
|
228
|
-
// Only measure latency for first file (it's input-independent)
|
|
229
|
-
if (input === inputs[0]) {
|
|
230
|
-
latencyMetrics = await measureAllLatencies(input, 10);
|
|
231
|
-
}
|
|
232
|
-
break;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Generate report if not disabled
|
|
237
|
-
if (!noReport) {
|
|
238
|
-
const results = runner.getResults();
|
|
239
|
-
|
|
240
|
-
const report: BenchmarkReport = {
|
|
241
|
-
systemInfo,
|
|
242
|
-
inputFileInfos,
|
|
243
|
-
transcodeResults: results.filter((r) => r.config.category === 'transcode'),
|
|
244
|
-
memoryResults: results.filter((r) => r.config.category === 'memory'),
|
|
245
|
-
latencyMetrics,
|
|
246
|
-
timestamp: new Date().toISOString(),
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
await writeReport(report);
|
|
250
|
-
saveResultsJSON(report);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
console.log(`
|
|
254
|
-
╔═══════════════════════════════════════════════════════════════╗
|
|
255
|
-
║ Benchmarks Complete ║
|
|
256
|
-
╚═══════════════════════════════════════════════════════════════╝
|
|
257
|
-
`);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Run main
|
|
261
|
-
main().catch((error) => {
|
|
262
|
-
console.error('Benchmark failed:', error);
|
|
263
|
-
process.exit(1);
|
|
264
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Regenerate BENCHMARK.md from existing results JSON
|
|
3
|
-
*/
|
|
4
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
5
|
-
import { dirname, resolve } from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
|
|
8
|
-
import { generateReport } from './utils/report.js';
|
|
9
|
-
|
|
10
|
-
import type { BenchmarkReport } from './utils/report.js';
|
|
11
|
-
|
|
12
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
const resultsPath = resolve(__dirname, 'results/benchmark-results.json');
|
|
14
|
-
const outputPath = resolve(__dirname, '../BENCHMARK.md');
|
|
15
|
-
|
|
16
|
-
const report: BenchmarkReport = JSON.parse(readFileSync(resultsPath, 'utf-8'));
|
|
17
|
-
report.timestamp = new Date().toISOString();
|
|
18
|
-
|
|
19
|
-
const markdown = await generateReport(report);
|
|
20
|
-
writeFileSync(outputPath, markdown, 'utf-8');
|
|
21
|
-
|
|
22
|
-
console.log('✓ BENCHMARK.md regenerated');
|