More doc adjustments, some type adjustments

This commit is contained in:
Vanilagy
2026-04-16 16:19:08 +02:00
parent 5465602344
commit 6dc4c2d499
6 changed files with 238 additions and 81 deletions
+48 -1
View File
@@ -625,4 +625,51 @@ const conversion = await Conversion.init({
await conversion.execute();
// Conversion is complete
```
```
## Reading HLS playlists
```ts
import { createInputFrom, HLS_FORMATS, desc } from 'mediabunny';
const input = createInputFrom('https://example.com/master.m3u8', HLS_FORMATS);
// Get all tracks
const tracks = await input.getTracks();
// Get video tracks by quality
const sortedVideoTracks = await input.getVideoTracks({
sortBy: async track => desc(await track.getDisplayHeight()),
});
// Select a quality
const bestVideoTrack = sortedVideoTracks[0]!;
// Get a matching audio track
const matchingAudioTrack = await bestVideoTrack.getPrimaryPairableAudioTrack();
// HLS tracks can be read like any other Mediabunny InputTrack
// ...
const isLive = await bestVideoTrack.isLive();
if (isLive) {
// Poll some data using the refresh interval, for example duration
let currentDuration: number | null = null;
const poll = async () => {
currentDuration = await bestVideoTrack.getDurationFromMetadata({
skipLiveWait: true,
});
const refreshInterval = await bestVideoTrack.getLiveRefreshInterval();
if (refreshInterval === null) {
return; // No longer live
}
setTimeout(poll, 1000 * refreshInterval);
};
await poll();
}
```
::: info
See [Reading HLS](./reading-hls) for an in-depth guide.
:::
+48
View File
@@ -46,6 +46,50 @@ Since Mediabunny lazy-loads all information, retrieving the list of all tracks i
If you point Mediabunny directly at a media playlist, then the list of tracks is deduced by the tracks present in the first segment of the playlist.
### Track queries
Mediabunny offers an [`InputTrackQuery`](../api/InputTrackQuery) system to aid with finding tracks in complex many-track inputs such as the ones common with HLS.
Here's a holistic example that constructs an HLS quality ladder and then selects audio tracks based on language:
```ts
import { desc, prefer } from 'mediabunny';
// Get video tracks sorted by their resolution (highest first)
const videoTracks = await input.getVideoTracks({
sortBy: async track => [
desc(await track.getDisplayHeight()),
// Tracks with matching resolution are sorted by bitrate
desc(await track.getBitrate()),
],
// Filter out #EXT-X-I-FRAME-STREAM-INF tracks
filter: async track => !(await track.hasOnlyKeyPackets()),
});
const availableQualities = videoTracks.length;
// Get the best quality video track
const video = videoTracks[0];
// Get the audio track that accompanies this video track
const matchingAudioTrack = await video.getPrimaryPairableAudioTrack();
// Get all audio tracks
const availableAudioTracks = await video.getPairableAudioTracks();
const availableLanguages = await Promise.all(
availableAudioTracks.map(track => track.getLanguageCode()),
);
// Get the Spanish audio track
const matchingSpanishAudio = await video.getPrimaryPairableAudioTrack({
filter: async track => await track.getLanguageCode() === 'es',
});
// Get the Spanish audio track if one exists, otherwise get
// the next best thing
const matchingAudioPreferSpanish = await video.getPrimaryPairableAudioTrack({
sortBy: async track => prefer(await track.getLanguageCode() === 'es'),
});
```
### Reading track metadata
For general reading of track metadata, see [Reading media files](./reading-media-files). Some notable metadata mappings for HLS are:
@@ -291,3 +335,7 @@ const playbackStartTime = currentDuration! - fac * refreshInterval!;
You can lower `fac` to move playback closer to the live edge (1.5 works fine too), although you should not lower it below 1.
You can make `fac` larger to increase resilience against flaky internet or an unreliable media producer.
## Subtitles
Reading subtitles from HLS playlists is not currently supported. Sorry!
+56 -1
View File
@@ -173,6 +173,57 @@ await output.start();
Then, add media data like normal. Since Mediabunny takes care of segmentation automatically, it is required to perform [Packet buffering](./writing-media-files#packet-buffering) internally. Therefore, try writing media data in a quasi-interleaved fashion to keep memory usage bounded.
### Multiple resolutions
A common pattern is to offer the same content in multiple resolutions and bitrates. This requires encoding the content multiple times, sometimes with additional downscaling. Mediabunny's [media sources](./media-sources) make this pattern a breeze.
Let's suppose we have a 1080p main video stream. We want to provide a 1080p, 720p, 480p, and 360p variant in the HLS playlist. For that, use this pattern:
```ts
const source1080p = new VideoSampleSource({
codec: 'avc',
bitrate: QUALITY_VERY_HIGH,
});
const source720p = new VideoSampleSource({
codec: 'avc',
bitrate: QUALITY_HIGH,
transform: {
// Frames will be automatically resized to 720p before being encoded
height: 720,
},
});
const source480p = new VideoSampleSource({
codec: 'avc',
bitrate: QUALITY_MEDIUM,
transform: {
height: 480,
},
});
const source360p = new VideoSampleSource({
codec: 'avc',
bitrate: QUALITY_LOW,
transform: {
height: 360,
},
});
const sources = [source1080p, source720p, source480p, source360p];
for (const source of sources) {
output.addVideoTrack(source);
}
await output.start();
// Then, when adding a new frame:
const sample = // ...
for (const source of sources) {
await source.add(sample);
}
```
You can extend this pattern to offer content in multiple codecs as well.
For the full list of transformation options, see [`VideoTransformOptions`](../api/VideoTransformOptions) and [`AudioTransformOptions`](../api/AudioTransformOptions).
### Track metadata
Often you'll want to provide additional [track metadata](../api/BaseTrackMetadata) when dealing with multiple tracks. For example:
@@ -577,4 +628,8 @@ Whenever a segment is popped off the playlist in this fashion, the `onSegmentPop
::: info
`onSegmentPopped` is not called when `singleFilePerPlaylist` is enabled.
:::
:::
## Subtitles
Writing subtitles to HLS playlists is not currently supported. Sorry!