mediabunny 1.50.9 → 1.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundles/mediabunny.cjs +284 -124
- package/dist/bundles/mediabunny.min.cjs +12 -12
- package/dist/bundles/mediabunny.min.mjs +12 -12
- package/dist/bundles/mediabunny.mjs +284 -124
- package/dist/bundles/mediabunny.node.cjs +284 -124
- package/dist/mediabunny.d.ts +57 -4
- package/dist/modules/src/conversion.d.ts +47 -4
- package/dist/modules/src/conversion.d.ts.map +1 -1
- package/dist/modules/src/conversion.js +245 -111
- package/dist/modules/src/hls/hls-muxer.js +5 -5
- package/dist/modules/src/index.d.ts +1 -1
- package/dist/modules/src/index.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-muxer.js +3 -3
- package/dist/modules/src/matroska/matroska-muxer.js +1 -1
- package/dist/modules/src/mpeg-ts/mpeg-ts-muxer.js +1 -1
- package/dist/modules/src/ogg/ogg-muxer.js +1 -1
- package/dist/modules/src/output.d.ts +9 -0
- package/dist/modules/src/output.d.ts.map +1 -1
- package/dist/modules/src/output.js +34 -13
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/conversion.ts +332 -127
- package/src/hls/hls-muxer.ts +5 -5
- package/src/index.ts +1 -0
- package/src/isobmff/isobmff-muxer.ts +3 -3
- package/src/matroska/matroska-muxer.ts +1 -1
- package/src/mpeg-ts/mpeg-ts-muxer.ts +1 -1
- package/src/ogg/ogg-muxer.ts +1 -1
- package/src/output.ts +41 -13
|
@@ -29000,7 +29000,7 @@ var Mediabunny = (() => {
|
|
|
29000
29000
|
this.initWriter = initWriter;
|
|
29001
29001
|
this.initBoxWriter = new IsobmffBoxWriter(initWriter);
|
|
29002
29002
|
}
|
|
29003
|
-
const holdsAvc = this.output.
|
|
29003
|
+
const holdsAvc = this.output.tracks.some((x) => x.isVideoTrack() && x.source._codec === "avc");
|
|
29004
29004
|
{
|
|
29005
29005
|
const boxWriter = this.initBoxWriter ?? this.boxWriter;
|
|
29006
29006
|
assert(boxWriter);
|
|
@@ -29024,7 +29024,7 @@ var Mediabunny = (() => {
|
|
|
29024
29024
|
}
|
|
29025
29025
|
if (this.fastStart === "in-memory") {
|
|
29026
29026
|
} else if (this.fastStart === "reserve") {
|
|
29027
|
-
for (const track of this.output.
|
|
29027
|
+
for (const track of this.output.tracks) {
|
|
29028
29028
|
if (track.metadata.maximumPacketCount === void 0) {
|
|
29029
29029
|
throw new Error(
|
|
29030
29030
|
"All tracks must specify maximumPacketCount in their metadata when using fastStart: 'reserve'."
|
|
@@ -29045,7 +29045,7 @@ var Mediabunny = (() => {
|
|
|
29045
29045
|
release();
|
|
29046
29046
|
}
|
|
29047
29047
|
allTracksAreKnown() {
|
|
29048
|
-
for (const track of this.output.
|
|
29048
|
+
for (const track of this.output.tracks) {
|
|
29049
29049
|
if (!track.source._closed && !this.trackDatas.some((x) => x.track === track)) {
|
|
29050
29050
|
return false;
|
|
29051
29051
|
}
|
|
@@ -30439,7 +30439,7 @@ var Mediabunny = (() => {
|
|
|
30439
30439
|
return this.ebmlWriter.dataOffsets.get(this.segment);
|
|
30440
30440
|
}
|
|
30441
30441
|
allTracksAreKnown() {
|
|
30442
|
-
for (const track of this.output.
|
|
30442
|
+
for (const track of this.output.tracks) {
|
|
30443
30443
|
if (!track.source._closed && !this.trackDatas.some((x) => x.track === track)) {
|
|
30444
30444
|
return false;
|
|
30445
30445
|
}
|
|
@@ -31288,7 +31288,7 @@ ${cue.notes ?? ""}`;
|
|
|
31288
31288
|
throw new Error("Subtitle tracks are not supported.");
|
|
31289
31289
|
}
|
|
31290
31290
|
allTracksAreKnown() {
|
|
31291
|
-
for (const track of this.output.
|
|
31291
|
+
for (const track of this.output.tracks) {
|
|
31292
31292
|
if (!track.source._closed && !this.trackDatas.some((x) => x.track === track)) {
|
|
31293
31293
|
return false;
|
|
31294
31294
|
}
|
|
@@ -31743,7 +31743,7 @@ ${cue.notes ?? ""}`;
|
|
|
31743
31743
|
return result;
|
|
31744
31744
|
}
|
|
31745
31745
|
allTracksAreKnown() {
|
|
31746
|
-
for (const track of this.output.
|
|
31746
|
+
for (const track of this.output.tracks) {
|
|
31747
31747
|
if (!track.source._closed && !this.trackDatas.some((x) => x.track === track)) {
|
|
31748
31748
|
return false;
|
|
31749
31749
|
}
|
|
@@ -34567,8 +34567,8 @@ ${cue.notes ?? ""}`;
|
|
|
34567
34567
|
}
|
|
34568
34568
|
async start() {
|
|
34569
34569
|
const release = await this.mutex.acquire();
|
|
34570
|
-
const someRelative = this.output.
|
|
34571
|
-
const someNotRelative = this.output.
|
|
34570
|
+
const someRelative = this.output.tracks.some((t) => t.metadata.isRelativeToUnixEpoch);
|
|
34571
|
+
const someNotRelative = this.output.tracks.some((t) => !t.metadata.isRelativeToUnixEpoch);
|
|
34572
34572
|
if (someRelative && someNotRelative) {
|
|
34573
34573
|
throw new Error(
|
|
34574
34574
|
"All tracks must agree on `relativeToUnixEpoch`: some tracks are relative to the Unix epoch and some are not."
|
|
@@ -34580,12 +34580,12 @@ ${cue.notes ?? ""}`;
|
|
|
34580
34580
|
let hasVideo = false;
|
|
34581
34581
|
let illegalPairingDetected = false;
|
|
34582
34582
|
let keyPacketsOnlyPairingWarned = false;
|
|
34583
|
-
for (const track of this.output.
|
|
34583
|
+
for (const track of this.output.tracks) {
|
|
34584
34584
|
if (track.type === "video") {
|
|
34585
34585
|
hasVideo = true;
|
|
34586
34586
|
}
|
|
34587
34587
|
const pairableGroups = /* @__PURE__ */ new Map();
|
|
34588
|
-
for (const otherTrack of this.output.
|
|
34588
|
+
for (const otherTrack of this.output.tracks) {
|
|
34589
34589
|
if (track === otherTrack) {
|
|
34590
34590
|
continue;
|
|
34591
34591
|
}
|
|
@@ -34639,7 +34639,7 @@ ${cue.notes ?? ""}`;
|
|
|
34639
34639
|
const variantStreams = [];
|
|
34640
34640
|
const unpairedVideoTracks = [];
|
|
34641
34641
|
const unpairedAudioTracks = [];
|
|
34642
|
-
for (const track of this.output.
|
|
34642
|
+
for (const track of this.output.tracks) {
|
|
34643
34643
|
const assignedGroupKeys = groupAssignment.get(track);
|
|
34644
34644
|
if (assignedGroupKeys) {
|
|
34645
34645
|
assert(assignedGroupKeys.length > 0);
|
|
@@ -36361,6 +36361,10 @@ ${cue.notes ?? ""}`;
|
|
|
36361
36361
|
* {@link BaseTrackMetadata.group}.
|
|
36362
36362
|
*/
|
|
36363
36363
|
this.defaultTrackGroup = new OutputTrackGroup();
|
|
36364
|
+
/**
|
|
36365
|
+
* The tracks that have been added to this output. Treat it as a readonly field; to add tracks, use the methods.
|
|
36366
|
+
*/
|
|
36367
|
+
this.tracks = [];
|
|
36364
36368
|
/** @internal */
|
|
36365
36369
|
this._onFinalize = null;
|
|
36366
36370
|
/** @internal */
|
|
@@ -36368,8 +36372,6 @@ ${cue.notes ?? ""}`;
|
|
|
36368
36372
|
/** @internal */
|
|
36369
36373
|
this._rootWriterPromise = null;
|
|
36370
36374
|
/** @internal */
|
|
36371
|
-
this._tracks = [];
|
|
36372
|
-
/** @internal */
|
|
36373
36375
|
this._startPromise = null;
|
|
36374
36376
|
/** @internal */
|
|
36375
36377
|
this._cancelPromise = null;
|
|
@@ -36549,7 +36551,7 @@ ${cue.notes ?? ""}`;
|
|
|
36549
36551
|
const metadataCopy = { ...metadata };
|
|
36550
36552
|
metadataCopy.group ??= this.defaultTrackGroup;
|
|
36551
36553
|
return this._addTrack(new OutputVideoTrack2(
|
|
36552
|
-
this.
|
|
36554
|
+
this.tracks.length + 1,
|
|
36553
36555
|
this,
|
|
36554
36556
|
source,
|
|
36555
36557
|
metadataCopy
|
|
@@ -36564,7 +36566,7 @@ ${cue.notes ?? ""}`;
|
|
|
36564
36566
|
const metadataCopy = { ...metadata };
|
|
36565
36567
|
metadataCopy.group ??= this.defaultTrackGroup;
|
|
36566
36568
|
return this._addTrack(new OutputAudioTrack2(
|
|
36567
|
-
this.
|
|
36569
|
+
this.tracks.length + 1,
|
|
36568
36570
|
this,
|
|
36569
36571
|
source,
|
|
36570
36572
|
metadataCopy
|
|
@@ -36579,7 +36581,7 @@ ${cue.notes ?? ""}`;
|
|
|
36579
36581
|
const metadataCopy = { ...metadata };
|
|
36580
36582
|
metadataCopy.group ??= this.defaultTrackGroup;
|
|
36581
36583
|
return this._addTrack(new OutputSubtitleTrack2(
|
|
36582
|
-
this.
|
|
36584
|
+
this.tracks.length + 1,
|
|
36583
36585
|
this,
|
|
36584
36586
|
source,
|
|
36585
36587
|
metadataCopy
|
|
@@ -36607,7 +36609,7 @@ ${cue.notes ?? ""}`;
|
|
|
36607
36609
|
throw new Error("Source is already used for a track.");
|
|
36608
36610
|
}
|
|
36609
36611
|
const supportedTrackCounts = this.format.getSupportedTrackCounts();
|
|
36610
|
-
const presentTracksOfThisType = this.
|
|
36612
|
+
const presentTracksOfThisType = this.tracks.reduce(
|
|
36611
36613
|
(count, t) => count + (t.type === track.type ? 1 : 0),
|
|
36612
36614
|
0
|
|
36613
36615
|
);
|
|
@@ -36618,7 +36620,7 @@ ${cue.notes ?? ""}`;
|
|
|
36618
36620
|
);
|
|
36619
36621
|
}
|
|
36620
36622
|
const maxTotalCount = supportedTrackCounts.total.max;
|
|
36621
|
-
if (this.
|
|
36623
|
+
if (this.tracks.length === maxTotalCount) {
|
|
36622
36624
|
throw new Error(
|
|
36623
36625
|
`${this.format._name} does not support more than ${maxTotalCount} tracks${maxTotalCount === 1 ? "" : "s"} in total.`
|
|
36624
36626
|
);
|
|
@@ -36657,10 +36659,32 @@ ${cue.notes ?? ""}`;
|
|
|
36657
36659
|
);
|
|
36658
36660
|
}
|
|
36659
36661
|
}
|
|
36660
|
-
this.
|
|
36662
|
+
this.tracks.push(track);
|
|
36661
36663
|
track.source._connectedTrack = track;
|
|
36662
36664
|
return track;
|
|
36663
36665
|
}
|
|
36666
|
+
/**
|
|
36667
|
+
* Whether the output has enough tracks (of the correct type) to be started, based on the requirements of the output
|
|
36668
|
+
* format.
|
|
36669
|
+
*/
|
|
36670
|
+
hasEnoughTracks() {
|
|
36671
|
+
const supportedTrackCounts = this.format.getSupportedTrackCounts();
|
|
36672
|
+
for (const trackType of ALL_TRACK_TYPES) {
|
|
36673
|
+
const presentTracksOfThisType = this.tracks.reduce(
|
|
36674
|
+
(count, track) => count + (track.type === trackType ? 1 : 0),
|
|
36675
|
+
0
|
|
36676
|
+
);
|
|
36677
|
+
const minCount = supportedTrackCounts[trackType].min;
|
|
36678
|
+
if (presentTracksOfThisType < minCount) {
|
|
36679
|
+
return false;
|
|
36680
|
+
}
|
|
36681
|
+
}
|
|
36682
|
+
const totalMinCount = supportedTrackCounts.total.min;
|
|
36683
|
+
if (this.tracks.length < totalMinCount) {
|
|
36684
|
+
return false;
|
|
36685
|
+
}
|
|
36686
|
+
return true;
|
|
36687
|
+
}
|
|
36664
36688
|
/**
|
|
36665
36689
|
* Starts the creation of the output file. This method should be called after all tracks have been added. Only after
|
|
36666
36690
|
* the output has started can media samples be added to the tracks.
|
|
@@ -36670,7 +36694,7 @@ ${cue.notes ?? ""}`;
|
|
|
36670
36694
|
async start() {
|
|
36671
36695
|
const supportedTrackCounts = this.format.getSupportedTrackCounts();
|
|
36672
36696
|
for (const trackType of ALL_TRACK_TYPES) {
|
|
36673
|
-
const presentTracksOfThisType = this.
|
|
36697
|
+
const presentTracksOfThisType = this.tracks.reduce(
|
|
36674
36698
|
(count, track) => count + (track.type === trackType ? 1 : 0),
|
|
36675
36699
|
0
|
|
36676
36700
|
);
|
|
@@ -36682,7 +36706,7 @@ ${cue.notes ?? ""}`;
|
|
|
36682
36706
|
}
|
|
36683
36707
|
}
|
|
36684
36708
|
const totalMinCount = supportedTrackCounts.total.min;
|
|
36685
|
-
if (this.
|
|
36709
|
+
if (this.tracks.length < totalMinCount) {
|
|
36686
36710
|
throw new Error(
|
|
36687
36711
|
totalMinCount === supportedTrackCounts.total.max ? `${this.format._name} requires exactly ${totalMinCount} track${totalMinCount === 1 ? "" : "s"}.` : `${this.format._name} requires at least ${totalMinCount} track${totalMinCount === 1 ? "" : "s"}.`
|
|
36688
36712
|
);
|
|
@@ -36699,7 +36723,7 @@ ${cue.notes ?? ""}`;
|
|
|
36699
36723
|
const release = await this._mutex.acquire();
|
|
36700
36724
|
try {
|
|
36701
36725
|
await this._muxer.start();
|
|
36702
|
-
const promises = this.
|
|
36726
|
+
const promises = this.tracks.map((track) => track.source._start());
|
|
36703
36727
|
await Promise.all(promises);
|
|
36704
36728
|
} finally {
|
|
36705
36729
|
release();
|
|
@@ -36734,7 +36758,7 @@ ${cue.notes ?? ""}`;
|
|
|
36734
36758
|
this.state = "canceled";
|
|
36735
36759
|
const release = await this._mutex.acquire();
|
|
36736
36760
|
try {
|
|
36737
|
-
const promises = this.
|
|
36761
|
+
const promises = this.tracks.map((x) => x.source._flushOrWaitForOngoingClose(true));
|
|
36738
36762
|
await Promise.all(promises);
|
|
36739
36763
|
await Promise.all([...this._unfinalizedTargets].map((target) => target._close()));
|
|
36740
36764
|
this._unfinalizedTargets.clear();
|
|
@@ -36762,7 +36786,7 @@ ${cue.notes ?? ""}`;
|
|
|
36762
36786
|
this.state = "finalizing";
|
|
36763
36787
|
const release = await this._mutex.acquire();
|
|
36764
36788
|
try {
|
|
36765
|
-
const promises = this.
|
|
36789
|
+
const promises = this.tracks.map((x) => x.source._flushOrWaitForOngoingClose(false));
|
|
36766
36790
|
await Promise.all(promises);
|
|
36767
36791
|
await this._muxer.finalize();
|
|
36768
36792
|
if (this._rootWriterPromise) {
|
|
@@ -36901,14 +36925,15 @@ ${cue.notes ?? ""}`;
|
|
|
36901
36925
|
var Conversion = class _Conversion {
|
|
36902
36926
|
/** Creates a new Conversion instance (duh). */
|
|
36903
36927
|
constructor(options) {
|
|
36904
|
-
/**
|
|
36905
|
-
|
|
36906
|
-
|
|
36907
|
-
|
|
36908
|
-
|
|
36909
|
-
|
|
36910
|
-
|
|
36911
|
-
|
|
36928
|
+
/**
|
|
36929
|
+
* The current state of the conversion.
|
|
36930
|
+
*
|
|
36931
|
+
* - `'idle'`: The conversion is not currently executing and isn't done; `execute` can be called.
|
|
36932
|
+
* - `'executing'`: A call to `execute` is currently running.
|
|
36933
|
+
* - `'canceled'`: The conversion has been canceled and can no longer be executed.
|
|
36934
|
+
* - `'done'`: The conversion has run to completion. Subsequent calls to `execute` do nothing.
|
|
36935
|
+
*/
|
|
36936
|
+
this.state = "idle";
|
|
36912
36937
|
/** @internal */
|
|
36913
36938
|
this._nextOutputTrackId = 0;
|
|
36914
36939
|
/** @internal */
|
|
@@ -36916,18 +36941,22 @@ ${cue.notes ?? ""}`;
|
|
|
36916
36941
|
/** @internal */
|
|
36917
36942
|
this._outputOwnTrackGroups = [];
|
|
36918
36943
|
/** @internal */
|
|
36919
|
-
this.
|
|
36944
|
+
this._trackPumps = [];
|
|
36945
|
+
/** @internal */
|
|
36946
|
+
this._composable = false;
|
|
36920
36947
|
/** @internal */
|
|
36921
36948
|
this._executed = false;
|
|
36922
36949
|
/** @internal */
|
|
36923
|
-
this.
|
|
36950
|
+
this._executionUntil = Infinity;
|
|
36951
|
+
/** @internal */
|
|
36952
|
+
this._pauseRequested = false;
|
|
36953
|
+
/** @internal */
|
|
36954
|
+
this._synchronizer = new TrackSynchronizer(this);
|
|
36924
36955
|
/** @internal */
|
|
36925
36956
|
this._totalDuration = null;
|
|
36926
36957
|
/** @internal */
|
|
36927
36958
|
this._maxTimestamps = /* @__PURE__ */ new Map();
|
|
36928
36959
|
// Track ID -> timestamp
|
|
36929
|
-
/** @internal */
|
|
36930
|
-
this._canceled = false;
|
|
36931
36960
|
/**
|
|
36932
36961
|
* A callback that is fired whenever the conversion progresses. Gets passed as first argument a number between
|
|
36933
36962
|
* 0 and 1, indicating the completion of the conversion. Note that a progress of 1 doesn't necessarily mean the
|
|
@@ -36944,7 +36973,8 @@ ${cue.notes ?? ""}`;
|
|
|
36944
36973
|
this._lastProgress = 0;
|
|
36945
36974
|
/**
|
|
36946
36975
|
* Whether this conversion, as it has been configured, is valid and can be executed. If this field is `false`, check
|
|
36947
|
-
* the `discardedTracks` field for reasons.
|
|
36976
|
+
* the `discardedTracks` field for reasons. Composable conversions are always valid, even if they utilize
|
|
36977
|
+
* zero tracks.
|
|
36948
36978
|
*
|
|
36949
36979
|
* Note: a conversion having discarded tracks does not automatically mean it is invalid; if the remaining, utilized
|
|
36950
36980
|
* tracks make for a valid output file, the conversion is still allowed.
|
|
@@ -36971,8 +37001,23 @@ ${cue.notes ?? ""}`;
|
|
|
36971
37001
|
"options.tracks, when provided, must be either 'all' or 'primary'."
|
|
36972
37002
|
);
|
|
36973
37003
|
}
|
|
36974
|
-
if (options.
|
|
36975
|
-
throw new TypeError("options.
|
|
37004
|
+
if (options.composable !== void 0 && typeof options.composable !== "boolean") {
|
|
37005
|
+
throw new TypeError("options.composable, when provided, must be a boolean.");
|
|
37006
|
+
}
|
|
37007
|
+
const composable = options.composable ?? false;
|
|
37008
|
+
if (!composable) {
|
|
37009
|
+
if (options.output.tracks.length > 0 || Object.keys(options.output._metadataTags).length > 0 || options.output.state !== "pending") {
|
|
37010
|
+
throw new TypeError("options.output must be fresh: no tracks or metadata tags added and not started.");
|
|
37011
|
+
}
|
|
37012
|
+
} else {
|
|
37013
|
+
if (options.tags !== void 0) {
|
|
37014
|
+
throw new TypeError(
|
|
37015
|
+
"options.tags cannot be set by a composable conversion; set metadata directly on the output instead."
|
|
37016
|
+
);
|
|
37017
|
+
}
|
|
37018
|
+
if (options.output.state !== "pending") {
|
|
37019
|
+
throw new TypeError("options.output must not have been started yet.");
|
|
37020
|
+
}
|
|
36976
37021
|
}
|
|
36977
37022
|
if (options.video !== void 0 && typeof options.video !== "function") {
|
|
36978
37023
|
if (Array.isArray(options.video)) {
|
|
@@ -37016,11 +37061,9 @@ ${cue.notes ?? ""}`;
|
|
|
37016
37061
|
throw new TypeError("options.showWarnings, when provided, must be a boolean.");
|
|
37017
37062
|
}
|
|
37018
37063
|
this._options = options;
|
|
37064
|
+
this._composable = composable;
|
|
37019
37065
|
this.input = options.input;
|
|
37020
37066
|
this.output = options.output;
|
|
37021
|
-
const { promise: started, resolve: start } = promiseWithResolvers();
|
|
37022
|
-
this._started = started;
|
|
37023
|
-
this._start = start;
|
|
37024
37067
|
}
|
|
37025
37068
|
/** Initializes a new conversion process without starting the conversion. */
|
|
37026
37069
|
static async init(options) {
|
|
@@ -37132,7 +37175,7 @@ ${cue.notes ?? ""}`;
|
|
|
37132
37175
|
const track = filteredTracks[i];
|
|
37133
37176
|
const options = filteredTrackOptions[i];
|
|
37134
37177
|
for (const option of options) {
|
|
37135
|
-
if (this.
|
|
37178
|
+
if (this.output.tracks.length === outputTrackCounts.total.max) {
|
|
37136
37179
|
this.discardedTracks.push({
|
|
37137
37180
|
track,
|
|
37138
37181
|
reason: "max_track_count_reached",
|
|
@@ -37140,7 +37183,11 @@ ${cue.notes ?? ""}`;
|
|
|
37140
37183
|
});
|
|
37141
37184
|
continue;
|
|
37142
37185
|
}
|
|
37143
|
-
|
|
37186
|
+
const addedCountOfType = this.output.tracks.reduce(
|
|
37187
|
+
(count, t) => count + (t.type === track.type ? 1 : 0),
|
|
37188
|
+
0
|
|
37189
|
+
);
|
|
37190
|
+
if (addedCountOfType === outputTrackCounts[track.type].max) {
|
|
37144
37191
|
this.discardedTracks.push({
|
|
37145
37192
|
track,
|
|
37146
37193
|
reason: "max_track_count_of_type_reached",
|
|
@@ -37171,22 +37218,28 @@ ${cue.notes ?? ""}`;
|
|
|
37171
37218
|
}
|
|
37172
37219
|
}
|
|
37173
37220
|
}
|
|
37174
|
-
|
|
37175
|
-
|
|
37176
|
-
|
|
37177
|
-
|
|
37178
|
-
|
|
37179
|
-
|
|
37180
|
-
|
|
37181
|
-
|
|
37221
|
+
if (!this._composable) {
|
|
37222
|
+
const inputTags = await this.input.getMetadataTags();
|
|
37223
|
+
let outputTags;
|
|
37224
|
+
if (this._options.tags) {
|
|
37225
|
+
const result = typeof this._options.tags === "function" ? await this._options.tags(inputTags) : this._options.tags;
|
|
37226
|
+
validateMetadataTags(result);
|
|
37227
|
+
outputTags = result;
|
|
37228
|
+
} else {
|
|
37229
|
+
outputTags = inputTags;
|
|
37230
|
+
}
|
|
37231
|
+
const inputAndOutputFormatMatch = inputFormat.mimeType === this.output.format.mimeType;
|
|
37232
|
+
const rawTagsAreUnchanged = inputTags.raw === outputTags.raw;
|
|
37233
|
+
if (inputTags.raw && rawTagsAreUnchanged && !inputAndOutputFormatMatch) {
|
|
37234
|
+
delete outputTags.raw;
|
|
37235
|
+
}
|
|
37236
|
+
this.output.setMetadataTags(outputTags);
|
|
37182
37237
|
}
|
|
37183
|
-
|
|
37184
|
-
|
|
37185
|
-
|
|
37186
|
-
|
|
37238
|
+
if (!this._composable) {
|
|
37239
|
+
this.isValid = this.output.hasEnoughTracks();
|
|
37240
|
+
} else {
|
|
37241
|
+
this.isValid = true;
|
|
37187
37242
|
}
|
|
37188
|
-
this.output.setMetadataTags(outputTags);
|
|
37189
|
-
this.isValid = this._totalTrackCount >= outputTrackCounts.total.min && this._addedCounts.video >= outputTrackCounts.video.min && this._addedCounts.audio >= outputTrackCounts.audio.min && this._addedCounts.subtitle >= outputTrackCounts.subtitle.min;
|
|
37190
37243
|
if (this._options.showWarnings ?? true) {
|
|
37191
37244
|
const warnElements = [];
|
|
37192
37245
|
const unintentionallyDiscardedTracks = this.discardedTracks.filter((x) => x.reason !== "discarded_by_user");
|
|
@@ -37272,59 +37325,116 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37272
37325
|
return elements;
|
|
37273
37326
|
}
|
|
37274
37327
|
/**
|
|
37275
|
-
* Executes the conversion process
|
|
37328
|
+
* Executes the conversion process and resolves when the conversion is complete. When
|
|
37329
|
+
* {@link ConversionExecuteOptions.until} is provided, the conversion will be suspended once that output timestamp
|
|
37330
|
+
* is reached and can be resumed with another call to `execute`. An ongoing execution may also be suspended via
|
|
37331
|
+
* {@link ConversionExecuteOptions.pauseSignal}.
|
|
37276
37332
|
*
|
|
37277
|
-
*
|
|
37333
|
+
* Execution will throw if `isValid` is `false`.
|
|
37278
37334
|
*/
|
|
37279
|
-
async execute() {
|
|
37335
|
+
async execute(options = {}) {
|
|
37336
|
+
if (!options || typeof options !== "object") {
|
|
37337
|
+
throw new TypeError("options must be an object.");
|
|
37338
|
+
}
|
|
37339
|
+
if (options.until !== void 0 && (typeof options.until !== "number" || Number.isNaN(options.until))) {
|
|
37340
|
+
throw new TypeError("options.until, when provided, must be a number.");
|
|
37341
|
+
}
|
|
37342
|
+
if (options.pauseSignal !== void 0 && !(options.pauseSignal instanceof AbortSignal)) {
|
|
37343
|
+
throw new TypeError("options.pauseSignal, when provided, must be an AbortSignal.");
|
|
37344
|
+
}
|
|
37280
37345
|
if (!this.isValid) {
|
|
37281
37346
|
throw new Error(
|
|
37282
37347
|
"Cannot execute this conversion because its output configuration is invalid. Make sure to always check the isValid field before executing a conversion.\n" + this._getInvalidityExplanation().join("")
|
|
37283
37348
|
);
|
|
37284
37349
|
}
|
|
37285
|
-
if (this.
|
|
37286
|
-
throw new Error("
|
|
37350
|
+
if (this.state === "executing") {
|
|
37351
|
+
throw new Error("Cannot call execute() while a previous call to execute() is still running.");
|
|
37287
37352
|
}
|
|
37288
|
-
this.
|
|
37289
|
-
|
|
37290
|
-
this._synchronizer.declareTrack(id);
|
|
37353
|
+
if (this.state === "canceled") {
|
|
37354
|
+
throw new ConversionCanceledError();
|
|
37291
37355
|
}
|
|
37292
|
-
if (this.
|
|
37293
|
-
|
|
37294
|
-
|
|
37295
|
-
|
|
37296
|
-
|
|
37297
|
-
|
|
37298
|
-
return await track.getDurationFromMetadata() ?? await track.computeDuration();
|
|
37299
|
-
});
|
|
37300
|
-
const duration = Math.max(0, ...await Promise.all(durationPromises));
|
|
37301
|
-
this._computeProgress = true;
|
|
37302
|
-
this._totalDuration = Math.min(
|
|
37303
|
-
duration - this._startTimestamp,
|
|
37304
|
-
this._endTimestamp - this._startTimestamp
|
|
37356
|
+
if (this.state === "done") {
|
|
37357
|
+
return;
|
|
37358
|
+
}
|
|
37359
|
+
if (this._composable && this.output.state === "pending") {
|
|
37360
|
+
throw new Error(
|
|
37361
|
+
"A composable conversion requires the output to be started. Call start() on the output before executing the conversion."
|
|
37305
37362
|
);
|
|
37363
|
+
}
|
|
37364
|
+
this.state = "executing";
|
|
37365
|
+
this._executionUntil = options.until ?? Infinity;
|
|
37366
|
+
this._pauseRequested = options.pauseSignal?.aborted ?? false;
|
|
37367
|
+
const onPause = () => {
|
|
37368
|
+
if (this.state !== "executing") {
|
|
37369
|
+
return;
|
|
37370
|
+
}
|
|
37371
|
+
this._pauseRequested = true;
|
|
37372
|
+
this._synchronizer.resolveAll();
|
|
37373
|
+
};
|
|
37374
|
+
options.pauseSignal?.addEventListener("abort", onPause);
|
|
37375
|
+
for (const pump of this._trackPumps) {
|
|
37376
|
+
if (!pump.done) {
|
|
37377
|
+
pump.resolvers = promiseWithResolvers();
|
|
37378
|
+
}
|
|
37379
|
+
}
|
|
37380
|
+
if (!this._executed) {
|
|
37381
|
+
this._executed = true;
|
|
37306
37382
|
for (const id of this._outputTrackIds) {
|
|
37307
|
-
this.
|
|
37383
|
+
this._synchronizer.declareTrack(id);
|
|
37384
|
+
}
|
|
37385
|
+
if (this.onProgress) {
|
|
37386
|
+
const uniqueUtilizedTracks = new Set(this.utilizedTracks);
|
|
37387
|
+
const durationPromises = [...uniqueUtilizedTracks].map(async (track) => {
|
|
37388
|
+
if (await track.isLive()) {
|
|
37389
|
+
return Infinity;
|
|
37390
|
+
}
|
|
37391
|
+
return await track.getDurationFromMetadata() ?? await track.computeDuration();
|
|
37392
|
+
});
|
|
37393
|
+
const duration = Math.max(0, ...await Promise.all(durationPromises));
|
|
37394
|
+
this._computeProgress = true;
|
|
37395
|
+
this._totalDuration = Math.min(
|
|
37396
|
+
duration - this._startTimestamp,
|
|
37397
|
+
this._endTimestamp - this._startTimestamp
|
|
37398
|
+
);
|
|
37399
|
+
for (const id of this._outputTrackIds) {
|
|
37400
|
+
this._maxTimestamps.set(id, 0);
|
|
37401
|
+
}
|
|
37402
|
+
this.onProgress?.(0, 0);
|
|
37403
|
+
}
|
|
37404
|
+
if (!this._composable) {
|
|
37405
|
+
await this.output.start();
|
|
37406
|
+
}
|
|
37407
|
+
for (const pump of this._trackPumps) {
|
|
37408
|
+
pump.start();
|
|
37409
|
+
}
|
|
37410
|
+
} else {
|
|
37411
|
+
for (const pump of this._trackPumps) {
|
|
37412
|
+
pump.wake?.();
|
|
37308
37413
|
}
|
|
37309
|
-
this.onProgress?.(0, 0);
|
|
37310
37414
|
}
|
|
37311
|
-
await this.output.start();
|
|
37312
|
-
this._start();
|
|
37313
37415
|
try {
|
|
37314
|
-
await Promise.all(this.
|
|
37416
|
+
await Promise.all(this._trackPumps.map((x) => x.resolvers.promise));
|
|
37315
37417
|
} catch (error) {
|
|
37316
|
-
if (
|
|
37418
|
+
if (this.state !== "canceled") {
|
|
37317
37419
|
void this.cancel();
|
|
37318
37420
|
}
|
|
37319
37421
|
throw error;
|
|
37422
|
+
} finally {
|
|
37423
|
+
options.pauseSignal?.removeEventListener("abort", onPause);
|
|
37320
37424
|
}
|
|
37321
|
-
if (this.
|
|
37425
|
+
if (this.state === "canceled") {
|
|
37322
37426
|
throw new ConversionCanceledError();
|
|
37323
37427
|
}
|
|
37324
|
-
|
|
37325
|
-
|
|
37326
|
-
|
|
37327
|
-
this.
|
|
37428
|
+
const isDone = this._trackPumps.every((x) => x.done);
|
|
37429
|
+
this.state = isDone ? "done" : "idle";
|
|
37430
|
+
if (isDone) {
|
|
37431
|
+
if (!this._composable) {
|
|
37432
|
+
await this.output.finalize();
|
|
37433
|
+
}
|
|
37434
|
+
if (this._computeProgress) {
|
|
37435
|
+
const minTimestamp = Math.min(...this._maxTimestamps.values());
|
|
37436
|
+
this.onProgress?.(1, minTimestamp);
|
|
37437
|
+
}
|
|
37328
37438
|
}
|
|
37329
37439
|
}
|
|
37330
37440
|
/**
|
|
@@ -37332,15 +37442,21 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37332
37442
|
* Does nothing if the conversion is already complete.
|
|
37333
37443
|
*/
|
|
37334
37444
|
async cancel() {
|
|
37335
|
-
if (this.
|
|
37445
|
+
if (this.state === "done") {
|
|
37336
37446
|
return;
|
|
37337
37447
|
}
|
|
37338
|
-
if (this.
|
|
37448
|
+
if (this.state === "canceled") {
|
|
37339
37449
|
Logging._warn("Conversion already canceled.");
|
|
37340
37450
|
return;
|
|
37341
37451
|
}
|
|
37342
|
-
this.
|
|
37343
|
-
|
|
37452
|
+
this.state = "canceled";
|
|
37453
|
+
for (const pump of this._trackPumps) {
|
|
37454
|
+
pump.wake?.();
|
|
37455
|
+
}
|
|
37456
|
+
this._synchronizer.resolveAll();
|
|
37457
|
+
if (!this._composable) {
|
|
37458
|
+
await this.output.cancel();
|
|
37459
|
+
}
|
|
37344
37460
|
}
|
|
37345
37461
|
/** @internal */
|
|
37346
37462
|
async _processVideoTrack(track, trackOptions, outputTrackId) {
|
|
@@ -37386,14 +37502,13 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37386
37502
|
if (!needsTranscode) {
|
|
37387
37503
|
const source = new EncodedVideoPacketSource(sourceCodec);
|
|
37388
37504
|
videoSource = source;
|
|
37389
|
-
this.
|
|
37390
|
-
await this._started;
|
|
37505
|
+
this._registerTrackPump(async (pump) => {
|
|
37391
37506
|
const sink = new EncodedPacketSink(track);
|
|
37392
37507
|
const decoderConfig = await track.getDecoderConfig();
|
|
37393
37508
|
const meta = { decoderConfig: decoderConfig ?? void 0 };
|
|
37394
37509
|
for await (const packet of sink.packets(void 0, void 0, { verifyKeyPackets: true })) {
|
|
37395
|
-
if (this.
|
|
37396
|
-
|
|
37510
|
+
if (this.state === "canceled") {
|
|
37511
|
+
break;
|
|
37397
37512
|
}
|
|
37398
37513
|
if (packet.timestamp >= this._endTimestamp) {
|
|
37399
37514
|
break;
|
|
@@ -37408,10 +37523,11 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37408
37523
|
if (this._synchronizer.shouldWait(outputTrackId, modifiedPacket.timestamp)) {
|
|
37409
37524
|
await this._synchronizer.wait(modifiedPacket.timestamp);
|
|
37410
37525
|
}
|
|
37526
|
+
await this._checkpoint(pump, modifiedPacket.timestamp);
|
|
37411
37527
|
}
|
|
37412
37528
|
source.close();
|
|
37413
37529
|
this._synchronizer.closeTrack(outputTrackId);
|
|
37414
|
-
})
|
|
37530
|
+
});
|
|
37415
37531
|
} else {
|
|
37416
37532
|
const canDecode2 = await track.canDecode();
|
|
37417
37533
|
if (!canDecode2) {
|
|
@@ -37507,15 +37623,14 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37507
37623
|
};
|
|
37508
37624
|
const source = new VideoSampleSource(encodingConfig);
|
|
37509
37625
|
videoSource = source;
|
|
37510
|
-
this.
|
|
37511
|
-
await this._started;
|
|
37626
|
+
this._registerTrackPump(async (pump) => {
|
|
37512
37627
|
const sink = new VideoSampleSink(track);
|
|
37513
37628
|
for await (var _sample of sink.samples(this._startTimestamp, this._endTimestamp)) {
|
|
37514
37629
|
var _stack2 = [];
|
|
37515
37630
|
try {
|
|
37516
37631
|
const sample = __using(_stack2, _sample);
|
|
37517
|
-
if (this.
|
|
37518
|
-
|
|
37632
|
+
if (this.state === "canceled") {
|
|
37633
|
+
break;
|
|
37519
37634
|
}
|
|
37520
37635
|
const adjustedSampleTimestamp = Math.max(sample.timestamp - this._startTimestamp, 0);
|
|
37521
37636
|
sample.setTimestamp(adjustedSampleTimestamp);
|
|
@@ -37526,6 +37641,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37526
37641
|
if (this._synchronizer.shouldWait(outputTrackId, lastSampleTimestamp)) {
|
|
37527
37642
|
await this._synchronizer.wait(lastSampleTimestamp);
|
|
37528
37643
|
}
|
|
37644
|
+
await this._checkpoint(pump, lastSampleTimestamp);
|
|
37529
37645
|
}
|
|
37530
37646
|
} catch (_2) {
|
|
37531
37647
|
var _error2 = _2, _hasError2 = true;
|
|
@@ -37535,10 +37651,10 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37535
37651
|
}
|
|
37536
37652
|
source.close();
|
|
37537
37653
|
this._synchronizer.closeTrack(outputTrackId);
|
|
37538
|
-
})
|
|
37654
|
+
});
|
|
37539
37655
|
}
|
|
37540
37656
|
let ownGroup = null;
|
|
37541
|
-
if (!trackOptions.group) {
|
|
37657
|
+
if (!trackOptions.group && !this._composable) {
|
|
37542
37658
|
ownGroup = new OutputTrackGroup();
|
|
37543
37659
|
}
|
|
37544
37660
|
const videoTrackLanguageCode = await track.getLanguageCode();
|
|
@@ -37551,8 +37667,6 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37551
37667
|
rotation: outputTrackRotation,
|
|
37552
37668
|
group: ownGroup ?? trackOptions.group
|
|
37553
37669
|
});
|
|
37554
|
-
this._addedCounts.video++;
|
|
37555
|
-
this._totalTrackCount++;
|
|
37556
37670
|
this.utilizedTracks.push(track);
|
|
37557
37671
|
this._outputTrackIds.push(outputTrackId);
|
|
37558
37672
|
this._outputOwnTrackGroups.push(ownGroup);
|
|
@@ -37580,14 +37694,13 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37580
37694
|
if (!trackOptions.forceTranscode && !trackOptions.bitrate && numberOfChannels === originalNumberOfChannels && sampleRate === originalSampleRate && !needsTrimming && !needsPadding && audioCodecs.includes(sourceCodec) && (!trackOptions.codec || trackOptions.codec === sourceCodec) && !trackOptions.process && trackOptions.sampleFormat === void 0) {
|
|
37581
37695
|
const source = new EncodedAudioPacketSource(sourceCodec);
|
|
37582
37696
|
audioSource = source;
|
|
37583
|
-
this.
|
|
37584
|
-
await this._started;
|
|
37697
|
+
this._registerTrackPump(async (pump) => {
|
|
37585
37698
|
const sink = new EncodedPacketSink(track);
|
|
37586
37699
|
const decoderConfig = await track.getDecoderConfig();
|
|
37587
37700
|
const meta = { decoderConfig: decoderConfig ?? void 0 };
|
|
37588
37701
|
for await (const packet of sink.packets()) {
|
|
37589
|
-
if (this.
|
|
37590
|
-
|
|
37702
|
+
if (this.state === "canceled") {
|
|
37703
|
+
break;
|
|
37591
37704
|
}
|
|
37592
37705
|
if (packet.timestamp >= this._endTimestamp) {
|
|
37593
37706
|
break;
|
|
@@ -37601,10 +37714,11 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37601
37714
|
if (this._synchronizer.shouldWait(outputTrackId, modifiedPacket.timestamp)) {
|
|
37602
37715
|
await this._synchronizer.wait(modifiedPacket.timestamp);
|
|
37603
37716
|
}
|
|
37717
|
+
await this._checkpoint(pump, modifiedPacket.timestamp);
|
|
37604
37718
|
}
|
|
37605
37719
|
source.close();
|
|
37606
37720
|
this._synchronizer.closeTrack(outputTrackId);
|
|
37607
|
-
})
|
|
37721
|
+
});
|
|
37608
37722
|
} else {
|
|
37609
37723
|
const canDecode2 = await track.canDecode();
|
|
37610
37724
|
if (!canDecode2) {
|
|
@@ -37669,8 +37783,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37669
37783
|
};
|
|
37670
37784
|
const source = new AudioSampleSource(encodingConfig);
|
|
37671
37785
|
audioSource = source;
|
|
37672
|
-
this.
|
|
37673
|
-
await this._started;
|
|
37786
|
+
this._registerTrackPump(async (pump) => {
|
|
37674
37787
|
const sink = new AudioSampleSink(track);
|
|
37675
37788
|
for await (var _sample of sink.samples(this._startTimestamp, this._endTimestamp)) {
|
|
37676
37789
|
var _stack3 = [];
|
|
@@ -37678,8 +37791,8 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37678
37791
|
const sample = __using(_stack3, _sample);
|
|
37679
37792
|
var _stack2 = [];
|
|
37680
37793
|
try {
|
|
37681
|
-
if (this.
|
|
37682
|
-
|
|
37794
|
+
if (this.state === "canceled") {
|
|
37795
|
+
break;
|
|
37683
37796
|
}
|
|
37684
37797
|
if (needsPadding) {
|
|
37685
37798
|
var _stack = [];
|
|
@@ -37700,7 +37813,13 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37700
37813
|
sampleRate: originalSampleRate,
|
|
37701
37814
|
timestamp: 0
|
|
37702
37815
|
}));
|
|
37703
|
-
await this._registerAudioSample(
|
|
37816
|
+
await this._registerAudioSample(
|
|
37817
|
+
pump,
|
|
37818
|
+
silentSample,
|
|
37819
|
+
source,
|
|
37820
|
+
outputTrackId,
|
|
37821
|
+
() => lastSampleTimestamp
|
|
37822
|
+
);
|
|
37704
37823
|
needsPadding = false;
|
|
37705
37824
|
} catch (_) {
|
|
37706
37825
|
var _error = _, _hasError = true;
|
|
@@ -37730,7 +37849,13 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37730
37849
|
}
|
|
37731
37850
|
const finalSample = __using(_stack2, finalSampleLet);
|
|
37732
37851
|
finalSample.setTimestamp(finalSample.timestamp - this._startTimestamp);
|
|
37733
|
-
await this._registerAudioSample(
|
|
37852
|
+
await this._registerAudioSample(
|
|
37853
|
+
pump,
|
|
37854
|
+
finalSample,
|
|
37855
|
+
source,
|
|
37856
|
+
outputTrackId,
|
|
37857
|
+
() => lastSampleTimestamp
|
|
37858
|
+
);
|
|
37734
37859
|
} catch (_2) {
|
|
37735
37860
|
var _error2 = _2, _hasError2 = true;
|
|
37736
37861
|
} finally {
|
|
@@ -37744,10 +37869,10 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37744
37869
|
}
|
|
37745
37870
|
source.close();
|
|
37746
37871
|
this._synchronizer.closeTrack(outputTrackId);
|
|
37747
|
-
})
|
|
37872
|
+
});
|
|
37748
37873
|
}
|
|
37749
37874
|
let ownGroup = null;
|
|
37750
|
-
if (!trackOptions.group) {
|
|
37875
|
+
if (!trackOptions.group && !this._composable) {
|
|
37751
37876
|
ownGroup = new OutputTrackGroup();
|
|
37752
37877
|
}
|
|
37753
37878
|
const audioTrackLanguageCode = await track.getLanguageCode();
|
|
@@ -37758,14 +37883,12 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37758
37883
|
disposition: await track.getDisposition(),
|
|
37759
37884
|
group: ownGroup ?? trackOptions.group
|
|
37760
37885
|
});
|
|
37761
|
-
this._addedCounts.audio++;
|
|
37762
|
-
this._totalTrackCount++;
|
|
37763
37886
|
this.utilizedTracks.push(track);
|
|
37764
37887
|
this._outputTrackIds.push(outputTrackId);
|
|
37765
37888
|
this._outputOwnTrackGroups.push(ownGroup);
|
|
37766
37889
|
}
|
|
37767
37890
|
/** @internal */
|
|
37768
|
-
async _registerAudioSample(sample, source, outputTrackId, getLastSampleTimestamp) {
|
|
37891
|
+
async _registerAudioSample(pump, sample, source, outputTrackId, getLastSampleTimestamp) {
|
|
37769
37892
|
this._reportProgress(outputTrackId, sample.timestamp + sample.duration);
|
|
37770
37893
|
await source.add(sample);
|
|
37771
37894
|
sample.close();
|
|
@@ -37774,6 +37897,33 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37774
37897
|
if (this._synchronizer.shouldWait(outputTrackId, lastSampleTimestamp)) {
|
|
37775
37898
|
await this._synchronizer.wait(lastSampleTimestamp);
|
|
37776
37899
|
}
|
|
37900
|
+
await this._checkpoint(pump, lastSampleTimestamp);
|
|
37901
|
+
}
|
|
37902
|
+
}
|
|
37903
|
+
/** @internal */
|
|
37904
|
+
_registerTrackPump(fn) {
|
|
37905
|
+
const pump = {
|
|
37906
|
+
done: false,
|
|
37907
|
+
resolvers: promiseWithResolvers(),
|
|
37908
|
+
wake: null,
|
|
37909
|
+
start: () => {
|
|
37910
|
+
void fn(pump).then(() => {
|
|
37911
|
+
pump.done = true;
|
|
37912
|
+
pump.resolvers.resolve();
|
|
37913
|
+
}, (error) => {
|
|
37914
|
+
pump.resolvers.reject(error);
|
|
37915
|
+
});
|
|
37916
|
+
}
|
|
37917
|
+
};
|
|
37918
|
+
this._trackPumps.push(pump);
|
|
37919
|
+
}
|
|
37920
|
+
/** @internal */
|
|
37921
|
+
async _checkpoint(pump, timestamp) {
|
|
37922
|
+
while (this.state !== "canceled" && (timestamp >= this._executionUntil || this._pauseRequested)) {
|
|
37923
|
+
pump.resolvers.resolve();
|
|
37924
|
+
const { promise, resolve } = promiseWithResolvers();
|
|
37925
|
+
pump.wake = resolve;
|
|
37926
|
+
await promise;
|
|
37777
37927
|
}
|
|
37778
37928
|
}
|
|
37779
37929
|
/** @internal */
|
|
@@ -37803,10 +37953,11 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37803
37953
|
};
|
|
37804
37954
|
var MAX_TIMESTAMP_GAP = 1;
|
|
37805
37955
|
var TrackSynchronizer = class {
|
|
37806
|
-
constructor() {
|
|
37956
|
+
constructor(conversion) {
|
|
37807
37957
|
this.maxTimestamps = /* @__PURE__ */ new Map();
|
|
37808
37958
|
// Track ID -> timestamp
|
|
37809
37959
|
this.resolvers = [];
|
|
37960
|
+
this.conversion = conversion;
|
|
37810
37961
|
}
|
|
37811
37962
|
declareTrack(trackId) {
|
|
37812
37963
|
this.maxTimestamps.set(trackId, 0);
|
|
@@ -37816,6 +37967,9 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37816
37967
|
assert(currentValue !== void 0);
|
|
37817
37968
|
this.maxTimestamps.set(trackId, Math.max(timestamp, currentValue));
|
|
37818
37969
|
const newMin = this.computeMinAndMaybeResolve();
|
|
37970
|
+
if (this.conversion.state === "canceled" || this.conversion._pauseRequested || timestamp >= this.conversion._executionUntil) {
|
|
37971
|
+
return false;
|
|
37972
|
+
}
|
|
37819
37973
|
return timestamp - newMin > MAX_TIMESTAMP_GAP;
|
|
37820
37974
|
}
|
|
37821
37975
|
wait(timestamp) {
|
|
@@ -37830,6 +37984,12 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
|
|
|
37830
37984
|
this.maxTimestamps.delete(trackId);
|
|
37831
37985
|
this.computeMinAndMaybeResolve();
|
|
37832
37986
|
}
|
|
37987
|
+
resolveAll() {
|
|
37988
|
+
for (const entry of this.resolvers) {
|
|
37989
|
+
entry.resolve();
|
|
37990
|
+
}
|
|
37991
|
+
this.resolvers.length = 0;
|
|
37992
|
+
}
|
|
37833
37993
|
computeMinAndMaybeResolve() {
|
|
37834
37994
|
let newMin = Infinity;
|
|
37835
37995
|
for (const [, timestamp] of this.maxTimestamps) {
|