bare-ffmpeg 1.0.0-27 → 1.0.0-29

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/README.md CHANGED
@@ -266,6 +266,12 @@ Parameters:
266
266
 
267
267
  #### Methods
268
268
 
269
+ ##### `InputFormatContext.inputFormat`
270
+
271
+ Gets the input format associated with this context.
272
+
273
+ **Returns**: `InputFormat` instance or `undefined` if not available
274
+
269
275
  ##### `InputFormatContext.destroy()`
270
276
 
271
277
  Destroys the `InputFormatContext` and closes the input format. Automatically called when the object is managed by a `using` declaration.
@@ -299,6 +305,12 @@ Parameters:
299
305
 
300
306
  **Returns**: A new `Stream` instance
301
307
 
308
+ ##### `OutputFormatContext.outputFormat`
309
+
310
+ Gets the output format associated with this context.
311
+
312
+ **Returns**: `OutputFormat` instance or `undefined` if not available
313
+
302
314
  ##### `OutputFormatContext.destroy()`
303
315
 
304
316
  Destroys the `OutputFormatContext` and closes the output format. Automatically called when the object is managed by a `using` declaration.
@@ -698,6 +710,28 @@ Parameters:
698
710
 
699
711
  **Returns**: A new `InputFormat` instance
700
712
 
713
+ #### Properties
714
+
715
+ ##### `InputFormat.extensions`
716
+
717
+ Gets the file extensions associated with this input format.
718
+
719
+ **Returns**: `string` - Comma-separated list of file extensions (e.g., `'mkv,mk3d,mka,mks,webm'`)
720
+
721
+ ##### `InputFormat.mimeType`
722
+
723
+ Gets the MIME type for this input format.
724
+
725
+ **Returns**: `string` - The MIME type (e.g., `'audio/webm,audio/x-matroska,video/webm,video/x-matroska'`)
726
+
727
+ #### Example
728
+
729
+ ```js
730
+ const format = new ffmpeg.InputFormat('webm')
731
+ console.log(format.extensions) // 'mkv,mk3d,mka,mks,webm'
732
+ console.log(format.mimeType) // 'audio/webm,audio/x-matroska,video/webm,video/x-matroska'
733
+ ```
734
+
701
735
  #### Methods
702
736
 
703
737
  ##### `InputFormat.destroy()`
@@ -720,6 +754,28 @@ Parameters:
720
754
 
721
755
  **Returns**: A new `OutputFormat` instance
722
756
 
757
+ #### Properties
758
+
759
+ ##### `OutputFormat.extensions`
760
+
761
+ Gets the file extensions associated with this output format.
762
+
763
+ **Returns**: `string` - Comma-separated list of file extensions (e.g., `'webm'`, `'mp4,m4a,m4v'`)
764
+
765
+ ##### `OutputFormat.mimeType`
766
+
767
+ Gets the MIME type for this output format.
768
+
769
+ **Returns**: `string` - The MIME type (e.g., `'video/webm'`, `'video/mp4'`)
770
+
771
+ #### Example
772
+
773
+ ```js
774
+ const format = new ffmpeg.OutputFormat('webm')
775
+ console.log(format.extensions) // 'webm'
776
+ console.log(format.mimeType) // 'video/webm'
777
+ ```
778
+
723
779
  #### Methods
724
780
 
725
781
  ##### `OutputFormat.destroy()`
@@ -784,6 +840,25 @@ Destroys the `Frame` and frees all associated resources. Automatically called wh
784
840
 
785
841
  **Returns**: `void`
786
842
 
843
+ ##### `Frame.copyProperties(otherFrame)`
844
+
845
+ Copies all metadata properties such as timestamps, timebase and width/height for videoframes and
846
+ sampleRate channelLayout for audioFrames.
847
+
848
+ see `av_frame_copy_props()` for details.
849
+
850
+ ```js
851
+ const src = new ffmpeg.Frame()
852
+ const dst = new ffmpeg.Frame()
853
+
854
+ decoder.receiveFrame(src)
855
+ rescaler.convert(src, dst)
856
+
857
+ dst.copyProperties(src) // transfer all meta-data
858
+ ```
859
+
860
+ **Returns**: `void`
861
+
787
862
  ### `Packet`
788
863
 
789
864
  This structure stores compressed data. It is typically exported by demuxers and then passed as input to decoders, or received as output from encoders and then passed to muxers.
package/binding.cc CHANGED
@@ -29,6 +29,7 @@ extern "C" {
29
29
  #include <libavutil/frame.h>
30
30
  #include <libavutil/imgutils.h>
31
31
  #include <libavutil/log.h>
32
+ #include <libavutil/mathematics.h>
32
33
  #include <libavutil/mem.h>
33
34
  #include <libavutil/pixfmt.h>
34
35
  #include <libavutil/rational.h>
@@ -129,12 +130,6 @@ typedef struct {
129
130
 
130
131
  static uv_once_t bare_ffmpeg__init_guard = UV_ONCE_INIT;
131
132
 
132
- static inline bool
133
- bare_ffmpeg__bad_timebase(const AVRational r) {
134
- return r.den < 1 || // Invalid denominator
135
- av_q2d(r) == 0; // Initial state (0 / 1)
136
- }
137
-
138
133
  static void
139
134
  bare_ffmpeg__on_init(void) {
140
135
  av_log_set_level(AV_LOG_ERROR);
@@ -376,6 +371,24 @@ bare_ffmpeg_input_format_get_flags(
376
371
  return format->handle->flags;
377
372
  }
378
373
 
374
+ static std::string
375
+ bare_ffmpeg_input_format_get_extensions(
376
+ js_env_t *env,
377
+ js_receiver_t,
378
+ js_arraybuffer_span_of_t<bare_ffmpeg_input_format_t, 1> context
379
+ ) {
380
+ return context->handle->extensions;
381
+ }
382
+
383
+ static std::string
384
+ bare_ffmpeg_input_format_get_mime_type(
385
+ js_env_t *env,
386
+ js_receiver_t,
387
+ js_arraybuffer_span_of_t<bare_ffmpeg_input_format_t, 1> context
388
+ ) {
389
+ return context->handle->mime_type;
390
+ }
391
+
379
392
  static js_arraybuffer_t
380
393
  bare_ffmpeg_format_context_open_input_with_io(
381
394
  js_env_t *env,
@@ -503,6 +516,24 @@ bare_ffmpeg_format_context_open_output(
503
516
  return handle;
504
517
  }
505
518
 
519
+ static std::string
520
+ bare_ffmpeg_output_format_get_extensions(
521
+ js_env_t *env,
522
+ js_receiver_t,
523
+ js_arraybuffer_span_of_t<bare_ffmpeg_output_format_t, 1> context
524
+ ) {
525
+ return context->handle->extensions;
526
+ }
527
+
528
+ static std::string
529
+ bare_ffmpeg_output_format_get_mime_type(
530
+ js_env_t *env,
531
+ js_receiver_t,
532
+ js_arraybuffer_span_of_t<bare_ffmpeg_output_format_t, 1> context
533
+ ) {
534
+ return context->handle->mime_type;
535
+ }
536
+
506
537
  static void
507
538
  bare_ffmpeg_format_context_close_output(
508
539
  js_env_t *env,
@@ -675,6 +706,48 @@ bare_ffmpeg_format_context_dump(
675
706
  }
676
707
  }
677
708
 
709
+ static std::optional<js_arraybuffer_t>
710
+ get_bare_ffmpeg_format_context_output_format(
711
+ js_env_t *env,
712
+ js_receiver_t,
713
+ js_arraybuffer_span_of_t<bare_ffmpeg_format_context_t, 1> context
714
+ ) {
715
+ int err;
716
+
717
+ if (!context->handle->oformat) return std::nullopt;
718
+
719
+ js_arraybuffer_t handle;
720
+
721
+ bare_ffmpeg_output_format_t *format;
722
+ err = js_create_arraybuffer(env, format, handle);
723
+ assert(err == 0);
724
+
725
+ format->handle = context->handle->oformat;
726
+
727
+ return handle;
728
+ }
729
+
730
+ static std::optional<js_arraybuffer_t>
731
+ get_bare_ffmpeg_format_context_input_format(
732
+ js_env_t *env,
733
+ js_receiver_t,
734
+ js_arraybuffer_span_of_t<bare_ffmpeg_format_context_t, 1> context
735
+ ) {
736
+ int err;
737
+
738
+ if (!context->handle->iformat) return std::nullopt;
739
+
740
+ js_arraybuffer_t handle;
741
+
742
+ bare_ffmpeg_input_format_t *format;
743
+ err = js_create_arraybuffer(env, format, handle);
744
+ assert(err == 0);
745
+
746
+ format->handle = context->handle->iformat;
747
+
748
+ return handle;
749
+ }
750
+
678
751
  static int32_t
679
752
  bare_ffmpeg_stream_get_index(
680
753
  js_env_t *env,
@@ -1157,6 +1230,23 @@ bare_ffmpeg_frame_set_channel_layout(
1157
1230
  assert(err == 0);
1158
1231
  }
1159
1232
 
1233
+ static void
1234
+ bare_ffmpeg_frame_copy_properties(
1235
+ js_env_t *env,
1236
+ js_receiver_t,
1237
+ js_arraybuffer_span_of_t<bare_ffmpeg_frame_t, 1> dst,
1238
+ js_arraybuffer_span_of_t<bare_ffmpeg_frame_t, 1> src
1239
+ ) {
1240
+ int err = av_frame_copy_props(dst->handle, src->handle);
1241
+
1242
+ if (err < 0) {
1243
+ err = js_throw_error(env, NULL, av_err2str(err));
1244
+ assert(err == 0);
1245
+
1246
+ throw js_pending_exception;
1247
+ }
1248
+ }
1249
+
1160
1250
  static bool
1161
1251
  bare_ffmpeg_codec_context_open_with_options(
1162
1252
  js_env_t *env,
@@ -2722,30 +2812,20 @@ bare_ffmpeg_packet_set_time_base(
2722
2812
  packet->handle->time_base.den = den;
2723
2813
  }
2724
2814
 
2725
- static int64_t
2815
+ static void
2726
2816
  bare_ffmpeg_packet_rescale_ts(
2727
2817
  js_env_t *env,
2728
2818
  js_arraybuffer_span_of_t<bare_ffmpeg_packet_t, 1> packet,
2729
- int32_t num,
2730
- int32_t den
2731
- ) {
2732
- AVRational src = packet->handle->time_base;
2733
- AVRational dst = {num, den};
2734
-
2735
- if (
2736
- bare_ffmpeg__bad_timebase(src) ||
2737
- bare_ffmpeg__bad_timebase(dst) ||
2738
- packet->handle->dts == AV_NOPTS_VALUE ||
2739
- packet->handle->pts == AV_NOPTS_VALUE
2740
- ) {
2741
- return false;
2742
- }
2743
-
2744
- av_packet_rescale_ts(packet->handle, src, dst);
2745
-
2746
- packet->handle->time_base = dst;
2747
-
2748
- return true;
2819
+ int32_t src_num,
2820
+ int32_t src_den,
2821
+ int32_t dst_num,
2822
+ int32_t dst_den
2823
+ ) {
2824
+ av_packet_rescale_ts(
2825
+ packet->handle,
2826
+ {src_num, src_den},
2827
+ {dst_num, dst_den}
2828
+ );
2749
2829
  }
2750
2830
 
2751
2831
  static int64_t
@@ -2892,11 +2972,6 @@ bare_ffmpeg_scaler_scale(
2892
2972
  int height,
2893
2973
  js_arraybuffer_span_of_t<bare_ffmpeg_frame_t, 1> target
2894
2974
  ) {
2895
- int err;
2896
-
2897
- err = av_frame_copy_props(target->handle, source->handle);
2898
- assert(err == 0);
2899
-
2900
2975
  return sws_scale(
2901
2976
  scaler->handle,
2902
2977
  reinterpret_cast<const uint8_t *const *>(source->handle->data),
@@ -3575,9 +3650,15 @@ bare_ffmpeg_rational_rescale_q(
3575
3650
  int32_t bq_num,
3576
3651
  int32_t bq_den,
3577
3652
  int32_t cq_num,
3578
- int32_t cq_den
3579
- ) {
3580
- return av_rescale_q(ts, {bq_num, bq_den}, {cq_num, cq_den});
3653
+ int32_t cq_den,
3654
+ int64_t av_round
3655
+ ) {
3656
+ return av_rescale_q_rnd(
3657
+ ts,
3658
+ {bq_num, bq_den},
3659
+ {cq_num, cq_den},
3660
+ static_cast<AVRounding>(av_round)
3661
+ );
3581
3662
  }
3582
3663
 
3583
3664
  static js_value_t *
@@ -3596,16 +3677,23 @@ bare_ffmpeg_exports(js_env_t *env, js_value_t *exports) {
3596
3677
  V("initIOContext", bare_ffmpeg_io_context_init)
3597
3678
  V("destroyIOContext", bare_ffmpeg_io_context_destroy)
3598
3679
 
3599
- V("initOutputFormat", bare_ffmpeg_output_format_init)
3600
3680
  V("initInputFormat", bare_ffmpeg_input_format_init)
3601
- V("getOutputFormatFlags", bare_ffmpeg_output_format_get_flags)
3602
3681
  V("getInputFormatFlags", bare_ffmpeg_input_format_get_flags)
3682
+ V("getInputFormatExtensions", bare_ffmpeg_input_format_get_extensions)
3683
+ V("getInputFormatMimeType", bare_ffmpeg_input_format_get_mime_type)
3684
+
3685
+ V("initOutputFormat", bare_ffmpeg_output_format_init)
3686
+ V("getOutputFormatFlags", bare_ffmpeg_output_format_get_flags)
3687
+ V("getOutputFormatExtensions", bare_ffmpeg_output_format_get_extensions)
3688
+ V("getOutputFormatMimeType", bare_ffmpeg_output_format_get_mime_type)
3603
3689
 
3604
3690
  V("openInputFormatContextWithIO", bare_ffmpeg_format_context_open_input_with_io)
3605
3691
  V("openInputFormatContextWithFormat", bare_ffmpeg_format_context_open_input_with_format)
3606
3692
  V("closeInputFormatContext", bare_ffmpeg_format_context_close_input)
3693
+
3607
3694
  V("openOutputFormatContext", bare_ffmpeg_format_context_open_output)
3608
3695
  V("closeOutputFormatContext", bare_ffmpeg_format_context_close_output)
3696
+
3609
3697
  V("getFormatContextStreams", bare_ffmpeg_format_context_get_streams)
3610
3698
  V("getFormatContextBestStreamIndex", bare_ffmpeg_format_context_get_best_stream_index)
3611
3699
  V("createFormatContextStream", bare_ffmpeg_format_context_create_stream)
@@ -3614,6 +3702,8 @@ bare_ffmpeg_exports(js_env_t *env, js_value_t *exports) {
3614
3702
  V("writeFormatContextFrame", bare_ffmpeg_format_context_write_frame)
3615
3703
  V("writeFormatContextTrailer", bare_ffmpeg_format_context_write_trailer)
3616
3704
  V("dumpFormatContext", bare_ffmpeg_format_context_dump)
3705
+ V("getFormatContextOutputFormat", get_bare_ffmpeg_format_context_output_format)
3706
+ V("getFormatContextInputFormat", get_bare_ffmpeg_format_context_input_format)
3617
3707
 
3618
3708
  V("getStreamIndex", bare_ffmpeg_stream_get_index)
3619
3709
  V("getStreamId", bare_ffmpeg_stream_get_id)
@@ -3737,6 +3827,7 @@ bare_ffmpeg_exports(js_env_t *env, js_value_t *exports) {
3737
3827
  V("setFramePacketDTS", bare_ffmpeg_frame_set_pkt_dts)
3738
3828
  V("getFrameTimeBase", bare_ffmpeg_frame_get_time_base)
3739
3829
  V("setFrameTimeBase", bare_ffmpeg_frame_set_time_base)
3830
+ V("copyFrameProperties", bare_ffmpeg_frame_copy_properties)
3740
3831
  V("allocFrame", bare_ffmpeg_frame_alloc)
3741
3832
 
3742
3833
  V("initImage", bare_ffmpeg_image_init)
@@ -4115,6 +4206,12 @@ bare_ffmpeg_exports(js_env_t *env, js_value_t *exports) {
4115
4206
  V(AV_CODEC_CONFIG_COLOR_RANGE)
4116
4207
  V(AV_CODEC_CONFIG_COLOR_SPACE)
4117
4208
 
4209
+ V(AV_ROUND_ZERO)
4210
+ V(AV_ROUND_INF)
4211
+ V(AV_ROUND_DOWN)
4212
+ V(AV_ROUND_UP)
4213
+ V(AV_ROUND_NEAR_INF) // default
4214
+ V(AV_ROUND_PASS_MINMAX)
4118
4215
  #undef V
4119
4216
 
4120
4217
  return exports;
@@ -217,7 +217,10 @@ module.exports = class FFmpegCodecContext {
217
217
  timeBase: this.timeBase,
218
218
  channelLayout: this.channelLayout,
219
219
  gopSize: this.gopSize,
220
- extraData: this.extraData
220
+ extraData: this.extraData,
221
+ frameRate: this.frameRate,
222
+ frameSize: this.frameSize,
223
+ frameNum: this.frameNum
221
224
  }
222
225
  }
223
226
  }
package/lib/constants.js CHANGED
@@ -193,6 +193,14 @@ module.exports = exports = {
193
193
  CHANNEL_LAYOUT: binding.AV_CODEC_CONFIG_CHANNEL_LAYOUT,
194
194
  COLOR_RANGE: binding.AV_CODEC_CONFIG_COLOR_RANGE,
195
195
  COLOR_SPACE: binding.AV_CODEC_CONFIG_COLOR_SPACE
196
+ },
197
+ rounding: {
198
+ AV_ROUND_ZERO: binding.AV_ROUND_ZERO,
199
+ AV_ROUND_INF: binding.AV_ROUND_INF,
200
+ AV_ROUND_DOWN: binding.AV_ROUND_DOWN,
201
+ AV_ROUND_UP: binding.AV_ROUND_UP,
202
+ AV_ROUND_NEAR_INF: binding.AV_ROUND_NEAR_INF,
203
+ AV_ROUND_PASS_MINMAX: binding.AV_ROUND_PASS_MINMAX
196
204
  }
197
205
  }
198
206
 
@@ -111,16 +111,21 @@ exports.InputFormatContext = class FFmpegInputFormatContext extends (
111
111
  }
112
112
  }
113
113
 
114
- dump(printIdx = 0, printUrl = '') {
115
- binding.dumpFormatContext(this._handle, false, printIdx, printUrl)
116
- }
117
-
118
114
  destroy() {
119
115
  super.destroy()
120
116
 
121
117
  binding.closeInputFormatContext(this._handle)
122
118
  this._handle = null
123
119
  }
120
+
121
+ dump(printIdx = 0, printUrl = '') {
122
+ binding.dumpFormatContext(this._handle, false, printIdx, printUrl)
123
+ }
124
+
125
+ get inputFormat() {
126
+ const handle = binding.getFormatContextInputFormat(this._handle)
127
+ if (handle) return InputFormat.from(handle)
128
+ }
124
129
  }
125
130
 
126
131
  exports.OutputFormatContext = class FFmpegOutputFormatContext extends (
@@ -167,4 +172,9 @@ exports.OutputFormatContext = class FFmpegOutputFormatContext extends (
167
172
  dump(printIdx = 0, printUrl = '') {
168
173
  binding.dumpFormatContext(this._handle, true, printIdx, printUrl)
169
174
  }
175
+
176
+ get outputFormat() {
177
+ const handle = binding.getFormatContextOutputFormat(this._handle)
178
+ if (handle) return OutputFormat.from(handle)
179
+ }
170
180
  }
package/lib/frame.js CHANGED
@@ -88,6 +88,10 @@ module.exports = class FFmpegFrame {
88
88
  binding.setFrameTimeBase(this._handle, value.numerator, value.denominator)
89
89
  }
90
90
 
91
+ copyProperties(source) {
92
+ binding.copyFrameProperties(this._handle, source._handle)
93
+ }
94
+
91
95
  alloc() {
92
96
  binding.allocFrame(this._handle, 32)
93
97
  }
@@ -19,11 +19,33 @@ switch (Bare.platform) {
19
19
  }
20
20
 
21
21
  module.exports = class FFmpegInputFormat {
22
- constructor(name = defaultName) {
23
- this._handle = binding.initInputFormat(name)
22
+ constructor(name = defaultName, handle) {
23
+ if (handle) this._handle = handle
24
+ else this._handle = binding.initInputFormat(name)
25
+ }
26
+
27
+ static from(handle) {
28
+ return new FFmpegInputFormat(null, handle)
24
29
  }
25
30
 
26
31
  get flags() {
27
32
  return binding.getInputFormatFlags(this._handle)
28
33
  }
34
+
35
+ get extensions() {
36
+ return binding.getInputFormatExtensions(this._handle)
37
+ }
38
+
39
+ get mimeType() {
40
+ return binding.getInputFormatMimeType(this._handle)
41
+ }
42
+
43
+ [Symbol.for('bare.inspect')]() {
44
+ return {
45
+ __proto__: { constructor: FFmpegInputFormat },
46
+ flags: this.flags,
47
+ extensions: this.extensions,
48
+ mimeType: this.mimeType
49
+ }
50
+ }
29
51
  }
@@ -1,11 +1,33 @@
1
1
  const binding = require('../binding')
2
2
 
3
3
  module.exports = class FFmpegOutputFormat {
4
- constructor(name) {
5
- this._handle = binding.initOutputFormat(name)
4
+ constructor(name, handle) {
5
+ if (handle) this._handle = handle
6
+ else this._handle = binding.initOutputFormat(name)
7
+ }
8
+
9
+ static from(handle) {
10
+ return new FFmpegOutputFormat(null, handle)
6
11
  }
7
12
 
8
13
  get flags() {
9
14
  return binding.getOutputFormatFlags(this._handle)
10
15
  }
16
+
17
+ get extensions() {
18
+ return binding.getOutputFormatExtensions(this._handle)
19
+ }
20
+
21
+ get mimeType() {
22
+ return binding.getOutputFormatMimeType(this._handle)
23
+ }
24
+
25
+ [Symbol.for('bare.inspect')]() {
26
+ return {
27
+ __proto__: { constructor: FFmpegOutputFormat },
28
+ flags: this.flags,
29
+ extensions: this.extensions,
30
+ mimeType: this.mimeType
31
+ }
32
+ }
11
33
  }
package/lib/packet.js CHANGED
@@ -130,11 +130,13 @@ module.exports = class FFmpegPacket {
130
130
  binding.setPacketTimeBase(this._handle, value.numerator, value.denominator)
131
131
  }
132
132
 
133
- rescaleTimestamps(rational) {
133
+ rescaleTimestamps(srcTimeBase, dstTimeBase) {
134
134
  return binding.rescalePacketTimestamps(
135
135
  this._handle,
136
- rational.numerator,
137
- rational.denominator
136
+ srcTimeBase.numerator,
137
+ srcTimeBase.denominator,
138
+ dstTimeBase.numerator,
139
+ dstTimeBase.denominator
138
140
  )
139
141
  }
140
142
 
package/lib/rational.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const binding = require('../binding')
2
+ const { AV_ROUND_NEAR_INF } = require('./constants').rounding
2
3
 
3
4
  module.exports = class FFmpegRational {
4
5
  constructor(numerator = 0, denominator = 1) {
@@ -38,7 +39,7 @@ module.exports = class FFmpegRational {
38
39
  return new FFmpegRational(view[0], view[1])
39
40
  }
40
41
 
41
- static rescaleQ(n, src, dst) {
42
+ static rescaleQ(n, src, dst, round = AV_ROUND_NEAR_INF) {
42
43
  if (src.equals(dst)) return n
43
44
 
44
45
  return binding.rationalRescaleQ(
@@ -46,7 +47,8 @@ module.exports = class FFmpegRational {
46
47
  src.numerator,
47
48
  src.denominator,
48
49
  dst.numerator,
49
- dst.denominator
50
+ dst.denominator,
51
+ round
50
52
  )
51
53
  }
52
54
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-ffmpeg",
3
- "version": "1.0.0-27",
3
+ "version": "1.0.0-29",
4
4
  "description": "Low-level FFmpeg bindings for Bare",
5
5
  "exports": {
6
6
  ".": "./index.js",