feat: add quality/transcoding options to live player (#6)
Manual quality profiles (source/1080p/720p/480p) in the player overflow menu plus an honest/preparatory Auto contract: adaptive when the HLS manifest exposes multiple levels, single-rendition automatic selection otherwise. - server: transcodeQualityProfiles service and qualityMode session option - player: quality menu, persisted preference, live switch with rollback - tests: npm test script and unit tests for quality profiles
This commit is contained in:
82
test/transcodeQualityProfiles.test.js
Normal file
82
test/transcodeQualityProfiles.test.js
Normal file
@ -0,0 +1,82 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const {
|
||||
QUALITY_MODES,
|
||||
resolveQualityMode
|
||||
} = require('../server/services/transcodeQualityProfiles');
|
||||
const { TranscodeSession } = require('../server/services/transcodeSession');
|
||||
|
||||
test('legacy payloads do not receive profile overrides', () => {
|
||||
assert.equal(resolveQualityMode(undefined, { maxResolution: '720p' }), null);
|
||||
});
|
||||
|
||||
test('manual quality profiles map to encoding height and bitrate', () => {
|
||||
const expected = {
|
||||
'1080p': { maxResolution: '1080p', targetVideoBitrateKbps: 6000 },
|
||||
'720p': { maxResolution: '720p', targetVideoBitrateKbps: 3500 },
|
||||
'480p': { maxResolution: '480p', targetVideoBitrateKbps: 1500 }
|
||||
};
|
||||
|
||||
for (const [qualityMode, profile] of Object.entries(expected)) {
|
||||
const selection = resolveQualityMode(qualityMode);
|
||||
assert.equal(selection.mode, 'single');
|
||||
assert.equal(selection.selectedProfile, qualityMode);
|
||||
assert.deepEqual(selection.availableProfiles, QUALITY_MODES);
|
||||
assert.deepEqual(selection.sessionOptions, {
|
||||
videoMode: 'encode',
|
||||
...profile,
|
||||
upscaleEnabled: false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('profile options produce the expected FFmpeg scale and bitrate arguments', () => {
|
||||
for (const qualityMode of ['1080p', '720p', '480p']) {
|
||||
const selection = resolveQualityMode(qualityMode);
|
||||
const session = new TranscodeSession('https://example.test/live.ts', {
|
||||
hwEncoder: 'software',
|
||||
audioMixPreset: 'passthrough',
|
||||
...selection.sessionOptions
|
||||
});
|
||||
const args = session.buildFFmpegArgs('software');
|
||||
const bitrate = selection.sessionOptions.targetVideoBitrateKbps;
|
||||
|
||||
assert.equal(args[args.indexOf('-vf') + 1], `scale=-2:${qualityMode.replace('p', '')}`);
|
||||
assert.equal(args[args.indexOf('-b:v') + 1], `${bitrate}k`);
|
||||
assert.equal(args[args.indexOf('-maxrate') + 1], `${bitrate}k`);
|
||||
assert.equal(args[args.indexOf('-bufsize') + 1], `${bitrate * 2}k`);
|
||||
}
|
||||
});
|
||||
|
||||
test('source profile preserves the original video stream', () => {
|
||||
const selection = resolveQualityMode('source');
|
||||
|
||||
assert.equal(selection.selectedProfile, 'source');
|
||||
assert.deepEqual(selection.sessionOptions, { videoMode: 'copy' });
|
||||
});
|
||||
|
||||
test('auto selects one configured rendition and reports single-rendition mode', () => {
|
||||
const selection = resolveQualityMode('auto', { maxResolution: '720p' });
|
||||
|
||||
assert.equal(selection.qualityMode, 'auto');
|
||||
assert.equal(selection.mode, 'single');
|
||||
assert.equal(selection.selectedProfile, '720p');
|
||||
assert.deepEqual(selection.sessionOptions, {
|
||||
videoMode: 'encode',
|
||||
maxResolution: '720p',
|
||||
targetVideoBitrateKbps: 3500,
|
||||
upscaleEnabled: false
|
||||
});
|
||||
});
|
||||
|
||||
test('auto falls back to 1080p for an unsupported global resolution', () => {
|
||||
assert.equal(resolveQualityMode('auto', { maxResolution: '4k' }).selectedProfile, '1080p');
|
||||
});
|
||||
|
||||
test('unsupported quality modes are rejected', () => {
|
||||
assert.throws(
|
||||
() => resolveQualityMode('adaptive'),
|
||||
error => error.code === 'INVALID_QUALITY_MODE'
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user