Skip to content

Commit bc87ba8

Browse files
committed
perf: process frames in worker thread
Do expensive scanning of frames in web worker. Doesn't seem to improve tracking performance very much but certainly unburdons the UI thread leading to higher FPS especially on mobile.
1 parent 0e3f21e commit bc87ba8

File tree

5 files changed

+117
-50
lines changed

5 files changed

+117
-50
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
"vue-loader": "^10.0.0",
8080
"vue-template-compiler": "^2.1.6",
8181
"webpack": "^2.1.0-beta.28",
82-
"webpack-merge": "^1.1.2"
82+
"webpack-merge": "^1.1.2",
83+
"worker-loader": "^2.0.0"
8384
},
8485
"dependencies": {
8586
"babel-runtime": "^6.26.0",

src/components/QrcodeReader.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ export default {
265265
async onDropFile (file) {
266266
this.onDetect('file', (async () => {
267267
const imageData = await imageDataFromFile(file)
268-
const scanResult = Scanner.scan(imageData)
268+
const scanResult = await Scanner.scan(imageData)
269269
270270
return scanResult
271271
})())
@@ -274,7 +274,7 @@ export default {
274274
async onDropUrl (url) {
275275
this.onDetect('url', (async () => {
276276
const imageData = await imageDataFromUrl(url)
277-
const scanResult = Scanner.scan(imageData)
277+
const scanResult = await Scanner.scan(imageData)
278278
279279
return scanResult
280280
})())

src/misc/scanner.js

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
import 'webrtc-adapter'
2-
import jsQR from 'jsqr'
2+
import Worker from 'worker-loader?inline=true&fallback=false!./worker.js'
33

44
export function scan (imageData) {
5-
const { data, width, height } = imageData
6-
const result = jsQR(data, width, height)
5+
const worker = new Worker()
76

8-
let content, location
7+
return new Promise(resolve => {
8+
worker.onmessage = event => {
9+
resolve(event.data)
910

10-
if (result === null) {
11-
content = null
12-
location = null
13-
} else {
14-
content = result.data
15-
location = result.location
16-
}
11+
worker.terminate()
12+
}
1713

18-
return { content, location, imageData }
14+
worker.postMessage(imageData, [imageData.data.buffer])
15+
})
1916
}
2017

2118
/**
@@ -24,8 +21,8 @@ export function scan (imageData) {
2421
*/
2522
export function keepScanning (camera, options) {
2623
const {
27-
locateHandler,
2824
detectHandler,
25+
locateHandler,
2926
shouldContinue,
3027
minDelay,
3128
} = options
@@ -34,27 +31,46 @@ export function keepScanning (camera, options) {
3431
let locationBefore = null
3532
let lastScanned = performance.now()
3633

34+
const worker = new Worker()
35+
36+
// If worker can't process frames fast enough, memory will quickly full up.
37+
// Make sure to process only one frame at a time.
38+
let workerBusy = false
39+
40+
worker.onmessage = event => {
41+
workerBusy = false
42+
43+
const { content, location } = event.data
44+
45+
if (content !== null && content !== contentBefore) {
46+
detectHandler(event.data)
47+
}
48+
49+
if (location !== locationBefore) {
50+
locateHandler(location)
51+
}
52+
53+
contentBefore = content || contentBefore
54+
locationBefore = location
55+
}
56+
3757
const processFrame = timeNow => {
3858
if (shouldContinue()) {
3959
window.requestAnimationFrame(processFrame)
4060

4161
if (timeNow - lastScanned >= minDelay) {
4262
lastScanned = timeNow
4363

44-
const imageData = camera.captureFrame()
45-
const { content, location } = scan(imageData)
64+
if (workerBusy === false) {
65+
workerBusy = true
4666

47-
if (content !== contentBefore && content !== null) {
48-
detectHandler({ content, location, imageData })
49-
}
67+
const imageData = camera.captureFrame()
5068

51-
if (location !== locationBefore) {
52-
locateHandler(location)
69+
worker.postMessage(imageData, [imageData.data.buffer])
5370
}
54-
55-
contentBefore = content || contentBefore
56-
locationBefore = location
5771
}
72+
} else {
73+
worker.terminate()
5874
}
5975
}
6076

src/misc/worker.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import jsQR from 'jsqr'
2+
3+
self.addEventListener('message', function (event) {
4+
const imageData = event.data
5+
6+
const result = jsQR(
7+
imageData.data,
8+
imageData.width,
9+
imageData.height
10+
)
11+
12+
let content = null
13+
let location = null
14+
15+
if (result !== null) {
16+
content = result.data
17+
location = result.location
18+
}
19+
20+
const message = { content, location, imageData }
21+
22+
self.postMessage(message, [imageData.data.buffer])
23+
})

yarn.lock

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ ajv-keywords@^1.0.0, ajv-keywords@^1.1.1:
185185
version "1.5.1"
186186
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
187187

188+
ajv-keywords@^3.1.0:
189+
version "3.2.0"
190+
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a"
191+
188192
ajv@^4.7.0, ajv@^4.9.1:
189193
version "4.11.8"
190194
resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
@@ -210,6 +214,15 @@ ajv@^5.3.0:
210214
fast-json-stable-stringify "^2.0.0"
211215
json-schema-traverse "^0.3.0"
212216

217+
ajv@^6.1.0:
218+
version "6.5.3"
219+
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
220+
dependencies:
221+
fast-deep-equal "^2.0.1"
222+
fast-json-stable-stringify "^2.0.0"
223+
json-schema-traverse "^0.4.1"
224+
uri-js "^4.2.2"
225+
213226
align-text@^0.1.1, align-text@^0.1.3:
214227
version "0.1.4"
215228
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
@@ -2245,7 +2258,7 @@ debug@3.1.0, debug@^3.1.0:
22452258
dependencies:
22462259
ms "2.0.0"
22472260

2248-
debuglog@*, debuglog@^1.0.1:
2261+
debuglog@^1.0.1:
22492262
version "1.0.1"
22502263
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
22512264

@@ -3022,6 +3035,10 @@ fast-deep-equal@^1.0.0:
30223035
version "1.0.0"
30233036
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
30243037

3038+
fast-deep-equal@^2.0.1:
3039+
version "2.0.1"
3040+
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
3041+
30253042
fast-glob@^2.0.2:
30263043
version "2.2.2"
30273044
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.2.tgz#71723338ac9b4e0e2fff1d6748a2a13d5ed352bf"
@@ -3931,7 +3948,7 @@ import-lazy@^2.1.0:
39313948
version "2.1.0"
39323949
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
39333950

3934-
imurmurhash@*, imurmurhash@^0.1.4:
3951+
imurmurhash@^0.1.4:
39353952
version "0.1.4"
39363953
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
39373954

@@ -4466,6 +4483,10 @@ json-schema-traverse@^0.3.0:
44664483
version "0.3.1"
44674484
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
44684485

4486+
json-schema-traverse@^0.4.1:
4487+
version "0.4.1"
4488+
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
4489+
44694490
json-schema@0.2.3:
44704491
version "0.2.3"
44714492
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
@@ -4747,7 +4768,7 @@ loader-utils@^0.2.10, loader-utils@^0.2.15, loader-utils@^0.2.16, loader-utils@^
47474768
json5 "^0.5.0"
47484769
object-assign "^4.0.1"
47494770

4750-
loader-utils@^1.0.2:
4771+
loader-utils@^1.0.0, loader-utils@^1.0.2:
47514772
version "1.1.0"
47524773
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
47534774
dependencies:
@@ -4824,36 +4845,22 @@ lodash._basefor@^3.0.0:
48244845
version "3.0.3"
48254846
resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2"
48264847

4827-
lodash._baseindexof@*:
4828-
version "3.1.0"
4829-
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
4830-
48314848
lodash._baseuniq@~4.6.0:
48324849
version "4.6.0"
48334850
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
48344851
dependencies:
48354852
lodash._createset "~4.0.0"
48364853
lodash._root "~3.0.0"
48374854

4838-
lodash._bindcallback@*, lodash._bindcallback@^3.0.0:
4855+
lodash._bindcallback@^3.0.0:
48394856
version "3.0.1"
48404857
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
48414858

4842-
lodash._cacheindexof@*:
4843-
version "3.0.2"
4844-
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
4845-
4846-
lodash._createcache@*:
4847-
version "3.1.2"
4848-
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
4849-
dependencies:
4850-
lodash._getnative "^3.0.0"
4851-
48524859
lodash._createset@~4.0.0:
48534860
version "4.0.3"
48544861
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
48554862

4856-
lodash._getnative@*, lodash._getnative@^3.0.0:
4863+
lodash._getnative@^3.0.0:
48574864
version "3.9.1"
48584865
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
48594866

@@ -4968,10 +4975,6 @@ lodash.rest@^4.0.0:
49684975
version "4.0.5"
49694976
resolved "https://registry.yarnpkg.com/lodash.rest/-/lodash.rest-4.0.5.tgz#954ef75049262038c96d1fc98b28fdaf9f0772aa"
49704977

4971-
lodash.restparam@*:
4972-
version "3.6.1"
4973-
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
4974-
49754978
lodash.toarray@^4.4.0:
49764979
version "4.4.0"
49774980
resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
@@ -6778,6 +6781,10 @@ punycode@^1.2.4, punycode@^1.4.1:
67786781
version "1.4.1"
67796782
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
67806783

6784+
punycode@^2.1.0:
6785+
version "2.1.1"
6786+
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
6787+
67816788
q@1.4.1, q@^1.1.2:
67826789
version "1.4.1"
67836790
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
@@ -7017,7 +7024,7 @@ readable-stream@~1.0.2:
70177024
isarray "0.0.1"
70187025
string_decoder "~0.10.x"
70197026

7020-
readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0:
7027+
readdir-scoped-modules@^1.0.0:
70217028
version "1.0.2"
70227029
resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747"
70237030
dependencies:
@@ -7458,6 +7465,13 @@ schema-utils@^0.3.0:
74587465
dependencies:
74597466
ajv "^5.0.0"
74607467

7468+
schema-utils@^0.4.0:
7469+
version "0.4.7"
7470+
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"
7471+
dependencies:
7472+
ajv "^6.1.0"
7473+
ajv-keywords "^3.1.0"
7474+
74617475
scss-tokenizer@^0.2.3:
74627476
version "0.2.3"
74637477
resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
@@ -8450,6 +8464,12 @@ update-notifier@^2.3.0, update-notifier@^2.5.0:
84508464
semver-diff "^2.0.0"
84518465
xdg-basedir "^3.0.0"
84528466

8467+
uri-js@^4.2.2:
8468+
version "4.2.2"
8469+
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
8470+
dependencies:
8471+
punycode "^2.1.0"
8472+
84538473
urix@^0.1.0:
84548474
version "0.1.0"
84558475
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
@@ -8738,6 +8758,13 @@ worker-farm@^1.6.0:
87388758
dependencies:
87398759
errno "~0.1.7"
87408760

8761+
worker-loader@^2.0.0:
8762+
version "2.0.0"
8763+
resolved "https://registry.yarnpkg.com/worker-loader/-/worker-loader-2.0.0.tgz#45fda3ef76aca815771a89107399ee4119b430ac"
8764+
dependencies:
8765+
loader-utils "^1.0.0"
8766+
schema-utils "^0.4.0"
8767+
87418768
wrap-ansi@^2.0.0:
87428769
version "2.1.0"
87438770
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"

0 commit comments

Comments
 (0)