Skip to content

Commit

Permalink
Add support for videoConstraints (#123)
Browse files Browse the repository at this point in the history
* Add support for videoConstraints

- Can be passed while starting the scan
- Added two new experimental APIs in `Html5Qrcode` class
 - getRunningTrackCapabilities() allows getting capabilities of a running stream
- applyVideoConstraints() allows setting constraints while the stream is running, doesn't support aspectRatio at the moment.

* Indent fixes
  • Loading branch information
mebjas authored Oct 11, 2020
1 parent b16b8d4 commit b396404
Show file tree
Hide file tree
Showing 7 changed files with 402 additions and 22 deletions.
50 changes: 50 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
### Version 1.2.3
- Added support for `videoConstraints` in config as an experimental config.
```js
/* videoConstraints: {MediaTrackConstraints}, Optional
* @beta(this config is not well supported yet).
*
* Important: When passed this will override other configurations
* like 'cameraIdOrConfig' or configurations like 'aspectRatio'.
*
* videoConstraints should be of type {@code MediaTrackConstraints}
* as defined in
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
* and is used to specify a variety of video or camera controls
* like: aspect ratio, facing mode, video frame rate.
*/
```
If passed this will override `cameraIdOrConfig` and `aspectRatio`.

- Added two new experimental APIs in `Html5Qrcode` class
- `getRunningTrackCapabilities()` - New
```js
/**
* Returns the capabilities of the running video track.
*
* @beta This is an experimental API
* @returns the capabilities of a running video track.
* @throws error if the scanning is not in running state.
*/
getRunningTrackCapabilities()
```
- `applyVideoConstraints(videoConstaints)` - New
```js
/**
* Apply a video constraints on running video track.
*
* Important:
* 1. Must be called only if the camera based scanning is in progress.
* 2. Changing aspectRatio while scanner is running is not yet supported.
*
* @beta This is an experimental API
* @param {MediaTrackConstraints} specifies a variety of video or camera
* controls as defined in
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
* @returns a Promise which succeeds if the passed constraints are applied,
* fails otherwise.
* @throws error if the scanning is not in running state.
*/
applyVideoConstraints(videoConstaints) {}
```

### Version 1.2.2
- Bug fix in `Html5QrcodeScanner` - file scanning.

Expand Down
2 changes: 1 addition & 1 deletion minified/html5-qrcode.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "html5-qrcode",
"version": "1.2.2",
"version": "1.2.3",
"description": "a cross platform HTML5 QR Code scanner",
"main": "html5-qrcode.js",
"scripts": {
Expand Down
11 changes: 11 additions & 0 deletions src/html5-qrcode-scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ class Html5QrcodeScanner {
* - disableFlip: Optional, if {@code true} flipped QR Code won't be
* scanned. Only use this if you are sure the camera cannot give
* mirrored feed if you are facing performance constraints.
* - videoConstraints: {MediaTrackConstraints}, Optional
* @beta(this config is not well supported yet).
*
* Important: When passed this will override other parameters
* like 'cameraIdOrConfig' or configurations like 'aspectRatio'.
*
* videoConstraints should be of type {@code MediaTrackConstraints}
* as defined in
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
* and is used to specify a variety of video or camera controls
* like: aspectRatio, facingMode, frameRate, etc.
* @param {Boolean} verbose - Optional argument, if true, all logs
* would be printed to console.
*/
Expand Down
165 changes: 160 additions & 5 deletions src/html5-qrcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,24 @@ class Html5Qrcode {
* - disableFlip: Optional, if {@code true} flipped QR Code won't be
* scanned. Only use this if you are sure the camera cannot give
* mirrored feed if you are facing performance constraints.
* - videoConstraints: {MediaTrackConstraints}, Optional
* @beta(this config is not well supported yet).
*
* Important: When passed this will override other parameters
* like 'cameraIdOrConfig' or configurations like 'aspectRatio'.
*
* videoConstraints should be of type {@code MediaTrackConstraints}
* as defined in
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
* and is used to specify a variety of video or camera controls
* like: aspectRatio, facingMode, frameRate, etc.
* @param {Function} qrCodeSuccessCallback callback on QR Code found.
* Example:
* function(qrCodeMessage) {}
* @param {Function} qrCodeErrorCallback callback on QR Code parse error.
* Example:
* function(errorMessage) {}
*
*
* @returns Promise for starting the scan. The Promise can fail if the user
* doesn't grant permission or some API is not supported by the browser.
*/
Expand Down Expand Up @@ -135,6 +146,20 @@ class Html5Qrcode {
const config = configuration ? configuration : {};
config.fps = config.fps ? config.fps : Html5Qrcode.SCAN_DEFAULT_FPS;

// Check if videoConstraints is passed and valid
let videoConstraintsAvailableAndValid = false;
if (config.videoConstraints) {
if (!this._isMediaStreamConstraintsValid(config.videoConstraints)) {
Html5Qrcode._logError(
"'videoConstraints' is not valid 'MediaStreamConstraints, "
+ "it will be ignored.'",
/* experimental= */ true);
} else {
videoConstraintsAvailableAndValid = true;
}
}
const videoConstraintsEnabled = videoConstraintsAvailableAndValid;

// qr shaded box
const isShadedBoxEnabled = config.qrbox != undefined;
const element = document.getElementById(this._elementId);
Expand Down Expand Up @@ -170,6 +195,7 @@ class Html5Qrcode {
const setupUi = (width, height) => {
const qrboxSize = config.qrbox;
if (qrboxSize > height) {
// TODO(mebjas): Migrate to common logging.
console.warn("[Html5Qrcode] config.qrboxsize is greater "
+ "than video height. Shading will be ignored");
}
Expand Down Expand Up @@ -300,7 +326,8 @@ class Html5Qrcode {
}

$this._localMediaStream = mediaStream;
if (!config.aspectRatio) {
// If videoConstraints is passed, ignore all other configs.
if (videoConstraintsEnabled || !config.aspectRatio) {
setupVideo();
} else {
const constraints = {
Expand All @@ -310,7 +337,11 @@ class Html5Qrcode {
track.applyConstraints(constraints)
.then(_ => setupVideo())
.catch(error => {
console.log("[Warning] [Html5Qrcode] Constriants could not be satisfied, ignoring constraints", error);
// TODO(mebjas): Migrate to common logging.
console.log(
"[Warning] [Html5Qrcode] Constriants could not "
+ "be satisfied, ignoring constraints",
error);
setupVideo();
});
}
Expand All @@ -320,8 +351,11 @@ class Html5Qrcode {

return new Promise((resolve, reject) => {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
const videoConstraints = $this._createVideoConstraints(
cameraIdOrConfig);
// Ignore all other video constraints if the videoConstraints
// is passed.
const videoConstraints = videoConstraintsEnabled
? config.videoConstraints
: $this._createVideoConstraints(cameraIdOrConfig);
navigator.mediaDevices.getUserMedia(
{
audio: false,
Expand Down Expand Up @@ -650,6 +684,77 @@ class Html5Qrcode {
});
}

/**
* Returns the capabilities of the running video track.
*
* @beta This is an experimental API
* @returns the capabilities of a running video track.
* @throws error if the scanning is not in running state.
*/
getRunningTrackCapabilities() {
if (this._localMediaStream == null) {
throw "Scanning is not in running state, call this API only when"
+ " QR code scanning using camera is in running state.";
}

if (this._localMediaStream.getVideoTracks().length == 0) {
throw "No video tracks found";
}

const videoTrack = this._localMediaStream.getVideoTracks()[0];
return videoTrack.getCapabilities();
}

/**
* Apply a video constraints on running video track from camera.
*
* Important:
* 1. Must be called only if the camera based scanning is in progress.
* 2. Changing aspectRatio while scanner is running is not yet supported.
*
* @beta This is an experimental API
* @param {MediaTrackConstraints} specifies a variety of video or camera
* controls as defined in
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
* @returns a Promise which succeeds if the passed constraints are applied,
* fails otherwise.
* @throws error if the scanning is not in running state.
*/
applyVideoConstraints(videoConstaints) {
if (!videoConstaints) {
throw "videoConstaints is required argument.";
} else if (!this._isMediaStreamConstraintsValid(videoConstaints)) {
throw "invalid videoConstaints passed, check logs for more details";
}

if (this._localMediaStream == null) {
throw "Scanning is not in running state, call this API only when"
+ " QR code scanning using camera is in running state.";
}

if (this._localMediaStream.getVideoTracks().length == 0) {
throw "No video tracks found";
}

return new Promise((resolve, reject) => {
if ("aspectRatio" in videoConstaints) {
reject("Chaning 'aspectRatio' in run-time is not yet "
+ "supported.");
return;
}
const videoTrack = this._localMediaStream.getVideoTracks()[0];
// TODO(mebjas): This can be simplified to just return the promise
// directly.
videoTrack.applyConstraints(videoConstaints)
.then(_ => {
resolve(_);
})
.catch(error => {
reject(error);
});
});
}

_clearElement() {
if (this._isScanning) {
throw 'Cannot clear while scan is ongoing, close it first.';
Expand Down Expand Up @@ -963,6 +1068,50 @@ class Html5Qrcode {
}
//#endregion

//#region private method to check for valid videoConstraints
_isMediaStreamConstraintsValid(videoConstraints) {
if (!videoConstraints) {
Html5Qrcode._logError(
"Empty videoConstraints", /* experimental= */ true);
return false;
}

if (typeof videoConstraints !== "object") {
const typeofVideoConstraints = typeof videoConstraints;
Html5Qrcode._logError(
"videoConstraints should be of type object, the "
+ `object passed is of type ${typeofVideoConstraints}.`,
/* experimental= */ true);
return false;
}
// TODO(mebjas): Make this validity check more sophisticuated
// Following keys are audio controls, audio controls are not supported.
const bannedKeys = [
"autoGainControl",
"channelCount",
"echoCancellation",
"latency",
"noiseSuppression",
"sampleRate",
"sampleSize",
"volume"
];
const bannedkeysSet = new Set(bannedKeys);
const keysInVideoConstraints = Object.keys(videoConstraints);
for (let i = 0; i < keysInVideoConstraints.length; i++) {
const key = keysInVideoConstraints[i];
if (bannedkeysSet.has(key)) {
Html5Qrcode._logError(
`${key} is not supported videoConstaints.`,
/* experimental= */ true);
return false;
}
}

return true;
}
//#endregion

static _getTimeoutFps(fps) {
return 1000 / fps;
}
Expand All @@ -972,4 +1121,10 @@ class Html5Qrcode {
console.log(message);
}
}

static _logError(message, experimental) {
if (Html5Qrcode.VERBOSE || experimental === true) {
console.error(message);
}
}
}
11 changes: 11 additions & 0 deletions transpiled/html5-qrcode-scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ var Html5QrcodeScanner = /*#__PURE__*/function () {
* - disableFlip: Optional, if {@code true} flipped QR Code won't be
* scanned. Only use this if you are sure the camera cannot give
* mirrored feed if you are facing performance constraints.
* - videoConstraints: {MediaTrackConstraints}, Optional
* @beta(this config is not well supported yet).
*
* Important: When passed this will override other parameters
* like 'cameraIdOrConfig' or configurations like 'aspectRatio'.
*
* videoConstraints should be of type {@code MediaTrackConstraints}
* as defined in
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
* and is used to specify a variety of video or camera controls
* like: aspectRatio, facingMode, frameRate, etc.
* @param {Boolean} verbose - Optional argument, if true, all logs
* would be printed to console.
*/
Expand Down
Loading

0 comments on commit b396404

Please sign in to comment.