2019-05-21 13:51:22 +00:00
|
|
|
import { task, of as taskOf } from 'folktale/concurrency/task'
|
2019-03-15 19:02:20 +00:00
|
|
|
import { makeRectangle, crop } from '/services/rectangle.js'
|
2019-03-15 18:25:36 +00:00
|
|
|
|
2019-03-15 18:07:26 +00:00
|
|
|
import {
|
|
|
|
GIF_WIDTH,
|
|
|
|
GIF_HEIGHT,
|
|
|
|
GIF_FRAME_RATE
|
|
|
|
} from '/constants.js'
|
|
|
|
|
2020-10-11 18:09:03 +00:00
|
|
|
export function capture ({ mediaStream, facingMode }, duration, progressCallback) {
|
2019-05-21 13:51:22 +00:00
|
|
|
const delayTime = 1000 / GIF_FRAME_RATE
|
|
|
|
const totalFrames = duration / 1000 * GIF_FRAME_RATE
|
2019-03-15 18:25:36 +00:00
|
|
|
|
2019-05-21 13:51:22 +00:00
|
|
|
if (totalFrames < 1) {
|
|
|
|
return taskOf({
|
|
|
|
imageWidth: GIF_WIDTH,
|
|
|
|
imageHeight: GIF_HEIGHT,
|
|
|
|
imageDataList: [],
|
|
|
|
delayTime
|
|
|
|
})
|
|
|
|
}
|
2019-03-15 19:02:20 +00:00
|
|
|
|
2019-05-21 13:51:22 +00:00
|
|
|
return task(resolver => {
|
|
|
|
const video = document.createElement('video')
|
|
|
|
video.setAttribute('playsinline', '')
|
|
|
|
video.setAttribute('webkit-playsinline', '')
|
|
|
|
video.srcObject = mediaStream
|
|
|
|
video.play()
|
2019-03-15 19:02:20 +00:00
|
|
|
|
2019-05-21 13:51:22 +00:00
|
|
|
video.addEventListener('canplaythrough', afterVideoAvailable, {
|
|
|
|
once: true
|
|
|
|
})
|
2019-03-15 19:02:20 +00:00
|
|
|
|
2019-05-21 13:51:22 +00:00
|
|
|
resolver.cleanup(() => {
|
|
|
|
video.removeEventListener('canplaythrough', afterVideoAvailable)
|
|
|
|
})
|
2019-03-10 04:37:22 +00:00
|
|
|
|
2020-10-11 18:09:03 +00:00
|
|
|
function afterVideoAvailable () {
|
2019-05-21 13:51:22 +00:00
|
|
|
const canvas = document.createElement('canvas')
|
|
|
|
canvas.width = GIF_WIDTH
|
|
|
|
canvas.height = GIF_HEIGHT
|
2019-03-10 04:37:22 +00:00
|
|
|
|
2019-05-21 13:51:22 +00:00
|
|
|
const canvasContext = canvas.getContext('2d')
|
2019-03-10 04:37:22 +00:00
|
|
|
|
2019-05-21 13:51:22 +00:00
|
|
|
if (facingMode === 'user' || facingMode === 'unknow') {
|
|
|
|
canvasContext.translate(canvas.width, 0)
|
|
|
|
canvasContext.scale(-1, 1)
|
|
|
|
}
|
2019-03-22 16:30:04 +00:00
|
|
|
|
2019-05-21 13:51:22 +00:00
|
|
|
const imageDataList = []
|
|
|
|
const destinationRectangle = makeRectangle(0, 0, canvas.width, canvas.height)
|
|
|
|
const soureRectangle = crop(makeRectangle(0, 0, video.videoWidth, video.videoHeight))
|
2019-03-22 16:30:04 +00:00
|
|
|
|
2019-05-21 13:51:22 +00:00
|
|
|
captureFrame()
|
|
|
|
|
|
|
|
const intervalId = setInterval(captureFrame, delayTime)
|
|
|
|
|
|
|
|
resolver.cleanup(() => {
|
|
|
|
clearInterval(intervalId)
|
|
|
|
})
|
|
|
|
|
|
|
|
function captureFrame () {
|
|
|
|
canvasContext.drawImage(
|
|
|
|
video,
|
|
|
|
soureRectangle.x,
|
|
|
|
soureRectangle.y,
|
|
|
|
soureRectangle.width,
|
|
|
|
soureRectangle.height,
|
|
|
|
destinationRectangle.x,
|
|
|
|
destinationRectangle.y,
|
|
|
|
destinationRectangle.width,
|
|
|
|
destinationRectangle.height
|
|
|
|
)
|
|
|
|
|
|
|
|
const imageData = canvasContext.getImageData(
|
|
|
|
destinationRectangle.x,
|
|
|
|
destinationRectangle.y,
|
|
|
|
destinationRectangle.width,
|
|
|
|
destinationRectangle.height
|
|
|
|
)
|
|
|
|
|
|
|
|
imageDataList.push(imageData)
|
|
|
|
|
|
|
|
progressCallback(imageDataList.length / totalFrames)
|
|
|
|
|
|
|
|
if (imageDataList.length >= totalFrames) {
|
|
|
|
resolver.resolve({
|
|
|
|
imageDataList,
|
|
|
|
imageWidth: GIF_WIDTH,
|
|
|
|
imageHeight: GIF_HEIGHT,
|
|
|
|
delayTime
|
|
|
|
})
|
|
|
|
}
|
2019-03-15 19:02:20 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-10 03:13:25 +00:00
|
|
|
})
|
2020-10-11 18:09:03 +00:00
|
|
|
}
|