mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-04 14:23:47 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bfa855f25 | ||
|
|
d768f3c63b | ||
|
|
c4d13ed698 |
@@ -49,6 +49,8 @@ Core features include:
|
||||
npm install mediabunny
|
||||
```
|
||||
|
||||
Requires any JavaScript environment that can run ECMAScript 2021 or later. Mediabunny is expected to be run in modern browsers. For types, TypeScript 5.7 or later is required.
|
||||
|
||||
### Read file metadata
|
||||
|
||||
```js
|
||||
|
||||
@@ -17,6 +17,10 @@ bun add mediabunny
|
||||
```
|
||||
:::
|
||||
|
||||
::: info
|
||||
Requires any JavaScript environment that can run ECMAScript 2021 or later. Mediabunny is expected to be run in modern browsers. For types, TypeScript 5.7 or later is required.
|
||||
:::
|
||||
|
||||
Then, simply import it like this:
|
||||
```ts
|
||||
import { ... } from 'mediabunny'; // ESM
|
||||
|
||||
@@ -286,6 +286,18 @@ See [Media sinks](./media-sinks) for a full list of sinks.
|
||||
|
||||
### Examples
|
||||
|
||||
Loop over all raw encoded packets of a track:
|
||||
```ts
|
||||
import { EncodedPacketSink } from 'mediabunny';
|
||||
|
||||
const videoTrack = await input.getPrimaryVideoTrack();
|
||||
const sink = new EncodedPacketSink(videoTrack);
|
||||
|
||||
for await (const packet of sink.packets()) {
|
||||
console.log(packet.timestamp);
|
||||
}
|
||||
```
|
||||
|
||||
Here we iterate over all samples (frames) of a video track:
|
||||
```ts
|
||||
import { VideoSampleSink } from 'mediabunny';
|
||||
|
||||
Generated
+6
-6
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "mediabunny",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mediabunny",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.2",
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"@types/dom-mediacapture-transform": "^0.1.11",
|
||||
"@types/dom-webcodecs": "^0.1.15"
|
||||
"@types/dom-webcodecs": "0.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.22.0",
|
||||
@@ -2443,9 +2443,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/dom-webcodecs": {
|
||||
"version": "0.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.15.tgz",
|
||||
"integrity": "sha512-omOlCPvTWyPm4ZE5bZUhlSvnHM2ZWM2U+1cPiYFL/e8aV5O9MouELp+L4dMKNTON0nTeHqEg+KWDfFQMY5Wkaw==",
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.13.tgz",
|
||||
"integrity": "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "mediabunny",
|
||||
"author": "Vanilagy",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.2",
|
||||
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
||||
"type": "module",
|
||||
"main": "./dist/bundles/mediabunny.cjs",
|
||||
@@ -49,7 +49,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/dom-mediacapture-transform": "^0.1.11",
|
||||
"@types/dom-webcodecs": "^0.1.15"
|
||||
"@types/dom-webcodecs": "0.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.22.0",
|
||||
|
||||
+3
-3
@@ -515,15 +515,15 @@ export const retriedFetch = async (
|
||||
try {
|
||||
return await fetch(url, requestInit);
|
||||
} catch (error) {
|
||||
console.error('Retrying failed fetch. Error:', error);
|
||||
|
||||
attempts++;
|
||||
|
||||
const retryDelayInSeconds = getRetryDelay(attempts);
|
||||
|
||||
if (retryDelayInSeconds === null) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.error('Retrying failed fetch. Error:', error);
|
||||
|
||||
if (!Number.isFinite(retryDelayInSeconds) || retryDelayInSeconds < 0) {
|
||||
throw new TypeError('Retry delay must be a non-negative finite number.');
|
||||
}
|
||||
|
||||
+27
-2
@@ -218,7 +218,8 @@ export class UrlSource extends Source {
|
||||
|
||||
const buffer = await response.arrayBuffer();
|
||||
|
||||
if (!range) {
|
||||
if (response.status === 200) {
|
||||
// The server didn't return 206 Partial Content, so it's not a range response
|
||||
this._fullData = buffer;
|
||||
}
|
||||
|
||||
@@ -252,6 +253,26 @@ export class UrlSource extends Source {
|
||||
return this._fullData.byteLength;
|
||||
}
|
||||
|
||||
// First, try a HEAD request to get the size
|
||||
try {
|
||||
const headResponse = await retriedFetch(
|
||||
this._url,
|
||||
mergeObjectsDeeply(this._options.requestInit ?? {}, {
|
||||
method: 'HEAD',
|
||||
}),
|
||||
this._options.getRetryDelay ?? (() => null),
|
||||
);
|
||||
|
||||
if (headResponse.ok) {
|
||||
const contentLength = headResponse.headers.get('Content-Length');
|
||||
if (contentLength) {
|
||||
return parseInt(contentLength);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// We tried
|
||||
}
|
||||
|
||||
// Try a range request to get the Content-Range header
|
||||
const rangeResponse = await retriedFetch(
|
||||
this._url,
|
||||
@@ -267,9 +288,13 @@ export class UrlSource extends Source {
|
||||
if (contentRange) {
|
||||
const match = contentRange.match(/bytes \d+-\d+\/(\d+)/);
|
||||
if (match && match[1]) {
|
||||
return parseInt(match[1], 10);
|
||||
return parseInt(match[1]);
|
||||
}
|
||||
}
|
||||
} else if (rangeResponse.status === 200) {
|
||||
// The server just returned the whole thing
|
||||
this._fullData = await rangeResponse.arrayBuffer();
|
||||
return this._fullData.byteLength;
|
||||
}
|
||||
|
||||
// If the range request didn't provide the size, make a full GET request
|
||||
|
||||
Reference in New Issue
Block a user