mirror of
https://github.com/GuerillaStudio/souvenir.git
synced 2024-11-08 09:11:52 +00:00
refact(capture): rewrite with task
This commit is contained in:
parent
a2017f3f47
commit
1711911d62
4 changed files with 93 additions and 107 deletions
24
package-lock.json
generated
24
package-lock.json
generated
|
@ -3227,11 +3227,6 @@
|
|||
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
|
||||
"dev": true
|
||||
},
|
||||
"eventemitter3": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
|
||||
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA=="
|
||||
},
|
||||
"events": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
|
||||
|
@ -6076,18 +6071,11 @@
|
|||
"os-tmpdir": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"p-event": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz",
|
||||
"integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==",
|
||||
"requires": {
|
||||
"p-timeout": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
|
||||
"dev": true
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "2.0.0",
|
||||
|
@ -6115,14 +6103,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"p-timeout": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz",
|
||||
"integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==",
|
||||
"requires": {
|
||||
"p-finally": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"package-json": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
|
||||
|
|
|
@ -12,12 +12,10 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.4.3",
|
||||
"eventemitter3": "^3.1.0",
|
||||
"folktale": "^2.3.2",
|
||||
"generic-pool": "^3.6.1",
|
||||
"gif-writer": "^0.9.3",
|
||||
"objectFitPolyfill": "^2.1.1",
|
||||
"p-event": "^4.0.0",
|
||||
"postcss-modules": "^1.4.1",
|
||||
"vue": "^2.6.10",
|
||||
"vue-router": "^3.0.2",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import EventEmitter from 'eventemitter3'
|
||||
import pEvent from 'p-event'
|
||||
import { task, of as taskOf } from 'folktale/concurrency/task'
|
||||
import { makeRectangle, crop } from '/services/rectangle.js'
|
||||
|
||||
import {
|
||||
|
@ -8,52 +7,60 @@ import {
|
|||
GIF_FRAME_RATE
|
||||
} from '/constants.js'
|
||||
|
||||
export function capture ({ mediaStream, facingMode }, duration) {
|
||||
const emitter = new EventEmitter()
|
||||
|
||||
Promise.resolve().then(async () => {
|
||||
export function capture({ mediaStream, facingMode }, duration, progressCallback) {
|
||||
const delayTime = 1000 / GIF_FRAME_RATE
|
||||
const totalFrames = duration / 1000 * GIF_FRAME_RATE
|
||||
|
||||
// Well, this is a very low frame rate or very short duration clip
|
||||
if (totalFrames < 1) {
|
||||
emitter.emit('done', {
|
||||
return taskOf({
|
||||
imageWidth: GIF_WIDTH,
|
||||
imageHeight: GIF_HEIGHT,
|
||||
imageDataList: [],
|
||||
delayTime
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const imageDataList = []
|
||||
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = GIF_WIDTH
|
||||
canvas.height = GIF_HEIGHT
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
return task(resolver => {
|
||||
const video = document.createElement('video')
|
||||
video.setAttribute('playsinline', '')
|
||||
video.setAttribute('webkit-playsinline', '')
|
||||
video.srcObject = mediaStream
|
||||
video.play()
|
||||
|
||||
await pEvent(video, 'canplaythrough')
|
||||
video.addEventListener('canplaythrough', afterVideoAvailable, {
|
||||
once: true
|
||||
})
|
||||
|
||||
resolver.cleanup(() => {
|
||||
video.removeEventListener('canplaythrough', afterVideoAvailable)
|
||||
})
|
||||
|
||||
function afterVideoAvailable() {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = GIF_WIDTH
|
||||
canvas.height = GIF_HEIGHT
|
||||
|
||||
const canvasContext = canvas.getContext('2d')
|
||||
|
||||
if (facingMode === 'user' || facingMode === 'unknow') {
|
||||
canvasContext.translate(canvas.width, 0)
|
||||
canvasContext.scale(-1, 1)
|
||||
}
|
||||
|
||||
const imageDataList = []
|
||||
const destinationRectangle = makeRectangle(0, 0, canvas.width, canvas.height)
|
||||
const soureRectangle = crop(makeRectangle(0, 0, video.videoWidth, video.videoHeight))
|
||||
|
||||
step()
|
||||
|
||||
function step () {
|
||||
captureFrame()
|
||||
|
||||
const intervalId = setInterval(captureFrame, delayTime)
|
||||
|
||||
resolver.cleanup(() => {
|
||||
clearInterval(intervalId)
|
||||
})
|
||||
|
||||
function captureFrame () {
|
||||
canvasContext.drawImage(
|
||||
video,
|
||||
soureRectangle.x,
|
||||
|
@ -75,12 +82,10 @@ export function capture ({ mediaStream, facingMode }, duration) {
|
|||
|
||||
imageDataList.push(imageData)
|
||||
|
||||
emitter.emit('progress', imageDataList.length / totalFrames)
|
||||
progressCallback(imageDataList.length / totalFrames)
|
||||
|
||||
if (imageDataList.length < totalFrames) {
|
||||
setTimeout(step, delayTime)
|
||||
} else {
|
||||
emitter.emit('done', {
|
||||
if (imageDataList.length >= totalFrames) {
|
||||
resolver.resolve({
|
||||
imageDataList,
|
||||
imageWidth: GIF_WIDTH,
|
||||
imageHeight: GIF_HEIGHT,
|
||||
|
@ -88,8 +93,6 @@ export function capture ({ mediaStream, facingMode }, duration) {
|
|||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => emitter.emit('error', error))
|
||||
|
||||
return emitter
|
||||
}
|
|
@ -119,23 +119,28 @@ export default {
|
|||
},
|
||||
runCapture () {
|
||||
this.capturing = true
|
||||
const capturing = capture(this.camera, this.duration.selected * 1000)
|
||||
|
||||
capturing.once('error', error => {
|
||||
console.error(error)
|
||||
this.capturing = false
|
||||
this.capturingProgress = 0
|
||||
})
|
||||
|
||||
capturing.on('progress', value => {
|
||||
const captureExecution = capture(
|
||||
this.camera,
|
||||
this.duration.selected * 1000,
|
||||
value => {
|
||||
this.capturingProgress = value
|
||||
})
|
||||
}
|
||||
).run()
|
||||
|
||||
capturing.once('done', captureData => {
|
||||
const cleanup = () => {
|
||||
this.capturing = false
|
||||
this.capturingProgress = 0
|
||||
}
|
||||
|
||||
captureExecution.listen({
|
||||
onCancelled: cleanup,
|
||||
onRejected: cleanup,
|
||||
onResolved: (captureData) => {
|
||||
cleanup()
|
||||
this.$store.commit('updateCapture', captureData)
|
||||
this.$router.push({ name: 'preview' })
|
||||
}
|
||||
})
|
||||
},
|
||||
async ensureCamera () {
|
||||
|
|
Loading…
Reference in a new issue