@mediabunny/server 1.49.0 → 1.50.1

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.
@@ -48,6 +48,14 @@ const video_sample_1 = require("./video-sample");
48
48
  const codec_data_1 = require("../../../src/codec-data");
49
49
  const codec_1 = require("../../../src/codec");
50
50
  const misc_2 = require("../../../src/misc");
51
+ const PRORES_FOURCC_TO_PROFILE = {
52
+ apco: NodeAv.AV_PROFILE_PRORES_PROXY,
53
+ apcs: NodeAv.AV_PROFILE_PRORES_LT,
54
+ apcn: NodeAv.AV_PROFILE_PRORES_STANDARD,
55
+ apch: NodeAv.AV_PROFILE_PRORES_HQ,
56
+ ap4h: NodeAv.AV_PROFILE_PRORES_4444,
57
+ ap4x: NodeAv.AV_PROFILE_PRORES_XQ,
58
+ };
51
59
  class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
52
60
  constructor() {
53
61
  super(...arguments);
@@ -61,8 +69,8 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
61
69
  this.preciseTimings = [];
62
70
  }
63
71
  static supports(codec, config) {
64
- return (codec === 'avc' || codec === 'hevc' || codec === 'vp8' || codec === 'vp9' || codec === 'av1')
65
- && config.bitrateMode !== 'quantizer';
72
+ return (codec === 'avc' || codec === 'hevc' || codec === 'vp8' || codec === 'vp9' || codec === 'av1'
73
+ || codec === 'prores') && config.bitrateMode !== 'quantizer';
66
74
  }
67
75
  async init() {
68
76
  this.frame = new NodeAv.Frame();
@@ -72,15 +80,25 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
72
80
  this.packet.alloc();
73
81
  const codecId = misc_1.CODEC_TO_CODEC_ID[this.codec];
74
82
  (0, misc_2.assert)(codecId !== undefined);
83
+ const getSoftwareCodec = () => {
84
+ if (this.codec === 'prores') {
85
+ // Prefer prores_ks for ProRes
86
+ const proresKs = NodeAv.Codec.findEncoderByName(NodeAv.FF_ENCODER_PRORES_KS);
87
+ if (proresKs) {
88
+ return proresKs;
89
+ }
90
+ }
91
+ return NodeAv.Codec.findEncoder(codecId);
92
+ };
75
93
  let codec = null;
76
94
  if (this.codec === 'vp9' && this.config.alpha === 'keep') {
77
95
  codec = NodeAv.Codec.findEncoderByName(NodeAv.FF_ENCODER_LIBVPX_VP9) ?? NodeAv.Codec.findEncoder(codecId);
78
96
  }
79
97
  else if (this.config.hardwareAcceleration === 'prefer-software') {
80
- codec = NodeAv.Codec.findEncoder(codecId);
98
+ codec = getSoftwareCodec();
81
99
  }
82
100
  else {
83
- codec = (await (0, misc_1.getHardwareEncoderCodec)(codecId)) ?? NodeAv.Codec.findEncoder(codecId);
101
+ codec = (await (0, misc_1.getHardwareEncoderCodec)(codecId)) ?? getSoftwareCodec();
84
102
  }
85
103
  if (!codec) {
86
104
  throw new Error(`Unable to obtain libav codec for '${this.codec}'.`);
@@ -97,8 +115,15 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
97
115
  if (!this.avCodec.pixelFormats.includes(NodeAv.AV_PIX_FMT_YUV420P)) {
98
116
  pixelFormat = this.avCodec.pixelFormats[0];
99
117
  }
100
- if (this.config.alpha === 'keep' && this.avCodec.pixelFormats.includes(NodeAv.AV_PIX_FMT_YUVA420P)) {
101
- pixelFormat = NodeAv.AV_PIX_FMT_YUVA420P;
118
+ if (this.config.alpha === 'keep') {
119
+ if (this.avCodec.pixelFormats.includes(NodeAv.AV_PIX_FMT_YUVA420P)) {
120
+ pixelFormat = NodeAv.AV_PIX_FMT_YUVA420P;
121
+ }
122
+ else {
123
+ // Let FFmpeg pick the best alpha-capable format it supports, minimizing data loss versus a
124
+ // high-quality YUVA source
125
+ pixelFormat = NodeAv.avcodecFindBestPixFmtOfList(this.avCodec.pixelFormats, NodeAv.AV_PIX_FMT_YUVA444P12LE);
126
+ }
102
127
  }
103
128
  }
104
129
  const pixelAspectRatio = (0, misc_2.simplifyRational)({
@@ -157,6 +182,12 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
157
182
  codecContext.setOption('preset', '12');
158
183
  }
159
184
  }
185
+ if (this.codec === 'prores') {
186
+ // Pick the encoder profile from the requested ProRes four-character code
187
+ const profile = PRORES_FOURCC_TO_PROFILE[this.config.codec];
188
+ (0, misc_2.assert)(profile !== undefined);
189
+ codecContext.setOption('profile', String(profile));
190
+ }
160
191
  const ret = await codecContext.open2();
161
192
  NodeAv.FFmpegError.throwIfError(ret, 'Open codec context');
162
193
  this.codecContext = codecContext;
@@ -318,6 +349,7 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
318
349
  hevcCodecInfo: null,
319
350
  vp9CodecInfo: null,
320
351
  av1CodecInfo: null,
352
+ proresFormat: null,
321
353
  });
322
354
  if (!expectsAnnexB) {
323
355
  decoderConfigDescription = serializedRecord;
@@ -377,6 +409,7 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
377
409
  hevcCodecInfo: null,
378
410
  vp9CodecInfo: null,
379
411
  av1CodecInfo: null,
412
+ proresFormat: null,
380
413
  });
381
414
  }
382
415
  }
@@ -394,6 +427,7 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
394
427
  hevcCodecInfo: null,
395
428
  vp9CodecInfo,
396
429
  av1CodecInfo: null,
430
+ proresFormat: null,
397
431
  });
398
432
  }
399
433
  }
@@ -411,6 +445,24 @@ class NodeAvVideoEncoder extends mediabunny_1.CustomVideoEncoder {
411
445
  hevcCodecInfo: null,
412
446
  vp9CodecInfo: null,
413
447
  av1CodecInfo,
448
+ proresFormat: null,
449
+ });
450
+ }
451
+ }
452
+ else if (this.codec === 'prores') {
453
+ if (!this.packetEmitted) {
454
+ decoderConfigCodecString = (0, codec_1.extractVideoCodecString)({
455
+ width: this.config.width,
456
+ height: this.config.height,
457
+ codec: 'prores',
458
+ codecDescription: null,
459
+ colorSpace: null,
460
+ avcType: null,
461
+ avcCodecInfo: null,
462
+ hevcCodecInfo: null,
463
+ vp9CodecInfo: null,
464
+ av1CodecInfo: null,
465
+ proresFormat: this.config.codec,
414
466
  });
415
467
  }
416
468
  }