mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
Fix typos in source, tests, and docs (#430)
* Fix typos in source, tests, and docs * Fix introduction guide typos
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
- Prefer functions declared using const, not using the function keyword
|
||||
- Code style is tab indent with semicolons
|
||||
- Mediabunny core code is contained in src/, extensions are in packages/*/, website is in docs/
|
||||
- Tests: Prefer fewer, longer test files over many small ones. Test files should be named after the general catergory of thing that is being tested, not after any individual single test.
|
||||
- Tests: Prefer fewer, longer test files over many small ones. Test files should be named after the general category of thing that is being tested, not after any individual single test.
|
||||
- Avoid ifs without a {} block. So no if (cond) return;, always do if (cond) { return; }
|
||||
- `type` instead of `interface` for object types
|
||||
- `type` instead of `interface` for object types
|
||||
|
||||
@@ -60,7 +60,7 @@ To get going with Mediabunny, here are some starting points:
|
||||
|
||||
## Server-side usage
|
||||
|
||||
Mediabunny's simple yet flexible API provides a modern alternative to traditional server-side media processing pipelines which may involve calling out to FFmpeg's CLI manually. Mediabunny was primary built for client-side environments, but when combined with the [`@mediabunny/server`](./extensions/server) extension, the full Mediabunny feature set is available in server-side environments such as Node, Bun, and Deno.
|
||||
Mediabunny's simple yet flexible API provides a modern alternative to traditional server-side media processing pipelines which may involve calling out to FFmpeg's CLI manually. Mediabunny was primarily built for client-side environments, but when combined with the [`@mediabunny/server`](./extensions/server) extension, the full Mediabunny feature set is available in server-side environments such as Node, Bun, and Deno.
|
||||
|
||||
The extension enables:
|
||||
- Video decoders and encoders for AVC (H.264), HEVC (H.265), VP8, VP9, and AV1. Supports both length-prefixed and Annex B AVC/HEVC as well as transparent video via VP9.
|
||||
@@ -74,7 +74,7 @@ For more, see [the corresponding guide](./extensions/server).
|
||||
|
||||
## Motivation
|
||||
|
||||
Mediabunny is the evolution of my previous libraries, [mp4-muxer](https://github.com/Vanilagy/mp4-muxer) and [webm-muxer](https://github.com/Vanilagy/webm-muxer), which were both created due to the advent of the WebCodecs API. While they fulfilled their job just fine, I saw a few painpoints:
|
||||
Mediabunny is the evolution of my previous libraries, [mp4-muxer](https://github.com/Vanilagy/mp4-muxer) and [webm-muxer](https://github.com/Vanilagy/webm-muxer), which were both created due to the advent of the WebCodecs API. While they fulfilled their job just fine, I saw a few pain points:
|
||||
- Lots of duplicated code between the two libraries, otherwise very similar API.
|
||||
- No help with the difficulties of navigating the WebCodecs API & related browser APIs.
|
||||
- "mp4-demuxer when??"
|
||||
@@ -99,4 +99,4 @@ At its core, Mediabunny is a collection of multiplexers and demultiplexers, one
|
||||
|
||||
Mediabunny then provides several wrappers around the WebCodecs API to simplify usage: for reading, it creates decoders with the correct codec configuration and efficiently decodes media data in a pipelined way. For writing, it figures out the necessary codec configuration and sets up encoders which are then used to encode raw media data, while respecting the backpressure applied by the encoder. Extracting the right decoder configuration from a media file can be tricky and sometimes involves diving into encoded media packet bitstreams.
|
||||
|
||||
The conversion abstraction is built on top of Mediabunny's reading and writing primitives and combines them both in a heavily-pipelined way, making sure reading and writing happen in lockstep. It also consists of a lot of conditional logic probing output track compatibility, decoding support, and finding encodable codec configurations. It makes use of the Canvas API for video processing operations, and uses a custom implementation for audio resampling and up/downmixing.
|
||||
The conversion abstraction is built on top of Mediabunny's reading and writing primitives and combines them both in a heavily-pipelined way, making sure reading and writing happen in lockstep. It also consists of a lot of conditional logic probing output track compatibility, decoding support, and finding encodable codec configurations. It makes use of the Canvas API for video processing operations, and uses a custom implementation for audio resampling and up/downmixing.
|
||||
|
||||
@@ -342,7 +342,7 @@ Each chunk written to the `WritableStream` represents a contiguous chunk of byte
|
||||
::: warning
|
||||
Note that some byte regions in the output file may be written to multiple times. It is therefore **incorrect** to construct the final file by simply concatenating all `Uint8Array`s together - you **must** write each chunk of data at the specified byte offset position _in the order_ in which the chunks arrived. If you don't do this, your output file will likely be invalid or corrupted.
|
||||
|
||||
Some [output formats](./output-formats) have *append-only* writing modes in which the byte offset of a written chunk will always be equal to the total number of bytes in all previously written chunks. In other words, when writing is append-only, simply concatening all `Uint8Array`s yields the correct result. Some APIs (like `appendBuffer` of Media Source Extensions) require this, so make sure to configure your output format accordingly for those cases.
|
||||
Some [output formats](./output-formats) have *append-only* writing modes in which the byte offset of a written chunk will always be equal to the total number of bytes in all previously written chunks. In other words, when writing is append-only, simply concatenating all `Uint8Array`s yields the correct result. Some APIs (like `appendBuffer` of Media Source Extensions) require this, so make sure to configure your output format accordingly for those cases.
|
||||
:::
|
||||
|
||||
#### Chunked mode
|
||||
@@ -545,4 +545,4 @@ The promise returned by `getMimeType` only resolves once the precise codec strin
|
||||
If you don't care about specific track codecs, you can instead use the simpler [`mimeType`](./output-formats#output-format-properties) property on the `Output`'s format:
|
||||
```ts
|
||||
output.format.mimeType; // => string
|
||||
```
|
||||
```
|
||||
|
||||
+5
-5
@@ -103,7 +103,7 @@ const mp3EncoderVariants = await createVariants(
|
||||
'packages/mp3-encoder/src/index.ts',
|
||||
'MediabunnyMp3Encoder',
|
||||
'packages/mp3-encoder/dist/bundles/mediabunny-mp3-encoder',
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependecy)
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependency)
|
||||
{
|
||||
plugins: [
|
||||
PluginExternalGlobal.externalGlobalPlugin({
|
||||
@@ -134,7 +134,7 @@ const ac3Variants = await createVariants(
|
||||
'packages/ac3/src/index.ts',
|
||||
'MediabunnyAc3',
|
||||
'packages/ac3/dist/bundles/mediabunny-ac3',
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependecy)
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependency)
|
||||
{
|
||||
plugins: [
|
||||
PluginExternalGlobal.externalGlobalPlugin({
|
||||
@@ -165,7 +165,7 @@ const aacEncoderVariants = await createVariants(
|
||||
'packages/aac-encoder/src/index.ts',
|
||||
'MediabunnyAacEncoder',
|
||||
'packages/aac-encoder/dist/bundles/mediabunny-aac-encoder',
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependecy)
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependency)
|
||||
{
|
||||
plugins: [
|
||||
PluginExternalGlobal.externalGlobalPlugin({
|
||||
@@ -196,7 +196,7 @@ const flacEncoderVariants = await createVariants(
|
||||
'packages/flac-encoder/src/index.ts',
|
||||
'MediabunnyFlacEncoder',
|
||||
'packages/flac-encoder/dist/bundles/mediabunny-flac-encoder',
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependecy)
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependency)
|
||||
{
|
||||
plugins: [
|
||||
PluginExternalGlobal.externalGlobalPlugin({
|
||||
@@ -227,7 +227,7 @@ const proresVariants = await createVariants(
|
||||
'packages/prores/src/index.ts',
|
||||
'MediabunnyProres',
|
||||
'packages/prores/dist/bundles/mediabunny-prores',
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependecy)
|
||||
'js', // The bundles are purely for the browser, not for Node (due to the peer dependency)
|
||||
{
|
||||
plugins: [
|
||||
PluginExternalGlobal.externalGlobalPlugin({
|
||||
|
||||
+1
-1
@@ -1878,7 +1878,7 @@ export type Av1CodecInfo = {
|
||||
chromaSamplePosition: number;
|
||||
};
|
||||
|
||||
/** Iterates over all OBUs in an AV1 packet bistream. */
|
||||
/** Iterates over all OBUs in an AV1 packet bitstream. */
|
||||
export const iterateAv1PacketObus = function* (packet: Uint8Array) {
|
||||
// https://aomediacodec.github.io/av1-spec/av1-spec.pdf
|
||||
|
||||
|
||||
+1
-1
@@ -838,7 +838,7 @@ export class Conversion {
|
||||
if (this._options.trim?.start !== undefined) {
|
||||
this._startTimestamp = this._options.trim.start;
|
||||
} else {
|
||||
// Compute the start timestamp from the set of filtered tracks. Techncially these can still be narrowed
|
||||
// Compute the start timestamp from the set of filtered tracks. Technically these can still be narrowed
|
||||
// down later due to discarded tracks, but we need to fix the start timestamp now due to track processing
|
||||
// depending on it.
|
||||
this._startTimestamp = Math.max(
|
||||
|
||||
@@ -186,7 +186,7 @@ export class FlacDemuxer extends Demuxer {
|
||||
// description is required, and has to be the following:
|
||||
// 1. The bytes 0x66 0x4C 0x61 0x43 ("fLaC" in ASCII)
|
||||
// 2. A metadata block (called the STREAMINFO block) as described in section 7 of [FLAC]
|
||||
// 3. Optionaly (sic) other metadata blocks, that are not used by the specification
|
||||
// 3. Optionally (sic) other metadata blocks, that are not used by the specification
|
||||
|
||||
bitstream.skipBits(16 * 8); // md5 hash
|
||||
|
||||
@@ -296,7 +296,7 @@ export class FlacDemuxer extends Demuxer {
|
||||
// we expect that there are at least `minimumFrameSize` bytes left in the file
|
||||
|
||||
// Ideally we also want to validate the next header is valid
|
||||
// to throw out an accidential sync word
|
||||
// to throw out an accidental sync word
|
||||
|
||||
// The shortest valid FLAC header I can think of, based off the code
|
||||
// of readFlacFrameHeader:
|
||||
|
||||
@@ -638,11 +638,11 @@ class OggAudioTrackBacking implements InputAudioTrackBacking {
|
||||
|
||||
const lowPages: Page[] = [lowPage];
|
||||
|
||||
// First, let's perform a binary serach (bisection search) on the file to find the approximate page where
|
||||
// First, let's perform a binary search (bisection search) on the file to find the approximate page where
|
||||
// we'll find the packet. We want to find a page whose end packet position is less than or equal to the
|
||||
// packet position we're searching for.
|
||||
|
||||
// Outer loop: Does the binary serach
|
||||
// Outer loop: Does the binary search
|
||||
outer:
|
||||
while (lowPage.headerStartPos + lowPage.totalSize < high) {
|
||||
const low = lowPage.headerStartPos;
|
||||
|
||||
+1
-1
@@ -172,7 +172,7 @@ export class AudioResampler {
|
||||
|
||||
async add(audioSample: AudioSample) {
|
||||
if (this.sourceSampleRate === null) {
|
||||
// This is the first sample, so let's init the missing data. Initting the sample rate from the decoded
|
||||
// This is the first sample, so let's init the missing data. Initing the sample rate from the decoded
|
||||
// sample is more reliable than using the file's metadata, because decoders are free to emit any sample rate
|
||||
// they see fit.
|
||||
this.sourceSampleRate = audioSample.sampleRate;
|
||||
|
||||
@@ -177,8 +177,8 @@ test('HLS track assignability is kept #1', async () => {
|
||||
|
||||
await output.finalize();
|
||||
|
||||
const masterPlayist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('master.m3u8')));
|
||||
expect(masterPlayist.match(/\.m3u8/g)?.length).toBe(1);
|
||||
const masterPlaylist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('master.m3u8')));
|
||||
expect(masterPlaylist.match(/\.m3u8/g)?.length).toBe(1);
|
||||
|
||||
using input = new Input({
|
||||
formats: ALL_FORMATS,
|
||||
@@ -208,8 +208,8 @@ test('HLS track assignability is kept #1', async () => {
|
||||
const conversion = await Conversion.init({ input, output: newOutput });
|
||||
await conversion.execute();
|
||||
|
||||
const newMasterPlayist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('new/master.m3u8')));
|
||||
expect(newMasterPlayist).toBe(masterPlayist);
|
||||
const newMasterPlaylist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('new/master.m3u8')));
|
||||
expect(newMasterPlaylist).toBe(masterPlaylist);
|
||||
});
|
||||
|
||||
test('HLS track assignability is kept #2', async () => {
|
||||
@@ -256,8 +256,8 @@ test('HLS track assignability is kept #2', async () => {
|
||||
|
||||
await output.finalize();
|
||||
|
||||
const masterPlayist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('master.m3u8')));
|
||||
expect(masterPlayist.match(/\.m3u8/g)?.length).toBe(2);
|
||||
const masterPlaylist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('master.m3u8')));
|
||||
expect(masterPlaylist.match(/\.m3u8/g)?.length).toBe(2);
|
||||
|
||||
using input = new Input({
|
||||
formats: ALL_FORMATS,
|
||||
@@ -287,8 +287,8 @@ test('HLS track assignability is kept #2', async () => {
|
||||
const conversion = await Conversion.init({ input, output: newOutput });
|
||||
await conversion.execute();
|
||||
|
||||
const newMasterPlayist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('new/master.m3u8')));
|
||||
expect(newMasterPlayist).toBe(masterPlayist);
|
||||
const newMasterPlaylist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('new/master.m3u8')));
|
||||
expect(newMasterPlaylist).toBe(masterPlaylist);
|
||||
});
|
||||
|
||||
test('HLS track assignability can be overridden', async () => {
|
||||
@@ -335,8 +335,8 @@ test('HLS track assignability can be overridden', async () => {
|
||||
|
||||
await output.finalize();
|
||||
|
||||
const masterPlayist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('master.m3u8')));
|
||||
expect(masterPlayist.match(/\.m3u8/g)?.length).toBe(2);
|
||||
const masterPlaylist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('master.m3u8')));
|
||||
expect(masterPlaylist.match(/\.m3u8/g)?.length).toBe(2);
|
||||
|
||||
using input = new Input({
|
||||
formats: ALL_FORMATS,
|
||||
@@ -371,9 +371,9 @@ test('HLS track assignability can be overridden', async () => {
|
||||
});
|
||||
await conversion.execute();
|
||||
|
||||
const newMasterPlayist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('new/master.m3u8')));
|
||||
expect(newMasterPlayist).not.toBe(masterPlayist);
|
||||
expect(newMasterPlayist.match(/\.m3u8/g)?.length).toBe(1);
|
||||
const newMasterPlaylist = sanitizeMasterPlaylist(new TextDecoder().decode(files.get('new/master.m3u8')));
|
||||
expect(newMasterPlaylist).not.toBe(masterPlaylist);
|
||||
expect(newMasterPlaylist.match(/\.m3u8/g)?.length).toBe(1);
|
||||
});
|
||||
|
||||
test('Fractional audio sample boundary', async () => {
|
||||
|
||||
Reference in New Issue
Block a user