mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 05:43:50 +02:00
Make default keyFrameInterval 2 seconds to align with default HLS segment duration
This commit is contained in:
@@ -73,7 +73,7 @@ type VideoEncodingConfig = {
|
|||||||
- `'keep'`: The samples' alpha data is also encoded as side data. Make sure to pair this mode with a container format that supports transparency (such as WebM or Matroska).
|
- `'keep'`: The samples' alpha data is also encoded as side data. Make sure to pair this mode with a container format that supports transparency (such as WebM or Matroska).
|
||||||
- `bitrateMode`: Can be used to control constant vs. variable bitrate.
|
- `bitrateMode`: Can be used to control constant vs. variable bitrate.
|
||||||
- `latencyMode`: The latency mode as specified by the WebCodecs API. Browsers default to `quality`. Media stream-driven video sources will automatically use the `realtime` setting.
|
- `latencyMode`: The latency mode as specified by the WebCodecs API. Browsers default to `quality`. Media stream-driven video sources will automatically use the `realtime` setting.
|
||||||
- `keyFrameInterval`: The maximum interval in seconds between two adjacent key frames. Defaults to 5 seconds. More frequent key frames improve seeking behavior but increase file size. When using multiple video tracks, this value should be set to the same value for all tracks.
|
- `keyFrameInterval`: The maximum interval in seconds between two adjacent key frames. Defaults to 2 seconds. More frequent key frames improve seeking behavior but increase file size. When using multiple video tracks, this value should be set to the same value for all tracks.
|
||||||
- `fullCodecString`: Allows you to optionally specify the full codec string used by the video encoder, as specified in the [Mediabunny Codec Registry](/codec-registry/overview). For example, you may set it to `'avc1.42001f'` when using AVC. Keep in mind that the codec string must still match the codec specified in `codec`. If you don't set this field, a codec string will be generated automatically.
|
- `fullCodecString`: Allows you to optionally specify the full codec string used by the video encoder, as specified in the [Mediabunny Codec Registry](/codec-registry/overview). For example, you may set it to `'avc1.42001f'` when using AVC. Keep in mind that the codec string must still match the codec specified in `codec`. If you don't set this field, a codec string will be generated automatically.
|
||||||
- `hardwareAcceleration`: A hint that configures the hardware acceleration method of this codec. This is best left on `'no-preference'`.
|
- `hardwareAcceleration`: A hint that configures the hardware acceleration method of this codec. This is best left on `'no-preference'`.
|
||||||
- `scalabilityMode`: An encoding scalability mode identifier as defined by [WebRTC-SVC](https://w3c.github.io/webrtc-svc/#scalabilitymodes*).
|
- `scalabilityMode`: An encoding scalability mode identifier as defined by [WebRTC-SVC](https://w3c.github.io/webrtc-svc/#scalabilitymodes*).
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@ export type VideoEncodingConfig = {
|
|||||||
*/
|
*/
|
||||||
bitrate: number | Quality;
|
bitrate: number | Quality;
|
||||||
/**
|
/**
|
||||||
* The interval, in seconds, of how often frames are encoded as a key frame. The default is 5 seconds. Frequent key
|
* The interval, in seconds, of how often frames are encoded as a key frame. The default is 2 seconds. Frequent key
|
||||||
* frames improve seeking behavior but increase file size. When using multiple video tracks, you should give them
|
* frames improve seeking behavior but increase file size. When using multiple video tracks, you should give them
|
||||||
* all the same key frame interval.
|
* all the same key frame interval.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+1
-1
@@ -531,7 +531,7 @@ class VideoEncoderWrapper {
|
|||||||
}
|
}
|
||||||
assert(this.encoderInitialized);
|
assert(this.encoderInitialized);
|
||||||
|
|
||||||
const keyFrameInterval = this.encodingConfig.keyFrameInterval ?? 5;
|
const keyFrameInterval = this.encodingConfig.keyFrameInterval ?? 2;
|
||||||
const multipleOfKeyFrameInterval = Math.floor(sampleToEncode.timestamp / keyFrameInterval);
|
const multipleOfKeyFrameInterval = Math.floor(sampleToEncode.timestamp / keyFrameInterval);
|
||||||
|
|
||||||
// Ensure a key frame every keyFrameInterval seconds. It is important that all video tracks
|
// Ensure a key frame every keyFrameInterval seconds. It is important that all video tracks
|
||||||
|
|||||||
@@ -1205,7 +1205,8 @@ export type HlsOutputFormatOptions = {
|
|||||||
*
|
*
|
||||||
* Mediabunny will try not to emit media segments longer than the target duration, but it is forced to if key frames
|
* Mediabunny will try not to emit media segments longer than the target duration, but it is forced to if key frames
|
||||||
* are provided with a longer period than the target duration. Therefore, make sure to encode a key frame at least
|
* are provided with a longer period than the target duration. Therefore, make sure to encode a key frame at least
|
||||||
* every `targetDuration` seconds to guarantee segment length.
|
* every `targetDuration` seconds to guarantee segment length, controllable via
|
||||||
|
* {@link VideoEncodingConfig.keyFrameInterval}.
|
||||||
*/
|
*/
|
||||||
targetDuration?: number;
|
targetDuration?: number;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { expect, test } from 'vitest';
|
||||||
|
import { Output } from '../../src/output.js';
|
||||||
|
import { HlsOutputFormat, MpegTsOutputFormat } from '../../src/output-format.js';
|
||||||
|
import { BufferTarget, PathedTarget } from '../../src/target.js';
|
||||||
|
import { CanvasSource } from '../../src/media-source.js';
|
||||||
|
import { QUALITY_HIGH } from '../../src/encode.js';
|
||||||
|
|
||||||
|
test('HLS output, key frames aligning with segment boundaries by default', async () => {
|
||||||
|
let playlistText: string | null = null;
|
||||||
|
|
||||||
|
const output = new Output({
|
||||||
|
format: new HlsOutputFormat({
|
||||||
|
segmentFormat: new MpegTsOutputFormat(),
|
||||||
|
onPlaylist: (text) => { playlistText = text; },
|
||||||
|
}),
|
||||||
|
target: new PathedTarget('', () => new BufferTarget()),
|
||||||
|
});
|
||||||
|
|
||||||
|
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 = 2;
|
||||||
|
const frameDuration = 1 / fps;
|
||||||
|
const totalFrames = 10 * fps;
|
||||||
|
for (let i = 0; i < totalFrames; i++) {
|
||||||
|
await videoSource.add(i * frameDuration, frameDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
await output.finalize();
|
||||||
|
|
||||||
|
expect(playlistText).toBe(`#EXTM3U
|
||||||
|
#EXT-X-VERSION:3
|
||||||
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
#EXT-X-TARGETDURATION:2
|
||||||
|
#EXT-X-INDEPENDENT-SEGMENTS
|
||||||
|
|
||||||
|
#EXTINF:2,
|
||||||
|
segment-1-1.ts
|
||||||
|
#EXTINF:2,
|
||||||
|
segment-1-2.ts
|
||||||
|
#EXTINF:2,
|
||||||
|
segment-1-3.ts
|
||||||
|
#EXTINF:2,
|
||||||
|
segment-1-4.ts
|
||||||
|
#EXTINF:2,
|
||||||
|
segment-1-5.ts
|
||||||
|
|
||||||
|
#EXT-X-ENDLIST
|
||||||
|
`);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user