mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-10 01:03:45 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab0fd6a8d8 | ||
|
|
6a099b4259 | ||
|
|
172b4a1fd2 | ||
|
|
43c1ea7efd | ||
|
|
cab92c55ec | ||
|
|
81bc9d7c44 | ||
|
|
3209363470 | ||
|
|
d16b1927ad |
@@ -506,6 +506,9 @@ type UrlSourceOptions = {
|
|||||||
// in memory. Defaults to 8 MiB.
|
// in memory. Defaults to 8 MiB.
|
||||||
maxCacheSize?: number;
|
maxCacheSize?: number;
|
||||||
|
|
||||||
|
// The maximum number of parallel requests to use for fetching. Defaults to 2.
|
||||||
|
parallelism?: number;
|
||||||
|
|
||||||
// Used to provide a custom fetch function
|
// Used to provide a custom fetch function
|
||||||
fetchFn?: typeof fetch;
|
fetchFn?: typeof fetch;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ const sponsors = {
|
|||||||
{ image: 'https://avatars.githubusercontent.com/u/84167135', name: 'Memenome', url: 'https://github.com/memenome' },
|
{ image: 'https://avatars.githubusercontent.com/u/84167135', name: 'Memenome', url: 'https://github.com/memenome' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/5913254', name: 'Brandon McConnell', url: 'https://github.com/brandonmcconnell' },
|
{ image: 'https://avatars.githubusercontent.com/u/5913254', name: 'Brandon McConnell', url: 'https://github.com/brandonmcconnell' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/9549394', name: 'studnitz', url: 'https://github.com/studnitz' },
|
{ image: 'https://avatars.githubusercontent.com/u/9549394', name: 'studnitz', url: 'https://github.com/studnitz' },
|
||||||
|
{ image: 'https://avatars.githubusercontent.com/u/4714175', name: 'Phoomparin Mano', url: 'https://github.com/heypoom' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/504909', name: 'Hirbod', url: 'https://github.com/hirbod' },
|
{ image: 'https://avatars.githubusercontent.com/u/504909', name: 'Hirbod', url: 'https://github.com/hirbod' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/2698271', name: 'Matthew Gardner', url: 'https://github.com/spheric' },
|
{ image: 'https://avatars.githubusercontent.com/u/2698271', name: 'Matthew Gardner', url: 'https://github.com/spheric' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/5475819', name: 'AJ Funk', url: 'https://github.com/AJFunk' },
|
{ image: 'https://avatars.githubusercontent.com/u/5475819', name: 'AJ Funk', url: 'https://github.com/AJFunk' },
|
||||||
@@ -122,6 +123,7 @@ const sponsors = {
|
|||||||
{ image: 'https://avatars.githubusercontent.com/u/38181164', name: 'wcw', url: 'https://github.com/asd55667' },
|
{ image: 'https://avatars.githubusercontent.com/u/38181164', name: 'wcw', url: 'https://github.com/asd55667' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/1836701', name: 'Bean Deng', url: 'https://github.com/HADB' },
|
{ image: 'https://avatars.githubusercontent.com/u/1836701', name: 'Bean Deng', url: 'https://github.com/HADB' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/255616819', name: 'cronischarles-del', url: 'https://github.com/cronischarles-del' },
|
{ image: 'https://avatars.githubusercontent.com/u/255616819', name: 'cronischarles-del', url: 'https://github.com/cronischarles-del' },
|
||||||
|
{ image: 'https://avatars.githubusercontent.com/u/37973863', name: 'Gomi', url: 'https://github.com/gxy5202' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/63088713', name: 'taf2000', url: 'https://github.com/taf2000' },
|
{ image: 'https://avatars.githubusercontent.com/u/63088713', name: 'taf2000', url: 'https://github.com/taf2000' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/58149663', name: 'H7GhosT', url: 'https://github.com/H7GhosT' },
|
{ image: 'https://avatars.githubusercontent.com/u/58149663', name: 'H7GhosT', url: 'https://github.com/H7GhosT' },
|
||||||
{ image: 'https://avatars.githubusercontent.com/u/91711202', name: 'ihasq', url: 'https://github.com/ihasq' },
|
{ image: 'https://avatars.githubusercontent.com/u/91711202', name: 'ihasq', url: 'https://github.com/ihasq' },
|
||||||
|
|||||||
Generated
+6
-6
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.31.0",
|
"version": "1.32.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.31.0",
|
"version": "1.32.1",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@@ -7739,9 +7739,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mediabunny": {
|
"node_modules/mediabunny": {
|
||||||
"version": "1.30.1",
|
"version": "1.32.0",
|
||||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.30.1.tgz",
|
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.32.0.tgz",
|
||||||
"integrity": "sha512-FRmQAUoRqYoSd84mBKK0A4HVYEJWHhnqw6gM88mPsVfsm0ki5OG008v35yHsiEh1YcXj06d4ZkPrU0VFgUb9Og==",
|
"integrity": "sha512-wMWynAQqZkmsLm+d2+fovcBal3zBQu/bot3u+yV4bDTfNxPeEDHv1wjiz6yjyKcXBuxfaQK96gImqLcKLfJG7w==",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
@@ -12065,7 +12065,7 @@
|
|||||||
},
|
},
|
||||||
"packages/mp3-encoder": {
|
"packages/mp3-encoder": {
|
||||||
"name": "@mediabunny/mp3-encoder",
|
"name": "@mediabunny/mp3-encoder",
|
||||||
"version": "1.31.0",
|
"version": "1.32.1",
|
||||||
"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.31.0",
|
"version": "1.32.1",
|
||||||
"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.31.0",
|
"version": "1.32.1",
|
||||||
"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",
|
||||||
|
|||||||
+5
-1
@@ -801,9 +801,13 @@ export class Conversion {
|
|||||||
this._executed = true;
|
this._executed = true;
|
||||||
|
|
||||||
if (this.onProgress) {
|
if (this.onProgress) {
|
||||||
|
// Compute duration using only the utilized tracks
|
||||||
|
const durationPromises = this.utilizedTracks.map(x => x.computeDuration());
|
||||||
|
const duration = Math.max(0, ...await Promise.all(durationPromises));
|
||||||
|
|
||||||
this._computeProgress = true;
|
this._computeProgress = true;
|
||||||
this._totalDuration = Math.min(
|
this._totalDuration = Math.min(
|
||||||
(await this.input.computeDuration()) - this._startTimestamp,
|
duration - this._startTimestamp,
|
||||||
this._endTimestamp - this._startTimestamp,
|
this._endTimestamp - this._startTimestamp,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+17
-7
@@ -21,14 +21,14 @@ import {
|
|||||||
} from './matroska/ebml';
|
} from './matroska/ebml';
|
||||||
import { MatroskaDemuxer } from './matroska/matroska-demuxer';
|
import { MatroskaDemuxer } from './matroska/matroska-demuxer';
|
||||||
import { Mp3Demuxer } from './mp3/mp3-demuxer';
|
import { Mp3Demuxer } from './mp3/mp3-demuxer';
|
||||||
import { FRAME_HEADER_SIZE } from '../shared/mp3-misc';
|
import { FRAME_HEADER_SIZE, getXingOffset, INFO, XING } from '../shared/mp3-misc';
|
||||||
import { ID3_V2_HEADER_SIZE, readId3V2Header } from './id3';
|
import { ID3_V2_HEADER_SIZE, readId3V2Header } from './id3';
|
||||||
import { readNextMp3FrameHeader } from './mp3/mp3-reader';
|
import { readNextMp3FrameHeader } from './mp3/mp3-reader';
|
||||||
import { OggDemuxer } from './ogg/ogg-demuxer';
|
import { OggDemuxer } from './ogg/ogg-demuxer';
|
||||||
import { WaveDemuxer } from './wave/wave-demuxer';
|
import { WaveDemuxer } from './wave/wave-demuxer';
|
||||||
import { MAX_ADTS_FRAME_HEADER_SIZE, MIN_ADTS_FRAME_HEADER_SIZE, readAdtsFrameHeader } from './adts/adts-reader';
|
import { MAX_ADTS_FRAME_HEADER_SIZE, MIN_ADTS_FRAME_HEADER_SIZE, readAdtsFrameHeader } from './adts/adts-reader';
|
||||||
import { AdtsDemuxer } from './adts/adts-demuxer';
|
import { AdtsDemuxer } from './adts/adts-demuxer';
|
||||||
import { readAscii, readBytes } from './reader';
|
import { readAscii, readBytes, readU32Be } from './reader';
|
||||||
import { FlacDemuxer } from './flac/flac-demuxer';
|
import { FlacDemuxer } from './flac/flac-demuxer';
|
||||||
import { MpegTsDemuxer } from './mpeg-ts/mpeg-ts-demuxer';
|
import { MpegTsDemuxer } from './mpeg-ts/mpeg-ts-demuxer';
|
||||||
import { TS_PACKET_SIZE } from './mpeg-ts/mpeg-ts-misc';
|
import { TS_PACKET_SIZE } from './mpeg-ts/mpeg-ts-misc';
|
||||||
@@ -261,10 +261,6 @@ export class WebMInputFormat extends MatroskaInputFormat {
|
|||||||
export class Mp3InputFormat extends InputFormat {
|
export class Mp3InputFormat extends InputFormat {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
async _canReadInput(input: Input) {
|
async _canReadInput(input: Input) {
|
||||||
let slice = input._reader.requestSlice(0, 10);
|
|
||||||
if (slice instanceof Promise) slice = await slice;
|
|
||||||
if (!slice) return false;
|
|
||||||
|
|
||||||
let currentPos = 0;
|
let currentPos = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -285,6 +281,21 @@ export class Mp3InputFormat extends InputFormat {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const firstHeader = firstResult.header;
|
||||||
|
const xingOffset = getXingOffset(firstHeader.mpegVersionId, firstHeader.channel);
|
||||||
|
|
||||||
|
let slice = input._reader.requestSlice(firstResult.startPos + xingOffset, 4);
|
||||||
|
if (slice instanceof Promise) slice = await slice;
|
||||||
|
if (!slice) return false;
|
||||||
|
|
||||||
|
const word = readU32Be(slice);
|
||||||
|
const isXing = word === XING || word === INFO;
|
||||||
|
|
||||||
|
if (isXing) {
|
||||||
|
// Gotta be MP3
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
currentPos = firstResult.startPos + firstResult.header.totalSize;
|
currentPos = firstResult.startPos + firstResult.header.totalSize;
|
||||||
|
|
||||||
// Fine, we found one frame header, but we're still not entirely sure this is MP3. Let's check if we can find
|
// Fine, we found one frame header, but we're still not entirely sure this is MP3. Let's check if we can find
|
||||||
@@ -294,7 +305,6 @@ export class Mp3InputFormat extends InputFormat {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstHeader = firstResult.header;
|
|
||||||
const secondHeader = secondResult.header;
|
const secondHeader = secondResult.header;
|
||||||
|
|
||||||
// In a well-formed MP3 file, we'd expect these two frames to share some similarities:
|
// In a well-formed MP3 file, we'd expect these two frames to share some similarities:
|
||||||
|
|||||||
+11
-3
@@ -343,6 +343,9 @@ export type UrlSourceOptions = {
|
|||||||
/** The maximum number of bytes the cache is allowed to hold in memory. Defaults to 64 MiB. */
|
/** The maximum number of bytes the cache is allowed to hold in memory. Defaults to 64 MiB. */
|
||||||
maxCacheSize?: number;
|
maxCacheSize?: number;
|
||||||
|
|
||||||
|
/** The maximum number of parallel requests to use for fetching. Defaults to 2. */
|
||||||
|
parallelism?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A WHATWG-compatible fetch function. You can use this field to polyfill the `fetch` function, add missing
|
* A WHATWG-compatible fetch function. You can use this field to polyfill the `fetch` function, add missing
|
||||||
* features, or use a custom implementation.
|
* features, or use a custom implementation.
|
||||||
@@ -403,6 +406,9 @@ export class UrlSource extends Source {
|
|||||||
) {
|
) {
|
||||||
throw new TypeError('options.maxCacheSize, when provided, must be a non-negative number.');
|
throw new TypeError('options.maxCacheSize, when provided, must be a non-negative number.');
|
||||||
}
|
}
|
||||||
|
if (options.parallelism !== undefined && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) {
|
||||||
|
throw new TypeError('options.parallelism, when provided, must be a positive number.');
|
||||||
|
}
|
||||||
if (options.fetchFn !== undefined && typeof options.fetchFn !== 'function') {
|
if (options.fetchFn !== undefined && typeof options.fetchFn !== 'function') {
|
||||||
throw new TypeError('options.fetchFn, when provided, must be a function.');
|
throw new TypeError('options.fetchFn, when provided, must be a function.');
|
||||||
// Won't bother validating this function beyond this
|
// Won't bother validating this function beyond this
|
||||||
@@ -414,11 +420,13 @@ export class UrlSource extends Source {
|
|||||||
this._options = options;
|
this._options = options;
|
||||||
this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY;
|
this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY;
|
||||||
|
|
||||||
|
// Most files in the real-world have a single sequential access pattern, but having two in parallel can
|
||||||
|
// also happen
|
||||||
|
const DEFAULT_PARALLELISM = 2;
|
||||||
|
|
||||||
this._orchestrator = new ReadOrchestrator({
|
this._orchestrator = new ReadOrchestrator({
|
||||||
maxCacheSize: options.maxCacheSize ?? (64 * 2 ** 20 /* 64 MiB */),
|
maxCacheSize: options.maxCacheSize ?? (64 * 2 ** 20 /* 64 MiB */),
|
||||||
// Most files in the real-world have a single sequential access pattern, but having two in parallel can
|
maxWorkerCount: options.parallelism ?? DEFAULT_PARALLELISM,
|
||||||
// also happen
|
|
||||||
maxWorkerCount: 2,
|
|
||||||
runWorker: this._runWorker.bind(this),
|
runWorker: this._runWorker.bind(this),
|
||||||
prefetchProfile: PREFETCH_PROFILES.network,
|
prefetchProfile: PREFETCH_PROFILES.network,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -425,6 +425,10 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
packetIndex: number,
|
packetIndex: number,
|
||||||
options: PacketRetrievalOptions,
|
options: PacketRetrievalOptions,
|
||||||
): Promise<EncodedPacket | null> {
|
): Promise<EncodedPacket | null> {
|
||||||
|
if (packetIndex < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
assert(this.demuxer.audioInfo);
|
assert(this.demuxer.audioInfo);
|
||||||
const startOffset = packetIndex * PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes;
|
const startOffset = packetIndex * PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes;
|
||||||
if (startOffset >= this.demuxer.dataSize) {
|
if (startOffset >= this.demuxer.dataSize) {
|
||||||
@@ -465,7 +469,7 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
|
|
||||||
this.demuxer.lastKnownPacketIndex = Math.max(
|
this.demuxer.lastKnownPacketIndex = Math.max(
|
||||||
packetIndex,
|
packetIndex,
|
||||||
timestamp,
|
this.demuxer.lastKnownPacketIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
return new EncodedPacket(
|
return new EncodedPacket(
|
||||||
|
|||||||
Reference in New Issue
Block a user