bare-ffmpeg 1.0.0-0 → 1.0.0-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,14 +1,39 @@
1
- exports.Codec = require('./lib/codec')
2
- exports.CodecContext = require('./lib/codec-context')
3
- exports.CodecParameters = require('./lib/codec-parameters')
4
- exports.Decoder = require('./lib/decoder')
5
- exports.Encoder = require('./lib/encoder')
6
- exports.FormatContext = require('./lib/format-context')
7
- exports.Frame = require('./lib/frame')
8
- exports.Image = require('./lib/image')
9
- exports.IOContext = require('./lib/io-context')
10
- exports.Packet = require('./lib/packet')
11
- exports.Scaler = require('./lib/scaler')
12
- exports.Stream = require('./lib/stream')
1
+ const Codec = require('./lib/codec')
2
+ const CodecContext = require('./lib/codec-context')
3
+ const CodecParameters = require('./lib/codec-parameters')
4
+ const Decoder = require('./lib/decoder')
5
+ const Encoder = require('./lib/encoder')
6
+ const {
7
+ InputFormatContext,
8
+ OutputFormatContext
9
+ } = require('./lib/format-context')
10
+ const Frame = require('./lib/frame')
11
+ const Image = require('./lib/image')
12
+ const IOContext = require('./lib/io-context')
13
+ const InputFormat = require('./lib/input-format')
14
+ const OutputFormat = require('./lib/output-format')
15
+ const Packet = require('./lib/packet')
16
+ const Scaler = require('./lib/scaler')
17
+ const Stream = require('./lib/stream')
18
+ const Rational = require('./lib/rational')
19
+ const Dictionary = require('./lib/dictionary')
20
+
21
+ exports.Codec = Codec
22
+ exports.CodecContext = CodecContext
23
+ exports.CodecParameters = CodecParameters
24
+ exports.Decoder = Decoder
25
+ exports.Encoder = Encoder
26
+ exports.Frame = Frame
27
+ exports.IOContext = IOContext
28
+ exports.Image = Image
29
+ exports.InputFormat = InputFormat
30
+ exports.InputFormatContext = InputFormatContext
31
+ exports.OutputFormat = OutputFormat
32
+ exports.OutputFormatContext = OutputFormatContext
33
+ exports.Packet = Packet
34
+ exports.Scaler = Scaler
35
+ exports.Stream = Stream
36
+ exports.Rational = Rational
37
+ exports.Dictionary = Dictionary
13
38
 
14
39
  exports.constants = require('./lib/constants')
@@ -1,38 +1,84 @@
1
1
  const binding = require('../binding')
2
+ const ReferenceCounted = require('./reference-counted')
3
+ const Rational = require('./rational')
4
+
5
+ module.exports = class FFmpegCodecContext extends ReferenceCounted {
6
+ constructor(codec) {
7
+ super()
2
8
 
3
- module.exports = class FFmpegCodecContext {
4
- constructor(codec, parameters) {
5
9
  this._codec = codec
6
- this._handle = binding.initCodecContext(codec._handle, parameters._handle)
10
+ this._opened = false
11
+ this._handle = binding.initCodecContext(codec._handle)
12
+ }
13
+
14
+ _destroy() {
15
+ binding.destroyCodecContext(this._handle)
16
+ this._handle = null
7
17
  }
8
18
 
9
19
  get pixelFormat() {
10
20
  return binding.getCodecContextPixelFormat(this._handle)
11
21
  }
12
22
 
23
+ set pixelFormat(value) {
24
+ binding.setCodecContextPixelFormat(this._handle, value)
25
+ }
26
+
13
27
  get width() {
14
28
  return binding.getCodecContextWidth(this._handle)
15
29
  }
16
30
 
31
+ set width(value) {
32
+ binding.setCodecContextWidth(this._handle, value)
33
+ }
34
+
17
35
  get height() {
18
36
  return binding.getCodecContextHeight(this._handle)
19
37
  }
20
38
 
21
- destroy() {
22
- if (this._handle === null) return
23
- binding.destroyCodecContext(this._handle)
24
- this._handle = null
39
+ set height(value) {
40
+ binding.setCodecContextHeight(this._handle, value)
41
+ }
42
+
43
+ get timeBase() {
44
+ const view = new Int32Array(binding.getCodecContextTimeBase(this._handle))
45
+ return new Rational(view[0], view[1])
46
+ }
47
+
48
+ set timeBase(value) {
49
+ const view = new Int32Array(2)
50
+ view[0] = value.numerator
51
+ view[1] = value.denominator
52
+ binding.setCodecContextTimeBase(this._handle, view.buffer)
25
53
  }
26
54
 
27
- [Symbol.dispose]() {
28
- this.destroy()
55
+ open(options) {
56
+ if (this._opened) return
57
+ this._opened = true
58
+ if (options) {
59
+ binding.openCodecContextWithOptions(this._handle, options._handle)
60
+ } else {
61
+ binding.openCodecContext(this._handle)
62
+ }
63
+ return this
29
64
  }
30
65
 
31
66
  sendPacket(packet) {
32
67
  binding.sendCodecContextPacket(this._handle, packet._handle)
68
+ return this
69
+ }
70
+
71
+ receivePacket(packet) {
72
+ const res = binding.receiveCodecContextPacket(this._handle, packet._handle)
73
+ if (res) packet._ref()
74
+ return res
75
+ }
76
+
77
+ sendFrame(frame) {
78
+ return binding.sendCodecContextFrame(this._handle, frame._handle)
33
79
  }
34
80
 
35
81
  receiveFrame(frame) {
36
- binding.receiveCodecContextFrame(this._handle, frame._handle)
82
+ return binding.receiveCodecContextFrame(this._handle, frame._handle)
37
83
  }
38
84
  }
@@ -1,5 +1,38 @@
1
- module.exports = class FFmpegCodecParameters {
1
+ const binding = require('../binding')
2
+ const ReferenceCounted = require('./reference-counted')
3
+
4
+ module.exports = class FFmpegCodecParameters extends ReferenceCounted {
2
5
  constructor(handle) {
6
+ super()
7
+
3
8
  this._handle = handle
4
9
  }
10
+
11
+ _destroy() {
12
+ this._handle = null
13
+ }
14
+
15
+ get bitRate() {
16
+ return binding.getCodecParametersBitRate(this._handle)
17
+ }
18
+
19
+ get bitsPerCodedSample() {
20
+ return binding.getCodecParametersBitsPerCodedSample(this._handle)
21
+ }
22
+
23
+ get bitsPerRawSample() {
24
+ return binding.getCodecParametersBitsPerRawSample(this._handle)
25
+ }
26
+
27
+ get sampleRate() {
28
+ return binding.getCodecParametersSampleRate(this._handle)
29
+ }
30
+
31
+ fromContext(context) {
32
+ binding.codecParametersFromContext(this._handle, context._handle)
33
+ }
34
+
35
+ toContext(context) {
36
+ binding.codecParametersToContext(context._handle, this._handle)
37
+ }
5
38
  }
package/lib/codec.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const Decoder = require('./decoder')
2
2
  const Encoder = require('./encoder')
3
+ const constants = require('./constants')
3
4
 
4
5
  const codecs = new Map()
5
6
 
@@ -32,4 +33,7 @@ module.exports = class FFmpegCodec {
32
33
  }
33
34
  return codec
34
35
  }
36
+
37
+ static MJPEG = this.for(constants.codecs.MJPEG)
38
+ static H264 = this.for(constants.codecs.H264)
35
39
  }
package/lib/constants.js CHANGED
@@ -1,8 +1,25 @@
1
1
  const binding = require('../binding')
2
2
 
3
3
  module.exports = exports = {
4
+ codecs: {
5
+ MJPEG: binding.AV_CODEC_ID_MJPEG,
6
+ H264: binding.AV_CODEC_ID_H264
7
+ },
4
8
  pixelFormats: {
5
- RGBA: binding.AV_PIX_FMT_RGBA
9
+ RGBA: binding.AV_PIX_FMT_RGBA,
10
+ RGB24: binding.AV_PIX_FMT_RGB24,
11
+ YUVJ420P: binding.AV_PIX_FMT_YUVJ420P,
12
+ UYVY422: binding.AV_PIX_FMT_UYVY422,
13
+ YUV420P: binding.AV_PIX_FMT_YUV420P
14
+ },
15
+ mediaType: {
16
+ UNKNOWN: binding.AVMEDIA_TYPE_UNKNOWN,
17
+ VIDEO: binding.AVMEDIA_TYPE_VIDEO,
18
+ AUDIO: binding.AVMEDIA_TYPE_AUDIO,
19
+ DATA: binding.AVMEDIA_TYPE_DATA,
20
+ SUBTITLE: binding.AVMEDIA_TYPE_SUBTITLE,
21
+ ATTACHEMENT: binding.AVMEDIA_TYPE_ATTACHMENT,
22
+ NB: binding.AVMEDIA_TYPE_NB
6
23
  }
7
24
  }
8
25
 
@@ -0,0 +1,33 @@
1
+ const binding = require('../binding')
2
+ const ReferenceCounted = require('./reference-counted')
3
+
4
+ module.exports = class FFmpegDictionary extends ReferenceCounted {
5
+ constructor() {
6
+ super()
7
+
8
+ this._handle = binding.initDictionary()
9
+ }
10
+
11
+ _destroy() {
12
+ binding.destroyDictionary(this._handle)
13
+ this._handle = null
14
+ }
15
+
16
+ get(key) {
17
+ if (typeof key !== 'string' || key.length < 1) {
18
+ throw new TypeError(`Key should be a non empty string`)
19
+ }
20
+ return binding.getDictionaryEntry(this._handle, key)
21
+ }
22
+
23
+ set(key, value) {
24
+ if (typeof key !== 'string' || key.length < 1) {
25
+ throw new TypeError(`Key should be a non empty string`)
26
+ }
27
+
28
+ if (typeof value !== 'string' || value.length < 1) {
29
+ throw new TypeError(`Value should be a non empty string`)
30
+ }
31
+ binding.setDictionaryEntry(this._handle, key, value)
32
+ }
33
+ }
@@ -1,15 +1,26 @@
1
1
  const binding = require('../binding')
2
2
  const Stream = require('./stream.js')
3
+ const ReferenceCounted = require('./reference-counted')
4
+ const OutputFormat = require('./output-format')
5
+ const IOContext = require('./io-context')
6
+ const InputFormat = require('./input-format')
3
7
 
4
- module.exports = class FFmpegFormatContext {
8
+ class FFmpegFormatContext extends ReferenceCounted {
5
9
  constructor(io) {
6
- this._io = io
10
+ super()
11
+
12
+ this._io = io ? io._ref() : null
7
13
  this._streams = []
8
- this._handle = binding.initFormatContext(io._handle)
14
+ }
9
15
 
10
- for (const handle of binding.getFormatContextStreams(this._handle)) {
11
- this._streams.push(new Stream(handle))
16
+ _destroy() {
17
+ if (this._io) {
18
+ this._io._unref()
19
+ this._io = null
12
20
  }
21
+
22
+ for (const stream of this._streams) stream.destroy()
23
+ this._streams = []
13
24
  }
14
25
 
15
26
  get io() {
@@ -20,18 +31,109 @@ module.exports = class FFmpegFormatContext {
20
31
  return this._streams
21
32
  }
22
33
 
23
- destroy() {
24
- if (this._handle === null) return
25
- binding.destroyFormatContext(this._handle)
26
- this._io = null
34
+ readFrame(packet) {
35
+ if (packet._refs !== 0) {
36
+ throw new Error('Cannot read into packet with active references')
37
+ }
38
+
39
+ const result = binding.readFormatContextFrame(this._handle, packet._handle)
40
+ if (result) packet._ref()
41
+ return result
42
+ }
43
+
44
+ getBestStream(type) {
45
+ if (typeof type !== 'number') {
46
+ throw new TypeError(
47
+ `Type parameter should be of type number but got: ${typeof type}`
48
+ )
49
+ }
50
+
51
+ if (this._streams.length == 0) {
52
+ return null
53
+ }
54
+
55
+ const bestIndex = binding.getFormatContextBestStreamIndex(
56
+ this._handle,
57
+ type
58
+ )
59
+
60
+ if (bestIndex < 0 || bestIndex >= this._streams.length) {
61
+ return null
62
+ }
63
+
64
+ return this._streams[bestIndex]
65
+ }
66
+ }
67
+
68
+ let defaultURL = null
69
+
70
+ switch (Bare.platform) {
71
+ case 'darwin':
72
+ defaultURL = '0'
73
+ break
74
+ case 'linux':
75
+ // TODO: test on real machine
76
+ defaultURL = '/dev/video0'
77
+ break
78
+ case 'win32':
79
+ defaultURL = 'video=Integrated Camera'
80
+ break
81
+ }
82
+
83
+ exports.InputFormatContext = class FFmpegInputFormatContext extends (
84
+ FFmpegFormatContext
85
+ ) {
86
+ constructor(io, options, url = defaultURL) {
87
+ if (io instanceof IOContext) {
88
+ super(io)
89
+ this._handle = binding.openInputFormatContextWithIO(io._handle)
90
+ } else if (io instanceof InputFormat) {
91
+ super()
92
+ this._handle = binding.openInputFormatContextWithFormat(
93
+ io._handle,
94
+ options._handle,
95
+ url
96
+ )
97
+ }
98
+
99
+ for (const handle of binding.getFormatContextStreams(this._handle)) {
100
+ this._streams.push(new Stream(handle))
101
+ }
102
+ }
103
+
104
+ _destroy() {
105
+ super._destroy()
106
+
107
+ binding.closeInputFormatContext(this._handle)
27
108
  this._handle = null
28
109
  }
110
+ }
111
+
112
+ exports.OutputFormatContext = class FFmpegOutputFormatContext extends (
113
+ FFmpegFormatContext
114
+ ) {
115
+ constructor(format, io) {
116
+ super(io)
117
+
118
+ if (typeof format === 'string') format = new OutputFormat(format)
29
119
 
30
- [Symbol.dispose]() {
31
- this.destroy()
120
+ this._handle = binding.openOutputFormatContext(format._handle, io._handle)
32
121
  }
33
122
 
34
- readFrame(packet) {
35
- binding.readFormatContextFrame(this._handle, packet._handle)
123
+ _destroy() {
124
+ super._destroy()
125
+
126
+ binding.closeOutputFormatContext(this._handle)
127
+ this._handle = null
128
+ }
129
+
130
+ createStream(codec) {
131
+ const stream = new Stream(
132
+ binding.createFormatContextStream(this._handle, codec._handle)
133
+ )
134
+
135
+ this._streams.push(stream)
136
+
137
+ return stream
36
138
  }
37
139
  }
package/lib/frame.js CHANGED
@@ -1,17 +1,51 @@
1
1
  const binding = require('../binding')
2
+ const ReferenceCounted = require('./reference-counted')
2
3
 
3
- module.exports = class FFmpegFrame {
4
+ module.exports = class FFmpegFrame extends ReferenceCounted {
4
5
  constructor() {
6
+ super()
7
+
5
8
  this._handle = binding.initFrame()
6
9
  }
7
10
 
8
- destroy() {
9
- if (this._handle === null) return
11
+ _destroy() {
10
12
  binding.destroyFrame(this._handle)
11
13
  this._handle = null
12
14
  }
13
15
 
14
- [Symbol.dispose]() {
15
- this.destroy()
16
+ channel(i) {
17
+ if (i < 0 || i > 7) {
18
+ throw new RangeError(`Channel index must be between 0 and 7`)
19
+ }
20
+
21
+ return Buffer.from(binding.getFrameChannel(this._handle, i))
22
+ }
23
+
24
+ set width(value) {
25
+ binding.setFrameWidth(this._handle, value)
26
+ }
27
+
28
+ get width() {
29
+ return binding.getFrameWidth(this._handle)
30
+ }
31
+
32
+ set height(value) {
33
+ binding.setFrameHeight(this._handle, value)
34
+ }
35
+
36
+ get height() {
37
+ return binding.getFrameHeight(this._handle)
38
+ }
39
+
40
+ set pixelFormat(value) {
41
+ binding.setFramePixelFormat(this._handle, value)
42
+ }
43
+
44
+ get pixelFormat() {
45
+ return binding.getFramePixelFormat(this._handle)
46
+ }
47
+
48
+ alloc() {
49
+ binding.allocFrame(this._handle, 32)
16
50
  }
17
51
  }
@@ -0,0 +1,24 @@
1
+ const binding = require('../binding')
2
+
3
+ let defaultName = null
4
+
5
+ switch (Bare.platform) {
6
+ case 'darwin':
7
+ defaultName = 'avfoundation'
8
+ break
9
+ case 'linux':
10
+ defaultName = 'v4l2'
11
+ break
12
+ case 'win32':
13
+ defaultName = 'dshow'
14
+ break
15
+ }
16
+
17
+ module.exports = class FFmpegInputFormat {
18
+ constructor(name = defaultName) {
19
+ if (typeof name !== 'string' || name.length < 1) {
20
+ throw new TypeError('Input format name should be a non empty string')
21
+ }
22
+ this._handle = binding.initInputFormat(name)
23
+ }
24
+ }
package/lib/io-context.js CHANGED
@@ -1,17 +1,15 @@
1
1
  const binding = require('../binding')
2
+ const ReferenceCounted = require('./reference-counted')
3
+
4
+ module.exports = class FFmpegIOContext extends ReferenceCounted {
5
+ constructor(buffer = Buffer.alloc(0)) {
6
+ super()
2
7
 
3
- module.exports = class FFmpegIOContext {
4
- constructor(buffer) {
5
8
  this._handle = binding.initIOContext(buffer)
6
9
  }
7
10
 
8
- destroy() {
9
- if (this._handle === null) return
11
+ _destroy() {
10
12
  binding.destroyIOContext(this._handle)
11
13
  this._handle = null
12
14
  }
13
-
14
- [Symbol.dispose]() {
15
- this.destroy()
16
- }
17
15
  }
@@ -0,0 +1,7 @@
1
+ const binding = require('../binding')
2
+
3
+ module.exports = class FFmpegOutputFormat {
4
+ constructor(name) {
5
+ this._handle = binding.initOutputFormat(name)
6
+ }
7
+ }
package/lib/packet.js CHANGED
@@ -1,21 +1,42 @@
1
1
  const binding = require('../binding')
2
+ const ReferenceCounted = require('./reference-counted')
2
3
 
3
- module.exports = class FFmpegPacket {
4
- constructor() {
5
- this._handle = binding.initPacket()
4
+ module.exports = class FFmpegPacket extends ReferenceCounted {
5
+ constructor(buffer) {
6
+ super()
7
+
8
+ if (buffer) {
9
+ if (!Buffer.isBuffer(buffer)) {
10
+ throw TypeError(
11
+ `Buffer parameter should be of type Buffer but got: ${typeof buffer}`
12
+ )
13
+ }
14
+
15
+ this._handle = binding.initPacketFromBuffer(
16
+ buffer.buffer,
17
+ buffer.byteOffset,
18
+ buffer.byteLength
19
+ )
20
+ } else {
21
+ this._handle = binding.initPacket()
22
+ }
23
+ }
24
+
25
+ _destroy() {
26
+ binding.destroyPacket(this._handle)
27
+ this._handle = null
6
28
  }
7
29
 
8
30
  unref() {
31
+ this._unref()
9
32
  binding.unrefPacket(this._handle)
10
33
  }
11
34
 
12
- destroy() {
13
- if (this._handle === null) return
14
- binding.destroyPacket(this._handle)
15
- this._handle = null
35
+ get streamIndex() {
36
+ return binding.getPacketStreamIndex(this._handle)
16
37
  }
17
38
 
18
- [Symbol.dispose]() {
19
- this.destroy()
39
+ get data() {
40
+ return Buffer.from(binding.getPacketData(this._handle))
20
41
  }
21
42
  }
@@ -0,0 +1,6 @@
1
+ module.exports = class FFmpegRational {
2
+ constructor(numerator, denominator) {
3
+ this.numerator = numerator
4
+ this.denominator = denominator
5
+ }
6
+ }
@@ -0,0 +1,39 @@
1
+ module.exports = class FFmpegReferenceCounted {
2
+ constructor() {
3
+ this._refs = 0
4
+ this._destroyed = false
5
+ }
6
+
7
+ _ref() {
8
+ if (this._destroyed === false) this._refs++
9
+ return this
10
+ }
11
+
12
+ _unref() {
13
+ if (this._refs === 0) {
14
+ throw new Error('Cannot unreference object with no active references')
15
+ }
16
+
17
+ if (--this._refs === 0 && this._destroyed === true) this._destroy()
18
+ return this
19
+ }
20
+
21
+ _destroy() {}
22
+
23
+ destroy() {
24
+ if (this._refs !== 0) {
25
+ throw new Error('Cannot destroy object with active references')
26
+ }
27
+
28
+ if (this._destroyed === true) {
29
+ throw new Error('Object has already been destroyed')
30
+ }
31
+
32
+ this._destroyed = true
33
+ this._destroy()
34
+ }
35
+
36
+ [Symbol.dispose]() {
37
+ this.destroy()
38
+ }
39
+ }
package/lib/scaler.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const binding = require('../binding')
2
2
  const constants = require('./constants')
3
+ const ReferenceCounted = require('./reference-counted')
3
4
 
4
- module.exports = class FFmpegScaler {
5
+ module.exports = class FFmpegScaler extends ReferenceCounted {
5
6
  constructor(
6
7
  sourcePixelFormat,
7
8
  sourceWidth,
@@ -10,6 +11,8 @@ module.exports = class FFmpegScaler {
10
11
  targetWidth,
11
12
  targetHeight
12
13
  ) {
14
+ super()
15
+
13
16
  sourcePixelFormat = constants.toPixelFormat(sourcePixelFormat)
14
17
  targetPixelFormat = constants.toPixelFormat(targetPixelFormat)
15
18
 
@@ -30,16 +33,11 @@ module.exports = class FFmpegScaler {
30
33
  )
31
34
  }
32
35
 
33
- destroy() {
34
- if (this._handle === null) return
36
+ _destroy() {
35
37
  binding.destroyScaler(this._handle)
36
38
  this._handle = null
37
39
  }
38
40
 
39
- [Symbol.dispose]() {
40
- this.destroy()
41
- }
42
-
43
41
  scale(source, y, height, target) {
44
42
  if (typeof y !== 'number') {
45
43
  target = y