fix: improve front camera detection on macOS by checking video track label

This commit is contained in:
2026-02-28 18:04:28 +00:00
parent 4d572b55ca
commit 616f615d7c

View File

@@ -8,7 +8,7 @@ const scannedCodes = ref([])
const hasMultipleCameras = ref(false) const hasMultipleCameras = ref(false)
const isFullscreen = ref(false) const isFullscreen = ref(false)
const videoAspect = ref(1) const videoAspect = ref(1)
const isFront = computed(() => facingMode.value === 'user') const isMirrored = ref(false)
const wrapperRef = ref(null) const wrapperRef = ref(null)
const bgCanvas = ref(null) const bgCanvas = ref(null)
let bgRafId = null let bgRafId = null
@@ -65,7 +65,7 @@ const paintDetections = (codes) => {
} }
const scale = drawWidth / vw const scale = drawWidth / vw
const isMirrored = isFront.value // Canvas is mirrored via CSS if isMirrored is true, so no manual coordinate mirroring needed
// Styles // Styles
const styles = getComputedStyle(document.documentElement) const styles = getComputedStyle(document.documentElement)
@@ -84,10 +84,6 @@ const paintDetections = (codes) => {
const transform = (p) => { const transform = (p) => {
let x = p.x * scale + startX let x = p.x * scale + startX
let y = p.y * scale + startY let y = p.y * scale + startY
if (isMirrored) {
x = width - x
}
return { x, y } return { x, y }
} }
@@ -203,6 +199,23 @@ const startScan = async () => {
stream = await navigator.mediaDevices.getUserMedia(constraints) stream = await navigator.mediaDevices.getUserMedia(constraints)
// Detect actual facing mode to mirror front camera correctly
const videoTrack = stream.getVideoTracks()[0]
if (videoTrack) {
const settings = videoTrack.getSettings()
if (settings.facingMode) {
isMirrored.value = settings.facingMode === 'user'
} else {
// Fallback: check label for desktop cameras or assume requested mode
const label = videoTrack.label ? videoTrack.label.toLowerCase() : ''
if (label.includes('front') || label.includes('facetime') || label.includes('macbook')) {
isMirrored.value = true
} else {
isMirrored.value = facingMode.value === 'user'
}
}
}
if (videoRef.value) { if (videoRef.value) {
videoRef.value.srcObject = stream videoRef.value.srcObject = stream
// Wait for metadata to play // Wait for metadata to play
@@ -464,7 +477,7 @@ const isUrl = (string) => {
<div <div
class="camera-wrapper" class="camera-wrapper"
:class="{ 'clickable': !isFullscreen, 'is-front': isFront }" :class="{ 'clickable': !isFullscreen, 'is-mirrored': isMirrored }"
:style="desktopFullscreenStyle" :style="desktopFullscreenStyle"
ref="wrapperRef" ref="wrapperRef"
@click="!isFullscreen && toggleFullscreen()" @click="!isFullscreen && toggleFullscreen()"
@@ -472,13 +485,13 @@ const isUrl = (string) => {
<video <video
ref="videoRef" ref="videoRef"
class="camera-feed" class="camera-feed"
:class="{ 'is-front': isFront }" :class="{ 'is-mirrored': isMirrored }"
autoplay autoplay
playsinline playsinline
muted muted
></video> ></video>
<canvas ref="overlayCanvas" class="scan-overlay-canvas"></canvas> <canvas ref="overlayCanvas" class="scan-overlay-canvas" :class="{ 'is-mirrored': isMirrored }"></canvas>
<div v-if="error" class="error-overlay"> <div v-if="error" class="error-overlay">
<p>{{ error }}</p> <p>{{ error }}</p>
@@ -632,7 +645,7 @@ const isUrl = (string) => {
display: block; display: block;
} }
.camera-feed.is-front { .camera-feed.is-mirrored {
transform: scaleX(-1); transform: scaleX(-1);
} }
@@ -646,6 +659,10 @@ const isUrl = (string) => {
z-index: 5; z-index: 5;
} }
.scan-overlay-canvas.is-mirrored {
transform: scaleX(-1);
}
/* front mirror canvas removed */ /* front mirror canvas removed */
.error-overlay { .error-overlay {