mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-02 05:13:50 +02:00
Merge main into release for tag v1.24.3
This commit is contained in:
+1
-1
@@ -115,7 +115,7 @@
|
|||||||
return ctx.canvas;
|
return ctx.canvas;
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
width: 300,
|
//width: 300,
|
||||||
//alpha: 'keep',
|
//alpha: 'keep',
|
||||||
//width: 320,
|
//width: 320,
|
||||||
//discard: true,
|
//discard: true,
|
||||||
|
|||||||
+22
-3
@@ -14,6 +14,24 @@
|
|||||||
source: new Mediabunny.BlobSource(file),
|
source: new Mediabunny.BlobSource(file),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const videoTrack = await input.getPrimaryVideoTrack();
|
||||||
|
const sink = new Mediabunny.VideoSampleSink(videoTrack);
|
||||||
|
|
||||||
|
console.log(await videoTrack.getDecoderConfig())
|
||||||
|
|
||||||
|
const sink2 = new Mediabunny.EncodedPacketSink(videoTrack);
|
||||||
|
for await (const packet of sink2.packets()) {
|
||||||
|
console.log(packet.data.join(', '))//, window.findNalUnitsInLengthPrefixed(packet.data, 4).map(x => window.extractNalUnitTypeForAvc(x)));
|
||||||
|
if (packet.timestamp > 1) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//return;
|
||||||
|
|
||||||
|
for await (const sample of sink.samples()) {
|
||||||
|
console.log(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
let total = 0;
|
let total = 0;
|
||||||
input.source.onread = (start, end) => {
|
input.source.onread = (start, end) => {
|
||||||
total += end - start;
|
total += end - start;
|
||||||
@@ -22,6 +40,7 @@
|
|||||||
|
|
||||||
const videoTrack = await input.getPrimaryVideoTrack();
|
const videoTrack = await input.getPrimaryVideoTrack();
|
||||||
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
||||||
|
*/
|
||||||
|
|
||||||
//console.log(await sink.getPacket(0));
|
//console.log(await sink.getPacket(0));
|
||||||
/*
|
/*
|
||||||
@@ -38,7 +57,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const stats = await videoTrack.computePacketStats();
|
//const stats = await videoTrack.computePacketStats();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
||||||
@@ -47,9 +66,9 @@
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
//console.log(await videoTrack.computeDuration());
|
//console.log(await videoTrack.computeDuration());
|
||||||
console.log("Done", stats, total, file.size)
|
//console.log("Done", stats, total, file.size)
|
||||||
|
|
||||||
console.log(input);
|
//console.log(input);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const videoTrack = await input.getPrimaryVideoTrack();
|
const videoTrack = await input.getPrimaryVideoTrack();
|
||||||
|
|||||||
Generated
+6
-6
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.24.2",
|
"version": "1.24.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.24.2",
|
"version": "1.24.3",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@@ -7749,9 +7749,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mediabunny": {
|
"node_modules/mediabunny": {
|
||||||
"version": "1.24.1",
|
"version": "1.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.24.1.tgz",
|
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.24.2.tgz",
|
||||||
"integrity": "sha512-k7ki4KGgFE7F4XaUn0sDpPzdB8Hgms5Hq3QonzXyVSMh75oRuyjNhuAWJtAAlzs45gUerlIHZCvHd6/5H7duow==",
|
"integrity": "sha512-+H2Jha7D8C92F1fysdN+nmBBAOgVV+pNv/Pxc+c//qo2E/idnv8MsZrft7VJsFE5WjK30ESkwW5ezM0oceFIkg==",
|
||||||
"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.24.2",
|
"version": "1.24.3",
|
||||||
"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.24.2",
|
"version": "1.24.3",
|
||||||
"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.24.2",
|
"version": "1.24.3",
|
||||||
"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",
|
||||||
|
|||||||
+8
-4
@@ -1159,7 +1159,7 @@ export class MediaStreamVideoTrackSource extends VideoSource {
|
|||||||
type: 'videoTrack',
|
type: 'videoTrack',
|
||||||
trackId: this._workerTrackId,
|
trackId: this._workerTrackId,
|
||||||
track: this._track,
|
track: this._track,
|
||||||
}, [this._track]);
|
});
|
||||||
|
|
||||||
this._workerListener = (event: MessageEvent) => {
|
this._workerListener = (event: MessageEvent) => {
|
||||||
const message = event.data as MediaStreamTrackProcessorWorkerMessage;
|
const message = event.data as MediaStreamTrackProcessorWorkerMessage;
|
||||||
@@ -1978,17 +1978,19 @@ const mediaStreamTrackProcessorWorkerCode = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const abortControllers = new Map<number, AbortController>();
|
const abortControllers = new Map<number, AbortController>();
|
||||||
const stoppedTracks = new Set<number>();
|
const activeTracks = new Map<number, MediaStreamVideoTrack>();
|
||||||
|
|
||||||
self.addEventListener('message', (event) => {
|
self.addEventListener('message', (event) => {
|
||||||
const message = event.data as MediaStreamTrackProcessorControllerMessage;
|
const message = event.data as MediaStreamTrackProcessorControllerMessage;
|
||||||
|
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case 'videoTrack': {
|
case 'videoTrack': {
|
||||||
|
activeTracks.set(message.trackId, message.track);
|
||||||
|
|
||||||
const processor = new MediaStreamTrackProcessor({ track: message.track });
|
const processor = new MediaStreamTrackProcessor({ track: message.track });
|
||||||
const consumer = new WritableStream<VideoFrame>({
|
const consumer = new WritableStream<VideoFrame>({
|
||||||
write: (videoFrame) => {
|
write: (videoFrame) => {
|
||||||
if (stoppedTracks.has(message.trackId)) {
|
if (!activeTracks.has(message.trackId)) {
|
||||||
videoFrame.close();
|
videoFrame.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2026,7 +2028,9 @@ const mediaStreamTrackProcessorWorkerCode = () => {
|
|||||||
abortControllers.delete(message.trackId);
|
abortControllers.delete(message.trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
stoppedTracks.add(message.trackId);
|
const track = activeTracks.get(message.trackId);
|
||||||
|
track?.stop();
|
||||||
|
activeTracks.delete(message.trackId);
|
||||||
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
type: 'trackStopped',
|
type: 'trackStopped',
|
||||||
|
|||||||
+30
-6
@@ -234,11 +234,19 @@ export class BlobSource extends Source {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (worker.aborted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
this.onread?.(worker.currentPos, worker.currentPos + value.length);
|
this.onread?.(worker.currentPos, worker.currentPos + value.length);
|
||||||
this._orchestrator.supplyWorkerData(worker, value);
|
this._orchestrator.supplyWorkerData(worker, value);
|
||||||
} else {
|
} else {
|
||||||
const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer();
|
const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer();
|
||||||
|
|
||||||
|
if (worker.aborted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
this.onread?.(worker.currentPos, worker.currentPos + data.byteLength);
|
this.onread?.(worker.currentPos, worker.currentPos + data.byteLength);
|
||||||
this._orchestrator.supplyWorkerData(worker, new Uint8Array(data));
|
this._orchestrator.supplyWorkerData(worker, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
@@ -457,7 +465,7 @@ export class UrlSource extends Source {
|
|||||||
/** @internal */
|
/** @internal */
|
||||||
private async _runWorker(worker: ReadWorker) {
|
private async _runWorker(worker: ReadWorker) {
|
||||||
// The outer loop is for resuming a request if it dies mid-response
|
// The outer loop is for resuming a request if it dies mid-response
|
||||||
while (!worker.aborted) {
|
while (true) {
|
||||||
const existing = this._existingResponses.get(worker);
|
const existing = this._existingResponses.get(worker);
|
||||||
this._existingResponses.delete(worker);
|
this._existingResponses.delete(worker);
|
||||||
|
|
||||||
@@ -534,6 +542,10 @@ export class UrlSource extends Source {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (worker.aborted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const { done, value } = readResult;
|
const { done, value } = readResult;
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
@@ -552,6 +564,10 @@ export class UrlSource extends Source {
|
|||||||
this.onread?.(worker.currentPos, worker.currentPos + value.length);
|
this.onread?.(worker.currentPos, worker.currentPos + value.length);
|
||||||
this._orchestrator.supplyWorkerData(worker, value);
|
this._orchestrator.supplyWorkerData(worker, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (worker.aborted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.running = false;
|
worker.running = false;
|
||||||
@@ -796,6 +812,10 @@ export class StreamSource extends Source {
|
|||||||
let data = this._options.read(worker.currentPos, originalTargetPos);
|
let data = this._options.read(worker.currentPos, originalTargetPos);
|
||||||
if (data instanceof Promise) data = await data;
|
if (data instanceof Promise) data = await data;
|
||||||
|
|
||||||
|
if (worker.aborted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (data instanceof Uint8Array) {
|
if (data instanceof Uint8Array) {
|
||||||
data = toUint8Array(data); // Normalize things like Node.js Buffer to Uint8Array
|
data = toUint8Array(data); // Normalize things like Node.js Buffer to Uint8Array
|
||||||
|
|
||||||
@@ -833,6 +853,10 @@ export class StreamSource extends Source {
|
|||||||
throw new TypeError('ReadableStream returned by options.read must yield Uint8Array chunks.');
|
throw new TypeError('ReadableStream returned by options.read must yield Uint8Array chunks.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (worker.aborted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const data = toUint8Array(value); // Normalize things like Node.js Buffer to Uint8Array
|
const data = toUint8Array(value); // Normalize things like Node.js Buffer to Uint8Array
|
||||||
|
|
||||||
this.onread?.(worker.currentPos, worker.currentPos + data.length);
|
this.onread?.(worker.currentPos, worker.currentPos + data.length);
|
||||||
@@ -1420,7 +1444,10 @@ class ReadOrchestrator {
|
|||||||
currentPos: startPos,
|
currentPos: startPos,
|
||||||
targetPos,
|
targetPos,
|
||||||
running: false,
|
running: false,
|
||||||
aborted: false,
|
// Due to async shenanigans, it can happen that workers are started after disposal. In this case, instead of
|
||||||
|
// simply not creating the worker, we allow it to run but immediately label it as aborted, so it can then
|
||||||
|
// shut itself down.
|
||||||
|
aborted: this.disposed,
|
||||||
pendingSlices: [],
|
pendingSlices: [],
|
||||||
age: this.nextAge++,
|
age: this.nextAge++,
|
||||||
};
|
};
|
||||||
@@ -1473,10 +1500,7 @@ 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) {
|
assert(!worker.aborted);
|
||||||
// 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;
|
||||||
|
|||||||
@@ -139,17 +139,18 @@ test('Can encode transparent video', async () => {
|
|||||||
probeContext.drawImage(video, 0, 0);
|
probeContext.drawImage(video, 0, 0);
|
||||||
|
|
||||||
let imageData = probeContext.getImageData(0, 0, probeCanvas.width, probeCanvas.height);
|
let imageData = probeContext.getImageData(0, 0, probeCanvas.width, probeCanvas.height);
|
||||||
expect(imageData.data[3]).lessThanOrEqual(2); // Transparent (within error)
|
const index1 = (100 + 100 * probeCanvas.width) * 4;
|
||||||
|
expect(imageData.data[index1 + 3]).toBe(0); // Transparent
|
||||||
|
|
||||||
const pos = { x: 300, y: 300 }; // Dead center in the red square
|
const pos = { x: 300, y: 300 }; // Dead center in the red square
|
||||||
const index = (pos.x + pos.y * probeCanvas.width) * 4;
|
const index2 = (pos.x + pos.y * probeCanvas.width) * 4;
|
||||||
|
|
||||||
// Red (within error)
|
// Red (within error)
|
||||||
expect(imageData.data[index + 0]).greaterThanOrEqual(253);
|
expect(imageData.data[index2 + 0]).greaterThanOrEqual(253);
|
||||||
expect(imageData.data[index + 1]).lessThanOrEqual(2);
|
expect(imageData.data[index2 + 1]).lessThanOrEqual(2);
|
||||||
expect(imageData.data[index + 2]).lessThanOrEqual(2);
|
expect(imageData.data[index2 + 2]).lessThanOrEqual(2);
|
||||||
|
|
||||||
expect(imageData.data[index + 3]).greaterThanOrEqual(253); // Opaque (within error)
|
expect(imageData.data[index2 + 3]).toBe(255); // Opaque
|
||||||
|
|
||||||
// Let's also check it's read correctly by Mediabunny
|
// Let's also check it's read correctly by Mediabunny
|
||||||
using input = new Input({
|
using input = new Input({
|
||||||
@@ -169,7 +170,8 @@ test('Can encode transparent video', async () => {
|
|||||||
firstSample.draw(probeContext, 0, 0);
|
firstSample.draw(probeContext, 0, 0);
|
||||||
|
|
||||||
imageData = probeContext.getImageData(0, 0, probeCanvas.width, probeCanvas.height);
|
imageData = probeContext.getImageData(0, 0, probeCanvas.width, probeCanvas.height);
|
||||||
expect(imageData.data[3]).lessThanOrEqual(2); // Transparent (within error)
|
|
||||||
|
expect(imageData.data[3]).toBe(0); // Transparent
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Can encode video with alternating transparency', async () => {
|
test('Can encode video with alternating transparency', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user