bare-ffmpeg 1.0.0-3 → 1.0.0-31

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.
Files changed (51) hide show
  1. package/CMakeLists.txt +10 -3
  2. package/README.md +1811 -0
  3. package/binding.cc +4638 -0
  4. package/cmake/ports/ffmpeg/port.cmake +514 -0
  5. package/cmake/ports/opus/patches/01-windows-clang.patch +52 -0
  6. package/cmake/ports/opus/port.cmake +42 -0
  7. package/cmake/ports/svt-av1/port.cmake +42 -0
  8. package/cmake/ports/x264/patches/01-windows-clang.patch +33 -0
  9. package/cmake/ports/x264/port.cmake +157 -0
  10. package/index.js +22 -4
  11. package/lib/audio-fifo.js +47 -0
  12. package/lib/channel-layout.js +35 -0
  13. package/lib/codec-context.js +210 -16
  14. package/lib/codec-parameters.js +242 -8
  15. package/lib/codec.js +19 -1
  16. package/lib/constants.js +245 -9
  17. package/lib/dictionary.js +28 -15
  18. package/lib/errors.js +38 -0
  19. package/lib/filter-context.js +7 -0
  20. package/lib/filter-graph.js +47 -0
  21. package/lib/filter-inout.js +55 -0
  22. package/lib/filter.js +7 -0
  23. package/lib/format-context.js +72 -31
  24. package/lib/frame.js +88 -22
  25. package/lib/image.js +22 -0
  26. package/lib/input-format.js +36 -4
  27. package/lib/io-context.js +36 -6
  28. package/lib/log.js +16 -0
  29. package/lib/output-format.js +33 -2
  30. package/lib/packet.js +153 -12
  31. package/lib/rational.js +49 -1
  32. package/lib/resampler.js +63 -0
  33. package/lib/samples.js +96 -0
  34. package/lib/scaler.js +8 -7
  35. package/lib/stream.js +58 -14
  36. package/package.json +9 -4
  37. package/prebuilds/android-arm/bare-ffmpeg.bare +0 -0
  38. package/prebuilds/android-arm64/bare-ffmpeg.bare +0 -0
  39. package/prebuilds/android-ia32/bare-ffmpeg.bare +0 -0
  40. package/prebuilds/android-x64/bare-ffmpeg.bare +0 -0
  41. package/prebuilds/darwin-arm64/bare-ffmpeg.bare +0 -0
  42. package/prebuilds/darwin-x64/bare-ffmpeg.bare +0 -0
  43. package/prebuilds/ios-arm64/bare-ffmpeg.bare +0 -0
  44. package/prebuilds/ios-arm64-simulator/bare-ffmpeg.bare +0 -0
  45. package/prebuilds/ios-x64-simulator/bare-ffmpeg.bare +0 -0
  46. package/prebuilds/linux-arm64/bare-ffmpeg.bare +0 -0
  47. package/prebuilds/linux-x64/bare-ffmpeg.bare +0 -0
  48. package/prebuilds/win32-arm64/bare-ffmpeg.bare +0 -0
  49. package/prebuilds/win32-x64/bare-ffmpeg.bare +0 -0
  50. package/binding.c +0 -2203
  51. package/lib/reference-counted.js +0 -39
package/lib/packet.js CHANGED
@@ -1,17 +1,45 @@
1
1
  const binding = require('../binding')
2
- const ReferenceCounted = require('./reference-counted')
2
+ const Rational = require('./rational')
3
3
 
4
- module.exports = class FFmpegPacket extends ReferenceCounted {
5
- constructor(buffer) {
6
- super()
4
+ class SideData {
5
+ constructor(handle, opts = {}) {
6
+ this._handle = handle
7
+ this._type = opts.type || null
8
+ this._data = opts.data || null
9
+ }
7
10
 
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
- }
11
+ static fromData(data, type) {
12
+ return new SideData(null, { data, type })
13
+ }
14
+
15
+ get type() {
16
+ if (this._type) return this._type
17
+ return binding.getSideDataType(this._handle)
18
+ }
19
+
20
+ get name() {
21
+ if (!this._handle) return null
22
+ return binding.getSideDataName(this._handle)
23
+ }
24
+
25
+ get data() {
26
+ if (this._data) return this._data
27
+ return Buffer.from(binding.getSideDataBuffer(this._handle))
28
+ }
29
+
30
+ [Symbol.for('bare.inspect')]() {
31
+ return {
32
+ __proto__: { constructor: SideData },
33
+ type: this.type,
34
+ name: this.name,
35
+ data: this.data
36
+ }
37
+ }
38
+ }
14
39
 
40
+ module.exports = class FFmpegPacket {
41
+ constructor(buffer) {
42
+ if (buffer) {
15
43
  this._handle = binding.initPacketFromBuffer(
16
44
  buffer.buffer,
17
45
  buffer.byteOffset,
@@ -22,13 +50,12 @@ module.exports = class FFmpegPacket extends ReferenceCounted {
22
50
  }
23
51
  }
24
52
 
25
- _destroy() {
53
+ destroy() {
26
54
  binding.destroyPacket(this._handle)
27
55
  this._handle = null
28
56
  }
29
57
 
30
58
  unref() {
31
- this._unref()
32
59
  binding.unrefPacket(this._handle)
33
60
  }
34
61
 
@@ -36,7 +63,121 @@ module.exports = class FFmpegPacket extends ReferenceCounted {
36
63
  return binding.getPacketStreamIndex(this._handle)
37
64
  }
38
65
 
66
+ set streamIndex(value) {
67
+ return binding.setPacketStreamIndex(this._handle, value)
68
+ }
69
+
39
70
  get data() {
40
71
  return Buffer.from(binding.getPacketData(this._handle))
41
72
  }
73
+
74
+ set data(value) {
75
+ binding.setPacketData(
76
+ this._handle,
77
+ value.buffer,
78
+ value.byteOffset,
79
+ value.byteLength
80
+ )
81
+ }
82
+
83
+ get sideData() {
84
+ const handles = binding.getPacketSideData(this._handle)
85
+ return handles.map((handle) => new SideData(handle))
86
+ }
87
+
88
+ set sideData(values) {
89
+ binding.setPacketSideData(
90
+ this._handle,
91
+ values.map((value) => ({
92
+ buffer: value.data.buffer,
93
+ offset: value.data.byteOffset,
94
+ length: value.data.byteLength,
95
+ type: value.type
96
+ }))
97
+ )
98
+ }
99
+
100
+ get isKeyframe() {
101
+ return binding.isPacketKeyframe(this._handle)
102
+ }
103
+
104
+ set isKeyframe(value) {
105
+ binding.setPacketIsKeyFrame(this._handle, value)
106
+ }
107
+
108
+ get dts() {
109
+ return binding.getPacketDTS(this._handle)
110
+ }
111
+
112
+ set dts(value) {
113
+ return binding.setPacketDTS(this._handle, value)
114
+ }
115
+
116
+ get pts() {
117
+ return binding.getPacketPTS(this._handle)
118
+ }
119
+
120
+ set pts(value) {
121
+ return binding.setPacketPTS(this._handle, value)
122
+ }
123
+
124
+ get timeBase() {
125
+ const view = new Int32Array(binding.getPacketTimeBase(this._handle))
126
+ return new Rational(view[0], view[1])
127
+ }
128
+
129
+ set timeBase(value) {
130
+ binding.setPacketTimeBase(this._handle, value.numerator, value.denominator)
131
+ }
132
+
133
+ rescaleTimestamps(srcTimeBase, dstTimeBase) {
134
+ return binding.rescalePacketTimestamps(
135
+ this._handle,
136
+ srcTimeBase.numerator,
137
+ srcTimeBase.denominator,
138
+ dstTimeBase.numerator,
139
+ dstTimeBase.denominator
140
+ )
141
+ }
142
+
143
+ copyPropsFrom(sourcePacket) {
144
+ binding.copyPacketProps(this._handle, sourcePacket._handle)
145
+ }
146
+
147
+ get duration() {
148
+ return binding.getPacketDuration(this._handle)
149
+ }
150
+
151
+ set duration(value) {
152
+ return binding.setPacketDuration(this._handle, value)
153
+ }
154
+
155
+ get flags() {
156
+ return binding.getPacketFlags(this._handle)
157
+ }
158
+
159
+ set flags(value) {
160
+ return binding.setPacketFlags(this._handle, value)
161
+ }
162
+
163
+ [Symbol.for('bare.inspect')]() {
164
+ return {
165
+ __proto__: { constructor: FFmpegPacket },
166
+ streamIndex: this.streamIndex,
167
+ flags: this.flags,
168
+ isKeyframe: this.isKeyframe,
169
+ timeBase: this.timeBase,
170
+ dts: this.dts,
171
+ pts: this.pts,
172
+ duration: this.duration,
173
+ data: this.data,
174
+ sideData: this.sideData
175
+ }
176
+ }
177
+
178
+ [Symbol.dispose]() {
179
+ this.destroy()
180
+ }
42
181
  }
182
+
183
+ module.exports.SideData = SideData
package/lib/rational.js CHANGED
@@ -1,6 +1,54 @@
1
+ const binding = require('../binding')
2
+ const { AV_ROUND_NEAR_INF } = require('./constants').rounding
3
+
1
4
  module.exports = class FFmpegRational {
2
- constructor(numerator, denominator) {
5
+ constructor(numerator = 0, denominator = 1) {
3
6
  this.numerator = numerator
4
7
  this.denominator = denominator
5
8
  }
9
+
10
+ get valid() {
11
+ // don't support negative denominators for now
12
+ if (this.denominator < 0) return false
13
+
14
+ const n = this.toNumber()
15
+
16
+ if (Number.isNaN(n) || n === 0) return false
17
+
18
+ return true
19
+ }
20
+
21
+ get uninitialized() {
22
+ // common initial value for AVRational(0, 1)
23
+ return this.numerator === 0 && this.denominator === 1
24
+ }
25
+
26
+ toNumber() {
27
+ return this.numerator / this.denominator
28
+ }
29
+
30
+ equals(other) {
31
+ return (
32
+ this.numerator === other.numerator &&
33
+ this.denominator === other.denominator
34
+ )
35
+ }
36
+
37
+ static from(num) {
38
+ const view = new Int32Array(binding.rationalD2Q(num))
39
+ return new FFmpegRational(view[0], view[1])
40
+ }
41
+
42
+ static rescaleQ(n, src, dst, round = AV_ROUND_NEAR_INF) {
43
+ if (src.equals(dst)) return n
44
+
45
+ return binding.rationalRescaleQ(
46
+ n,
47
+ src.numerator,
48
+ src.denominator,
49
+ dst.numerator,
50
+ dst.denominator,
51
+ round
52
+ )
53
+ }
6
54
  }
@@ -0,0 +1,63 @@
1
+ const binding = require('../binding')
2
+ const ChannelLayout = require('./channel-layout')
3
+
4
+ class FFmpegResampler {
5
+ constructor(
6
+ inputSampleRate,
7
+ inputChannelLayout,
8
+ inputFormat,
9
+ outputSampleRate,
10
+ outputChannelLayout,
11
+ outputFormat
12
+ ) {
13
+ inputChannelLayout = ChannelLayout.from(inputChannelLayout)
14
+ outputChannelLayout = ChannelLayout.from(outputChannelLayout)
15
+
16
+ this._inputSampleRate = inputSampleRate
17
+ this._outputSampleRate = outputSampleRate
18
+
19
+ this._handle = binding.initResampler(
20
+ inputSampleRate,
21
+ inputFormat,
22
+ inputChannelLayout._handle,
23
+ outputSampleRate,
24
+ outputFormat,
25
+ outputChannelLayout._handle
26
+ )
27
+ }
28
+
29
+ get inputSampleRate() {
30
+ return this._inputSampleRate
31
+ }
32
+
33
+ get outputSampleRate() {
34
+ return this._outputSampleRate
35
+ }
36
+
37
+ get delay() {
38
+ return binding.getResamplerDelay(this._handle, this._inputSampleRate)
39
+ }
40
+
41
+ convert(inputFrame, outputFrame) {
42
+ return binding.convertResampler(
43
+ this._handle,
44
+ inputFrame._handle,
45
+ outputFrame._handle
46
+ )
47
+ }
48
+
49
+ flush(outputFrame) {
50
+ return binding.flushResampler(this._handle, outputFrame._handle)
51
+ }
52
+
53
+ destroy() {
54
+ binding.destroyResampler(this._handle)
55
+ this._handle = null
56
+ }
57
+
58
+ [Symbol.dispose]() {
59
+ this.destroy()
60
+ }
61
+ }
62
+
63
+ module.exports = FFmpegResampler
package/lib/samples.js ADDED
@@ -0,0 +1,96 @@
1
+ const binding = require('../binding')
2
+
3
+ module.exports = class FFmpegSamples {
4
+ _data
5
+ _frame
6
+
7
+ constructor({ noAlignment = false } = {}) {
8
+ this._noAlignment = noAlignment
9
+ }
10
+
11
+ get data() {
12
+ return this._data
13
+ }
14
+
15
+ get format() {
16
+ return this._frame.format
17
+ }
18
+
19
+ get channelLayout() {
20
+ return this._frame.channelLayout
21
+ }
22
+
23
+ get nbSamples() {
24
+ return this._frame.nbSamples
25
+ }
26
+
27
+ get nbChannels() {
28
+ return this.channelLayout && this.channelLayout.nbChannels
29
+ }
30
+
31
+ get pts() {
32
+ return this._frame.pts
33
+ }
34
+
35
+ fill(frame) {
36
+ const { format, channelLayout, nbSamples } = frame
37
+
38
+ const len = FFmpegSamples.bufferSize(
39
+ format,
40
+ channelLayout.nbChannels,
41
+ nbSamples,
42
+ this._noAlignment
43
+ )
44
+
45
+ if (!this._data || len !== this._data.length) {
46
+ this._data = Buffer.allocUnsafe(len)
47
+ }
48
+
49
+ const res = binding.fillSamples(
50
+ frame._handle,
51
+ this._data.buffer,
52
+ this._data.byteOffset,
53
+ this._noAlignment
54
+ )
55
+
56
+ this._frame = frame
57
+
58
+ return res
59
+ }
60
+
61
+ read(frame) {
62
+ const { format, channelLayout, nbSamples } = frame
63
+
64
+ const len = FFmpegSamples.bufferSize(
65
+ format,
66
+ channelLayout.nbChannels,
67
+ nbSamples,
68
+ this._noAlignment
69
+ )
70
+
71
+ if (!this._data || len !== this._data.length) {
72
+ this._data = Buffer.allocUnsafe(len)
73
+ }
74
+
75
+ binding.readSamples(
76
+ frame._handle,
77
+ this._data.buffer,
78
+ this._data.byteOffset,
79
+ this._noAlignment
80
+ )
81
+ }
82
+
83
+ copy(frame, dstOffset = 0, srcOffset = 0) {
84
+ binding.copySamples(
85
+ frame._handle,
86
+ this._frame._handle,
87
+ dstOffset,
88
+ srcOffset,
89
+ this.nbSamples
90
+ )
91
+ }
92
+
93
+ static bufferSize(format, nbChannels, nbSamples, noAlignment = false) {
94
+ return binding.samplesBufferSize(format, nbChannels, nbSamples, noAlignment)
95
+ }
96
+ }
package/lib/scaler.js CHANGED
@@ -1,8 +1,7 @@
1
1
  const binding = require('../binding')
2
2
  const constants = require('./constants')
3
- const ReferenceCounted = require('./reference-counted')
4
3
 
5
- module.exports = class FFmpegScaler extends ReferenceCounted {
4
+ module.exports = class FFmpegScaler {
6
5
  constructor(
7
6
  sourcePixelFormat,
8
7
  sourceWidth,
@@ -11,8 +10,6 @@ module.exports = class FFmpegScaler extends ReferenceCounted {
11
10
  targetWidth,
12
11
  targetHeight
13
12
  ) {
14
- super()
15
-
16
13
  sourcePixelFormat = constants.toPixelFormat(sourcePixelFormat)
17
14
  targetPixelFormat = constants.toPixelFormat(targetPixelFormat)
18
15
 
@@ -33,7 +30,7 @@ module.exports = class FFmpegScaler extends ReferenceCounted {
33
30
  )
34
31
  }
35
32
 
36
- _destroy() {
33
+ destroy() {
37
34
  binding.destroyScaler(this._handle)
38
35
  this._handle = null
39
36
  }
@@ -42,10 +39,10 @@ module.exports = class FFmpegScaler extends ReferenceCounted {
42
39
  if (typeof y !== 'number') {
43
40
  target = y
44
41
  y = 0
45
- height = this._targetHeight
42
+ height = source.height
46
43
  } else if (typeof height !== 'number') {
47
44
  target = height
48
- height = this._targetHeight
45
+ height = source.height
49
46
  }
50
47
 
51
48
  return binding.scaleScaler(
@@ -56,4 +53,8 @@ module.exports = class FFmpegScaler extends ReferenceCounted {
56
53
  target._handle
57
54
  )
58
55
  }
56
+
57
+ [Symbol.dispose]() {
58
+ this.destroy()
59
+ }
59
60
  }
package/lib/stream.js CHANGED
@@ -2,43 +2,87 @@ const binding = require('../binding')
2
2
  const Codec = require('./codec')
3
3
  const CodecContext = require('./codec-context')
4
4
  const CodecParameters = require('./codec-parameters')
5
- const ReferenceCounted = require('./reference-counted')
5
+ const Rational = require('./rational')
6
6
 
7
- module.exports = class FFmpegStream extends ReferenceCounted {
7
+ module.exports = class FFmpegStream {
8
8
  constructor(handle) {
9
- super()
10
-
11
9
  this._handle = handle
12
10
 
13
- this._codec = Codec.for(binding.getStreamCodec(this._handle))
14
-
15
11
  this._codecParameters = new CodecParameters(
16
12
  binding.getStreamCodecParameters(this._handle)
17
13
  )
18
14
  }
19
15
 
20
- _destroy() {
21
- this._codecParameters.destroy()
22
- this._codecParameters = null
16
+ get id() {
17
+ return binding.getStreamId(this._handle)
18
+ }
19
+
20
+ set id(value) {
21
+ binding.setStreamId(this._handle, value)
22
+ }
23
+
24
+ get index() {
25
+ return binding.getStreamIndex(this._handle)
23
26
  }
24
27
 
25
28
  get codec() {
26
- return this._codec
29
+ return Codec.for(this.codecParameters.id)
27
30
  }
28
31
 
29
32
  get codecParameters() {
30
33
  return this._codecParameters
31
34
  }
32
35
 
36
+ get timeBase() {
37
+ const view = new Int32Array(binding.getStreamTimeBase(this._handle))
38
+ return new Rational(view[0], view[1])
39
+ }
40
+
41
+ set timeBase(value) {
42
+ binding.setStreamTimeBase(this._handle, value.numerator, value.denominator)
43
+ }
44
+
45
+ get avgFramerate() {
46
+ const view = new Int32Array(binding.getStreamAverageFramerate(this._handle))
47
+ return new Rational(view[0], view[1])
48
+ }
49
+
50
+ set avgFramerate(value) {
51
+ binding.setStreamAverageFramerate(
52
+ this._handle,
53
+ value.numerator,
54
+ value.denominator
55
+ )
56
+ }
57
+
58
+ get duration() {
59
+ return binding.getStreamDuration(this._handle)
60
+ }
61
+
62
+ set duration(value) {
63
+ binding.setStreamDuration(this._handle, value)
64
+ }
65
+
33
66
  decoder() {
34
- const context = new CodecContext(this._codec.decoder)
67
+ const context = new CodecContext(this.codec.decoder)
35
68
  this._codecParameters.toContext(context)
36
- return context.open()
69
+ return context
37
70
  }
38
71
 
39
72
  encoder() {
40
- const context = new CodecContext(this._codec.encoder)
73
+ const context = new CodecContext(this.codec.encoder)
41
74
  this._codecParameters.toContext(context)
42
- return context.open()
75
+ return context
76
+ }
77
+
78
+ [Symbol.for('bare.inspect')]() {
79
+ return {
80
+ __proto__: { constructor: FFmpegStream },
81
+ id: this.id,
82
+ index: this.index,
83
+ timeBase: this.timeBase,
84
+ avgFramerate: this.avgFramerate,
85
+ codecParameters: this.codecParameters
86
+ }
43
87
  }
44
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-ffmpeg",
3
- "version": "1.0.0-3",
3
+ "version": "1.0.0-31",
4
4
  "description": "Low-level FFmpeg bindings for Bare",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -8,15 +8,18 @@
8
8
  },
9
9
  "files": [
10
10
  "index.js",
11
- "binding.c",
11
+ "binding.cc",
12
12
  "binding.js",
13
13
  "CMakeLists.txt",
14
14
  "lib",
15
- "prebuilds"
15
+ "prebuilds",
16
+ "cmake"
16
17
  ],
17
18
  "addon": true,
18
19
  "scripts": {
19
- "test": "prettier . --check && bare test.js"
20
+ "test": "prettier . --check && bare test.js",
21
+ "format": "prettier . --write && clang-format -i binding.cc",
22
+ "example": "bare ./examples/index.js"
20
23
  },
21
24
  "repository": {
22
25
  "type": "git",
@@ -29,8 +32,10 @@
29
32
  },
30
33
  "homepage": "https://github.com/holepunchto/bare-ffmpeg#readme",
31
34
  "devDependencies": {
35
+ "bare-assert": "^1.1.0",
32
36
  "brittle": "^3.4.0",
33
37
  "cmake-bare": "^1.1.2",
38
+ "cmake-harden": "^1.0.2",
34
39
  "cmake-ports": "^1.5.0",
35
40
  "prettier": "^3.3.3",
36
41
  "prettier-config-standard": "^7.0.0"