supervision 0.1.0 → 0.1.2
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/README.md +3 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +102 -12
- package/dist/index.js.map +1 -1
- package/dist/media/media-normalization.d.ts.map +1 -1
- package/dist/media/media-probe.d.ts.map +1 -1
- package/dist/renderers/media-frame-capture.d.ts +24 -0
- package/dist/renderers/media-frame-capture.d.ts.map +1 -0
- package/dist/renderers/media-renderer-core.d.ts.map +1 -1
- package/dist/renderers/media-renderer-scene.d.ts +6 -1
- package/dist/renderers/media-renderer-scene.d.ts.map +1 -1
- package/dist/renderers/pixi-media-scene.d.ts.map +1 -1
- package/dist/sessions/media-session.d.ts.map +1 -1
- package/dist/types/media-renderer.d.ts +44 -0
- package/dist/types/media-renderer.d.ts.map +1 -1
- package/dist/types/media-session.d.ts +9 -1
- package/dist/types/media-session.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,12 +8,11 @@ styling, interaction, and editing for images, video, and browser media streams.
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
10
10
|
```sh
|
|
11
|
-
npm install supervision
|
|
11
|
+
npm install supervision
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
The
|
|
15
|
-
|
|
16
|
-
its internal core dependency. Consumers import the public browser entrypoints:
|
|
14
|
+
The package includes its internal core dependency. Consumers import the public
|
|
15
|
+
browser entrypoints:
|
|
17
16
|
|
|
18
17
|
```ts
|
|
19
18
|
import { createMediaSession } from "supervision";
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { createImageUrlMediaSource, createStaticImageMediaSource, type HostFrame
|
|
|
15
15
|
export { createMediaStreamRendererSource, type MediaStreamRendererSourceOptions, } from "#media/media-stream-media-source";
|
|
16
16
|
export { createMediaRenderer } from "#renderers/media-renderer";
|
|
17
17
|
export { createMediaSession } from "#sessions/media-session";
|
|
18
|
+
export type { MediaFrameCapture, MediaFrameCaptureOptions, } from "#types/media-renderer";
|
|
18
19
|
export { BaseBoxStyle } from "supervision-js-core";
|
|
19
20
|
export type { BaseBoxStyleOptions } from "supervision-js-core";
|
|
20
21
|
export { BaseFocusStyle } from "supervision-js-core";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,oCAAoC,EAAE,MAAM,gDAAgD,CAAC;AACtG,OAAO,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,iCAAiC,EAAE,MAAM,4CAA4C,CAAC;AAC/F,OAAO,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,mCAAmC,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mCAAmC,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,kCAAkC,EAAE,MAAM,qBAAqB,CAAC;AAGzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,EACL,cAAc,EACd,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,YAAY,EACV,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,+BAA+B,EAC/B,KAAK,gCAAgC,GACtC,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -624,7 +624,7 @@ const DEFAULT_MEDIA_PROBE_TARGETS = [
|
|
|
624
624
|
},
|
|
625
625
|
];
|
|
626
626
|
async function probeMedia(source, options = {}) {
|
|
627
|
-
const { ALL_FORMATS, BlobSource, Input, canEncodeVideo } = await import('mediabunny');
|
|
627
|
+
const { ALL_FORMATS, BlobSource, Input, Quality, canEncodeVideo } = await import('mediabunny');
|
|
628
628
|
const input = new Input({
|
|
629
629
|
formats: ALL_FORMATS,
|
|
630
630
|
source: new BlobSource(source),
|
|
@@ -681,6 +681,7 @@ async function probeMedia(source, options = {}) {
|
|
|
681
681
|
const target = await selectMediaProbeTarget({
|
|
682
682
|
canEncodeVideo,
|
|
683
683
|
primaryVideo,
|
|
684
|
+
Quality,
|
|
684
685
|
targets: options.targets ?? DEFAULT_MEDIA_PROBE_TARGETS,
|
|
685
686
|
});
|
|
686
687
|
if (!target) {
|
|
@@ -719,8 +720,10 @@ async function selectMediaProbeTarget(options) {
|
|
|
719
720
|
for (const target of options.targets) {
|
|
720
721
|
const canEncode = await options.canEncodeVideo(target.videoCodec, {
|
|
721
722
|
...includeDefined({
|
|
722
|
-
bitrate: target.bitrate,
|
|
723
723
|
height: target.height ?? options.primaryVideo.height,
|
|
724
|
+
quality: target.bitrate === undefined
|
|
725
|
+
? undefined
|
|
726
|
+
: new options.Quality({ bitrate: target.bitrate }),
|
|
724
727
|
width: target.width ?? options.primaryVideo.width,
|
|
725
728
|
}),
|
|
726
729
|
});
|
|
@@ -751,7 +754,7 @@ const DEFAULT_KEY_FRAME_INTERVAL = 1;
|
|
|
751
754
|
const MEDIA_NORMALIZATION_ABORT_MESSAGE = "Media normalization was aborted.";
|
|
752
755
|
async function normalizeMedia(source, options = {}) {
|
|
753
756
|
throwIfAborted(options.signal);
|
|
754
|
-
const { ALL_FORMATS, BlobSource, BufferTarget, Conversion, Input, Mp4OutputFormat, Output, WebMOutputFormat, } = await import('mediabunny');
|
|
757
|
+
const { ALL_FORMATS, BlobSource, BufferTarget, Conversion, Input, Mp4OutputFormat, Output, Quality, WebMOutputFormat, } = await import('mediabunny');
|
|
755
758
|
const container = options.container ?? MediaNormalizationContainer.WebM;
|
|
756
759
|
const target = new BufferTarget();
|
|
757
760
|
const output = new Output({
|
|
@@ -770,12 +773,12 @@ async function normalizeMedia(source, options = {}) {
|
|
|
770
773
|
const inputMetadata = await collectInputMetadata(input, source);
|
|
771
774
|
throwIfAborted(options.signal);
|
|
772
775
|
conversion = await Conversion.init({
|
|
773
|
-
audio: buildAudioOptions(options.audio),
|
|
776
|
+
audio: buildAudioOptions(Quality, options.audio),
|
|
774
777
|
input,
|
|
775
778
|
output,
|
|
776
779
|
showWarnings: false,
|
|
777
780
|
tracks: "primary",
|
|
778
|
-
video: buildVideoOptions(container, options.video),
|
|
781
|
+
video: buildVideoOptions(Quality, container, options.video),
|
|
779
782
|
});
|
|
780
783
|
if (options.signal) {
|
|
781
784
|
abortConversion = () => {
|
|
@@ -825,7 +828,7 @@ async function normalizeMedia(source, options = {}) {
|
|
|
825
828
|
}
|
|
826
829
|
async function normalizeMediaProgressively(source, options = {}) {
|
|
827
830
|
throwIfAborted(options.signal);
|
|
828
|
-
const { ALL_FORMATS, AppendOnlyStreamTarget, BlobSource, Conversion, Input, Output, ReadableStreamSource, WEBM, WebMOutputFormat, } = await import('mediabunny');
|
|
831
|
+
const { ALL_FORMATS, AppendOnlyStreamTarget, BlobSource, Conversion, Input, Output, Quality, ReadableStreamSource, WEBM, WebMOutputFormat, } = await import('mediabunny');
|
|
829
832
|
const container = options.container ?? MediaNormalizationContainer.WebM;
|
|
830
833
|
if (container !== MediaNormalizationContainer.WebM) {
|
|
831
834
|
throw new Error("Progressive media normalization currently requires WebM.");
|
|
@@ -864,12 +867,12 @@ async function normalizeMediaProgressively(source, options = {}) {
|
|
|
864
867
|
target,
|
|
865
868
|
});
|
|
866
869
|
conversion = await Conversion.init({
|
|
867
|
-
audio: buildAudioOptions(options.audio),
|
|
870
|
+
audio: buildAudioOptions(Quality, options.audio),
|
|
868
871
|
input,
|
|
869
872
|
output,
|
|
870
873
|
showWarnings: false,
|
|
871
874
|
tracks: "primary",
|
|
872
|
-
video: buildVideoOptions(container, options.video),
|
|
875
|
+
video: buildVideoOptions(Quality, container, options.video),
|
|
873
876
|
});
|
|
874
877
|
if (!conversion.isValid) {
|
|
875
878
|
throw new Error(`Mediabunny conversion is invalid: ${formatDiscardedTracks(conversion.discardedTracks)}.`);
|
|
@@ -985,12 +988,14 @@ function isConversionAbortError(error, signal) {
|
|
|
985
988
|
return (signal?.aborted === true ||
|
|
986
989
|
(error instanceof Error && error.name === "ConversionCanceledError"));
|
|
987
990
|
}
|
|
988
|
-
function buildVideoOptions(container, options = {}) {
|
|
991
|
+
function buildVideoOptions(Quality, container, options = {}) {
|
|
989
992
|
return {
|
|
990
993
|
...includeDefined({
|
|
991
|
-
bitrate: options.bitrate,
|
|
992
994
|
fit: options.fit,
|
|
993
995
|
height: options.height,
|
|
996
|
+
quality: options.bitrate === undefined
|
|
997
|
+
? undefined
|
|
998
|
+
: new Quality({ bitrate: options.bitrate }),
|
|
994
999
|
width: options.width,
|
|
995
1000
|
}),
|
|
996
1001
|
codec: (options.codec ??
|
|
@@ -1002,12 +1007,14 @@ function buildVideoOptions(container, options = {}) {
|
|
|
1002
1007
|
keyFrameInterval: options.keyFrameInterval ?? DEFAULT_KEY_FRAME_INTERVAL,
|
|
1003
1008
|
};
|
|
1004
1009
|
}
|
|
1005
|
-
function buildAudioOptions(options = {}) {
|
|
1010
|
+
function buildAudioOptions(Quality, options = {}) {
|
|
1006
1011
|
return {
|
|
1007
1012
|
...includeDefined({
|
|
1008
|
-
bitrate: options.bitrate,
|
|
1009
1013
|
codec: options.codec,
|
|
1010
1014
|
numberOfChannels: options.numberOfChannels,
|
|
1015
|
+
quality: options.bitrate === undefined
|
|
1016
|
+
? undefined
|
|
1017
|
+
: new Quality({ bitrate: options.bitrate }),
|
|
1011
1018
|
sampleRate: options.sampleRate,
|
|
1012
1019
|
}),
|
|
1013
1020
|
discard: options.discard ?? true,
|
|
@@ -2406,6 +2413,15 @@ async function createMediaRendererCore(options, providers) {
|
|
|
2406
2413
|
runtimeState.recordPresentationUpdate(presentedSample);
|
|
2407
2414
|
}
|
|
2408
2415
|
},
|
|
2416
|
+
async captureFrame(captureOptions) {
|
|
2417
|
+
if (runtimeState.isDestroyed()) {
|
|
2418
|
+
throw new Error("Media renderer has been destroyed.");
|
|
2419
|
+
}
|
|
2420
|
+
if (!mediaScene?.captureFrame) {
|
|
2421
|
+
throw new Error("Media renderer is not ready.");
|
|
2422
|
+
}
|
|
2423
|
+
return mediaScene.captureFrame(captureOptions);
|
|
2424
|
+
},
|
|
2409
2425
|
getState() {
|
|
2410
2426
|
return runtimeState.snapshot();
|
|
2411
2427
|
},
|
|
@@ -2718,6 +2734,56 @@ function clampSeekTime(options) {
|
|
|
2718
2734
|
return Math.min(Math.max(mediaTime, startTime), endTime ?? mediaTime);
|
|
2719
2735
|
}
|
|
2720
2736
|
|
|
2737
|
+
/** Encoded image type used when a capture does not request one. */
|
|
2738
|
+
const DEFAULT_MEDIA_FRAME_CAPTURE_TYPE = "image/jpeg";
|
|
2739
|
+
/** Lossy encoder quality used when a capture does not request one. */
|
|
2740
|
+
const DEFAULT_MEDIA_FRAME_CAPTURE_QUALITY = 0.92;
|
|
2741
|
+
/**
|
|
2742
|
+
* Encodes media pixels a renderer has already presented.
|
|
2743
|
+
*
|
|
2744
|
+
* The presented pixels and their timestamp are copied synchronously before the
|
|
2745
|
+
* first await, so a frame presented while the encoder runs cannot change the
|
|
2746
|
+
* captured image or desynchronize it from `mediaTime`.
|
|
2747
|
+
*/
|
|
2748
|
+
async function captureCanvasMediaFrame(request) {
|
|
2749
|
+
const { height, width } = request.source;
|
|
2750
|
+
if (width <= 0 || height <= 0) {
|
|
2751
|
+
throw new Error("No media frame has been presented yet.");
|
|
2752
|
+
}
|
|
2753
|
+
const type = request.capture?.type ?? DEFAULT_MEDIA_FRAME_CAPTURE_TYPE;
|
|
2754
|
+
const quality = request.capture?.quality ?? DEFAULT_MEDIA_FRAME_CAPTURE_QUALITY;
|
|
2755
|
+
if (!Number.isFinite(quality) || quality < 0 || quality > 1) {
|
|
2756
|
+
throw new RangeError("quality must be a number between 0 and 1.");
|
|
2757
|
+
}
|
|
2758
|
+
const snapshot = request.createCanvas();
|
|
2759
|
+
snapshot.width = width;
|
|
2760
|
+
snapshot.height = height;
|
|
2761
|
+
const context = snapshot.getContext("2d");
|
|
2762
|
+
if (!context) {
|
|
2763
|
+
throw new Error("Unable to create a media frame capture context.");
|
|
2764
|
+
}
|
|
2765
|
+
context.drawImage(request.source, 0, 0);
|
|
2766
|
+
const blob = await encodeCanvas(snapshot, type, quality);
|
|
2767
|
+
return {
|
|
2768
|
+
blob,
|
|
2769
|
+
height,
|
|
2770
|
+
mediaTime: request.mediaTime,
|
|
2771
|
+
type: blob.type || type,
|
|
2772
|
+
width,
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
function encodeCanvas(canvas, type, quality) {
|
|
2776
|
+
return new Promise((resolve, reject) => {
|
|
2777
|
+
canvas.toBlob((blob) => {
|
|
2778
|
+
if (blob) {
|
|
2779
|
+
resolve(blob);
|
|
2780
|
+
return;
|
|
2781
|
+
}
|
|
2782
|
+
reject(new Error(`Unable to encode the presented media frame as ${type}.`));
|
|
2783
|
+
}, type, quality);
|
|
2784
|
+
});
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2721
2787
|
function resolveScreenLength(value, viewportScale) {
|
|
2722
2788
|
return value / Math.max(viewportScale, Number.EPSILON);
|
|
2723
2789
|
}
|
|
@@ -7792,6 +7858,11 @@ async function createPixiMediaScene(options) {
|
|
|
7792
7858
|
let viewportScale = 1;
|
|
7793
7859
|
const viewport = createViewportController({ scale: 1 });
|
|
7794
7860
|
let hasPresentedSample = false;
|
|
7861
|
+
/**
|
|
7862
|
+
* Timestamp of the sample whose pixels are on the staging canvas. Unlike
|
|
7863
|
+
* `currentMediaTime`, presentation and selection updates never move it.
|
|
7864
|
+
*/
|
|
7865
|
+
let presentedSampleTimestamp = null;
|
|
7795
7866
|
let baseFit;
|
|
7796
7867
|
const interactionLayer = options.interaction || options.editingEngine
|
|
7797
7868
|
? createPixiInteractionLayer({
|
|
@@ -8050,6 +8121,7 @@ async function createPixiMediaScene(options) {
|
|
|
8050
8121
|
hasPresentedSample = true;
|
|
8051
8122
|
if (!collectFrameTimings) {
|
|
8052
8123
|
sample.draw(stagingContext, 0, 0, mediaWidth, mediaHeight);
|
|
8124
|
+
presentedSampleTimestamp = sample.timestamp;
|
|
8053
8125
|
stagingTextureSource?.update();
|
|
8054
8126
|
stagingTexture?.update();
|
|
8055
8127
|
maskLayer?.drawFrame(sample.timestamp);
|
|
@@ -8076,6 +8148,7 @@ async function createPixiMediaScene(options) {
|
|
|
8076
8148
|
let focusMs = 0;
|
|
8077
8149
|
mediaUploadMs = measure(() => {
|
|
8078
8150
|
sample.draw(stagingContext, 0, 0, mediaWidth, mediaHeight);
|
|
8151
|
+
presentedSampleTimestamp = sample.timestamp;
|
|
8079
8152
|
stagingTextureSource?.update();
|
|
8080
8153
|
stagingTexture?.update();
|
|
8081
8154
|
});
|
|
@@ -8122,6 +8195,17 @@ async function createPixiMediaScene(options) {
|
|
|
8122
8195
|
sample.close();
|
|
8123
8196
|
}
|
|
8124
8197
|
},
|
|
8198
|
+
captureFrame(captureOptions) {
|
|
8199
|
+
if (presentedSampleTimestamp === null) {
|
|
8200
|
+
return Promise.reject(new Error("No media frame has been presented yet."));
|
|
8201
|
+
}
|
|
8202
|
+
return captureCanvasMediaFrame({
|
|
8203
|
+
capture: captureOptions,
|
|
8204
|
+
createCanvas: () => document.createElement("canvas"),
|
|
8205
|
+
mediaTime: presentedSampleTimestamp,
|
|
8206
|
+
source: stagingCanvas,
|
|
8207
|
+
});
|
|
8208
|
+
},
|
|
8125
8209
|
waitForRenderPreparation(mediaTime, gateOptions) {
|
|
8126
8210
|
return Promise.all([
|
|
8127
8211
|
maskLayer?.waitForRenderPreparation(mediaTime, gateOptions),
|
|
@@ -9340,6 +9424,12 @@ async function createMediaSession(options) {
|
|
|
9340
9424
|
refresh() {
|
|
9341
9425
|
return renderer.refresh();
|
|
9342
9426
|
},
|
|
9427
|
+
captureFrame(captureOptions) {
|
|
9428
|
+
if (destroyed) {
|
|
9429
|
+
throw new Error("Media session has been destroyed.");
|
|
9430
|
+
}
|
|
9431
|
+
return renderer.captureFrame(captureOptions);
|
|
9432
|
+
},
|
|
9343
9433
|
setPresentation(presentation) {
|
|
9344
9434
|
currentPresentation = presentation;
|
|
9345
9435
|
renderer.setPresentation(resolvePresentation(currentPresentation));
|