@mediabunny/server 1.45.4 → 1.46.0

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 (37) hide show
  1. package/README.md +16 -0
  2. package/dist/bundles/mediabunny-server.cjs +67 -12
  3. package/dist/bundles/mediabunny-server.min.cjs +2 -2
  4. package/dist/bundles/mediabunny-server.min.mjs +2 -2
  5. package/dist/bundles/mediabunny-server.mjs +74 -13
  6. package/dist/mediabunny-server.d.ts +20 -1
  7. package/dist/modules/src/audio-decoder.d.ts +1 -1
  8. package/dist/modules/src/audio-decoder.d.ts.map +1 -1
  9. package/dist/modules/src/audio-decoder.js +8 -1
  10. package/dist/modules/src/audio-encoder.d.ts +3 -3
  11. package/dist/modules/src/audio-encoder.d.ts.map +1 -1
  12. package/dist/modules/src/audio-encoder.js +6 -2
  13. package/dist/modules/src/audio-sample.d.ts.map +1 -1
  14. package/dist/modules/src/audio-sample.js +3 -0
  15. package/dist/modules/src/index.d.ts +21 -2
  16. package/dist/modules/src/index.d.ts.map +1 -1
  17. package/dist/modules/src/index.js +24 -2
  18. package/dist/modules/src/misc.d.ts +2 -2
  19. package/dist/modules/src/misc.d.ts.map +1 -1
  20. package/dist/modules/src/misc.js +23 -2
  21. package/dist/modules/src/video-decoder.d.ts.map +1 -1
  22. package/dist/modules/src/video-decoder.js +3 -2
  23. package/dist/modules/src/video-encoder.d.ts +3 -3
  24. package/dist/modules/src/video-encoder.d.ts.map +1 -1
  25. package/dist/modules/src/video-encoder.js +8 -4
  26. package/dist/modules/src/video-sample.d.ts.map +1 -1
  27. package/dist/modules/src/video-sample.js +3 -0
  28. package/dist/modules/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +1 -1
  30. package/src/audio-decoder.ts +8 -2
  31. package/src/audio-encoder.ts +7 -3
  32. package/src/audio-sample.ts +3 -0
  33. package/src/index.ts +63 -2
  34. package/src/misc.ts +31 -2
  35. package/src/video-decoder.ts +5 -2
  36. package/src/video-encoder.ts +12 -11
  37. package/src/video-sample.ts +3 -0
@@ -47,6 +47,10 @@ const misc_1 = require("./misc");
47
47
  const misc_2 = require("../../../src/misc");
48
48
  const audio_sample_1 = require("./audio-sample");
49
49
  class NodeAvAudioDecoder extends mediabunny_1.CustomAudioDecoder {
50
+ constructor() {
51
+ super(...arguments);
52
+ this.codecContext = null;
53
+ }
50
54
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
51
55
  static supports(codec, config) {
52
56
  return codec === 'aac'
@@ -83,6 +87,7 @@ class NodeAvAudioDecoder extends mediabunny_1.CustomAudioDecoder {
83
87
  this.codecContext = codecContext;
84
88
  }
85
89
  async decode(packet) {
90
+ (0, misc_2.assert)(this.codecContext);
86
91
  this.packet.isKeyframe = packet.type === 'key';
87
92
  this.packet.data = Buffer.from(packet.data);
88
93
  this.packet.timeBase = { num: 1, den: this.config.sampleRate };
@@ -91,6 +96,7 @@ class NodeAvAudioDecoder extends mediabunny_1.CustomAudioDecoder {
91
96
  this.packet.duration = BigInt(Math.round(packet.duration * this.config.sampleRate));
92
97
  const ret = await this.codecContext.sendPacket(this.packet);
93
98
  NodeAv.FFmpegError.throwIfError(ret, 'Send packet');
99
+ this.packet.unref(); // Don't need the data again, so just unref it
94
100
  while (true) {
95
101
  const receiveRet = await this.codecContext.receiveFrame(this.frame);
96
102
  if (receiveRet === NodeAv.AVERROR_EAGAIN || receiveRet === NodeAv.AVERROR_EOF) {
@@ -109,6 +115,7 @@ class NodeAvAudioDecoder extends mediabunny_1.CustomAudioDecoder {
109
115
  this.onSample(new mediabunny_1.AudioSample(new audio_sample_1.AvFrameAudioSampleResource(clone)));
110
116
  }
111
117
  async flush() {
118
+ (0, misc_2.assert)(this.codecContext);
112
119
  // Send null packet to signal flush
113
120
  const ret = await this.codecContext.sendPacket(null);
114
121
  NodeAv.FFmpegError.throwIfError(ret, 'Flush decoder');
@@ -124,7 +131,7 @@ class NodeAvAudioDecoder extends mediabunny_1.CustomAudioDecoder {
124
131
  this.codecContext.flushBuffers();
125
132
  }
126
133
  close() {
127
- this.codecContext.freeContext();
134
+ this.codecContext?.freeContext();
128
135
  this.frame.free();
129
136
  this.packet.free();
130
137
  }
@@ -11,15 +11,15 @@ import { AdtsHeaderTemplate } from '../../../shared/aac-misc';
11
11
  export declare class NodeAvAudioEncoder extends CustomAudioEncoder {
12
12
  frame: NodeAv.Frame;
13
13
  packet: NodeAv.Packet;
14
- avCodec: NodeAv.Codec;
15
14
  codecContext: NodeAv.CodecContext | null;
15
+ resampler: NodeAv.SoftwareResampleContext | null;
16
+ dstFrame: NodeAv.Frame | null;
17
+ avCodec: NodeAv.Codec;
16
18
  firstExpectedTimestamp: number | null;
17
19
  outputTimestampOffset: number;
18
- resampler: NodeAv.SoftwareResampleContext | null;
19
20
  inputParametersKey: string | null;
20
21
  resamplerInputSampleRate: number | null;
21
22
  nextResamplerPts: bigint | null;
22
- dstFrame: NodeAv.Frame | null;
23
23
  packetEmitted: boolean;
24
24
  adtsHeaderTemplate: AdtsHeaderTemplate | null;
25
25
  static supports(codec: AudioCodec, config: AudioEncoderConfig): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"audio-encoder.d.ts","sourceRoot":"","sources":["../../../src/audio-encoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,KAAK,YAAY,EAGjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAIlC,OAAO,EACN,kBAAkB,EAGlB,MAAM,0BAA0B,CAAC;AAUlC,qBAAa,kBAAmB,SAAQ,kBAAkB;IACzD,KAAK,EAAG,MAAM,CAAC,KAAK,CAAC;IACrB,MAAM,EAAG,MAAM,CAAC,MAAM,CAAC;IACvB,OAAO,EAAG,MAAM,CAAC,KAAK,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAQ;IAChD,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC7C,qBAAqB,SAAK;IAE1B,SAAS,EAAE,MAAM,CAAC,uBAAuB,GAAG,IAAI,CAAQ;IACxD,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACzC,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC/C,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACvC,QAAQ,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAQ;IACrC,aAAa,UAAS;IACtB,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,CAAQ;WAErC,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO;IA2B1E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBrB,kBAAkB;IA+BlB,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA6E/C,mBAAmB;IAuBnB,0BAA0B,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI;IAgB3D,aAAa,CAAC,GAAG,EAAE,MAAM;IAsGnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2C5B,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC;CAO3B"}
1
+ {"version":3,"file":"audio-encoder.d.ts","sourceRoot":"","sources":["../../../src/audio-encoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,KAAK,YAAY,EAGjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAIlC,OAAO,EACN,kBAAkB,EAGlB,MAAM,0BAA0B,CAAC;AAUlC,qBAAa,kBAAmB,SAAQ,kBAAkB;IACzD,KAAK,EAAG,MAAM,CAAC,KAAK,CAAC;IACrB,MAAM,EAAG,MAAM,CAAC,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAQ;IAChD,SAAS,EAAE,MAAM,CAAC,uBAAuB,GAAG,IAAI,CAAQ;IACxD,QAAQ,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAQ;IACrC,OAAO,EAAG,MAAM,CAAC,KAAK,CAAC;IACvB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC7C,qBAAqB,SAAK;IAE1B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACzC,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC/C,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACvC,aAAa,UAAS;IACtB,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,CAAQ;WAErC,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO;IA2B1E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBrB,kBAAkB;IA+BlB,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiF/C,mBAAmB;IAuBnB,0BAA0B,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI;IAgB3D,aAAa,CAAC,GAAG,EAAE,MAAM;IAsGnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2C5B,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC;CAO3B"}
@@ -56,13 +56,13 @@ class NodeAvAudioEncoder extends mediabunny_1.CustomAudioEncoder {
56
56
  constructor() {
57
57
  super(...arguments);
58
58
  this.codecContext = null;
59
+ this.resampler = null;
60
+ this.dstFrame = null;
59
61
  this.firstExpectedTimestamp = null;
60
62
  this.outputTimestampOffset = 0;
61
- this.resampler = null;
62
63
  this.inputParametersKey = null;
63
64
  this.resamplerInputSampleRate = null;
64
65
  this.nextResamplerPts = null;
65
- this.dstFrame = null;
66
66
  this.packetEmitted = false;
67
67
  this.adtsHeaderTemplate = null;
68
68
  }
@@ -122,6 +122,10 @@ class NodeAvAudioEncoder extends mediabunny_1.CustomAudioEncoder {
122
122
  }
123
123
  this.firstExpectedTimestamp ??= audioSample.timestamp;
124
124
  if (audioSample._data instanceof audio_sample_1.AvFrameAudioSampleResource) {
125
+ // Release any buffers still referenced from the previous encode before reffing the new frame, otherwise
126
+ // av_frame_ref leaks them
127
+ // https://github.com/Vanilagy/mediabunny/issues/392
128
+ this.frame.unref();
125
129
  this.frame.ref(audioSample._data.frame);
126
130
  }
127
131
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"audio-sample.d.ts","sourceRoot":"","sources":["../../../src/audio-sample.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAIlC;;;;;;;;;;;GAWG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB;IAIlE;;;OAGG;IACH,IAAI,KAAK,iBAMR;gBAEW,KAAK,EAAE,MAAM,CAAC,KAAK;IAU/B,SAAS,IAAI,iBAAiB;IAU9B,aAAa,IAAI,MAAM;IAIvB,mBAAmB,IAAI,MAAM;IAI7B,iBAAiB,IAAI,MAAM;IAI3B,YAAY,IAAI,MAAM;IAItB,KAAK,IAAI,IAAI;IAKb,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU;CAI5C;AAED,eAAO,MAAM,wBAAwB,GAAI,QAAQ,WAAW,EAAE,OAAO,MAAM,CAAC,KAAK,SAYhF,CAAC"}
1
+ {"version":3,"file":"audio-sample.d.ts","sourceRoot":"","sources":["../../../src/audio-sample.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAIlC;;;;;;;;;;;GAWG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB;IAIlE;;;OAGG;IACH,IAAI,KAAK,iBAMR;gBAEW,KAAK,EAAE,MAAM,CAAC,KAAK;IAa/B,SAAS,IAAI,iBAAiB;IAU9B,aAAa,IAAI,MAAM;IAIvB,mBAAmB,IAAI,MAAM;IAI7B,iBAAiB,IAAI,MAAM;IAI3B,YAAY,IAAI,MAAM;IAItB,KAAK,IAAI,IAAI;IAKb,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU;CAI5C;AAED,eAAO,MAAM,wBAAwB,GAAI,QAAQ,WAAW,EAAE,OAAO,MAAM,CAAC,KAAK,SAYhF,CAAC"}
@@ -70,6 +70,9 @@ class AvFrameAudioSampleResource extends mediabunny_1.AudioSampleResource {
70
70
  }
71
71
  constructor(frame) {
72
72
  super();
73
+ if (!(frame instanceof NodeAv.Frame)) {
74
+ throw new TypeError('frame must be a NodeAv.Frame.');
75
+ }
73
76
  if (frame.getMediaType() !== NodeAv.AVMEDIA_TYPE_AUDIO) {
74
77
  throw new Error('AvFrameAudioSampleResource must be initialized with an audio frame.');
75
78
  }
@@ -5,8 +5,24 @@
5
5
  * License, v. 2.0. If a copy of the MPL was not distributed with this
6
6
  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
7
  */
8
- import { AudioSample, VideoSample } from 'mediabunny';
8
+ import { AudioSample, MaybePromise, VideoSample } from 'mediabunny';
9
9
  import * as NodeAv from 'node-av';
10
+ /**
11
+ * Options for configuring Mediabunny's server-side polyfills.
12
+ * @group \@mediabunny/server
13
+ * @public
14
+ */
15
+ type MediabunnyServerOptions = {
16
+ /**
17
+ * The hardware context to use for hardware-accelerated decoding and encoding. When set to a
18
+ * `NodeAv.HardwareContext`, that context is used directly. When set to a function, the function is invoked (with
19
+ * no caching) every time a hardware decoder or encoder codec is resolved, receiving the codec ID and returning the
20
+ * context to use for it (or `null` for no hardware acceleration).
21
+ *
22
+ * When not set, a context is automatically detected on first use and then cached.
23
+ */
24
+ hardwareContext?: NodeAv.HardwareContext | null | ((codecId: NodeAv.AVCodecID) => MaybePromise<NodeAv.HardwareContext | null>);
25
+ };
10
26
  /**
11
27
  * Registers video and audio decoders and encoders for all codecs, using FFmpeg's libavcodec under the hood.
12
28
  * Additionally, a custom `VideoSample` transformer based on libavfilter is registered to enable resizing, rotation and
@@ -17,10 +33,13 @@ import * as NodeAv from 'node-av';
17
33
  * The decoders and encoders will automatically detect hardware acceleration support for each codec and platform and
18
34
  * make use of it if applicable.
19
35
  *
36
+ * You can pass optional {@link MediabunnyServerOptions} for additional configuration.
37
+ *
20
38
  * @group \@mediabunny/server
21
39
  * @public
22
40
  */
23
- export declare const registerMediabunnyServer: () => void;
41
+ export declare const registerMediabunnyServer: (options?: MediabunnyServerOptions) => void;
42
+ export type { MediabunnyServerOptions };
24
43
  export { AvFrameVideoSampleResource } from './video-sample';
25
44
  export { AvFrameAudioSampleResource } from './audio-sample';
26
45
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAoE,WAAW,EAAE,MAAM,YAAY,CAAC;AACxH,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAqBlC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,YAiBpC,CAAC;AAEF,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,GAAU,QAAQ,WAAW,GAAG,WAAW,EAAE,OAAO,MAAM,CAAC,KAAK,kBA0BrF,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,WAAW,EACX,YAAY,EAIZ,WAAW,EACX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAqBlC;;;;GAIG;AACH,KAAK,uBAAuB,GAAG;IAC9B;;;;;;;OAOG;IACH,eAAe,CAAC,EACb,MAAM,CAAC,eAAe,GACtB,IAAI,GACJ,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,KAAK,YAAY,CAAC,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;CAChF,CAAC;AAKF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GAAI,UAAS,uBAA4B,SAiC7E,CAAC;AAEF,YAAY,EAAE,uBAAuB,EAAE,CAAC;AAExC,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,GAAU,QAAQ,WAAW,GAAG,WAAW,EAAE,OAAO,MAAM,CAAC,KAAK,kBAqCrF,CAAC"}
@@ -40,7 +40,7 @@ var __importStar = (this && this.__importStar) || (function () {
40
40
  };
41
41
  })();
42
42
  Object.defineProperty(exports, "__esModule", { value: true });
43
- exports.toAvFrame = exports.AvFrameAudioSampleResource = exports.AvFrameVideoSampleResource = exports.registerMediabunnyServer = void 0;
43
+ exports.toAvFrame = exports.AvFrameAudioSampleResource = exports.AvFrameVideoSampleResource = exports.registerMediabunnyServer = exports._serverOptions = void 0;
44
44
  const mediabunny_1 = require("mediabunny");
45
45
  const NodeAv = __importStar(require("node-av"));
46
46
  const video_decoder_1 = require("./video-decoder");
@@ -58,6 +58,8 @@ if (globalThis[SERVER_LOADED_SYMBOL]) {
58
58
  }
59
59
  globalThis[SERVER_LOADED_SYMBOL] = true;
60
60
  let registered = false;
61
+ /** @internal */
62
+ exports._serverOptions = {};
61
63
  /**
62
64
  * Registers video and audio decoders and encoders for all codecs, using FFmpeg's libavcodec under the hood.
63
65
  * Additionally, a custom `VideoSample` transformer based on libavfilter is registered to enable resizing, rotation and
@@ -68,14 +70,24 @@ let registered = false;
68
70
  * The decoders and encoders will automatically detect hardware acceleration support for each codec and platform and
69
71
  * make use of it if applicable.
70
72
  *
73
+ * You can pass optional {@link MediabunnyServerOptions} for additional configuration.
74
+ *
71
75
  * @group \@mediabunny/server
72
76
  * @public
73
77
  */
74
- const registerMediabunnyServer = () => {
78
+ const registerMediabunnyServer = (options = {}) => {
79
+ if (typeof options !== 'object' || !options) {
80
+ throw new TypeError('options must be an object.');
81
+ }
82
+ if (options.hardwareContext != null
83
+ && !(options.hardwareContext instanceof NodeAv.HardwareContext || typeof options.hardwareContext === 'function')) {
84
+ throw new TypeError('options.hardwareContext, when provided, must be a NodeAv.HardwareContext, a function, or null.');
85
+ }
75
86
  if (registered) {
76
87
  return;
77
88
  }
78
89
  registered = true;
90
+ exports._serverOptions = options;
79
91
  NodeAv.Log.setLevel(NodeAv.AV_LOG_ERROR);
80
92
  // Video
81
93
  (0, mediabunny_1.registerDecoder)(video_decoder_1.NodeAvVideoDecoder);
@@ -103,8 +115,16 @@ Object.defineProperty(exports, "AvFrameAudioSampleResource", { enumerable: true,
103
115
  * @public
104
116
  */
105
117
  const toAvFrame = async (sample, frame) => {
118
+ if (!(sample instanceof mediabunny_1.VideoSample) && !(sample instanceof mediabunny_1.AudioSample)) {
119
+ throw new TypeError('sample must be a VideoSample or an AudioSample.');
120
+ }
121
+ if (!(frame instanceof NodeAv.Frame)) {
122
+ throw new TypeError('frame must be a NodeAv.Frame.');
123
+ }
106
124
  if (sample instanceof mediabunny_1.VideoSample) {
107
125
  if (sample._data instanceof video_sample_1.AvFrameVideoSampleResource) {
126
+ // We're overriding the frame, so release whatever it referenced before, otherwise av_frame_ref leaks it
127
+ frame.unref();
108
128
  frame.ref(sample._data.frame);
109
129
  }
110
130
  else {
@@ -119,6 +139,8 @@ const toAvFrame = async (sample, frame) => {
119
139
  }
120
140
  else {
121
141
  if (sample._data instanceof audio_sample_1.AvFrameAudioSampleResource) {
142
+ // We're overriding the frame, so release whatever it referenced before, otherwise av_frame_ref leaks it
143
+ frame.unref();
122
144
  frame.ref(sample._data.frame);
123
145
  }
124
146
  else {
@@ -9,8 +9,8 @@ import { VideoSamplePixelFormat, MediaCodec } from 'mediabunny';
9
9
  import * as NodeAv from 'node-av';
10
10
  export declare const CODEC_TO_CODEC_ID: Partial<Record<MediaCodec, NodeAv.AVCodecID>>;
11
11
  export declare const getHardwareContext: () => NodeAv.HardwareContext | null;
12
- export declare const getHardwareDecoderCodec: (codecId: NodeAv.AVCodecID) => NodeAv.Codec | null;
13
- export declare const getHardwareEncoderCodec: (codecId: NodeAv.AVCodecID) => NodeAv.Codec | null;
12
+ export declare const getHardwareDecoderCodec: (codecId: NodeAv.AVCodecID) => Promise<NodeAv.Codec | null>;
13
+ export declare const getHardwareEncoderCodec: (codecId: NodeAv.AVCodecID) => Promise<NodeAv.Codec | null>;
14
14
  export declare const mapColorPrimaries: (primaries: string) => NodeAv.AVColorPrimaries | null;
15
15
  export declare const unmapColorPrimaries: (primaries: number) => "bt709" | "bt470bg" | "smpte170m" | "bt2020" | "smpte432" | null;
16
16
  export declare const mapTransferCharacteristics: (transfer: string) => NodeAv.AVColorTransferCharacteristic | null;
@@ -1 +1 @@
1
- {"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../../src/misc.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAElC,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,CAc3E,CAAC;AAGF,eAAO,MAAM,kBAAkB,QAAO,MAAM,CAAC,eAAe,GAAG,IAK9D,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAAI,SAAS,MAAM,CAAC,SAAS,KAAG,MAAM,CAAC,KAAK,GAAG,IAMlF,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAAI,SAAS,MAAM,CAAC,SAAS,KAAG,MAAM,CAAC,KAAK,GAAG,IAMlF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,mCAUlD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,WAAW,MAAM,qEAUpD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,UAAU,MAAM,gDAW1D,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,UAAU,MAAM,4EAW5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,+BAUnD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,oEAUrD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,mBAAmB,MAAM,CAAC,aAAa,KAAG,sBAAsB,GAAG,IAqChG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,aAAa,sBAAsB,yBA+BlE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,oBAAoB,MAAM,CAAC,cAAc,KAAG,iBAAiB,GAAG,IAanG,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,cAAc,iBAAiB,KAAG,MAAM,CAAC,cAa9E,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,KAAG,MAAM,CAAC,aAS7D,CAAC"}
1
+ {"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../../src/misc.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAGlC,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,CAc3E,CAAC;AAGF,eAAO,MAAM,kBAAkB,QAAO,MAAM,CAAC,eAAe,GAAG,IAU9D,CAAC;AAYF,eAAO,MAAM,uBAAuB,GAAU,SAAS,MAAM,CAAC,SAAS,KAAG,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAapG,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAAU,SAAS,MAAM,CAAC,SAAS,KAAG,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAapG,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,mCAUlD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,WAAW,MAAM,qEAUpD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,UAAU,MAAM,gDAW1D,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,UAAU,MAAM,4EAW5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,+BAUnD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,oEAUrD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,mBAAmB,MAAM,CAAC,aAAa,KAAG,sBAAsB,GAAG,IAqChG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,aAAa,sBAAsB,yBA+BlE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,oBAAoB,MAAM,CAAC,cAAc,KAAG,iBAAiB,GAAG,IAanG,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,cAAc,iBAAiB,KAAG,MAAM,CAAC,cAa9E,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,KAAG,MAAM,CAAC,aAS7D,CAAC"}
@@ -42,6 +42,7 @@ var __importStar = (this && this.__importStar) || (function () {
42
42
  Object.defineProperty(exports, "__esModule", { value: true });
43
43
  exports.getChannelLayout = exports.fromAudioSampleFormat = exports.toAudioSampleFormat = exports.fromPixelFormat = exports.toPixelFormat = exports.unmapMatrixCoefficients = exports.mapMatrixCoefficients = exports.unmapTransferCharacteristics = exports.mapTransferCharacteristics = exports.unmapColorPrimaries = exports.mapColorPrimaries = exports.getHardwareEncoderCodec = exports.getHardwareDecoderCodec = exports.getHardwareContext = exports.CODEC_TO_CODEC_ID = void 0;
44
44
  const NodeAv = __importStar(require("node-av"));
45
+ const index_1 = require("./index");
45
46
  exports.CODEC_TO_CODEC_ID = {
46
47
  avc: NodeAv.AV_CODEC_ID_H264,
47
48
  hevc: NodeAv.AV_CODEC_ID_HEVC,
@@ -58,14 +59,29 @@ exports.CODEC_TO_CODEC_ID = {
58
59
  };
59
60
  let cachedHardwareContext = undefined;
60
61
  const getHardwareContext = () => {
62
+ if (index_1._serverOptions.hardwareContext !== undefined && typeof index_1._serverOptions.hardwareContext !== 'function') {
63
+ // Return the user-provided one
64
+ return index_1._serverOptions.hardwareContext;
65
+ }
61
66
  if (cachedHardwareContext === undefined) {
62
67
  cachedHardwareContext = NodeAv.HardwareContext.auto();
63
68
  }
64
69
  return cachedHardwareContext;
65
70
  };
66
71
  exports.getHardwareContext = getHardwareContext;
72
+ const validateHwContext = (hw) => {
73
+ if (hw !== null && !(hw instanceof NodeAv.HardwareContext)) {
74
+ throw new TypeError('When serverOptions.hardwareContext is a function, it must return or resolve to a'
75
+ + ' NodeAv.HardwareContext or null.');
76
+ }
77
+ };
67
78
  const hardwareDecoderCodecCache = new Map();
68
- const getHardwareDecoderCodec = (codecId) => {
79
+ const getHardwareDecoderCodec = async (codecId) => {
80
+ if (typeof index_1._serverOptions.hardwareContext === 'function') {
81
+ const hw = await index_1._serverOptions.hardwareContext(codecId);
82
+ validateHwContext(hw);
83
+ return hw?.getDecoderCodec(codecId) ?? null;
84
+ }
69
85
  if (!hardwareDecoderCodecCache.has(codecId)) {
70
86
  const hw = (0, exports.getHardwareContext)();
71
87
  hardwareDecoderCodecCache.set(codecId, hw?.getDecoderCodec(codecId) ?? null);
@@ -74,7 +90,12 @@ const getHardwareDecoderCodec = (codecId) => {
74
90
  };
75
91
  exports.getHardwareDecoderCodec = getHardwareDecoderCodec;
76
92
  const hardwareEncoderCodecCache = new Map();
77
- const getHardwareEncoderCodec = (codecId) => {
93
+ const getHardwareEncoderCodec = async (codecId) => {
94
+ if (typeof index_1._serverOptions.hardwareContext === 'function') {
95
+ const hw = await index_1._serverOptions.hardwareContext(codecId);
96
+ validateHwContext(hw);
97
+ return hw?.getEncoderCodec(codecId) ?? null;
98
+ }
78
99
  if (!hardwareEncoderCodecCache.has(codecId)) {
79
100
  const hw = (0, exports.getHardwareContext)();
80
101
  hardwareEncoderCodecCache.set(codecId, hw?.getEncoderCodec(codecId) ?? null);
@@ -1 +1 @@
1
- {"version":3,"file":"video-decoder.d.ts","sourceRoot":"","sources":["../../../src/video-decoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAe,KAAK,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrH,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAKlC,qBAAa,kBAAmB,SAAQ,kBAAkB;IACzD,KAAK,EAAG,MAAM,CAAC,KAAK,CAAC;IACrB,MAAM,EAAG,MAAM,CAAC,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAQ;IAChD,gBAAgB,EAAG,QAAQ,CAAC;IAG5B,cAAc,EAAE;QACf,oBAAoB,EAAE,MAAM,CAAC;QAC7B,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,OAAO,CAAC;KACzB,EAAE,CAAM;WAGO,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO;IAI1E,IAAI;IAOJ,gBAAgB,CAAC,MAAM,EAAE,aAAa;IAiDtC,MAAM,CAAC,MAAM,EAAE,aAAa;IAkElC,YAAY,CAAC,GAAG,EAAE,MAAM;IAuClB,KAAK;IAuBX,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC;CAK3B"}
1
+ {"version":3,"file":"video-decoder.d.ts","sourceRoot":"","sources":["../../../src/video-decoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAe,KAAK,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrH,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAKlC,qBAAa,kBAAmB,SAAQ,kBAAkB;IACzD,KAAK,EAAG,MAAM,CAAC,KAAK,CAAC;IACrB,MAAM,EAAG,MAAM,CAAC,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAQ;IAChD,gBAAgB,EAAG,QAAQ,CAAC;IAG5B,cAAc,EAAE;QACf,oBAAoB,EAAE,MAAM,CAAC;QAC7B,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,OAAO,CAAC;KACzB,EAAE,CAAM;WAGO,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO;IAI1E,IAAI;IAOJ,gBAAgB,CAAC,MAAM,EAAE,aAAa;IAiDtC,MAAM,CAAC,MAAM,EAAE,aAAa;IAqElC,YAAY,CAAC,GAAG,EAAE,MAAM;IAuClB,KAAK;IAuBX,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC;CAK3B"}
@@ -82,7 +82,7 @@ class NodeAvVideoDecoder extends mediabunny_1.CustomVideoDecoder {
82
82
  codec = NodeAv.Codec.findDecoder(codecId);
83
83
  }
84
84
  else {
85
- codec = (0, misc_1.getHardwareDecoderCodec)(codecId) ?? NodeAv.Codec.findDecoder(codecId);
85
+ codec = (await (0, misc_1.getHardwareDecoderCodec)(codecId)) ?? NodeAv.Codec.findDecoder(codecId);
86
86
  }
87
87
  if (!codec) {
88
88
  throw new Error(`Unable to obtain libav codec for '${this.codec}'.`);
@@ -108,8 +108,8 @@ class NodeAvVideoDecoder extends mediabunny_1.CustomVideoDecoder {
108
108
  async decode(packet) {
109
109
  if (this.codecContext === null) {
110
110
  await this.initCodecContext(packet);
111
- (0, misc_2.assert)(this.codecContext);
112
111
  }
112
+ (0, misc_2.assert)(this.codecContext);
113
113
  this.packet.isKeyframe = packet.type === 'key';
114
114
  this.packet.data = Buffer.from(packet.data);
115
115
  this.packet.timeBase = { num: 1, den: 1e6 };
@@ -151,6 +151,7 @@ class NodeAvVideoDecoder extends mediabunny_1.CustomVideoDecoder {
151
151
  }
152
152
  const ret = await this.codecContext.sendPacket(this.packet);
153
153
  NodeAv.FFmpegError.throwIfError(ret, 'Send packet');
154
+ this.packet.unref(); // Don't need the data again, so just unref it
154
155
  while (true) {
155
156
  const receiveRet = await this.codecContext.receiveFrame(this.frame);
156
157
  if (receiveRet === NodeAv.AVERROR_EAGAIN || receiveRet === NodeAv.AVERROR_EOF) {
@@ -10,13 +10,13 @@ import * as NodeAv from 'node-av';
10
10
  export declare class NodeAvVideoEncoder extends CustomVideoEncoder {
11
11
  frame: NodeAv.Frame;
12
12
  packet: NodeAv.Packet;
13
- avCodec: NodeAv.Codec;
14
13
  codecContext: NodeAv.CodecContext | null;
14
+ scaler: NodeAv.SoftwareScaleContext | null;
15
+ dstFrame: NodeAv.Frame | null;
16
+ avCodec: NodeAv.Codec;
15
17
  lastBuffer: Buffer | null;
16
18
  packetEmitted: boolean;
17
- scaler: NodeAv.SoftwareScaleContext | null;
18
19
  lastScalerKey: string | null;
19
- dstFrame: NodeAv.Frame | null;
20
20
  preciseTimings: {
21
21
  microsecondTimestamp: number;
22
22
  timestamp: number;
@@ -1 +1 @@
1
- {"version":3,"file":"video-encoder.d.ts","sourceRoot":"","sources":["../../../src/video-encoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,kBAAkB,EAClB,KAAK,YAAY,EAEjB,UAAU,EACV,WAAW,EAGX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AA0BlC,qBAAa,kBAAmB,SAAQ,kBAAkB;IACzD,KAAK,EAAG,MAAM,CAAC,KAAK,CAAC;IACrB,MAAM,EAAG,MAAM,CAAC,MAAM,CAAC;IACvB,OAAO,EAAG,MAAM,CAAC,KAAK,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAQ;IAChD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IACjC,aAAa,UAAS;IAEtB,MAAM,EAAE,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAQ;IAClD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAQ;IACpC,QAAQ,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAQ;IAGrC,cAAc,EAAE;QACf,oBAAoB,EAAE,MAAM,CAAC;QAC7B,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,OAAO,CAAC;KACzB,EAAE,CAAM;WAEO,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO;IAK1E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BrB,kBAAkB;IAoFlB,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoHzF,aAAa,CAAC,GAAG,EAAE,MAAM;IA4OnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC;CAO3B"}
1
+ {"version":3,"file":"video-encoder.d.ts","sourceRoot":"","sources":["../../../src/video-encoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,kBAAkB,EAClB,KAAK,YAAY,EAEjB,UAAU,EACV,WAAW,EAGX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AA0BlC,qBAAa,kBAAmB,SAAQ,kBAAkB;IACzD,KAAK,EAAG,MAAM,CAAC,KAAK,CAAC;IACrB,MAAM,EAAG,MAAM,CAAC,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAQ;IAChD,MAAM,EAAE,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAQ;IAClD,QAAQ,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAQ;IACrC,OAAO,EAAG,MAAM,CAAC,KAAK,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IACjC,aAAa,UAAS;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGpC,cAAc,EAAE;QACf,oBAAoB,EAAE,MAAM,CAAC;QAC7B,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,OAAO,CAAC;KACzB,EAAE,CAAM;WAEO,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO;IAK1E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BrB,kBAAkB;IAoFlB,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwHzF,aAAa,CAAC,GAAG,EAAE,MAAM;IA0OnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC;CAO3B"}
@@ -52,11 +52,11 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
52
52
  constructor() {
53
53
  super(...arguments);
54
54
  this.codecContext = null;
55
+ this.scaler = null;
56
+ this.dstFrame = null;
55
57
  this.lastBuffer = null;
56
58
  this.packetEmitted = false;
57
- this.scaler = null;
58
59
  this.lastScalerKey = null;
59
- this.dstFrame = null;
60
60
  // Bookkeeping to restore the original timing information
61
61
  this.preciseTimings = [];
62
62
  }
@@ -80,7 +80,7 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
80
80
  codec = NodeAv.Codec.findEncoder(codecId);
81
81
  }
82
82
  else {
83
- codec = (0, misc_1.getHardwareEncoderCodec)(codecId) ?? NodeAv.Codec.findEncoder(codecId);
83
+ codec = (await (0, misc_1.getHardwareEncoderCodec)(codecId)) ?? NodeAv.Codec.findEncoder(codecId);
84
84
  }
85
85
  if (!codec) {
86
86
  throw new Error(`Unable to obtain libav codec for '${this.codec}'.`);
@@ -164,9 +164,13 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
164
164
  async encode(videoSample, options) {
165
165
  if (this.codecContext === null) {
166
166
  await this.createCodecContext();
167
- (0, misc_2.assert)(this.codecContext);
168
167
  }
168
+ (0, misc_2.assert)(this.codecContext);
169
169
  if (videoSample._data instanceof video_sample_1.AvFrameVideoSampleResource) {
170
+ // Release any buffers still referenced from the previous encode before reffing the new frame, otherwise
171
+ // av_frame_ref leaks them
172
+ // https://github.com/Vanilagy/mediabunny/issues/392
173
+ this.frame.unref();
170
174
  this.frame.ref(videoSample._data.frame);
171
175
  }
172
176
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"video-sample.d.ts","sourceRoot":"","sources":["../../../src/video-sample.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,KAAK,YAAY,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACX,eAAe,EACf,WAAW,EACX,cAAc,EACd,oCAAoC,EACpC,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAqBlC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB;IAIlE;;;OAGG;IACH,IAAI,KAAK,iBAMR;gBAEW,KAAK,EAAE,MAAM,CAAC,KAAK;IAU/B,SAAS,IAAI,sBAAsB,GAAG,IAAI;IAI1C,aAAa,IAAI,MAAM;IAIvB,cAAc,IAAI,MAAM;IAIxB,mBAAmB,IAAI,MAAM;IAQ7B,oBAAoB,IAAI,MAAM;IAQ9B,aAAa,IAAI,qBAAqB;IActC,KAAK,IAAI,IAAI;IAKb,aAAa,IAAI,YAAY,CAAC,cAAc,EAAE,CAAC;IASzC,WAAW,CAChB,IAAI,EAAE,WAAW,CAAC,eAAe,EAAE,WAAW,CAAC,EAG/C,UAAU,EAAE,oBAAoB,GAC9B,OAAO,CAAC,WAAW,CAAC;CAiCvB;AAED,eAAO,MAAM,wBAAwB,GAAU,QAAQ,WAAW,EAAE,OAAO,MAAM,CAAC,KAAK,EAAE,YAAY,MAAM,GAAG,IAAI,qCA+BjH,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAChC,QAAQ,WAAW,EACnB,aAAa,oCAAoC,KAC/C,OAAO,CAAC,WAAW,GAAG,IAAI,CAkG5B,CAAC"}
1
+ {"version":3,"file":"video-sample.d.ts","sourceRoot":"","sources":["../../../src/video-sample.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,KAAK,YAAY,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACX,eAAe,EACf,WAAW,EACX,cAAc,EACd,oCAAoC,EACpC,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAqBlC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB;IAIlE;;;OAGG;IACH,IAAI,KAAK,iBAMR;gBAEW,KAAK,EAAE,MAAM,CAAC,KAAK;IAa/B,SAAS,IAAI,sBAAsB,GAAG,IAAI;IAI1C,aAAa,IAAI,MAAM;IAIvB,cAAc,IAAI,MAAM;IAIxB,mBAAmB,IAAI,MAAM;IAQ7B,oBAAoB,IAAI,MAAM;IAQ9B,aAAa,IAAI,qBAAqB;IActC,KAAK,IAAI,IAAI;IAKb,aAAa,IAAI,YAAY,CAAC,cAAc,EAAE,CAAC;IASzC,WAAW,CAChB,IAAI,EAAE,WAAW,CAAC,eAAe,EAAE,WAAW,CAAC,EAG/C,UAAU,EAAE,oBAAoB,GAC9B,OAAO,CAAC,WAAW,CAAC;CAiCvB;AAED,eAAO,MAAM,wBAAwB,GAAU,QAAQ,WAAW,EAAE,OAAO,MAAM,CAAC,KAAK,EAAE,YAAY,MAAM,GAAG,IAAI,qCA+BjH,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAChC,QAAQ,WAAW,EACnB,aAAa,oCAAoC,KAC/C,OAAO,CAAC,WAAW,GAAG,IAAI,CAkG5B,CAAC"}
@@ -81,6 +81,9 @@ class AvFrameVideoSampleResource extends mediabunny_1.VideoSampleResource {
81
81
  }
82
82
  constructor(frame) {
83
83
  super();
84
+ if (!(frame instanceof NodeAv.Frame)) {
85
+ throw new TypeError('frame must be a NodeAv.Frame.');
86
+ }
84
87
  if (frame.getMediaType() !== NodeAv.AVMEDIA_TYPE_VIDEO) {
85
88
  throw new Error('AvFrameVideoSampleResource must be initialized with a video frame.');
86
89
  }