bare-ffmpeg 1.0.0-2 → 1.0.0-21
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/CMakeLists.txt +10 -3
- package/README.md +1097 -0
- package/binding.cc +3330 -0
- package/cmake/ports/ffmpeg/port.cmake +513 -0
- package/cmake/ports/opus/patches/01-windows-clang.patch +52 -0
- package/cmake/ports/opus/port.cmake +42 -0
- package/cmake/ports/svt-av1/port.cmake +42 -0
- package/cmake/ports/x264/patches/01-windows-clang.patch +33 -0
- package/cmake/ports/x264/port.cmake +157 -0
- package/index.js +14 -4
- package/lib/audio-fifo.js +47 -0
- package/lib/channel-layout.js +35 -0
- package/lib/codec-context.js +92 -15
- package/lib/codec-parameters.js +230 -8
- package/lib/codec.js +19 -0
- package/lib/constants.js +163 -8
- package/lib/dictionary.js +18 -15
- package/lib/errors.js +38 -0
- package/lib/format-context.js +62 -31
- package/lib/frame.js +87 -16
- package/lib/image.js +22 -0
- package/lib/input-format.js +8 -3
- package/lib/io-context.js +29 -6
- package/lib/log.js +16 -0
- package/lib/output-format.js +4 -0
- package/lib/packet.js +88 -13
- package/lib/rational.js +35 -1
- package/lib/resampler.js +63 -0
- package/lib/samples.js +49 -0
- package/lib/scaler.js +8 -7
- package/lib/stream.js +37 -12
- package/package.json +7 -4
- package/prebuilds/android-arm/bare-ffmpeg.bare +0 -0
- package/prebuilds/android-arm64/bare-ffmpeg.bare +0 -0
- package/prebuilds/android-ia32/bare-ffmpeg.bare +0 -0
- package/prebuilds/android-x64/bare-ffmpeg.bare +0 -0
- package/prebuilds/darwin-arm64/bare-ffmpeg.bare +0 -0
- package/prebuilds/darwin-x64/bare-ffmpeg.bare +0 -0
- package/prebuilds/ios-arm64/bare-ffmpeg.bare +0 -0
- package/prebuilds/ios-arm64-simulator/bare-ffmpeg.bare +0 -0
- package/prebuilds/ios-x64-simulator/bare-ffmpeg.bare +0 -0
- package/prebuilds/linux-arm64/bare-ffmpeg.bare +0 -0
- package/prebuilds/linux-x64/bare-ffmpeg.bare +0 -0
- package/prebuilds/win32-arm64/bare-ffmpeg.bare +0 -0
- package/prebuilds/win32-x64/bare-ffmpeg.bare +0 -0
- package/binding.c +0 -2128
- package/lib/reference-counted.js +0 -39
package/lib/codec.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const Decoder = require('./decoder')
|
|
2
2
|
const Encoder = require('./encoder')
|
|
3
3
|
const constants = require('./constants')
|
|
4
|
+
const binding = require('../binding')
|
|
4
5
|
|
|
5
6
|
const codecs = new Map()
|
|
6
7
|
|
|
@@ -25,6 +26,21 @@ module.exports = class FFmpegCodec {
|
|
|
25
26
|
return this._encoder
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
get name() {
|
|
30
|
+
if (Number.isInteger(this._id)) {
|
|
31
|
+
return binding.getCodecNameByID(this._id)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
[Symbol.for('bare.inspect')]() {
|
|
36
|
+
return {
|
|
37
|
+
__proto__: { constructor: FFmpegCodec },
|
|
38
|
+
id: this.id,
|
|
39
|
+
name: this.name
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** @return {FFmpegCodec} */
|
|
28
44
|
static for(id) {
|
|
29
45
|
let codec = codecs.get(id)
|
|
30
46
|
if (codec === undefined) {
|
|
@@ -36,4 +52,7 @@ module.exports = class FFmpegCodec {
|
|
|
36
52
|
|
|
37
53
|
static MJPEG = this.for(constants.codecs.MJPEG)
|
|
38
54
|
static H264 = this.for(constants.codecs.H264)
|
|
55
|
+
static AAC = this.for(constants.codecs.AAC)
|
|
56
|
+
static OPUS = this.for(constants.codecs.OPUS)
|
|
57
|
+
static AV1 = this.for(constants.codecs.AV1)
|
|
39
58
|
}
|
package/lib/constants.js
CHANGED
|
@@ -1,9 +1,42 @@
|
|
|
1
1
|
const binding = require('../binding')
|
|
2
|
+
const errors = require('./errors')
|
|
3
|
+
|
|
4
|
+
// Helpers
|
|
5
|
+
function makeTag(a, b, c, d) {
|
|
6
|
+
return (
|
|
7
|
+
a.charCodeAt(0) |
|
|
8
|
+
(b.charCodeAt(0) << 8) |
|
|
9
|
+
(c.charCodeAt(0) << 16) |
|
|
10
|
+
(d.charCodeAt(0) << 24)
|
|
11
|
+
)
|
|
12
|
+
}
|
|
2
13
|
|
|
3
14
|
module.exports = exports = {
|
|
4
15
|
codecs: {
|
|
5
16
|
MJPEG: binding.AV_CODEC_ID_MJPEG,
|
|
6
|
-
H264: binding.AV_CODEC_ID_H264
|
|
17
|
+
H264: binding.AV_CODEC_ID_H264,
|
|
18
|
+
AAC: binding.AV_CODEC_ID_AAC,
|
|
19
|
+
OPUS: binding.AV_CODEC_ID_OPUS,
|
|
20
|
+
AV1: binding.AV_CODEC_ID_AV1,
|
|
21
|
+
FLAC: binding.AV_CODEC_ID_FLAC,
|
|
22
|
+
MP3: binding.AV_CODEC_ID_MP3
|
|
23
|
+
},
|
|
24
|
+
tags: {
|
|
25
|
+
// Source Ref:
|
|
26
|
+
// https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/riff.c#L36
|
|
27
|
+
// https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/riff.c#L530
|
|
28
|
+
MJPEG: makeTag('M', 'J', 'P', 'G'),
|
|
29
|
+
H264: makeTag('H', '2', '6', '4'),
|
|
30
|
+
AV1: makeTag('A', 'V', '0', '1'),
|
|
31
|
+
AAC: 0x00ff,
|
|
32
|
+
FLAC: 0xf1ac,
|
|
33
|
+
MP3: 0x0055
|
|
34
|
+
},
|
|
35
|
+
profiles: {
|
|
36
|
+
H264_MAIN: binding.AV_PROFILE_H264_MAIN
|
|
37
|
+
},
|
|
38
|
+
levels: {
|
|
39
|
+
UNKNOWN: binding.AV_LEVEL_UNKNOWN
|
|
7
40
|
},
|
|
8
41
|
pixelFormats: {
|
|
9
42
|
RGBA: binding.AV_PIX_FMT_RGBA,
|
|
@@ -12,7 +45,7 @@ module.exports = exports = {
|
|
|
12
45
|
UYVY422: binding.AV_PIX_FMT_UYVY422,
|
|
13
46
|
YUV420P: binding.AV_PIX_FMT_YUV420P
|
|
14
47
|
},
|
|
15
|
-
|
|
48
|
+
mediaTypes: {
|
|
16
49
|
UNKNOWN: binding.AVMEDIA_TYPE_UNKNOWN,
|
|
17
50
|
VIDEO: binding.AVMEDIA_TYPE_VIDEO,
|
|
18
51
|
AUDIO: binding.AVMEDIA_TYPE_AUDIO,
|
|
@@ -20,17 +53,139 @@ module.exports = exports = {
|
|
|
20
53
|
SUBTITLE: binding.AVMEDIA_TYPE_SUBTITLE,
|
|
21
54
|
ATTACHEMENT: binding.AVMEDIA_TYPE_ATTACHMENT,
|
|
22
55
|
NB: binding.AVMEDIA_TYPE_NB
|
|
56
|
+
},
|
|
57
|
+
sampleFormats: {
|
|
58
|
+
NONE: binding.AV_SAMPLE_FMT_NONE,
|
|
59
|
+
U8: binding.AV_SAMPLE_FMT_U8,
|
|
60
|
+
S16: binding.AV_SAMPLE_FMT_S16,
|
|
61
|
+
S32: binding.AV_SAMPLE_FMT_S32,
|
|
62
|
+
S64: binding.AV_SAMPLE_FMT_S64,
|
|
63
|
+
FLT: binding.AV_SAMPLE_FMT_FLT,
|
|
64
|
+
DBL: binding.AV_SAMPLE_FMT_DBL,
|
|
65
|
+
U8P: binding.AV_SAMPLE_FMT_U8P,
|
|
66
|
+
S16P: binding.AV_SAMPLE_FMT_S16P,
|
|
67
|
+
S32P: binding.AV_SAMPLE_FMT_S32P,
|
|
68
|
+
S64P: binding.AV_SAMPLE_FMT_S64P,
|
|
69
|
+
FLTP: binding.AV_SAMPLE_FMT_FLTP,
|
|
70
|
+
DBLP: binding.AV_SAMPLE_FMT_DBLP,
|
|
71
|
+
NB: binding.AV_SAMPLE_FMT_NB
|
|
72
|
+
},
|
|
73
|
+
channelLayouts: {
|
|
74
|
+
MONO: binding.AV_CH_LAYOUT_MONO,
|
|
75
|
+
STEREO: binding.AV_CH_LAYOUT_STEREO,
|
|
76
|
+
QUAD: binding.AV_CH_LAYOUT_QUAD,
|
|
77
|
+
SURROUND: binding.AV_CH_LAYOUT_SURROUND,
|
|
78
|
+
2_1: binding.AV_CH_LAYOUT_2POINT1,
|
|
79
|
+
5_0: binding.AV_CH_LAYOUT_5POINT0,
|
|
80
|
+
5_1: binding.AV_CH_LAYOUT_5POINT1,
|
|
81
|
+
7_1: binding.AV_CH_LAYOUT_7POINT1,
|
|
82
|
+
// Aliases
|
|
83
|
+
2.1: binding.AV_CH_LAYOUT_2POINT1,
|
|
84
|
+
'5.0': binding.AV_CH_LAYOUT_5POINT0,
|
|
85
|
+
5.1: binding.AV_CH_LAYOUT_5POINT1,
|
|
86
|
+
7.1: binding.AV_CH_LAYOUT_7POINT1
|
|
87
|
+
},
|
|
88
|
+
pictureTypes: {
|
|
89
|
+
NONE: binding.AV_PICTURE_TYPE_NONE,
|
|
90
|
+
I: binding.AV_PICTURE_TYPE_I,
|
|
91
|
+
P: binding.AV_PICTURE_TYPE_P,
|
|
92
|
+
B: binding.AV_PICTURE_TYPE_B,
|
|
93
|
+
S: binding.AV_PICTURE_TYPE_S,
|
|
94
|
+
SI: binding.AV_PICTURE_TYPE_SI,
|
|
95
|
+
SP: binding.AV_PICTURE_TYPE_SP,
|
|
96
|
+
BI: binding.AV_PICTURE_TYPE_BI
|
|
97
|
+
},
|
|
98
|
+
logLevels: {
|
|
99
|
+
QUIET: binding.AV_LOG_QUIET,
|
|
100
|
+
PANIC: binding.AV_LOG_PANIC,
|
|
101
|
+
FATAL: binding.AV_LOG_FATAL,
|
|
102
|
+
ERROR: binding.AV_LOG_ERROR,
|
|
103
|
+
WARNING: binding.AV_LOG_WARNING,
|
|
104
|
+
INFO: binding.AV_LOG_INFO,
|
|
105
|
+
VERBOSE: binding.AV_LOG_VERBOSE,
|
|
106
|
+
DEBUG: binding.AV_LOG_DEBUG,
|
|
107
|
+
TRACE: binding.AV_LOG_TRACE
|
|
108
|
+
},
|
|
109
|
+
codecFlags: {
|
|
110
|
+
COPY_OPAQUE: binding.AV_CODEC_FLAG_COPY_OPAQUE,
|
|
111
|
+
FRAME_DURATION: binding.AV_CODEC_FLAG_FRAME_DURATION,
|
|
112
|
+
PASS1: binding.AV_CODEC_FLAG_PASS1,
|
|
113
|
+
PASS2: binding.AV_CODEC_FLAG_PASS2,
|
|
114
|
+
LOOP_FILTER: binding.AV_CODEC_FLAG_LOOP_FILTER,
|
|
115
|
+
GRAY: binding.AV_CODEC_FLAG_GRAY,
|
|
116
|
+
PSNR: binding.AV_CODEC_FLAG_PSNR,
|
|
117
|
+
INTERLACED_DCT: binding.AV_CODEC_FLAG_INTERLACED_DCT,
|
|
118
|
+
LOW_DELAY: binding.AV_CODEC_FLAG_LOW_DELAY,
|
|
119
|
+
GLOBAL_HEADER: binding.AV_CODEC_FLAG_GLOBAL_HEADER,
|
|
120
|
+
BITEXACT: binding.AV_CODEC_FLAG_BITEXACT,
|
|
121
|
+
AC_PRED: binding.AV_CODEC_FLAG_AC_PRED,
|
|
122
|
+
INTERLACED_ME: binding.AV_CODEC_FLAG_INTERLACED_ME,
|
|
123
|
+
CLOSED_GOP: binding.AV_CODEC_FLAG_CLOSED_GOP
|
|
124
|
+
},
|
|
125
|
+
formatFlags: {
|
|
126
|
+
SHOW_IDS: binding.AVFMT_SHOW_IDS,
|
|
127
|
+
GENERIC_INDEX: binding.AVFMT_GENERIC_INDEX,
|
|
128
|
+
TS_DISCONT: binding.AVFMT_TS_DISCONT,
|
|
129
|
+
NOBINSEARCH: binding.AVFMT_NOBINSEARCH,
|
|
130
|
+
NOGENSEARCH: binding.AVFMT_NOGENSEARCH,
|
|
131
|
+
NO_BYTE_SEEK: binding.AVFMT_NO_BYTE_SEEK,
|
|
132
|
+
SEEK_TO_PTS: binding.AVFMT_SEEK_TO_PTS,
|
|
133
|
+
GLOBALHEADER: binding.AVFMT_GLOBALHEADER,
|
|
134
|
+
VARIABLE_FPS: binding.AVFMT_VARIABLE_FPS,
|
|
135
|
+
NODIMENSIONS: binding.AVFMT_NODIMENSIONS,
|
|
136
|
+
NOSTREAMS: binding.AVFMT_NOSTREAMS,
|
|
137
|
+
TS_NONSTRICT: binding.AVFMT_TS_NONSTRICT,
|
|
138
|
+
TS_NEGATIVE: binding.AVFMT_TS_NEGATIVE,
|
|
139
|
+
NOFILE: binding.AVFMT_NOFILE,
|
|
140
|
+
NEEDNUMBER: binding.AVFMT_NEEDNUMBER,
|
|
141
|
+
NOTIMESTAMPS: binding.AVFMT_NOTIMESTAMPS
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
exports.toPixelFormat = function toPixelFormat(format) {
|
|
146
|
+
if (typeof format === 'number') return format
|
|
147
|
+
|
|
148
|
+
if (typeof format === 'string') {
|
|
149
|
+
if (format in exports.pixelFormats === false) {
|
|
150
|
+
throw errors.UNKNOWN_PIXEL_FORMAT(`Unknown pixel format '${format}'`)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return exports.pixelFormats[format]
|
|
23
154
|
}
|
|
155
|
+
|
|
156
|
+
throw new TypeError(
|
|
157
|
+
`Pixel format must be a number or string. Received ${typeof format} (${format})`
|
|
158
|
+
)
|
|
24
159
|
}
|
|
25
160
|
|
|
26
|
-
exports.
|
|
27
|
-
if (typeof
|
|
161
|
+
exports.toSampleFormat = function toSampleFormat(format) {
|
|
162
|
+
if (typeof format === 'number') return format
|
|
28
163
|
|
|
29
|
-
if (typeof
|
|
30
|
-
if (
|
|
31
|
-
throw errors.
|
|
164
|
+
if (typeof format === 'string') {
|
|
165
|
+
if (format in exports.sampleFormats === false) {
|
|
166
|
+
throw errors.UNKNOWN_SAMPLE_FORMAT(`Unknown sample format '${format}'`)
|
|
32
167
|
}
|
|
33
168
|
|
|
34
|
-
return exports.
|
|
169
|
+
return exports.sampleFormats[format]
|
|
35
170
|
}
|
|
171
|
+
|
|
172
|
+
throw new TypeError(
|
|
173
|
+
`Sample format must be a number or string. Received ${typeof format} (${format})`
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
exports.toChannelLayout = function toChannelLayout(layout) {
|
|
178
|
+
if (typeof layout === 'number') return layout
|
|
179
|
+
|
|
180
|
+
if (typeof layout === 'string') {
|
|
181
|
+
if (layout in exports.channelLayouts === false) {
|
|
182
|
+
throw errors.UNKNOWN_CHANNEL_LAYOUT(`Unknown channel layout '${layout}'`)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return exports.channelLayouts[layout]
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
throw new TypeError(
|
|
189
|
+
`Channel layout must be a number or string. Received ${typeof layout} (${layout})`
|
|
190
|
+
)
|
|
36
191
|
}
|
package/lib/dictionary.js
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
const binding = require('../binding')
|
|
2
|
-
const ReferenceCounted = require('./reference-counted')
|
|
3
2
|
|
|
4
|
-
module.exports = class FFmpegDictionary
|
|
3
|
+
module.exports = class FFmpegDictionary {
|
|
5
4
|
constructor() {
|
|
6
|
-
super()
|
|
7
|
-
|
|
8
5
|
this._handle = binding.initDictionary()
|
|
9
6
|
}
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
destroy() {
|
|
12
9
|
binding.destroyDictionary(this._handle)
|
|
13
10
|
this._handle = null
|
|
14
11
|
}
|
|
15
12
|
|
|
16
13
|
get(key) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return binding.getDictionaryEntry(this._handle, key)
|
|
14
|
+
const value = binding.getDictionaryEntry(this._handle, key)
|
|
15
|
+
if (value === undefined) return null
|
|
16
|
+
return value
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
set(key, value) {
|
|
24
|
-
if (typeof
|
|
25
|
-
throw new TypeError(`Key should be a non empty string`)
|
|
26
|
-
}
|
|
20
|
+
if (typeof value !== 'string') value = String(value)
|
|
27
21
|
|
|
28
|
-
if (typeof value !== 'string' || value.length < 1) {
|
|
29
|
-
throw new TypeError(`Value should be a non empty string`)
|
|
30
|
-
}
|
|
31
22
|
binding.setDictionaryEntry(this._handle, key, value)
|
|
32
23
|
}
|
|
24
|
+
|
|
25
|
+
entries() {
|
|
26
|
+
return binding.getDictionaryEntries(this._handle)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
*[Symbol.iterator]() {
|
|
30
|
+
yield* this.entries()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
[Symbol.dispose]() {
|
|
34
|
+
this.destroy()
|
|
35
|
+
}
|
|
33
36
|
}
|
package/lib/errors.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module.exports = class FFmpegError extends Error {
|
|
2
|
+
constructor(msg, code, fn = FFmpegError) {
|
|
3
|
+
super(`${code}: ${msg}`)
|
|
4
|
+
this.code = code
|
|
5
|
+
|
|
6
|
+
if (Error.captureStackTrace) {
|
|
7
|
+
Error.captureStackTrace(this, fn)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get name() {
|
|
12
|
+
return 'FFmpegError'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static UNKNOWN_PIXEL_FORMAT(msg) {
|
|
16
|
+
return new FFmpegError(
|
|
17
|
+
msg,
|
|
18
|
+
'UNKNOWN_PIXEL_FORMAT',
|
|
19
|
+
FFmpegError.UNKNOWN_PIXEL_FORMAT
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static UNKNOWN_SAMPLE_FORMAT(msg) {
|
|
24
|
+
return new FFmpegError(
|
|
25
|
+
msg,
|
|
26
|
+
'UNKNOWN_SAMPLE_FORMAT',
|
|
27
|
+
FFmpegError.UNKNOWN_SAMPLE_FORMAT
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static UNKNOWN_CHANNEL_LAYOUT(msg) {
|
|
32
|
+
return new FFmpegError(
|
|
33
|
+
msg,
|
|
34
|
+
'UNKNOWN_CHANNEL_LAYOUT',
|
|
35
|
+
FFmpegError.UNKNOWN_CHANNEL_LAYOUT
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
}
|
package/lib/format-context.js
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
const binding = require('../binding')
|
|
2
2
|
const Stream = require('./stream.js')
|
|
3
|
-
const ReferenceCounted = require('./reference-counted')
|
|
4
3
|
const OutputFormat = require('./output-format')
|
|
5
4
|
const IOContext = require('./io-context')
|
|
6
5
|
const InputFormat = require('./input-format')
|
|
6
|
+
const Dictionary = require('./dictionary')
|
|
7
|
+
/** @typedef {import('./packet')} Packet */
|
|
7
8
|
|
|
8
|
-
class FFmpegFormatContext
|
|
9
|
+
class FFmpegFormatContext {
|
|
9
10
|
constructor(io) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this._io = io ? io._ref() : null
|
|
11
|
+
this._io = io
|
|
13
12
|
this._streams = []
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
destroy() {
|
|
17
16
|
if (this._io) {
|
|
18
|
-
this._io.
|
|
17
|
+
this._io.destroy()
|
|
19
18
|
this._io = null
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
for (const stream of this._streams) stream.destroy()
|
|
23
|
-
this._streams = []
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
get io() {
|
|
@@ -32,23 +28,24 @@ class FFmpegFormatContext extends ReferenceCounted {
|
|
|
32
28
|
}
|
|
33
29
|
|
|
34
30
|
readFrame(packet) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
31
|
+
return binding.readFormatContextFrame(this._handle, packet._handle)
|
|
32
|
+
}
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return result
|
|
34
|
+
getBestStreamIndex(type) {
|
|
35
|
+
return binding.getFormatContextBestStreamIndex(this._handle, type)
|
|
42
36
|
}
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
`Type parameter should be of type number but got: ${typeof type}`
|
|
48
|
-
)
|
|
38
|
+
getStream(index) {
|
|
39
|
+
if (index < 0 || index >= this._streams.length) {
|
|
40
|
+
return null
|
|
49
41
|
}
|
|
50
42
|
|
|
51
|
-
|
|
43
|
+
return this._streams[index]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** @returns {Stream|null} */
|
|
47
|
+
getBestStream(type) {
|
|
48
|
+
if (this._streams.length === 0) {
|
|
52
49
|
return null
|
|
53
50
|
}
|
|
54
51
|
|
|
@@ -63,16 +60,23 @@ class FFmpegFormatContext extends ReferenceCounted {
|
|
|
63
60
|
|
|
64
61
|
return this._streams[bestIndex]
|
|
65
62
|
}
|
|
63
|
+
|
|
64
|
+
[Symbol.dispose]() {
|
|
65
|
+
this.destroy()
|
|
66
|
+
}
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
let defaultURL = null
|
|
69
70
|
|
|
70
71
|
switch (Bare.platform) {
|
|
71
72
|
case 'darwin':
|
|
72
|
-
|
|
73
|
+
case 'ios':
|
|
74
|
+
defaultURL = '0:0'
|
|
73
75
|
break
|
|
74
76
|
case 'linux':
|
|
75
77
|
// TODO: test on real machine
|
|
78
|
+
// we might need separate contexts for linux
|
|
79
|
+
// video: V4L2 and audio: ALSA/PulseAudio
|
|
76
80
|
defaultURL = '/dev/video0'
|
|
77
81
|
break
|
|
78
82
|
case 'win32':
|
|
@@ -86,14 +90,20 @@ exports.InputFormatContext = class FFmpegInputFormatContext extends (
|
|
|
86
90
|
constructor(io, options, url = defaultURL) {
|
|
87
91
|
if (io instanceof IOContext) {
|
|
88
92
|
super(io)
|
|
93
|
+
|
|
89
94
|
this._handle = binding.openInputFormatContextWithIO(io._handle)
|
|
90
95
|
} else if (io instanceof InputFormat) {
|
|
91
96
|
super()
|
|
97
|
+
|
|
98
|
+
options = options || new Dictionary()
|
|
99
|
+
|
|
92
100
|
this._handle = binding.openInputFormatContextWithFormat(
|
|
93
101
|
io._handle,
|
|
94
102
|
options._handle,
|
|
95
103
|
url
|
|
96
104
|
)
|
|
105
|
+
|
|
106
|
+
options.destroy()
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
for (const handle of binding.getFormatContextStreams(this._handle)) {
|
|
@@ -101,8 +111,12 @@ exports.InputFormatContext = class FFmpegInputFormatContext extends (
|
|
|
101
111
|
}
|
|
102
112
|
}
|
|
103
113
|
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
dump(printIdx = 0, printUrl = '') {
|
|
115
|
+
binding.dumpFormatContext(this._handle, false, printIdx, printUrl)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
destroy() {
|
|
119
|
+
super.destroy()
|
|
106
120
|
|
|
107
121
|
binding.closeInputFormatContext(this._handle)
|
|
108
122
|
this._handle = null
|
|
@@ -118,22 +132,39 @@ exports.OutputFormatContext = class FFmpegOutputFormatContext extends (
|
|
|
118
132
|
if (typeof format === 'string') format = new OutputFormat(format)
|
|
119
133
|
|
|
120
134
|
this._handle = binding.openOutputFormatContext(format._handle, io._handle)
|
|
135
|
+
this._isOutput = true
|
|
121
136
|
}
|
|
122
137
|
|
|
123
|
-
|
|
124
|
-
super.
|
|
138
|
+
destroy() {
|
|
139
|
+
super.destroy()
|
|
125
140
|
|
|
126
141
|
binding.closeOutputFormatContext(this._handle)
|
|
127
142
|
this._handle = null
|
|
128
143
|
}
|
|
129
144
|
|
|
130
|
-
createStream(
|
|
131
|
-
const stream = new Stream(
|
|
132
|
-
binding.createFormatContextStream(this._handle, codec._handle)
|
|
133
|
-
)
|
|
145
|
+
createStream() {
|
|
146
|
+
const stream = new Stream(binding.createFormatContextStream(this._handle))
|
|
134
147
|
|
|
135
148
|
this._streams.push(stream)
|
|
136
149
|
|
|
137
150
|
return stream
|
|
138
151
|
}
|
|
152
|
+
|
|
153
|
+
/** @param {Dictionary} [options] format options */
|
|
154
|
+
writeHeader(options) {
|
|
155
|
+
binding.writeFormatContextHeader(this._handle, options?._handle)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** @param {Packet} packet */
|
|
159
|
+
writeFrame(packet) {
|
|
160
|
+
binding.writeFormatContextFrame(this._handle, packet._handle)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
writeTrailer() {
|
|
164
|
+
binding.writeFormatContextTrailer(this._handle)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
dump(printIdx = 0, printUrl = '') {
|
|
168
|
+
binding.dumpFormatContext(this._handle, true, printIdx, printUrl)
|
|
169
|
+
}
|
|
139
170
|
}
|
package/lib/frame.js
CHANGED
|
@@ -1,51 +1,122 @@
|
|
|
1
1
|
const binding = require('../binding')
|
|
2
|
-
const
|
|
2
|
+
const ChannelLayout = require('./channel-layout')
|
|
3
|
+
const Rational = require('./rational')
|
|
3
4
|
|
|
4
|
-
module.exports = class FFmpegFrame
|
|
5
|
+
module.exports = class FFmpegFrame {
|
|
5
6
|
constructor() {
|
|
6
|
-
super()
|
|
7
|
-
|
|
8
7
|
this._handle = binding.initFrame()
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
destroy() {
|
|
12
11
|
binding.destroyFrame(this._handle)
|
|
13
12
|
this._handle = null
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
15
|
+
unref() {
|
|
16
|
+
binding.unrefFrame(this._handle)
|
|
17
|
+
}
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
get width() {
|
|
20
|
+
return binding.getFrameWidth(this._handle)
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
set width(value) {
|
|
25
24
|
binding.setFrameWidth(this._handle, value)
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
get
|
|
29
|
-
return binding.
|
|
27
|
+
get height() {
|
|
28
|
+
return binding.getFrameHeight(this._handle)
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
set height(value) {
|
|
33
32
|
binding.setFrameHeight(this._handle, value)
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
get
|
|
37
|
-
return binding.
|
|
35
|
+
get pixelFormat() {
|
|
36
|
+
return binding.getFramePixelFormat(this._handle)
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
set pixelFormat(value) {
|
|
41
40
|
binding.setFramePixelFormat(this._handle, value)
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
get
|
|
45
|
-
return binding.
|
|
43
|
+
get format() {
|
|
44
|
+
return binding.getFrameFormat(this._handle)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
set format(value) {
|
|
48
|
+
binding.setFrameFormat(this._handle, value)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get channelLayout() {
|
|
52
|
+
return new ChannelLayout(binding.getFrameChannelLayout(this._handle))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
set channelLayout(value) {
|
|
56
|
+
binding.setFrameChannelLayout(
|
|
57
|
+
this._handle,
|
|
58
|
+
ChannelLayout.from(value)._handle
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get nbSamples() {
|
|
63
|
+
return binding.getFrameNbSamples(this._handle)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
set nbSamples(value) {
|
|
67
|
+
binding.setFrameNbSamples(this._handle, value)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get pictType() {
|
|
71
|
+
return binding.getFramePictType(this._handle)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get pts() {
|
|
75
|
+
return binding.getFramePTS(this._handle)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
set pts(value) {
|
|
79
|
+
return binding.setFramePTS(this._handle, value)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get packetDTS() {
|
|
83
|
+
return binding.getFramePacketDTS(this._handle)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
set packetDTS(value) {
|
|
87
|
+
return binding.setFramePacketDTS(this._handle, value)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get timeBase() {
|
|
91
|
+
const view = new Int32Array(binding.getFrameTimeBase(this._handle))
|
|
92
|
+
return new Rational(view[0], view[1])
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
set timeBase(value) {
|
|
96
|
+
binding.setFrameTimeBase(this._handle, value.numerator, value.denominator)
|
|
46
97
|
}
|
|
47
98
|
|
|
48
99
|
alloc() {
|
|
49
100
|
binding.allocFrame(this._handle, 32)
|
|
50
101
|
}
|
|
102
|
+
|
|
103
|
+
[Symbol.dispose]() {
|
|
104
|
+
this.destroy()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
[Symbol.for('bare.inspect')]() {
|
|
108
|
+
return {
|
|
109
|
+
__proto__: { constructor: FFmpegFrame },
|
|
110
|
+
width: this.width,
|
|
111
|
+
height: this.height,
|
|
112
|
+
pixelFormat: this.pixelFormat,
|
|
113
|
+
format: this.format,
|
|
114
|
+
channelLayout: this.channelLayout,
|
|
115
|
+
nbSamples: this.nbSamples,
|
|
116
|
+
pictType: this.pictType,
|
|
117
|
+
pts: this.pts,
|
|
118
|
+
packetDTS: this.packetDTS,
|
|
119
|
+
timeBase: this.timeBase
|
|
120
|
+
}
|
|
121
|
+
}
|
|
51
122
|
}
|
package/lib/image.js
CHANGED
|
@@ -40,8 +40,30 @@ module.exports = class FFmpegImage {
|
|
|
40
40
|
this._pixelFormat,
|
|
41
41
|
this._width,
|
|
42
42
|
this._height,
|
|
43
|
+
this._align,
|
|
43
44
|
this._data.buffer,
|
|
45
|
+
this._data.byteOffset,
|
|
44
46
|
frame._handle
|
|
45
47
|
)
|
|
46
48
|
}
|
|
49
|
+
|
|
50
|
+
read(frame) {
|
|
51
|
+
binding.readImage(
|
|
52
|
+
this._pixelFormat,
|
|
53
|
+
this._width,
|
|
54
|
+
this._height,
|
|
55
|
+
this._align,
|
|
56
|
+
this._data.buffer,
|
|
57
|
+
this._data.byteOffset,
|
|
58
|
+
frame._handle
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
lineSize(plane = 0) {
|
|
63
|
+
return binding.getImageLineSize(this._pixelFormat, this._width, plane)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static lineSize(pixelFormat, width, plane = 0) {
|
|
67
|
+
return binding.getImageLineSize(pixelFormat, width, plane)
|
|
68
|
+
}
|
|
47
69
|
}
|
package/lib/input-format.js
CHANGED
|
@@ -3,7 +3,11 @@ const binding = require('../binding')
|
|
|
3
3
|
let defaultName = null
|
|
4
4
|
|
|
5
5
|
switch (Bare.platform) {
|
|
6
|
+
case 'android':
|
|
7
|
+
defaultName = 'android_camera'
|
|
8
|
+
break
|
|
6
9
|
case 'darwin':
|
|
10
|
+
case 'ios':
|
|
7
11
|
defaultName = 'avfoundation'
|
|
8
12
|
break
|
|
9
13
|
case 'linux':
|
|
@@ -16,9 +20,10 @@ switch (Bare.platform) {
|
|
|
16
20
|
|
|
17
21
|
module.exports = class FFmpegInputFormat {
|
|
18
22
|
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
23
|
this._handle = binding.initInputFormat(name)
|
|
23
24
|
}
|
|
25
|
+
|
|
26
|
+
get flags() {
|
|
27
|
+
return binding.getInputFormatFlags(this._handle)
|
|
28
|
+
}
|
|
24
29
|
}
|