fix(preview/capture) flip with user facing camera

This commit is contained in:
wryk 2019-03-22 17:30:04 +01:00
parent 3c4652f6b0
commit 4b4c3bac1b
5 changed files with 69 additions and 28 deletions

View file

@ -49,6 +49,10 @@
content: none;
}
.preview--flip {
transform: scaleX(-1);
}
.preview-visual {
position: absolute;
top: 0;

29
src/services/camera.js Normal file
View file

@ -0,0 +1,29 @@
export async function getCamera (shouldFaceUser) {
const facingModeList = shouldFaceUser
? ['user', 'environment']
: ['environment', 'user']
const [preferredFacingMode] = facingModeList
const constraintsList = [
...facingModeList.map(facingMode => ({ exact: facingMode })),
preferredFacingMode
].map(facingModeConstraint => ({ video: { facingMode: facingModeConstraint } }))
for (let constraints of constraintsList) {
try {
console.log(constraints)
return {
mediaStream: await navigator.mediaDevices.getUserMedia(constraints),
facingMode: constraints.video.facingMode.exact ? constraints.video.facingMode.exact : 'unknow'
}
} catch (error) {
console.log(error)
if (error.name !== 'OverconstrainedError' && error.constraint === 'facingMode') {
throw error
}
}
}
throw new Error('Overconstrained')
}

View file

@ -8,7 +8,7 @@ import {
GIF_FRAME_RATE
} from '/constants.js'
export function capture (mediaStream, duration) {
export function capture (mediaStream, duration, facingMode) {
const emitter = new EventEmitter()
Promise.resolve().then(async () => {
@ -33,9 +33,15 @@ export function capture (mediaStream, duration) {
canvas.width = GIF_WIDTH
canvas.height = GIF_HEIGHT
const canvasContext = canvas.getContext('2d')
const destinationRectangle = makeRectangle(0, 0, canvas.width, canvas.height)
const canvasContext = canvas.getContext('2d')
if (facingMode === 'user' || facingMode === 'unknow') {
canvasContext.translate(destinationRectangle.width, 0)
canvasContext.scale(-1, 1)
}
const video = document.createElement('video')
video.setAttribute('playsinline', '')
video.setAttribute('webkit-playsinline', '')

View file

@ -1,6 +1,7 @@
import Vue from 'vue'
import Vuex from 'vuex'
import { getCamera } from '/services/camera.js'
import { capture } from '/services/capture.js'
import { encode } from '/services/encode.js'
@ -11,6 +12,7 @@ export default new Vuex.Store({
state: {
welcomed: false,
mediaStream: null,
facingMode: null,
timer: {
selected: 2,
list: [2, 3, 5]
@ -34,8 +36,9 @@ export default new Vuex.Store({
updateWelcomed (state, welcome) {
state.welcomed = welcome
},
startCamera (state, mediaStream) {
startCamera (state, { mediaStream, facingMode }) {
state.mediaStream = mediaStream
state.facingMode = facingMode
},
stopCamera (state) {
if (state.mediaStream) {
@ -43,6 +46,10 @@ export default new Vuex.Store({
}
state.mediaStream = null
state.facingMode = null
},
updateFacingMode (state, facingMode) {
state.facingMode = facingMode
},
inverseFacingMode (state) {
state.capturing.shouldFaceUser = !state.capturing.shouldFaceUser
@ -84,37 +91,28 @@ export default new Vuex.Store({
}
},
actions: {
requestCamera ({ state, commit }, inverseFacingMode) {
async requestCamera ({ state, commit }, inverseFacingMode) {
commit('stopCamera')
const shouldFaceUser = inverseFacingMode
? !state.capturing.shouldFaceUser
: state.capturing.shouldFaceUser
const constraints = {
video: {
facingMode: shouldFaceUser ? 'user' : 'environment'
},
audio: false
try {
commit('startCamera', await getCamera(shouldFaceUser))
if (inverseFacingMode) {
commit('inverseFacingMode')
}
} catch (error) {
console.error(error)
window.alert('You haven\'t allowed to use your camera.\n\nOr maybe your browser is not compatible :(')
commit('updateWelcomed', false)
}
commit('stopCamera')
navigator.mediaDevices.getUserMedia(constraints)
.then(mediaStream => {
commit('startCamera', mediaStream)
if (inverseFacingMode) {
commit('inverseFacingMode')
}
})
.catch(error => {
console.error(error)
window.alert('You haven\'t allowed to use your camera.\n\nOr maybe your browser is not compatible :(')
commit('updateWelcomed', false)
})
},
capture ({ state, commit, dispatch }) {
commit('startCapture')
const capturing = capture(state.mediaStream, state.timer.selected * 1000)
const capturing = capture(state.mediaStream, state.timer.selected * 1000, state.facingMode)
capturing.once('error', error => console.error(error))

View file

@ -6,7 +6,7 @@
<capture-options v-else></capture-options>
<div class="preview">
<video ref="preview" class="preview-visual" preload="yes" autoplay muted playsinline webkit-playsinline></video>
<video ref="preview" class="preview-visual" :class="{ 'preview--flip': flipActive }" preload="yes" autoplay muted playsinline webkit-playsinline></video>
</div>
<button class="capture-btn" :class="{ 'capture-btn--capturing': capturing.status }" :disabled="!mediaStream" @click.prevent="startCapture">Capture</button>
@ -34,10 +34,14 @@ export default {
computed: {
...mapState([
'mediaStream',
'facingMode',
'capturing',
'timer',
'encoding'
])
]),
flipActive () {
return this.facingMode === 'user' || this.facingMode === 'unknow'
}
},
methods: {
startCapture () {