bare-ffmpeg 1.0.0-1 → 1.0.0-11
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 +809 -0
- package/index.js +8 -2
- package/lib/channel-layout.js +33 -0
- package/lib/codec-context.js +53 -13
- package/lib/codec-parameters.js +25 -5
- package/lib/codec.js +4 -0
- package/lib/constants.js +91 -7
- package/lib/dictionary.js +9 -16
- package/lib/errors.js +38 -0
- package/lib/format-context.js +81 -20
- package/lib/frame.js +37 -17
- package/lib/image.js +10 -0
- package/lib/input-format.js +1 -3
- package/lib/io-context.js +11 -6
- package/lib/packet.js +25 -9
- package/lib/resampler.js +63 -0
- package/lib/samples.js +49 -0
- package/lib/scaler.js +6 -5
- package/lib/stream.js +6 -5
- package/package.json +3 -2
- 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 -1819
- package/lib/reference-counted.js +0 -39
package/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
const ChannelLayout = require('./lib/channel-layout')
|
|
1
2
|
const Codec = require('./lib/codec')
|
|
2
3
|
const CodecContext = require('./lib/codec-context')
|
|
3
4
|
const CodecParameters = require('./lib/codec-parameters')
|
|
4
5
|
const Decoder = require('./lib/decoder')
|
|
6
|
+
const Dictionary = require('./lib/dictionary')
|
|
5
7
|
const Encoder = require('./lib/encoder')
|
|
6
8
|
const {
|
|
7
9
|
InputFormatContext,
|
|
@@ -13,15 +15,18 @@ const IOContext = require('./lib/io-context')
|
|
|
13
15
|
const InputFormat = require('./lib/input-format')
|
|
14
16
|
const OutputFormat = require('./lib/output-format')
|
|
15
17
|
const Packet = require('./lib/packet')
|
|
18
|
+
const Samples = require('./lib/samples')
|
|
16
19
|
const Scaler = require('./lib/scaler')
|
|
17
20
|
const Stream = require('./lib/stream')
|
|
18
21
|
const Rational = require('./lib/rational')
|
|
19
|
-
const
|
|
22
|
+
const Resampler = require('./lib/resampler')
|
|
20
23
|
|
|
24
|
+
exports.ChannelLayout = ChannelLayout
|
|
21
25
|
exports.Codec = Codec
|
|
22
26
|
exports.CodecContext = CodecContext
|
|
23
27
|
exports.CodecParameters = CodecParameters
|
|
24
28
|
exports.Decoder = Decoder
|
|
29
|
+
exports.Dictionary = Dictionary
|
|
25
30
|
exports.Encoder = Encoder
|
|
26
31
|
exports.Frame = Frame
|
|
27
32
|
exports.IOContext = IOContext
|
|
@@ -31,9 +36,10 @@ exports.InputFormatContext = InputFormatContext
|
|
|
31
36
|
exports.OutputFormat = OutputFormat
|
|
32
37
|
exports.OutputFormatContext = OutputFormatContext
|
|
33
38
|
exports.Packet = Packet
|
|
39
|
+
exports.Samples = Samples
|
|
34
40
|
exports.Scaler = Scaler
|
|
35
41
|
exports.Stream = Stream
|
|
36
42
|
exports.Rational = Rational
|
|
37
|
-
exports.
|
|
43
|
+
exports.Resampler = Resampler
|
|
38
44
|
|
|
39
45
|
exports.constants = require('./lib/constants')
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const binding = require('../binding')
|
|
2
|
+
const constants = require('./constants')
|
|
3
|
+
|
|
4
|
+
module.exports = class FFmpegChannelLayout {
|
|
5
|
+
constructor(handle) {
|
|
6
|
+
this._handle = handle
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
get nbChannels() {
|
|
10
|
+
return binding.getChannelLayoutNbChannels(this._handle)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
destroy() {
|
|
14
|
+
binding.destroyChannelLayout(this._handle)
|
|
15
|
+
this._handle = null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
[Symbol.dispose]() {
|
|
19
|
+
this.destroy()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static from(value) {
|
|
23
|
+
if (typeof value === 'string') value = constants.toChannelLayout(value)
|
|
24
|
+
|
|
25
|
+
if (typeof value === 'number') {
|
|
26
|
+
value = binding.channelLayoutFromMask(value)
|
|
27
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
28
|
+
value = binding.copyChannelLayout(value._handle)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return new this(value)
|
|
32
|
+
}
|
|
33
|
+
}
|
package/lib/codec-context.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
const binding = require('../binding')
|
|
2
|
-
const ReferenceCounted = require('./reference-counted')
|
|
3
2
|
const Rational = require('./rational')
|
|
3
|
+
const ChannelLayout = require('./channel-layout')
|
|
4
4
|
|
|
5
|
-
module.exports = class FFmpegCodecContext
|
|
5
|
+
module.exports = class FFmpegCodecContext {
|
|
6
6
|
constructor(codec) {
|
|
7
|
-
super()
|
|
8
|
-
|
|
9
7
|
this._codec = codec
|
|
10
8
|
this._opened = false
|
|
11
9
|
this._handle = binding.initCodecContext(codec._handle)
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
destroy() {
|
|
15
13
|
binding.destroyCodecContext(this._handle)
|
|
16
14
|
this._handle = null
|
|
17
15
|
}
|
|
@@ -40,31 +38,73 @@ module.exports = class FFmpegCodecContext extends ReferenceCounted {
|
|
|
40
38
|
binding.setCodecContextHeight(this._handle, value)
|
|
41
39
|
}
|
|
42
40
|
|
|
41
|
+
get sampleFormat() {
|
|
42
|
+
return binding.getCodecContextSampleFormat(this._handle)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
set sampleFormat(value) {
|
|
46
|
+
return binding.setCodecContextSampleFormat(this._handle, value)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get sampleRate() {
|
|
50
|
+
return binding.getCodecContextSampleRate(this._handle)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
set sampleRate(value) {
|
|
54
|
+
binding.setCodecContextSampleRate(this._handle, value)
|
|
55
|
+
}
|
|
56
|
+
|
|
43
57
|
get timeBase() {
|
|
44
58
|
const view = new Int32Array(binding.getCodecContextTimeBase(this._handle))
|
|
45
59
|
return new Rational(view[0], view[1])
|
|
46
60
|
}
|
|
47
61
|
|
|
48
62
|
set timeBase(value) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
63
|
+
binding.setCodecContextTimeBase(
|
|
64
|
+
this._handle,
|
|
65
|
+
value.numerator,
|
|
66
|
+
value.denominator
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get channelLayout() {
|
|
71
|
+
return new ChannelLayout(binding.getCodecContextChannelLayout(this._handle))
|
|
53
72
|
}
|
|
54
73
|
|
|
55
|
-
|
|
74
|
+
set channelLayout(value) {
|
|
75
|
+
using copy = ChannelLayout.from(value)
|
|
76
|
+
|
|
77
|
+
binding.setCodecContextChannelLayout(this._handle, copy._handle)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
open(options) {
|
|
56
81
|
if (this._opened) return
|
|
57
82
|
this._opened = true
|
|
58
|
-
|
|
83
|
+
if (options) {
|
|
84
|
+
binding.openCodecContextWithOptions(this._handle, options._handle)
|
|
85
|
+
} else {
|
|
86
|
+
binding.openCodecContext(this._handle)
|
|
87
|
+
}
|
|
59
88
|
return this
|
|
60
89
|
}
|
|
61
90
|
|
|
62
91
|
sendPacket(packet) {
|
|
63
|
-
binding.sendCodecContextPacket(this._handle, packet._handle)
|
|
64
|
-
|
|
92
|
+
return binding.sendCodecContextPacket(this._handle, packet._handle)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
receivePacket(packet) {
|
|
96
|
+
return binding.receiveCodecContextPacket(this._handle, packet._handle)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
sendFrame(frame) {
|
|
100
|
+
return binding.sendCodecContextFrame(this._handle, frame._handle)
|
|
65
101
|
}
|
|
66
102
|
|
|
67
103
|
receiveFrame(frame) {
|
|
68
104
|
return binding.receiveCodecContextFrame(this._handle, frame._handle)
|
|
69
105
|
}
|
|
106
|
+
|
|
107
|
+
[Symbol.dispose]() {
|
|
108
|
+
this.destroy()
|
|
109
|
+
}
|
|
70
110
|
}
|
package/lib/codec-parameters.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
const binding = require('../binding')
|
|
2
|
-
const
|
|
2
|
+
const ChannelLayout = require('./channel-layout')
|
|
3
3
|
|
|
4
|
-
module.exports = class FFmpegCodecParameters
|
|
4
|
+
module.exports = class FFmpegCodecParameters {
|
|
5
5
|
constructor(handle) {
|
|
6
|
-
super()
|
|
7
|
-
|
|
8
6
|
this._handle = handle
|
|
9
7
|
}
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
destroy() {
|
|
12
10
|
this._handle = null
|
|
13
11
|
}
|
|
14
12
|
|
|
@@ -24,10 +22,28 @@ module.exports = class FFmpegCodecParameters extends ReferenceCounted {
|
|
|
24
22
|
return binding.getCodecParametersBitsPerRawSample(this._handle)
|
|
25
23
|
}
|
|
26
24
|
|
|
25
|
+
get format() {
|
|
26
|
+
return binding.getCodecParametersFormat(this._handle)
|
|
27
|
+
}
|
|
28
|
+
|
|
27
29
|
get sampleRate() {
|
|
28
30
|
return binding.getCodecParametersSampleRate(this._handle)
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
get nbChannels() {
|
|
34
|
+
return binding.getCodecParametersNbChannels(this._handle)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get codecType() {
|
|
38
|
+
return binding.getCodecParametersCodecType(this._handle)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get channelLayout() {
|
|
42
|
+
return new ChannelLayout(
|
|
43
|
+
binding.getCodecParametersChannelLayout(this._handle)
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
31
47
|
fromContext(context) {
|
|
32
48
|
binding.codecParametersFromContext(this._handle, context._handle)
|
|
33
49
|
}
|
|
@@ -35,4 +51,8 @@ module.exports = class FFmpegCodecParameters extends ReferenceCounted {
|
|
|
35
51
|
toContext(context) {
|
|
36
52
|
binding.codecParametersToContext(context._handle, this._handle)
|
|
37
53
|
}
|
|
54
|
+
|
|
55
|
+
[Symbol.dispose]() {
|
|
56
|
+
this.destroy()
|
|
57
|
+
}
|
|
38
58
|
}
|
package/lib/codec.js
CHANGED
|
@@ -35,4 +35,8 @@ module.exports = class FFmpegCodec {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
static MJPEG = this.for(constants.codecs.MJPEG)
|
|
38
|
+
static H264 = this.for(constants.codecs.H264)
|
|
39
|
+
static AAC = this.for(constants.codecs.AAC)
|
|
40
|
+
static OPUS = this.for(constants.codecs.OPUS)
|
|
41
|
+
static AV1 = this.for(constants.codecs.AV1)
|
|
38
42
|
}
|
package/lib/constants.js
CHANGED
|
@@ -1,24 +1,108 @@
|
|
|
1
1
|
const binding = require('../binding')
|
|
2
|
+
const errors = require('./errors')
|
|
3
|
+
const ChannelLayout = require('./channel-layout')
|
|
2
4
|
|
|
3
5
|
module.exports = exports = {
|
|
4
6
|
codecs: {
|
|
5
|
-
MJPEG: binding.AV_CODEC_ID_MJPEG
|
|
7
|
+
MJPEG: binding.AV_CODEC_ID_MJPEG,
|
|
8
|
+
H264: binding.AV_CODEC_ID_H264,
|
|
9
|
+
AAC: binding.AV_CODEC_ID_AAC,
|
|
10
|
+
OPUS: binding.AV_CODEC_ID_OPUS,
|
|
11
|
+
AV1: binding.AV_CODEC_ID_AV1
|
|
6
12
|
},
|
|
7
13
|
pixelFormats: {
|
|
8
14
|
RGBA: binding.AV_PIX_FMT_RGBA,
|
|
15
|
+
RGB24: binding.AV_PIX_FMT_RGB24,
|
|
9
16
|
YUVJ420P: binding.AV_PIX_FMT_YUVJ420P,
|
|
17
|
+
UYVY422: binding.AV_PIX_FMT_UYVY422,
|
|
10
18
|
YUV420P: binding.AV_PIX_FMT_YUV420P
|
|
19
|
+
},
|
|
20
|
+
mediaTypes: {
|
|
21
|
+
UNKNOWN: binding.AVMEDIA_TYPE_UNKNOWN,
|
|
22
|
+
VIDEO: binding.AVMEDIA_TYPE_VIDEO,
|
|
23
|
+
AUDIO: binding.AVMEDIA_TYPE_AUDIO,
|
|
24
|
+
DATA: binding.AVMEDIA_TYPE_DATA,
|
|
25
|
+
SUBTITLE: binding.AVMEDIA_TYPE_SUBTITLE,
|
|
26
|
+
ATTACHEMENT: binding.AVMEDIA_TYPE_ATTACHMENT,
|
|
27
|
+
NB: binding.AVMEDIA_TYPE_NB
|
|
28
|
+
},
|
|
29
|
+
sampleFormats: {
|
|
30
|
+
NONE: binding.AV_SAMPLE_FMT_NONE,
|
|
31
|
+
U8: binding.AV_SAMPLE_FMT_U8,
|
|
32
|
+
S16: binding.AV_SAMPLE_FMT_S16,
|
|
33
|
+
S32: binding.AV_SAMPLE_FMT_S32,
|
|
34
|
+
S64: binding.AV_SAMPLE_FMT_S64,
|
|
35
|
+
FLT: binding.AV_SAMPLE_FMT_FLT,
|
|
36
|
+
DBL: binding.AV_SAMPLE_FMT_DBL,
|
|
37
|
+
U8P: binding.AV_SAMPLE_FMT_U8P,
|
|
38
|
+
S16P: binding.AV_SAMPLE_FMT_S16P,
|
|
39
|
+
S32P: binding.AV_SAMPLE_FMT_S32P,
|
|
40
|
+
S64P: binding.AV_SAMPLE_FMT_S64P,
|
|
41
|
+
FLTP: binding.AV_SAMPLE_FMT_FLTP,
|
|
42
|
+
DBLP: binding.AV_SAMPLE_FMT_DBLP,
|
|
43
|
+
NB: binding.AV_SAMPLE_FMT_NB
|
|
44
|
+
},
|
|
45
|
+
channelLayouts: {
|
|
46
|
+
MONO: binding.AV_CH_LAYOUT_MONO,
|
|
47
|
+
STEREO: binding.AV_CH_LAYOUT_STEREO,
|
|
48
|
+
QUAD: binding.AV_CH_LAYOUT_QUAD,
|
|
49
|
+
SURROUND: binding.AV_CH_LAYOUT_SURROUND,
|
|
50
|
+
2_1: binding.AV_CH_LAYOUT_2POINT1,
|
|
51
|
+
5_0: binding.AV_CH_LAYOUT_5POINT0,
|
|
52
|
+
5_1: binding.AV_CH_LAYOUT_5POINT1,
|
|
53
|
+
7_1: binding.AV_CH_LAYOUT_7POINT1,
|
|
54
|
+
// Aliases
|
|
55
|
+
2.1: binding.AV_CH_LAYOUT_2POINT1,
|
|
56
|
+
'5.0': binding.AV_CH_LAYOUT_5POINT0,
|
|
57
|
+
5.1: binding.AV_CH_LAYOUT_5POINT1,
|
|
58
|
+
7.1: binding.AV_CH_LAYOUT_7POINT1
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
exports.toPixelFormat = function toPixelFormat(format) {
|
|
63
|
+
if (typeof format === 'number') return format
|
|
64
|
+
|
|
65
|
+
if (typeof format === 'string') {
|
|
66
|
+
if (format in exports.pixelFormats === false) {
|
|
67
|
+
throw errors.UNKNOWN_PIXEL_FORMAT(`Unknown pixel format '${format}'`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return exports.pixelFormats[format]
|
|
11
71
|
}
|
|
72
|
+
|
|
73
|
+
throw new TypeError(
|
|
74
|
+
`Pixel format must be a number or string. Received ${typeof format} (${format})`
|
|
75
|
+
)
|
|
12
76
|
}
|
|
13
77
|
|
|
14
|
-
exports.
|
|
15
|
-
if (typeof
|
|
78
|
+
exports.toSampleFormat = function toSampleFormat(format) {
|
|
79
|
+
if (typeof format === 'number') return format
|
|
16
80
|
|
|
17
|
-
if (typeof
|
|
18
|
-
if (
|
|
19
|
-
throw errors.
|
|
81
|
+
if (typeof format === 'string') {
|
|
82
|
+
if (format in exports.sampleFormats === false) {
|
|
83
|
+
throw errors.UNKNOWN_SAMPLE_FORMAT(`Unknown sample format '${format}'`)
|
|
20
84
|
}
|
|
21
85
|
|
|
22
|
-
return exports.
|
|
86
|
+
return exports.sampleFormats[format]
|
|
23
87
|
}
|
|
88
|
+
|
|
89
|
+
throw new TypeError(
|
|
90
|
+
`Sample format must be a number or string. Received ${typeof format} (${format})`
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
exports.toChannelLayout = function toChannelLayout(layout) {
|
|
95
|
+
if (typeof layout === 'number') return layout
|
|
96
|
+
|
|
97
|
+
if (typeof layout === 'string') {
|
|
98
|
+
if (layout in exports.channelLayouts === false) {
|
|
99
|
+
throw errors.UNKNOWN_CHANNEL_LAYOUT(`Unknown channel layout '${layout}'`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return exports.channelLayouts[layout]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
throw new TypeError(
|
|
106
|
+
`Channel layout must be a number or string. Received ${typeof layout} (${layout})`
|
|
107
|
+
)
|
|
24
108
|
}
|
package/lib/dictionary.js
CHANGED
|
@@ -1,33 +1,26 @@
|
|
|
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 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
20
|
binding.setDictionaryEntry(this._handle, key, value)
|
|
32
21
|
}
|
|
22
|
+
|
|
23
|
+
[Symbol.dispose]() {
|
|
24
|
+
this.destroy()
|
|
25
|
+
}
|
|
33
26
|
}
|
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,19 +1,21 @@
|
|
|
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')
|
|
4
|
+
const IOContext = require('./io-context')
|
|
5
|
+
const InputFormat = require('./input-format')
|
|
6
|
+
const Dictionary = require('./dictionary')
|
|
5
7
|
|
|
6
|
-
class FFmpegFormatContext
|
|
8
|
+
class FFmpegFormatContext {
|
|
7
9
|
constructor(io) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
this._io = io._ref()
|
|
10
|
+
this._io = io
|
|
11
11
|
this._streams = []
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
this._io
|
|
16
|
-
|
|
14
|
+
destroy() {
|
|
15
|
+
if (this._io) {
|
|
16
|
+
this._io.destroy()
|
|
17
|
+
this._io = null
|
|
18
|
+
}
|
|
17
19
|
|
|
18
20
|
for (const stream of this._streams) stream.destroy()
|
|
19
21
|
this._streams = []
|
|
@@ -28,31 +30,90 @@ class FFmpegFormatContext extends ReferenceCounted {
|
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
readFrame(packet) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
return binding.readFormatContextFrame(this._handle, packet._handle)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getBestStreamIndex(type) {
|
|
37
|
+
return binding.getFormatContextBestStreamIndex(this._handle, type)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getStream(index) {
|
|
41
|
+
if (index < 0 || index >= this._streams.length) {
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return this._streams[index]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getBestStream(type) {
|
|
49
|
+
if (this._streams.length == 0) {
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const bestIndex = binding.getFormatContextBestStreamIndex(
|
|
54
|
+
this._handle,
|
|
55
|
+
type
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
if (bestIndex < 0 || bestIndex >= this._streams.length) {
|
|
59
|
+
return null
|
|
33
60
|
}
|
|
34
61
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
62
|
+
return this._streams[bestIndex]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
[Symbol.dispose]() {
|
|
66
|
+
this.destroy()
|
|
38
67
|
}
|
|
39
68
|
}
|
|
40
69
|
|
|
70
|
+
let defaultURL = null
|
|
71
|
+
|
|
72
|
+
switch (Bare.platform) {
|
|
73
|
+
case 'darwin':
|
|
74
|
+
case 'ios':
|
|
75
|
+
defaultURL = '0:0'
|
|
76
|
+
break
|
|
77
|
+
case 'linux':
|
|
78
|
+
// TODO: test on real machine
|
|
79
|
+
// we might need separate contexts for linux
|
|
80
|
+
// video: V4L2 and audio: ALSA/PulseAudio
|
|
81
|
+
defaultURL = '/dev/video0'
|
|
82
|
+
break
|
|
83
|
+
case 'win32':
|
|
84
|
+
defaultURL = 'video=Integrated Camera'
|
|
85
|
+
break
|
|
86
|
+
}
|
|
87
|
+
|
|
41
88
|
exports.InputFormatContext = class FFmpegInputFormatContext extends (
|
|
42
89
|
FFmpegFormatContext
|
|
43
90
|
) {
|
|
44
|
-
constructor(io) {
|
|
45
|
-
|
|
91
|
+
constructor(io, options, url = defaultURL) {
|
|
92
|
+
if (io instanceof IOContext) {
|
|
93
|
+
super(io)
|
|
94
|
+
|
|
95
|
+
this._handle = binding.openInputFormatContextWithIO(io._handle)
|
|
96
|
+
} else if (io instanceof InputFormat) {
|
|
97
|
+
super()
|
|
46
98
|
|
|
47
|
-
|
|
99
|
+
options = options || new Dictionary()
|
|
100
|
+
|
|
101
|
+
this._handle = binding.openInputFormatContextWithFormat(
|
|
102
|
+
io._handle,
|
|
103
|
+
options._handle,
|
|
104
|
+
url
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
options.destroy()
|
|
108
|
+
}
|
|
48
109
|
|
|
49
110
|
for (const handle of binding.getFormatContextStreams(this._handle)) {
|
|
50
111
|
this._streams.push(new Stream(handle))
|
|
51
112
|
}
|
|
52
113
|
}
|
|
53
114
|
|
|
54
|
-
|
|
55
|
-
super.
|
|
115
|
+
destroy() {
|
|
116
|
+
super.destroy()
|
|
56
117
|
|
|
57
118
|
binding.closeInputFormatContext(this._handle)
|
|
58
119
|
this._handle = null
|
|
@@ -70,8 +131,8 @@ exports.OutputFormatContext = class FFmpegOutputFormatContext extends (
|
|
|
70
131
|
this._handle = binding.openOutputFormatContext(format._handle, io._handle)
|
|
71
132
|
}
|
|
72
133
|
|
|
73
|
-
|
|
74
|
-
super.
|
|
134
|
+
destroy() {
|
|
135
|
+
super.destroy()
|
|
75
136
|
|
|
76
137
|
binding.closeOutputFormatContext(this._handle)
|
|
77
138
|
this._handle = null
|
package/lib/frame.js
CHANGED
|
@@ -1,51 +1,71 @@
|
|
|
1
1
|
const binding = require('../binding')
|
|
2
|
-
const
|
|
2
|
+
const ChannelLayout = require('./channel-layout')
|
|
3
3
|
|
|
4
|
-
module.exports = class FFmpegFrame
|
|
4
|
+
module.exports = class FFmpegFrame {
|
|
5
5
|
constructor() {
|
|
6
|
-
super()
|
|
7
|
-
|
|
8
6
|
this._handle = binding.initFrame()
|
|
9
7
|
}
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
destroy() {
|
|
12
10
|
binding.destroyFrame(this._handle)
|
|
13
11
|
this._handle = null
|
|
14
12
|
}
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
throw new RangeError(`Channel index must be between 0 and 7`)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return Buffer.from(binding.getFrameChannel(this._handle, i))
|
|
14
|
+
get width() {
|
|
15
|
+
return binding.getFrameWidth(this._handle)
|
|
22
16
|
}
|
|
23
17
|
|
|
24
18
|
set width(value) {
|
|
25
19
|
binding.setFrameWidth(this._handle, value)
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
get
|
|
29
|
-
return binding.
|
|
22
|
+
get height() {
|
|
23
|
+
return binding.getFrameHeight(this._handle)
|
|
30
24
|
}
|
|
31
25
|
|
|
32
26
|
set height(value) {
|
|
33
27
|
binding.setFrameHeight(this._handle, value)
|
|
34
28
|
}
|
|
35
29
|
|
|
36
|
-
get
|
|
37
|
-
return binding.
|
|
30
|
+
get pixelFormat() {
|
|
31
|
+
return binding.getFramePixelFormat(this._handle)
|
|
38
32
|
}
|
|
39
33
|
|
|
40
34
|
set pixelFormat(value) {
|
|
41
35
|
binding.setFramePixelFormat(this._handle, value)
|
|
42
36
|
}
|
|
43
37
|
|
|
44
|
-
get
|
|
45
|
-
return binding.
|
|
38
|
+
get format() {
|
|
39
|
+
return binding.getFrameFormat(this._handle)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
set format(value) {
|
|
43
|
+
binding.setFrameFormat(this._handle, value)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get channelLayout() {
|
|
47
|
+
return new ChannelLayout(binding.getFrameChannelLayout(this._handle))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
set channelLayout(value) {
|
|
51
|
+
using copy = ChannelLayout.from(value)
|
|
52
|
+
|
|
53
|
+
binding.setFrameChannelLayout(this._handle, copy._handle)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get nbSamples() {
|
|
57
|
+
return binding.getFrameNbSamples(this._handle)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
set nbSamples(value) {
|
|
61
|
+
binding.setFrameNbSamples(this._handle, value)
|
|
46
62
|
}
|
|
47
63
|
|
|
48
64
|
alloc() {
|
|
49
65
|
binding.allocFrame(this._handle, 32)
|
|
50
66
|
}
|
|
67
|
+
|
|
68
|
+
[Symbol.dispose]() {
|
|
69
|
+
this.destroy()
|
|
70
|
+
}
|
|
51
71
|
}
|
package/lib/image.js
CHANGED
|
@@ -40,8 +40,18 @@ 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
|
+
lineSize(plane = 0) {
|
|
51
|
+
return binding.getImageLineSize(this._pixelFormat, this._width, plane)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static lineSize(pixelFormat, width, plane = 0) {
|
|
55
|
+
return binding.getImageLineSize(pixelFormat, width, plane)
|
|
56
|
+
}
|
|
47
57
|
}
|