Open PaloJeDobryClovek opened 3 years ago
Yeah, will write in a few days. Please ping me here if it takes too long.
You will made my day when you write example :)
Just to give a tip before we move on (I'm a little busy this week), you can add controls to the decodeFromVideoDevice
params so you have a strong reference to the controls variable inside the callback scope:
.decodeFromVideoDevice(undefined, video.current, function (result, error, controls) {
if (typeof result !== "undefined") {
controls.stop(); // stops the scanning
callback(result); // redirect on different page and not render this
}
})
You can also make use of decodeOnceFromVideoDevice
:
.decodeOnceFromVideoDevice(undefined, video.current, function (result, error) {
if (typeof result !== "undefined") {
callback(result); // redirect on different page and not render this
}
// the scanning proccess stops by itself after first successful decode
})
I'll try to create some working example soon, thanks for being patient!
Try
const controlsPromise = codeReader
.decodeFromVideoDevice(undefined, video.current, function (result, error) {
if (typeof result !== "undefined") {
callback(result); // redirect on different page and not render this
}
})
return function cleanup() {
console.log('clean');
controlsPromise.then(controls => controls.stop());
};
I ended up doing this
const mountedRef = useRef(true);
useEffect(() => {
mountedRef.current = true;
...
codeReader
.decodeFromVideoDevice(undefined, video.current, function (result, error, controls) {
if (mountedRef.current === false) {
controls.stop();
return;
}
if (typeof result !== "undefined") {
callback(result); // redirect on different page and not render this
}
})
return function cleanup() {
console.log('clean');
mountedRef.current = false;
};
You could do something like:
const mountedRef = useRef(true);
useEffect(() => {
mountedRef.current = true;
...
codeReader
.decodeFromVideoDevice(undefined, video.current, function (result, error, controls) {
if (mountedRef.current === false) {
controls.stop();
return;
}
if (typeof result !== "undefined") {
controls.stop(); // you only needed this to stop the scanner
callback(result); // redirect on different page and not render this
}
})
return function cleanup() {
console.log('clean');
mountedRef.current = false;
};
@odahcam you're right, the first controls.stop()
is to break the loop when a user does not do a scan and just head to some where else, and the second controls.stop()
is to break the loop when a user does do a scan. I was so into how to deal with the first case, so I left out the second one. Thanks!
Hi, is possible start again stopped IScannerControls
? Becauouse I dont see any method to use. Or just process pause loop ?
I have use case...scan code (pause scanner)...send request to server, if its correct redirect, if not continue in scanning. And I dont know how handle it correctly.
There's no way yet. It's actually very requested so I will create something about it soon. For now you can use controls.stop()
and then call codeReader.decodeFromVideoDevice(...)
again; I would suggest you create a wrapper function like startScanner()
around the codeReader.decodeFrom...()
call so you don't have to repeat it every time.
This is my workaround to stop video after scanning done without redirecting to different page.
function decodeOnce(selectedDeviceId) {
codeReader.decodeOnceFromVideoDevice(selectedDeviceId, 'video')
.then((result) => {
console.log(result)
setCode(result.text);
}).catch((err) => {
console.error(err)
}).then(() => {
video.current.srcObject.getTracks()[0].stop();
setTimeout(() => {
props.done(code); // Tell parent component to stop rendering
}, 1000);
});
}
I try everything it says here and in other topics and nothing works 100%. It works the first time, maybe the second time and then it doesn't work anymore until you refresh the page. Navigation handled by a react router, for example in NextJs, does not refresh the page so the camera is not released.
If I find a way that works 100% I'll come back with the solution
@mmalomo I had a similar issue only in Safari.
Using qrScanner.current.stop()
disabled scanning process but didn't affect camera's light on my laptop. Fortunately I spotted a difference in streams ids that I got from navigator.mediaDevices.getUserMedia({ video: true })
and videoRef.current.srcObject
.
Thus I decided to save stream
from getUserMedia
and use it to stop all the video tracks.
<script type="text/javascript">
window.addEventListener('load', async () => {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const codeReader = new ZXingBrowser.BrowserQRCodeReader();
const previewElem = document.querySelector('#video');
// undefined - takes 1st available camera
try {
const controls = await codeReader.decodeFromVideoDevice(undefined, previewElem, (result) => {
console.log('scan ...');
});
// stop after 1.5 sec
setTimeout(() => {
stream.getVideoTracks().forEach(track => track.stop());
controls.stop();
}, 1500);
} catch (error) {
console.warn(error);
}
});
</script>
In React I do this to stop scanning + camera's light.
streamRef.current.getVideoTracks().forEach((track) => track.stop());
qrScannerControls.current.stop();
Hello, I have in react component, when is render I want run scanner, if not stop scanning barcode.
but it now works correctly and after scan and render different page scanner still work, could you please write example in react?