mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-28 11:23:45 +02:00
Add CMAF format and CMAF/init segment support to HLS muxer
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { Output } from '../../src/output.js';
|
||||
import { CmafOutputFormat } from '../../src/output-format.js';
|
||||
import { BufferTarget } from '../../src/target.js';
|
||||
import { CanvasSource } from '../../src/media-source.js';
|
||||
import { QUALITY_HIGH } from '../../src/encode.js';
|
||||
import { Input } from '../../src/input.js';
|
||||
import { BufferSource } from '../../src/source.js';
|
||||
import { ALL_FORMATS } from '../../src/input-format.js';
|
||||
|
||||
test('CMAF throws without initTarget', async () => {
|
||||
const output = new Output({
|
||||
format: new CmafOutputFormat(),
|
||||
target: new BufferTarget(),
|
||||
});
|
||||
|
||||
const canvas = new OffscreenCanvas(640, 480);
|
||||
const videoSource = new CanvasSource(canvas, {
|
||||
codec: 'avc',
|
||||
bitrate: QUALITY_HIGH,
|
||||
});
|
||||
output.addVideoTrack(videoSource);
|
||||
|
||||
await expect(output.start()).rejects.toThrow('initTarget');
|
||||
});
|
||||
|
||||
test('CMAF with video track', async () => {
|
||||
const initTarget = new BufferTarget();
|
||||
let initTargetCalled = false;
|
||||
|
||||
const output = new Output({
|
||||
format: new CmafOutputFormat(),
|
||||
target: new BufferTarget(),
|
||||
initTarget: () => {
|
||||
initTargetCalled = true;
|
||||
return initTarget;
|
||||
},
|
||||
});
|
||||
|
||||
const canvas = new OffscreenCanvas(640, 480);
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
ctx.fillStyle = '#ff0000';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const videoSource = new CanvasSource(canvas, {
|
||||
codec: 'avc',
|
||||
bitrate: QUALITY_HIGH,
|
||||
});
|
||||
output.addVideoTrack(videoSource);
|
||||
|
||||
await output.start();
|
||||
|
||||
const fps = 30;
|
||||
const frameDuration = 1 / fps;
|
||||
for (let i = 0; i < fps; i++) {
|
||||
await videoSource.add(i * frameDuration, frameDuration);
|
||||
}
|
||||
|
||||
await output.finalize();
|
||||
|
||||
expect(initTargetCalled).toBe(true);
|
||||
|
||||
// Reading the segment without initInput should throw because the moov box is in the init segment
|
||||
using segmentInput = new Input({
|
||||
source: new BufferSource(output.target.buffer!),
|
||||
formats: ALL_FORMATS,
|
||||
});
|
||||
|
||||
await expect(segmentInput.getTracks()).rejects.toThrow('initInput');
|
||||
|
||||
// Reading with initInput should work
|
||||
using initInput = new Input({
|
||||
source: new BufferSource(initTarget.buffer!),
|
||||
formats: ALL_FORMATS,
|
||||
});
|
||||
|
||||
using segmentInputWithInit = new Input({
|
||||
source: new BufferSource(output.target.buffer!),
|
||||
formats: ALL_FORMATS,
|
||||
initInput,
|
||||
});
|
||||
|
||||
const tracks = await segmentInputWithInit.getTracks();
|
||||
expect(tracks).toHaveLength(1);
|
||||
expect(tracks[0]!.isVideoTrack()).toBe(true);
|
||||
});
|
||||
|
||||
test('CMAF with empty video track', async () => {
|
||||
const initTarget = new BufferTarget();
|
||||
|
||||
const output = new Output({
|
||||
format: new CmafOutputFormat(),
|
||||
target: new BufferTarget(),
|
||||
initTarget,
|
||||
});
|
||||
|
||||
const canvas = new OffscreenCanvas(640, 480);
|
||||
const videoSource = new CanvasSource(canvas, {
|
||||
codec: 'avc',
|
||||
bitrate: QUALITY_HIGH,
|
||||
});
|
||||
output.addVideoTrack(videoSource);
|
||||
|
||||
await output.start();
|
||||
await output.finalize();
|
||||
|
||||
expect(initTarget.buffer).toBeDefined();
|
||||
expect(output.target.buffer).toBeDefined();
|
||||
});
|
||||
Reference in New Issue
Block a user