Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V2.3.2 #616

Merged
merged 14 commits into from
Nov 21, 2022
2 changes: 1 addition & 1 deletion minified/html5-qrcode.min.js

Large diffs are not rendered by default.

100 changes: 92 additions & 8 deletions src/camera/core-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,91 @@

import {
Camera,
CameraCapabilities,
CameraCapability,
CameraRenderingOptions,
RenderedCamera,
RenderingCallbacks
} from "./core";

/** Interface for a range value. */
interface RangeValue {
min: number;
max: number;
step: number;
}

/** Abstract camera capability class. */
abstract class AbstractCameraCapability implements CameraCapability {
protected readonly name: string;
protected readonly track: MediaStreamTrack;

constructor(name: string, track: MediaStreamTrack) {
this.name = name;
this.track = track;
}

public isSupported(): boolean {
return this.name in this.track.getCapabilities();
}

public min(): number {
return this.getCapabilities().min;
}

public max(): number {
return this.getCapabilities().max;
}

public step(): number {
return this.getCapabilities().step;
}

public apply(value: number): Promise<void> {
let constraint: any = {};
constraint[this.name] = value;
let constraints = {advanced: [ constraint ]};
return this.track.applyConstraints(constraints);
}

private getCapabilities(): RangeValue {
this.failIfNotSupported();
let capabilities: any = this.track.getCapabilities();
let capability: any = capabilities[this.name];
return {
min: capability.min,
max: capability.max,
step: capability.step,
};
}

private failIfNotSupported() {
if (!this.isSupported()) {
throw new Error(`${this.name} capability not supported`);
}
}
}

/** Zoom capability of a camera. */
class ZoomCamera extends AbstractCameraCapability {
constructor(track: MediaStreamTrack) {
super("zoom", track);
}
}

/** Implementation of {@link CameraCapabilities}. */
class CameraCapabilitiesImpl implements CameraCapabilities {
private readonly track: MediaStreamTrack;

constructor(track: MediaStreamTrack) {
this.track = track;
}

zoomFeature(): CameraCapability {
return new ZoomCamera(this.track);
}
}

/** Implementation of {@link RenderedCamera}. */
class RenderedCameraImpl implements RenderedCamera {

Expand Down Expand Up @@ -55,18 +135,18 @@ class RenderedCameraImpl implements RenderedCamera {
throw "RenderedCameraImpl video surface onerror() called";
};

this.surface.addEventListener("playing", () => this.onVideoStart());
let onVideoStart = () => {
const videoWidth = this.surface.clientWidth;
const videoHeight = this.surface.clientHeight;
this.callbacks.onRenderSurfaceReady(videoWidth, videoHeight);
this.surface.removeEventListener("playing", onVideoStart);
};

this.surface.addEventListener("playing", onVideoStart);
this.surface.srcObject = this.mediaStream;
this.surface.play();
}

private onVideoStart() {
const videoWidth = this.surface.clientWidth;
const videoHeight = this.surface.clientHeight;
this.callbacks.onRenderSurfaceReady(videoWidth, videoHeight);
this.surface.removeEventListener("playing", this.onVideoStart);
}

static async create(
parentElement: HTMLElement,
mediaStream: MediaStream,
Expand Down Expand Up @@ -177,6 +257,10 @@ class RenderedCameraImpl implements RenderedCamera {

});
}

getCapabilities(): CameraCapabilities {
return new CameraCapabilitiesImpl(this.getFirstTrackOrFail());
}
//#endregion
}

Expand Down
33 changes: 33 additions & 0 deletions src/camera/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,34 @@ export interface CameraDevice {
label: string;
}

//#region Features
/** Capability of the camera. */
export interface CameraCapability {
/** Returns {@code true} if the capability is supported by the camera. */
isSupported(): boolean;

/** Min value allowed for this capability. */
min(): number;

/** Max value allowed for this capability. */
max(): number;

/** Steps allowed for this capability. */
step(): number;

/** Apply the {@code value} to camera for this capability. */
apply(value: number): Promise<void>;
}

/** Class exposing different capabilities of camera. */
export interface CameraCapabilities {

/** Zoom capability of camera. */
zoomFeature(): CameraCapability;
}

//#endregion

/** Type for callback called when camera surface is ready. */
export type OnRenderSurfaceReady
= (viewfinderWidth: number, viewfinderHeight: number) => void;
Expand Down Expand Up @@ -102,6 +130,11 @@ export interface RenderedCamera {
* @throws error if {@link RenderedCamera} instance is already closed.
*/
applyVideoConstraints(constraints: MediaTrackConstraints): Promise<void>;

/**
* Returns all capabilities of the camera.
*/
getCapabilities(): CameraCapabilities;
}

/** Options for rendering camera feed. */
Expand Down
12 changes: 12 additions & 0 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,4 +320,16 @@ export class BaseLoggger implements Logger {
export function isNullOrUndefined(obj?: any) {
return (typeof obj === "undefined") || obj === null;
}

/** Clips the {@code value} between {@code minValue} and {@code maxValue}. */
export function clip(value: number, minValue: number, maxValue: number) {
mebjas marked this conversation as resolved.
Show resolved Hide resolved
if (value > maxValue) {
return maxValue;
}
if (value < minValue) {
return minValue;
}

return value;
}
//#endregion
Loading