diff --git a/src/views/step2.vue b/src/views/step2.vue index 6f01a7c..fb29394 100644 --- a/src/views/step2.vue +++ b/src/views/step2.vue @@ -168,8 +168,9 @@ async function videoUrlToBlob(videoUrl: string): Promise { return res.blob(); } -async function setupNativeRecorder() { - cameraReady.value = false; +type CameraFacing = 'front' | 'rear'; + +function getCameraPreviewLayout() { const vw = Math.round(window.innerWidth); const vh = Math.round(window.innerHeight); // 让预览按比例“contain”居中,避免满屏裁剪导致人脸变大 @@ -184,46 +185,58 @@ async function setupNativeRecorder() { const desiredCenterY = Math.round(vh * RETICLE_CENTER_Y); const pyRaw = Math.round(desiredCenterY - ph / 2); const py = Math.max(0, Math.min(vh - ph, pyRaw)); + return { pw, ph, px, py }; +} - await CameraPreview.start({ - parent: PREVIEW_ID, - toBack: true, - position: 'front', - enableVideoMode: true, - disableAudio: true, - // 不铺满:按比例居中显示(可能出现上下/左右留黑边) - aspectMode: 'contain', - width: pw, - height: ph, - x: px, - y: py, - storeToFile: true, - rotateWhenOrientationChanged: true, - force: true - }); +async function setupNativeRecorder() { + cameraReady.value = false; + const { pw, ph, px, py } = getCameraPreviewLayout(); + + const startPreviewAndRecord = async (position: CameraFacing) => { + await CameraPreview.start({ + parent: PREVIEW_ID, + toBack: true, + position, + enableVideoMode: true, + disableAudio: true, + // 不铺满:按比例居中显示(可能出现上下/左右留黑边) + aspectMode: 'contain', + width: pw, + height: ph, + x: px, + y: py, + storeToFile: true, + rotateWhenOrientationChanged: true, + force: true + }); + await CameraPreview.startRecordVideo({}); + }; + + let usedFacing: CameraFacing = 'front'; + try { + await startPreviewAndRecord('front'); + } catch (firstErr) { + console.warn('前置摄像头不可用,尝试后置:', firstErr); + try { + await CameraPreview.stop({ force: true }); + } catch { + /* ignore */ + } + await startPreviewAndRecord('rear'); + usedFacing = 'rear'; + } - await CameraPreview.startRecordVideo({}); started = true; isRecording.value = true; cameraReady.value = true; - statusText.value = '前置摄像头录制中'; + statusText.value ='前置摄像头录制中' + // 尺寸变化时同步更新原生预览,保持按比例居中 const onResize = async () => { if (!Capacitor.isNativePlatform() || released) return; try { - const vw = Math.round(window.innerWidth); - const vh = Math.round(window.innerHeight); - let pw = vw; - let ph = Math.round(pw * PREVIEW_ASPECT); - if (ph > vh) { - ph = vh; - pw = Math.round(ph / PREVIEW_ASPECT); - } - const px = Math.round((vw - pw) / 2); - const desiredCenterY = Math.round(vh * RETICLE_CENTER_Y); - const pyRaw = Math.round(desiredCenterY - ph / 2); - const py = Math.max(0, Math.min(vh - ph, pyRaw)); + const { pw, ph, px, py } = getCameraPreviewLayout(); await CameraPreview.setPreviewSize({ width: pw, height: ph,