mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-10 09:13:47 +02:00
Automatically close new VideoFrames created by toCanvasImageSource, reduce clones in mediaSamplesAtTimestamps
This commit is contained in:
+15
-5
@@ -60,7 +60,16 @@
|
|||||||
6.933333333333334,
|
6.933333333333334,
|
||||||
7.039999999999999,
|
7.039999999999999,
|
||||||
7.1466666666666665,
|
7.1466666666666665,
|
||||||
7.253333333333333
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
|
7.253333333333333,
|
||||||
];
|
];
|
||||||
|
|
||||||
console.log(timestamps);
|
console.log(timestamps);
|
||||||
@@ -88,21 +97,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < 1000; i++) {
|
for (let i = 0; i < 40; i++) {
|
||||||
const count = Math.floor(50 * Math.random());
|
const count = Math.floor(50 * Math.random());
|
||||||
const timestamps = Array.from({ length: count }, () => Math.random() * 20).sort((a, b) => a-b);
|
const timestamps = Array.from({ length: count }, () => Math.random() * 20).sort((a, b) => a-b);
|
||||||
|
|
||||||
for await (const wrappedCanvas of sink.canvasesAtTimestamps(timestamps)) {
|
for await (const wrappedCanvas of sink.samplesAtTimestamps(timestamps)) {
|
||||||
//console.log(wrappedCanvas);
|
//console.log(wrappedCanvas);
|
||||||
|
wrappedCanvas.close()
|
||||||
}
|
}
|
||||||
console.log("don")
|
console.log("don")
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("DONE!")
|
console.log("DONE!")
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -328,6 +328,10 @@ videoSample.toCanvasImageSource(); // => VideoFrame | OffscreenCanvas;
|
|||||||
|
|
||||||
This method returns a valid `CanvasImageSource` you can use with [drawImage](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage).
|
This method returns a valid `CanvasImageSource` you can use with [drawImage](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage).
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
If this method returns a `VideoFrame`, you should use that frame immediately. This is because any internally-created video frames will automatically be closed in the next microtask.
|
||||||
|
:::
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Sometimes you may want direct access to the underlying pixel data. To do this, `VideoSample` allows you to copy this data into an `ArrayBuffer`.
|
Sometimes you may want direct access to the underlying pixel data. To do this, `VideoSample` allows you to copy this data into an `ArrayBuffer`.
|
||||||
|
|||||||
+7
-9
@@ -461,7 +461,6 @@ export abstract class BaseMediaSampleSink<
|
|||||||
// the consumer.
|
// the consumer.
|
||||||
let outOfBandError = null as Error | null;
|
let outOfBandError = null as Error | null;
|
||||||
|
|
||||||
let lastUsedSample = null as MediaSample | null;
|
|
||||||
const pushToQueue = (sample: MediaSample | null) => {
|
const pushToQueue = (sample: MediaSample | null) => {
|
||||||
sampleQueue.push(sample);
|
sampleQueue.push(sample);
|
||||||
onQueueNotEmpty();
|
onQueueNotEmpty();
|
||||||
@@ -479,19 +478,20 @@ export abstract class BaseMediaSampleSink<
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sampleUsed = false;
|
let sampleUses = 0;
|
||||||
while (
|
while (
|
||||||
timestampsOfInterest.length > 0
|
timestampsOfInterest.length > 0
|
||||||
&& sample.timestamp - timestampsOfInterest[0]! > -1e-10 // Give it a little epsilon
|
&& sample.timestamp - timestampsOfInterest[0]! > -1e-10 // Give it a little epsilon
|
||||||
) {
|
) {
|
||||||
pushToQueue(sample.clone() as MediaSample);
|
sampleUses++;
|
||||||
timestampsOfInterest.shift();
|
timestampsOfInterest.shift();
|
||||||
sampleUsed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sampleUsed) {
|
if (sampleUses > 0) {
|
||||||
lastUsedSample?.close();
|
for (let i = 0; i < sampleUses; i++) {
|
||||||
lastUsedSample = sample;
|
// Clone the sample if we need to emit it multiple times
|
||||||
|
pushToQueue((i < sampleUses - 1 ? sample.clone() : sample) as MediaSample);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sample.close();
|
sample.close();
|
||||||
}
|
}
|
||||||
@@ -601,7 +601,6 @@ export abstract class BaseMediaSampleSink<
|
|||||||
}
|
}
|
||||||
|
|
||||||
await flushDecoder();
|
await flushDecoder();
|
||||||
lastUsedSample?.close();
|
|
||||||
}
|
}
|
||||||
decoder.close();
|
decoder.close();
|
||||||
|
|
||||||
@@ -641,7 +640,6 @@ export abstract class BaseMediaSampleSink<
|
|||||||
for (const sample of sampleQueue) {
|
for (const sample of sampleQueue) {
|
||||||
sample?.close();
|
sample?.close();
|
||||||
}
|
}
|
||||||
lastUsedSample?.close();
|
|
||||||
|
|
||||||
return { value: undefined, done: true };
|
return { value: undefined, done: true };
|
||||||
},
|
},
|
||||||
|
|||||||
+10
-2
@@ -414,7 +414,12 @@ export class VideoSample {
|
|||||||
context.restore();
|
context.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts this video sample to a CanvasImageSource for drawing to a canvas. */
|
/**
|
||||||
|
* Converts this video sample to a CanvasImageSource for drawing to a canvas.
|
||||||
|
*
|
||||||
|
* You must use the value returned by this method immediately, as any VideoFrame created internally will
|
||||||
|
* automatically be closed in the next microtask.
|
||||||
|
*/
|
||||||
toCanvasImageSource() {
|
toCanvasImageSource() {
|
||||||
if (this._closed) {
|
if (this._closed) {
|
||||||
throw new Error('VideoSample is closed.');
|
throw new Error('VideoSample is closed.');
|
||||||
@@ -424,7 +429,10 @@ export class VideoSample {
|
|||||||
|
|
||||||
if (this._data instanceof Uint8Array) {
|
if (this._data instanceof Uint8Array) {
|
||||||
// Requires VideoFrame to be defined
|
// Requires VideoFrame to be defined
|
||||||
return this.toVideoFrame();
|
const videoFrame = this.toVideoFrame();
|
||||||
|
queueMicrotask(() => videoFrame.close()); // Let's automatically close the frame in the next microtask
|
||||||
|
|
||||||
|
return videoFrame;
|
||||||
} else {
|
} else {
|
||||||
return this._data;
|
return this._data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
- https://github.com/Vanilagy/mp4-muxer/issues/83 tell him it's possible now
|
- https://github.com/Vanilagy/mp4-muxer/issues/83 tell him it's possible now
|
||||||
- textsubtitlesource, chunked piping
|
- textsubtitlesource, chunked piping
|
||||||
- More efficient MP3 loading when reading sequentially
|
- More efficient MP3 loading when reading sequentially
|
||||||
- toCanvasImageSource might return a new videoframe; how to handle this?
|
|
||||||
Reference in New Issue
Block a user