Skip to content

Commit 0db0943

Browse files
committed
perf: reduce scan frequency when not tracking
When visual tracking is disabled it's not necessary to scan so frequently thus reducing expensive computation. See #39
1 parent c058df3 commit 0db0943

File tree

3 files changed

+41
-20
lines changed

3 files changed

+41
-20
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ methods: {
7474
```
7575
### `track` prop
7676

77-
By default detected QR codes are visually highlighted. A transparent canvas overlays the camera stream. When a QR code is detected, its location is painted to the canvas. You can enable/disable this feature by passing `true`/`false` via the `track` prop.
77+
By default detected QR codes are visually highlighted. A transparent canvas overlays the camera stream. When a QR code is detected, its location is painted to the canvas. You can enable/disable this feature by passing `true`/`false` via the `track` prop. If tracking is disabled the camera stream is scanned much less frequently. So if you encounter performance problems on your target device, this might help.
7878

79-
You can also pass a function to customize the way the location is painted. This function is called to produce each frame. It receives the location object as the first argument and a `CanvasRenderingContext2D` instance as the second argument.
79+
You can also pass a function with `track` to customize the way the location is painted. This function is called to produce each frame. It receives the location object as the first argument and a `CanvasRenderingContext2D` instance as the second argument.
8080

8181
:point_right: Avoid access to reactive properties in this function (like stuff in `data`, `computed` or your Vuex store). The function is called several times a second and might cause memory leaks. If you want to be save don't access `this` at all.
8282

@@ -155,6 +155,7 @@ This component uses [getUserMedia](https://developer.mozilla.org/en-US/docs/Web/
155155
facingMode: { ideal: 'environment' }, // use rear camera if available
156156
width: { min: 360, ideal: 680, max: 1920 }, // constrain video width resolution
157157
height: { min: 240, ideal: 480, max: 1080 }, // constrain video height resolution
158+
frameRate: { min: 10, ideal: 25 }
158159
}
159160
}
160161
```

src/components/QrcodeReader.vue

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ export default {
5858
this.readyAfterPause
5959
},
6060
61+
/**
62+
* Minimum delay in milliseconds between frames to be scanned. Don't scan
63+
* so often when visual tracking is disabled to improve performance.
64+
*/
65+
scanInterval () {
66+
if (this.track === false) {
67+
return 500
68+
} else {
69+
return 40 // ~ 25fps
70+
}
71+
},
72+
6173
/**
6274
* Full constraints object which is passed to `getUserMedia` to request a
6375
* camera stream. Properties define if a certain camera is adequate or not.
@@ -179,6 +191,7 @@ export default {
179191
decodeHandler: this.onDecode,
180192
locateHandler: this.onLocate,
181193
shouldContinue: () => this.shouldScan,
194+
minDelay: this.scanInterval,
182195
})
183196
},
184197

src/misc/Scanner.js

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,38 @@ export function keepScanning (camera, options) {
2727
decodeHandler,
2828
locateHandler,
2929
shouldContinue,
30-
scanInterval = 16, // milliseconds
30+
minDelay,
3131
} = options
3232

33-
const recur = (contentBefore, locationBefore) => {
34-
return () => {
35-
const imageData = camera.captureFrame()
36-
const { content, location } = scan(imageData)
33+
let contentBefore = null
34+
let locationBefore = null
35+
let lastScanned = performance.now()
3736

38-
if (content !== null && content !== contentBefore) {
39-
decodeHandler(content)
40-
}
37+
const processFrame = () => {
38+
if (shouldContinue()) {
39+
window.requestAnimationFrame(processFrame)
4140

42-
if (location !== locationBefore) {
43-
locateHandler(location)
44-
}
41+
const timeNow = performance.now()
42+
43+
if (timeNow - lastScanned >= minDelay) {
44+
lastScanned = timeNow
45+
46+
const imageData = camera.captureFrame()
47+
const { content, location } = scan(imageData)
48+
49+
if (content !== null && content !== contentBefore) {
50+
decodeHandler(content)
51+
}
52+
53+
if (location !== locationBefore) {
54+
locateHandler(location)
55+
}
4556

46-
if (shouldContinue()) {
47-
window.setTimeout(() => {
48-
window.requestAnimationFrame(
49-
recur(content || contentBefore, location)
50-
)
51-
}, scanInterval)
57+
contentBefore = content || contentBefore
58+
locationBefore = location
5259
}
5360
}
5461
}
5562

56-
window.requestAnimationFrame(recur(null, null))
63+
processFrame()
5764
}

0 commit comments

Comments
 (0)