-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathcapture-frames.js
119 lines (104 loc) · 2.72 KB
/
capture-frames.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { EventEmitter } from 'events'
import toBlob from 'data-uri-to-blob'
export default function (video, options, cb) {
if (typeof options == 'function') {
cb = options
options = {}
}
const opts = {
numFrames: options.numFrames || 10,
fps: options.fps || 5,
format: options.format || 'image/jpeg',
quality: options.quality || 0.92,
width: options.width || video.videoWidth,
height: options.height || video.videoHeight,
}
const frameDelay = 1000 / opts.fps
let canvas
let context
const frames = new Array(opts.numFrames)
const emitter = new EventEmitter()
let awaitingShot = opts.numFrames
let awaitingSave = opts.numFrames
let index = 0
const dimens = {
left: 0,
top: 0,
width: video.videoWidth,
height: video.videoHeight,
}
const targetAspect = opts.width / opts.height
const actualAspect = dimens.width / dimens.height
if (targetAspect > actualAspect) {
dimens.height = Math.round(dimens.width / targetAspect)
} else {
dimens.width = Math.round(dimens.height * targetAspect)
}
dimens.left = Math.floor((video.videoWidth - dimens.width) / 2)
dimens.top = Math.floor((video.videoHeight - dimens.height) / 2)
setTimeout(begin, 0)
return emitter
function begin() {
canvas = document.createElement('canvas')
canvas.width = opts.width
canvas.height = opts.height
context = canvas.getContext('2d')
emitter.emit('progress', 0.1)
captureFrame()
}
function captureFrame() {
let t
awaitingShot--
if (awaitingShot > 0) {
t = setTimeout(captureFrame, frameDelay)
}
;(function (i) {
try {
context.drawImage(
video,
dimens.left,
dimens.top,
dimens.width,
dimens.height,
0,
0,
canvas.width,
canvas.height,
)
} catch (err) {
if (t) clearTimeout(t)
if (cb) {
cb(err)
return
} else {
emitter.emit('error', err)
return
}
}
// + 2 because we want the progress to indicate what frame we are *taking*
if (i + 1 < opts.numFrames) {
emitter.emit('progress', (i + 2) / opts.numFrames)
}
compatToBlob(canvas, opts.format, opts.quality, function (blob) {
frames[i] = blob
awaitingSave--
maybeDone()
})
})(index++)
function maybeDone() {
if (awaitingSave) return
if (cb) {
cb(null, frames)
} else {
emitter.emit('done', frames)
}
}
}
}
function compatToBlob(canvas, format, opts, cb) {
if (canvas.toBlob) {
canvas.toBlob(cb, format, opts)
return
}
setTimeout(() => cb(toBlob(canvas.toDataURL(format, opts))), 0)
}