-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathencode.js
More file actions
135 lines (113 loc) · 2.7 KB
/
encode.js
File metadata and controls
135 lines (113 loc) · 2.7 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
var stream = require('readable-stream')
var Box = require('mp4-box-encoding')
var queueMicrotask = require('queue-microtask')
function noop () {}
class Encoder extends stream.Readable {
constructor (opts) {
super(opts)
this.destroyed = false
this._finalized = false
this._reading = false
this._stream = null
this._drain = null
this._want = false
this._onreadable = () => {
if (!this._want) return
this._want = false
this._read()
}
this._onend = () => {
this._stream = null
}
}
mdat (size, cb) {
this.mediaData(size, cb)
}
mediaData (size, cb) {
var stream = new MediaData(this)
this.box({ type: 'mdat', contentLength: size, encodeBufferLen: 8, stream: stream }, cb)
return stream
}
box (box, cb) {
if (!cb) cb = noop
if (this.destroyed) return cb(new Error('Encoder is destroyed'))
var buf
if (box.encodeBufferLen) {
buf = Buffer.alloc(box.encodeBufferLen)
}
if (box.stream) {
box.buffer = null
buf = Box.encode(box, buf)
this.push(buf)
this._stream = box.stream
this._stream.on('readable', this._onreadable)
this._stream.on('end', this._onend)
this._stream.on('end', cb)
this._forward()
} else {
buf = Box.encode(box, buf)
var drained = this.push(buf)
if (drained) return queueMicrotask(cb)
this._drain = cb
}
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
if (this._stream && this._stream.destroy) this._stream.destroy()
this._stream = null
if (this._drain) {
var cb = this._drain
this._drain = null
cb(err)
}
if (err) this.emit('error', err)
this.emit('close')
}
finalize () {
this._finalized = true
if (!this._stream && !this._drain) {
this.push(null)
}
}
_forward () {
if (!this._stream) return
while (!this.destroyed) {
var buf = this._stream.read()
if (!buf) {
this._want = !!this._stream
return
}
if (!this.push(buf)) return
}
}
_read () {
if (this._reading || this.destroyed) return
this._reading = true
if (this._stream) this._forward()
if (this._drain) {
var drain = this._drain
this._drain = null
drain()
}
this._reading = false
if (this._finalized) {
this.push(null)
}
}
}
class MediaData extends stream.PassThrough {
constructor (parent) {
super()
this._parent = parent
this.destroyed = false
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
this._parent.destroy(err)
if (err) this.emit('error', err)
this.emit('close')
}
}
module.exports = Encoder