Files
mediabunny/test/browser/quality.test.ts
T

94 lines
3.4 KiB
TypeScript

import { expect, test } from 'vitest';
import { Input } from '../../src/input.js';
import { UrlSource } from '../../src/source.js';
import { ALL_FORMATS } from '../../src/input-format.js';
import { Output } from '../../src/output.js';
import { MkvOutputFormat, Mp4OutputFormat } from '../../src/output-format.js';
import { BufferTarget } from '../../src/target.js';
import { Conversion } from '../../src/conversion.js';
import { canEncodeVideo, Quality, QualityLevel } from '../../src/encode.js';
import { VideoCodec } from '../../src/codec.js';
const QUALITY_LEVELS: QualityLevel[] = ['very-low', 'low', 'medium', 'high', 'very-high'];
for (const level of QUALITY_LEVELS) {
test(`AVC, qualitative quality '${level}'`, { timeout: 10_000 }, async () => {
await convertVideo(new Quality(level), 'avc');
});
}
test('AVC, custom qualitative quality', { timeout: 10_000 }, async () => {
await convertVideo(new Quality(0.85), 'avc');
});
test('AVC, qualitative quality with preferBitrate', { timeout: 10_000 }, async () => {
await convertVideo(new Quality({ quality: 0.5, preferBitrate: true }), 'avc');
});
test('AVC, explicit bitrate', { timeout: 10_000 }, async () => {
await convertVideo(new Quality({ bitrate: 1_000_000 }), 'avc');
});
test('AVC, explicit bitrate with constant bitrate mode', { timeout: 10_000 }, async () => {
await convertVideo(new Quality({ bitrate: 1_000_000, bitrateMode: 'constant' }), 'avc');
});
test('AVC, explicit quantizer', { timeout: 10_000 }, async () => {
// No bitrate fallback here, so environments without quantizer support are expected to reject the track
await convertVideo(new Quality({ quantizer: 30 }), 'avc', true);
});
test('AVC, explicit quantizer with bitrate fallback', { timeout: 10_000 }, async () => {
await convertVideo(new Quality({ quantizer: 30, bitrate: 1_000_000 }), 'avc');
});
// Medium quality prefers quantizer-based encoding, so this hits the quantizer path for every codec that supports it
const TESTED_VIDEO_CODECS: VideoCodec[] = ['avc', 'hevc', 'vp9', 'av1', 'vp8'];
for (const codec of TESTED_VIDEO_CODECS) {
test(`Medium quality with codec '${codec}'`, { timeout: 10_000 }, async () => {
const quality = new Quality('medium');
if (!await canEncodeVideo(codec, { quality })) {
// The environment can't encode this codec at all; nothing to test
return;
}
await convertVideo(quality, codec);
});
}
/** Converts the first two seconds of the test video using the given quality and codec. */
const convertVideo = async (quality: Quality, codec: VideoCodec, allowMissingQuantizerSupport = false) => {
using input = new Input({
source: new UrlSource('/video.mp4'),
formats: ALL_FORMATS,
});
const output = new Output({
// Matroska supports all video codecs we test here
format: codec === 'avc' ? new Mp4OutputFormat() : new MkvOutputFormat(),
target: new BufferTarget(),
});
const conversion = await Conversion.init({
input,
output,
trim: { start: 0, end: 2 },
video: { codec, quality },
audio: { discard: true },
showWarnings: false,
});
if (allowMissingQuantizerSupport && !conversion.isValid) {
// The environment can't do quantizer-based encoding; a correctly-explained rejection also satisfies the test
await expect(conversion.execute()).rejects.toThrow(
`not able to encode '${codec}' with the provided parameters`,
);
return;
}
await conversion.execute();
expect(conversion.utilizedTracks.some(x => x.isVideoTrack())).toBe(true);
};