bare-ffmpeg 1.0.0-0 → 1.0.0-10

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,45 @@
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 ChannelLayout = require('./lib/channel-layout')
2
+ const Codec = require('./lib/codec')
3
+ const CodecContext = require('./lib/codec-context')
4
+ const CodecParameters = require('./lib/codec-parameters')
5
+ const Decoder = require('./lib/decoder')
6
+ const Dictionary = require('./lib/dictionary')
7
+ const Encoder = require('./lib/encoder')
8
+ const {
9
+ InputFormatContext,
10
+ OutputFormatContext
11
+ } = require('./lib/format-context')
12
+ const Frame = require('./lib/frame')
13
+ const Image = require('./lib/image')
14
+ const IOContext = require('./lib/io-context')
15
+ const InputFormat = require('./lib/input-format')
16
+ const OutputFormat = require('./lib/output-format')
17
+ const Packet = require('./lib/packet')
18
+ const Samples = require('./lib/samples')
19
+ const Scaler = require('./lib/scaler')
20
+ const Stream = require('./lib/stream')
21
+ const Rational = require('./lib/rational')
22
+ const Resampler = require('./lib/resampler')
23
+
24
+ exports.ChannelLayout = ChannelLayout
25
+ exports.Codec = Codec
26
+ exports.CodecContext = CodecContext
27
+ exports.CodecParameters = CodecParameters
28
+ exports.Decoder = Decoder
29
+ exports.Dictionary = Dictionary
30
+ exports.Encoder = Encoder
31
+ exports.Frame = Frame
32
+ exports.IOContext = IOContext
33
+ exports.Image = Image
34
+ exports.InputFormat = InputFormat
35
+ exports.InputFormatContext = InputFormatContext
36
+ exports.OutputFormat = OutputFormat
37
+ exports.OutputFormatContext = OutputFormatContext
38
+ exports.Packet = Packet
39
+ exports.Samples = Samples
40
+ exports.Scaler = Scaler
41
+ exports.Stream = Stream
42
+ exports.Rational = Rational
43
+ exports.Resampler = Resampler
13
44
 
14
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
+ }
@@ -1,38 +1,91 @@
1
1
  const binding = require('../binding')
2
+ const Rational = require('./rational')
2
3
 
3
4
  module.exports = class FFmpegCodecContext {
4
- constructor(codec, parameters) {
5
+ constructor(codec) {
5
6
  this._codec = codec
6
- this._handle = binding.initCodecContext(codec._handle, parameters._handle)
7
+ this._opened = false
8
+ this._handle = binding.initCodecContext(codec._handle)
9
+ }
10
+
11
+ destroy() {
12
+ binding.destroyCodecContext(this._handle)
13
+ this._handle = null
7
14
  }
8
15
 
9
16
  get pixelFormat() {
10
17
  return binding.getCodecContextPixelFormat(this._handle)
11
18
  }
12
19
 
20
+ set pixelFormat(value) {
21
+ binding.setCodecContextPixelFormat(this._handle, value)
22
+ }
23
+
13
24
  get width() {
14
25
  return binding.getCodecContextWidth(this._handle)
15
26
  }
16
27
 
28
+ set width(value) {
29
+ binding.setCodecContextWidth(this._handle, value)
30
+ }
31
+
17
32
  get height() {
18
33
  return binding.getCodecContextHeight(this._handle)
19
34
  }
20
35
 
21
- destroy() {
22
- if (this._handle === null) return
23
- binding.destroyCodecContext(this._handle)
24
- this._handle = null
36
+ set height(value) {
37
+ binding.setCodecContextHeight(this._handle, value)
25
38
  }
26
39
 
27
- [Symbol.dispose]() {
28
- this.destroy()
40
+ get sampleFormat() {
41
+ return binding.getCodecContextSampleFormat(this._handle)
42
+ }
43
+
44
+ set sampleFormat(value) {
45
+ return binding.setCodecContextSampleFormat(this._handle, value)
46
+ }
47
+
48
+ get timeBase() {
49
+ const view = new Int32Array(binding.getCodecContextTimeBase(this._handle))
50
+ return new Rational(view[0], view[1])
51
+ }
52
+
53
+ set timeBase(value) {
54
+ binding.setCodecContextTimeBase(
55
+ this._handle,
56
+ value.numerator,
57
+ value.denominator
58
+ )
59
+ }
60
+
61
+ open(options) {
62
+ if (this._opened) return
63
+ this._opened = true
64
+ if (options) {
65
+ binding.openCodecContextWithOptions(this._handle, options._handle)
66
+ } else {
67
+ binding.openCodecContext(this._handle)
68
+ }
69
+ return this
29
70
  }
30
71
 
31
72
  sendPacket(packet) {
32
- binding.sendCodecContextPacket(this._handle, packet._handle)
73
+ return binding.sendCodecContextPacket(this._handle, packet._handle)
74
+ }
75
+
76
+ receivePacket(packet) {
77
+ return binding.receiveCodecContextPacket(this._handle, packet._handle)
78
+ }
79
+
80
+ sendFrame(frame) {
81
+ return binding.sendCodecContextFrame(this._handle, frame._handle)
33
82
  }
34
83
 
35
84
  receiveFrame(frame) {
36
- binding.receiveCodecContextFrame(this._handle, frame._handle)
85
+ return binding.receiveCodecContextFrame(this._handle, frame._handle)
86
+ }
87
+
88
+ [Symbol.dispose]() {
89
+ this.destroy()
37
90
  }
38
91
  }
@@ -1,5 +1,58 @@
1
+ const binding = require('../binding')
2
+ const ChannelLayout = require('./channel-layout')
3
+
1
4
  module.exports = class FFmpegCodecParameters {
2
5
  constructor(handle) {
3
6
  this._handle = handle
4
7
  }
8
+
9
+ destroy() {
10
+ this._handle = null
11
+ }
12
+
13
+ get bitRate() {
14
+ return binding.getCodecParametersBitRate(this._handle)
15
+ }
16
+
17
+ get bitsPerCodedSample() {
18
+ return binding.getCodecParametersBitsPerCodedSample(this._handle)
19
+ }
20
+
21
+ get bitsPerRawSample() {
22
+ return binding.getCodecParametersBitsPerRawSample(this._handle)
23
+ }
24
+
25
+ get format() {
26
+ return binding.getCodecParametersFormat(this._handle)
27
+ }
28
+
29
+ get sampleRate() {
30
+ return binding.getCodecParametersSampleRate(this._handle)
31
+ }
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
+
47
+ fromContext(context) {
48
+ binding.codecParametersFromContext(this._handle, context._handle)
49
+ }
50
+
51
+ toContext(context) {
52
+ binding.codecParametersToContext(context._handle, this._handle)
53
+ }
54
+
55
+ [Symbol.dispose]() {
56
+ this.destroy()
57
+ }
5
58
  }
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,10 @@ 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)
39
+ static AAC = this.for(constants.codecs.AAC)
40
+ static OPUS = this.for(constants.codecs.OPUS)
41
+ static AV1 = this.for(constants.codecs.AV1)
35
42
  }
package/lib/constants.js CHANGED
@@ -1,19 +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 = {
6
+ codecs: {
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
12
+ },
4
13
  pixelFormats: {
5
- RGBA: binding.AV_PIX_FMT_RGBA
14
+ RGBA: binding.AV_PIX_FMT_RGBA,
15
+ RGB24: binding.AV_PIX_FMT_RGB24,
16
+ YUVJ420P: binding.AV_PIX_FMT_YUVJ420P,
17
+ UYVY422: binding.AV_PIX_FMT_UYVY422,
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
6
59
  }
7
60
  }
8
61
 
9
- exports.toPixelFormat = function toPixelFormat(pixelFormat) {
10
- if (typeof pixelFormat === 'number') return pixelFormat
62
+ exports.toPixelFormat = function toPixelFormat(format) {
63
+ if (typeof format === 'number') return format
11
64
 
12
- if (typeof pixelFormat === 'string') {
13
- if (pixelFormat in exports.pixelFormats === false) {
14
- throw errors.UNKNOWN_PIXEL_FORMAT(`Unknown pixel format '${pixelFormat}'`)
65
+ if (typeof format === 'string') {
66
+ if (format in exports.pixelFormats === false) {
67
+ throw errors.UNKNOWN_PIXEL_FORMAT(`Unknown pixel format '${format}'`)
15
68
  }
16
69
 
17
- return exports.pixelFormats[pixelFormat]
70
+ return exports.pixelFormats[format]
18
71
  }
72
+
73
+ throw new TypeError(
74
+ `Pixel format must be a number or string. Received ${typeof format} (${format})`
75
+ )
76
+ }
77
+
78
+ exports.toSampleFormat = function toSampleFormat(format) {
79
+ if (typeof format === 'number') return format
80
+
81
+ if (typeof format === 'string') {
82
+ if (format in exports.sampleFormats === false) {
83
+ throw errors.UNKNOWN_SAMPLE_FORMAT(`Unknown sample format '${format}'`)
84
+ }
85
+
86
+ return exports.sampleFormats[format]
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
+ )
19
108
  }
@@ -0,0 +1,26 @@
1
+ const binding = require('../binding')
2
+
3
+ module.exports = class FFmpegDictionary {
4
+ constructor() {
5
+ this._handle = binding.initDictionary()
6
+ }
7
+
8
+ destroy() {
9
+ binding.destroyDictionary(this._handle)
10
+ this._handle = null
11
+ }
12
+
13
+ get(key) {
14
+ const value = binding.getDictionaryEntry(this._handle, key)
15
+ if (value === undefined) return null
16
+ return value
17
+ }
18
+
19
+ set(key, value) {
20
+ binding.setDictionaryEntry(this._handle, key, value)
21
+ }
22
+
23
+ [Symbol.dispose]() {
24
+ this.destroy()
25
+ }
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
+ }
@@ -1,15 +1,24 @@
1
1
  const binding = require('../binding')
2
2
  const Stream = require('./stream.js')
3
+ const OutputFormat = require('./output-format')
4
+ const IOContext = require('./io-context')
5
+ const InputFormat = require('./input-format')
6
+ const Dictionary = require('./dictionary')
3
7
 
4
- module.exports = class FFmpegFormatContext {
8
+ class FFmpegFormatContext {
5
9
  constructor(io) {
6
10
  this._io = io
7
11
  this._streams = []
8
- this._handle = binding.initFormatContext(io._handle)
12
+ }
9
13
 
10
- for (const handle of binding.getFormatContextStreams(this._handle)) {
11
- this._streams.push(new Stream(handle))
14
+ destroy() {
15
+ if (this._io) {
16
+ this._io.destroy()
17
+ this._io = null
12
18
  }
19
+
20
+ for (const stream of this._streams) stream.destroy()
21
+ this._streams = []
13
22
  }
14
23
 
15
24
  get io() {
@@ -20,18 +29,122 @@ module.exports = class FFmpegFormatContext {
20
29
  return this._streams
21
30
  }
22
31
 
23
- destroy() {
24
- if (this._handle === null) return
25
- binding.destroyFormatContext(this._handle)
26
- this._io = null
27
- this._handle = null
32
+ readFrame(packet) {
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
60
+ }
61
+
62
+ return this._streams[bestIndex]
28
63
  }
29
64
 
30
65
  [Symbol.dispose]() {
31
66
  this.destroy()
32
67
  }
68
+ }
33
69
 
34
- readFrame(packet) {
35
- binding.readFormatContextFrame(this._handle, packet._handle)
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
+
88
+ exports.InputFormatContext = class FFmpegInputFormatContext extends (
89
+ FFmpegFormatContext
90
+ ) {
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()
98
+
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
+ }
109
+
110
+ for (const handle of binding.getFormatContextStreams(this._handle)) {
111
+ this._streams.push(new Stream(handle))
112
+ }
113
+ }
114
+
115
+ destroy() {
116
+ super.destroy()
117
+
118
+ binding.closeInputFormatContext(this._handle)
119
+ this._handle = null
120
+ }
121
+ }
122
+
123
+ exports.OutputFormatContext = class FFmpegOutputFormatContext extends (
124
+ FFmpegFormatContext
125
+ ) {
126
+ constructor(format, io) {
127
+ super(io)
128
+
129
+ if (typeof format === 'string') format = new OutputFormat(format)
130
+
131
+ this._handle = binding.openOutputFormatContext(format._handle, io._handle)
132
+ }
133
+
134
+ destroy() {
135
+ super.destroy()
136
+
137
+ binding.closeOutputFormatContext(this._handle)
138
+ this._handle = null
139
+ }
140
+
141
+ createStream(codec) {
142
+ const stream = new Stream(
143
+ binding.createFormatContextStream(this._handle, codec._handle)
144
+ )
145
+
146
+ this._streams.push(stream)
147
+
148
+ return stream
36
149
  }
37
150
  }
package/lib/frame.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const binding = require('../binding')
2
+ const ChannelLayout = require('./channel-layout')
2
3
 
3
4
  module.exports = class FFmpegFrame {
4
5
  constructor() {
@@ -6,11 +7,64 @@ module.exports = class FFmpegFrame {
6
7
  }
7
8
 
8
9
  destroy() {
9
- if (this._handle === null) return
10
10
  binding.destroyFrame(this._handle)
11
11
  this._handle = null
12
12
  }
13
13
 
14
+ get width() {
15
+ return binding.getFrameWidth(this._handle)
16
+ }
17
+
18
+ set width(value) {
19
+ binding.setFrameWidth(this._handle, value)
20
+ }
21
+
22
+ get height() {
23
+ return binding.getFrameHeight(this._handle)
24
+ }
25
+
26
+ set height(value) {
27
+ binding.setFrameHeight(this._handle, value)
28
+ }
29
+
30
+ get pixelFormat() {
31
+ return binding.getFramePixelFormat(this._handle)
32
+ }
33
+
34
+ set pixelFormat(value) {
35
+ binding.setFramePixelFormat(this._handle, value)
36
+ }
37
+
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)
62
+ }
63
+
64
+ alloc() {
65
+ binding.allocFrame(this._handle, 32)
66
+ }
67
+
14
68
  [Symbol.dispose]() {
15
69
  this.destroy()
16
70
  }
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
  }