camera input select

This commit is contained in:
Michal Kolář
2023-01-31 11:59:40 +01:00
committed by Stanislav Fifik
parent b30273ede8
commit ba65d90627
2 changed files with 94 additions and 56 deletions

View File

@@ -1,56 +0,0 @@
import Node from './Node';
export default class Webcam extends Node {
constructor(options) {
super('Webcam', {}, {
image: {
type: 'Image'
},
width: {
type: 'Number',
},
height: {
type: 'Number',
}
});
this.start()
.catch(console.error.bind(console))
}
async start() {
const devices = (await navigator.mediaDevices.enumerateDevices()).filter((d) => d.kind === 'videoinput')
const last = (ary) => ary[ary.length - 1];
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: { min: 480, ideal: 1920, max: 1920 },
height: { min: 320, ideal: 1080, max: 1080 },
deviceId: last(devices).deviceId
},
});
/** @type {HTMLVideoElement} */
const video = document.createElement('video');
// @ts-ignore
video.playsinline = true;
video.srcObject = stream;
video.play();
let lastFrameTime = null;
const feedLoop = () => {
const currentTime = video.currentTime;
if (lastFrameTime !== currentTime) {
lastFrameTime = currentTime;
this.out.image.value = video;
this.out.width.value = video.videoWidth;
this.out.height.value = video.videoHeight;
}
if (!this._stopped) {
requestAnimationFrame(feedLoop);
} else {
video.src = null;
}
};
feedLoop();
}
}

94
src/nodes/Webcam.ts Normal file
View File

@@ -0,0 +1,94 @@
import Node from './Node';
import {last} from 'lodash/array';
import {find} from 'lodash/collection';
import {NumberVar, StringVar, ImageVar} from './io/AbstractIOSet';
const outputs = {
image: {
type: 'Image'
} as ImageVar,
width: {
type: 'Number',
} as NumberVar,
height: {
type: 'Number',
} as NumberVar,
camera: {
type: 'String',
enum: [],
} as StringVar
}
export default class Webcam extends Node<any, typeof outputs> {
devices: MediaDeviceInfo[];
currentDeviceId: string;
video: HTMLVideoElement
constructor(options) {
super('Webcam', {}, outputs);
this.start()
.catch(console.error.bind(console))
}
async start() {
this.devices = (await navigator.mediaDevices.enumerateDevices()).filter((d) => d.kind === 'videoinput');
this.out.camera.__definition.enum = this.devices.map(device => device.label)
const deviceId = last(this.devices).deviceId;
this.out.camera.value = this.getDeviceById(deviceId).label;
await this.startDevice(deviceId)
this.out.camera.onchange(async (label) => {
this.video = null;
const selectedDeviceId = this.getDeviceByLabel(label).deviceId;
await this.startDevice(selectedDeviceId)
})
}
private async startDevice(deviceId) {
this.currentDeviceId = deviceId;
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: { min: 480, ideal: 1920, max: 1920 },
height: { min: 320, ideal: 1080, max: 1080 },
deviceId
},
});
/** @type {HTMLVideoElement} */
this.video = document.createElement('video');
// @ts-ignore
this.video.playsinline = true;
this.video.srcObject = stream;
this.video.play();
let lastFrameTime = null;
const feedLoop = () => {
if (!this.video) {
return;
}
const currentTime = this.video.currentTime;
if (lastFrameTime !== currentTime) {
lastFrameTime = currentTime;
// @ts-ignore
this.out.image.value = this.video;
// @ts-ignore
this.out.width.value = this.video.videoWidth;
// @ts-ignore
this.out.height.value = this.video.videoHeight;
}
if (!this._stopped) {
requestAnimationFrame(feedLoop);
} else {
this.video.src = null;
}
};
feedLoop();
}
private getDeviceByLabel(label: string) {
return find(this.devices, device => device.label === label);
}
private getDeviceById(id: string) {
return find(this.devices, device => device.deviceId === id);
}
}