Cancel stale playback probes and verify Linux QSV support
This commit is contained in:
54
test/qsv-detection.test.js
Normal file
54
test/qsv-detection.test.js
Normal file
@ -0,0 +1,54 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const vm = require('node:vm');
|
||||
const { createRequire } = require('node:module');
|
||||
function fixture({ nodes = [], vendors = {}, inaccessible = [], pci = '', fail = false, platform = 'linux' } = {}) {
|
||||
const calls = [], filename = path.join(__dirname, '../server/services/hwDetect.js'), module = { exports: {} };
|
||||
vm.runInNewContext(fs.readFileSync(filename, 'utf8'), { module, console: { log() {} }, require: name => ({
|
||||
os: { platform: () => platform }, fs: { constants: fs.constants, readdirSync: () => nodes,
|
||||
accessSync: device => { if (inaccessible.includes(device)) throw Error('EACCES'); },
|
||||
readFileSync: file => { const name = file.split('/')[4]; if (!vendors[name]) throw Error('ENOENT'); return vendors[name]; } },
|
||||
child_process: { execSync: command => { calls.push({ command }); return pci; },
|
||||
execFile: (binary, args, options, callback) => { calls.push({ binary, args, options }); callback(fail ? Error('Encode unavailable or timeout') : null); } }
|
||||
})[name] }, { filename });
|
||||
return { hw: module.exports, calls };
|
||||
}
|
||||
test('QSV verifies a mapped Intel device with the configured FFmpeg and bounded H.264 encode', async () => {
|
||||
const f = fixture({ nodes: ['card0', 'renderD129', 'renderD128'], vendors: { renderD129: '0x8086\n', renderD128: '0x1002' } });
|
||||
const qsv = await f.hw.detectQuickSync('/configured/ffmpeg');
|
||||
assert.equal(qsv.available, true); assert.equal(qsv.device, '/dev/dri/renderD129');
|
||||
assert.equal(f.calls.length, 1); const call = f.calls[0];
|
||||
assert.equal(call.binary, '/configured/ffmpeg'); assert.equal(call.options.timeout, 5000);
|
||||
assert.equal(call.options.windowsHide, true); assert.equal(call.options.maxBuffer, 262144);
|
||||
assert.ok(call.args.includes('qsv=probe:hw,child_device=/dev/dri/renderD129,child_device_type=vaapi'));
|
||||
assert.ok(call.args.includes('h264_qsv')); assert.ok(call.args.includes('format=nv12,hwupload=extra_hw_frames=16'));
|
||||
});
|
||||
test('QSV rejects unmapped, AMD, inaccessible and unusable Intel devices', async () => {
|
||||
for (const options of [{ pci: 'VGA Intel' }, { nodes: ['renderD128'], vendors: { renderD128: '0x1002' }, pci: 'VGA Intel' },
|
||||
{ nodes: ['renderD128'], vendors: { renderD128: '0x8086' }, inaccessible: ['/dev/dri/renderD128'] },
|
||||
{ nodes: ['renderD128'], vendors: { renderD128: '0x8086' }, fail: true },
|
||||
{ nodes: ['renderD128', 'renderD129'], pci: 'VGA Intel' }]) {
|
||||
const f = fixture(options); assert.equal((await f.hw.detectQuickSync()).available, false);
|
||||
if (!options.fail) assert.equal(f.calls.filter(call => call.binary).length, 0);
|
||||
}
|
||||
});
|
||||
test('QSV handles a hidden sysfs vendor with PCI fallback and preserves Windows detection', async () => {
|
||||
const f = fixture({ nodes: ['renderD128'], pci: '00:02.0 VGA compatible controller: Intel Corporation UHD Graphics' });
|
||||
assert.equal((await f.hw.detectQuickSync()).available, true); assert.equal(f.calls[0].command, 'lspci');
|
||||
const noIntel = fixture({ nodes: ['renderD128'], pci: 'VGA AMD Radeon' }); assert.equal((await noIntel.hw.detectQuickSync()).available, false);
|
||||
const windows = fixture({ platform: 'win32', pci: 'Name\nIntel UHD Graphics' });
|
||||
assert.equal((await windows.hw.detectQuickSync()).available, true); assert.equal(windows.calls.length, 1);
|
||||
});
|
||||
test('QSV sessions use the detected render node and keep Windows or forced defaults', () => {
|
||||
const filename = path.join(__dirname, '../server/services/transcodeSession.js'), realRequire = createRequire(filename), module = { exports: {} };
|
||||
let device = '/dev/dri/renderD129';
|
||||
vm.runInNewContext(fs.readFileSync(filename, 'utf8'), { module, process, console, setTimeout, clearTimeout, setInterval, clearInterval,
|
||||
require: name => name === './hwDetect' ? { getCapabilities: () => ({ qsv: { device } }) } : realRequire(name) }, { filename });
|
||||
const session = Object.create(module.exports.TranscodeSession.prototype), args = [];
|
||||
session.addHwAccelInputArgs(args, 'qsv');
|
||||
assert.ok(args.includes('qsv=nodecast:hw,child_device=/dev/dri/renderD129,child_device_type=vaapi'));
|
||||
assert.ok(args.includes('nodecast')); device = undefined;
|
||||
const defaults = []; session.addHwAccelInputArgs(defaults, 'qsv'); assert.deepEqual(defaults, ['-hwaccel', 'qsv', '-hwaccel_output_format', 'qsv']);
|
||||
});
|
||||
Reference in New Issue
Block a user