mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 05:43:50 +02:00
Merge main into release for tag v1.23.0
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
> [!NOTE]
|
||||||
|
> I'm on vacation until 18 October, so expect slow or no replies to issues during that time. 🏖️
|
||||||
|
|
||||||
# Mediabunny - JavaScript media toolkit
|
# Mediabunny - JavaScript media toolkit
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/mediabunny)
|
[](https://www.npmjs.com/package/mediabunny)
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ By default, data will be emitted by the `StreamTarget` as soon as it is availabl
|
|||||||
new StreamTarget(writable, {
|
new StreamTarget(writable, {
|
||||||
chunked: true,
|
chunked: true,
|
||||||
chunkSize: 2 ** 20, // Optional; defaults to 16 MiB
|
chunkSize: 2 ** 20, // Optional; defaults to 16 MiB
|
||||||
}),
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Applying backpressure
|
#### Applying backpressure
|
||||||
@@ -329,6 +329,33 @@ const output = new Output({
|
|||||||
await output.finalize(); // Will automatically close the writable stream
|
await output.finalize(); // Will automatically close the writable stream
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `FilePathTarget`
|
||||||
|
|
||||||
|
This target writes to a file at the specified path. It is intended for server-side usage in Node, Bun, or Deno, and offers a simpler API than `StreamTarget` when you just want to write directly to a file path.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Output, FilePathTarget } from 'mediabunny';
|
||||||
|
|
||||||
|
const output = new Output({
|
||||||
|
target: new FilePathTarget('/path/to/output.mp4'),
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
await output.finalize(); // Will automatically close the file handle
|
||||||
|
```
|
||||||
|
|
||||||
|
The internally held file handle will be closed when `finalize` or `cancel` are called on the `Output`.
|
||||||
|
|
||||||
|
Writing is chunked by default, for performance. Like `StreamTarget`, you can configure chunked mode options:
|
||||||
|
```ts
|
||||||
|
new FilePathTarget('/path/to/output.mp4', {
|
||||||
|
chunked: false, // Disable chunking (slower)
|
||||||
|
chunkSize: 2 ** 20, // Optional; defaults to 16 MiB
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### `NullTarget`
|
### `NullTarget`
|
||||||
|
|
||||||
This target simply discards all data that is passed into it. It is useful for when you need an `Output` but extract data from it differently, for example through output format-specific callbacks or encoder events.
|
This target simply discards all data that is passed into it. It is useful for when you need an `Output` but extract data from it differently, for example through output format-specific callbacks or encoder events.
|
||||||
|
|||||||
Generated
+6
-6
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@@ -7749,9 +7749,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mediabunny": {
|
"node_modules/mediabunny": {
|
||||||
"version": "1.21.1",
|
"version": "1.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.21.1.tgz",
|
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.22.0.tgz",
|
||||||
"integrity": "sha512-heBCNei4nBRJ2jkA08LL2zDZVyV9ADsSwFWOaRn37PEjUr6A46vlD+qlUYVTSSv5iIjIt1YTqTP7Nqo+q1hEvw==",
|
"integrity": "sha512-T8zsXwrRtKEAlITRizn0RiJc1GllVMw3Zcze5ACyluTy3jndUPhAM4SrwjR2SWgqqUa+4nlJ3MmyAi2XuRxwFg==",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
@@ -12242,7 +12242,7 @@
|
|||||||
},
|
},
|
||||||
"packages/mp3-encoder": {
|
"packages/mp3-encoder": {
|
||||||
"name": "@mediabunny/mp3-encoder",
|
"name": "@mediabunny/mp3-encoder",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/emscripten": "^1.40.1"
|
"@types/emscripten": "^1.40.1"
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"author": "Vanilagy",
|
"author": "Vanilagy",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@mediabunny/mp3-encoder",
|
"name": "@mediabunny/mp3-encoder",
|
||||||
"author": "Vanilagy",
|
"author": "Vanilagy",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"description": "MP3 encoder extension for Mediabunny, based on LAME.",
|
"description": "MP3 encoder extension for Mediabunny, based on LAME.",
|
||||||
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||||
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ export {
|
|||||||
export {
|
export {
|
||||||
Target,
|
Target,
|
||||||
BufferTarget,
|
BufferTarget,
|
||||||
|
FilePathTarget,
|
||||||
|
FilePathTargetOptions,
|
||||||
NullTarget,
|
NullTarget,
|
||||||
StreamTarget,
|
StreamTarget,
|
||||||
StreamTargetOptions,
|
StreamTargetOptions,
|
||||||
|
|||||||
@@ -1224,6 +1224,7 @@ class ReadOrchestrator {
|
|||||||
workers: ReadWorker[] = [];
|
workers: ReadWorker[] = [];
|
||||||
cache: CacheEntry[] = [];
|
cache: CacheEntry[] = [];
|
||||||
currentCacheSize = 0;
|
currentCacheSize = 0;
|
||||||
|
disposed = false;
|
||||||
|
|
||||||
constructor(public options: {
|
constructor(public options: {
|
||||||
maxCacheSize: number;
|
maxCacheSize: number;
|
||||||
@@ -1472,6 +1473,11 @@ class ReadOrchestrator {
|
|||||||
|
|
||||||
/** Called by a worker when it has read some data. */
|
/** Called by a worker when it has read some data. */
|
||||||
supplyWorkerData(worker: ReadWorker, bytes: Uint8Array) {
|
supplyWorkerData(worker: ReadWorker, bytes: Uint8Array) {
|
||||||
|
if (this.disposed) {
|
||||||
|
// Writes may still come in after disposal, but we just ignore those
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const start = worker.currentPos;
|
const start = worker.currentPos;
|
||||||
const end = start + bytes.length;
|
const end = start + bytes.length;
|
||||||
|
|
||||||
@@ -1645,5 +1651,6 @@ class ReadOrchestrator {
|
|||||||
|
|
||||||
this.workers.length = 0;
|
this.workers.length = 0;
|
||||||
this.cache.length = 0;
|
this.cache.length = 0;
|
||||||
|
this.disposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,15 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { FileHandle } from 'node:fs/promises';
|
||||||
import { BufferTargetWriter, NullTargetWriter, StreamTargetWriter, Writer } from './writer';
|
import { BufferTargetWriter, NullTargetWriter, StreamTargetWriter, Writer } from './writer';
|
||||||
import { Output } from './output';
|
import { Output } from './output';
|
||||||
|
import * as nodeAlias from './node';
|
||||||
|
import { assert } from './misc';
|
||||||
|
|
||||||
|
const node = typeof nodeAlias !== 'undefined'
|
||||||
|
? nodeAlias // Aliasing it prevents some bundler warnings
|
||||||
|
: undefined!;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for targets, specifying where output files are written.
|
* Base class for targets, specifying where output files are written.
|
||||||
@@ -121,6 +128,68 @@ export class StreamTarget extends Target {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for {@link FilePathTarget}.
|
||||||
|
* @group Output targets
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export type FilePathTargetOptions = StreamTargetOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A target that writes to a file at the specified path. Intended for server-side usage in Node, Bun, or Deno.
|
||||||
|
*
|
||||||
|
* Writing is chunked by default. The internally held file handle will be closed when `.finalize()` or `.cancel()` are
|
||||||
|
* called on the corresponding {@link Output}.
|
||||||
|
* @group Output targets
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export class FilePathTarget extends Target {
|
||||||
|
/** @internal */
|
||||||
|
_streamTarget: StreamTarget;
|
||||||
|
/** @internal */
|
||||||
|
_fileHandle: FileHandle | null = null;
|
||||||
|
|
||||||
|
/** Creates a new {@link FilePathTarget} that writes to the file at the specified file path. */
|
||||||
|
constructor(filePath: string, options: FilePathTargetOptions = {}) {
|
||||||
|
if (typeof filePath !== 'string') {
|
||||||
|
throw new TypeError('filePath must be a string.');
|
||||||
|
}
|
||||||
|
if (!options || typeof options !== 'object') {
|
||||||
|
throw new TypeError('options must be an object.');
|
||||||
|
}
|
||||||
|
|
||||||
|
super();
|
||||||
|
|
||||||
|
// Let's back this target with a StreamTarget, makes the implementation very simple
|
||||||
|
const writable = new WritableStream<StreamTargetChunk>({
|
||||||
|
start: async () => {
|
||||||
|
this._fileHandle = await node.fs.open(filePath, 'w');
|
||||||
|
},
|
||||||
|
write: async (chunk) => {
|
||||||
|
assert(this._fileHandle);
|
||||||
|
await this._fileHandle.write(chunk.data, 0, chunk.data.byteLength, chunk.position);
|
||||||
|
},
|
||||||
|
close: async () => {
|
||||||
|
if (this._fileHandle) {
|
||||||
|
await this._fileHandle.close();
|
||||||
|
this._fileHandle = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this._streamTarget = new StreamTarget(writable, {
|
||||||
|
chunked: true,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
this._streamTarget._output = this._output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_createWriter(): Writer {
|
||||||
|
return this._streamTarget._createWriter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This target just discards all incoming data. It is useful for when you need an {@link Output} but extract data from
|
* This target just discards all incoming data. It is useful for when you need an {@link Output} but extract data from
|
||||||
* it differently, for example through format-specific callbacks (`onMoof`, `onMdat`, ...) or encoder events.
|
* it differently, for example through format-specific callbacks (`onMoof`, `onMdat`, ...) or encoder events.
|
||||||
|
|||||||
Reference in New Issue
Block a user