mirror of
https://github.com/GuerillaStudio/souvenir.git
synced 2025-01-20 15:50:20 +00:00
fix(preview/capture) flip with user facing camera
This commit is contained in:
parent
3c4652f6b0
commit
4b4c3bac1b
5 changed files with 69 additions and 28 deletions
|
@ -49,6 +49,10 @@
|
|||
content: none;
|
||||
}
|
||||
|
||||
.preview--flip {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.preview-visual {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
29
src/services/camera.js
Normal file
29
src/services/camera.js
Normal 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')
|
||||
}
|
|
@ -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', '')
|
||||
|
|
46
src/store.js
46
src/store.js
|
@ -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))
|
||||
|
||||
|
|
|
@ -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 () {
|
||||
|
|
Loading…
Reference in a new issue