@remotion/webcodecs 4.0.233 → 4.0.235

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.
@@ -1,2 +1 @@
1
- import type { LogLevel } from './log';
2
- export declare const getAudioDecoderConfig: (config: AudioDecoderConfig, logLevel: LogLevel) => Promise<AudioDecoderConfig | null>;
1
+ export declare const getAudioDecoderConfig: (config: AudioDecoderConfig) => Promise<AudioDecoderConfig | null>;
@@ -1,41 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAudioDecoderConfig = void 0;
4
- const browser_quirks_1 = require("./browser-quirks");
5
- const log_1 = require("./log");
6
- const overrideBrowserQuirks = ({ config, logLevel, }) => {
7
- const bytes = config.description;
8
- if (!bytes) {
9
- return config;
10
- }
11
- if (bytes[0] === 18 && bytes[1] === 8) {
12
- // riverside_use_cursor_.mp4
13
- if ((0, browser_quirks_1.isFirefox)()) {
14
- return {
15
- ...config,
16
- codec: 'mp4a.40.2',
17
- description: bytes,
18
- };
19
- }
20
- if (!(0, browser_quirks_1.isChrome)()) {
21
- return config;
22
- }
23
- log_1.Log.warn(logLevel, 'Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330');
24
- return {
25
- ...config,
26
- description: new Uint8Array([18, 16]),
27
- };
28
- }
29
- if (bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136) {
30
- log_1.Log.warn(logLevel, 'Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330');
31
- return {
32
- ...config,
33
- description: new Uint8Array([18, 144]),
34
- };
35
- }
36
- return config;
37
- };
38
- const getAudioDecoderConfig = async (config, logLevel) => {
4
+ const getAudioDecoderConfig = async (config) => {
39
5
  if (config.codec === 'pcm-s16') {
40
6
  return config;
41
7
  }
@@ -45,12 +11,8 @@ const getAudioDecoderConfig = async (config, logLevel) => {
45
11
  if (typeof EncodedAudioChunk === 'undefined') {
46
12
  return null;
47
13
  }
48
- const realConfig = overrideBrowserQuirks({
49
- config,
50
- logLevel,
51
- });
52
- if ((await AudioDecoder.isConfigSupported(realConfig)).supported) {
53
- return realConfig;
14
+ if ((await AudioDecoder.isConfigSupported(config)).supported) {
15
+ return config;
54
16
  }
55
17
  return null;
56
18
  };
@@ -1,8 +1,7 @@
1
- import type { AudioTrack, LogLevel } from '@remotion/media-parser';
1
+ import type { AudioTrack } from '@remotion/media-parser';
2
2
  import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
3
- export declare const canReencodeAudioTrack: ({ track, audioCodec, bitrate, logLevel, }: {
3
+ export declare const canReencodeAudioTrack: ({ track, audioCodec, bitrate, }: {
4
4
  track: AudioTrack;
5
5
  audioCodec: ConvertMediaAudioCodec;
6
6
  bitrate: number;
7
- logLevel?: LogLevel;
8
7
  }) => Promise<boolean>;
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canReencodeAudioTrack = void 0;
4
4
  const audio_decoder_config_1 = require("./audio-decoder-config");
5
5
  const audio_encoder_config_1 = require("./audio-encoder-config");
6
- const canReencodeAudioTrack = async ({ track, audioCodec, bitrate, logLevel = 'info', }) => {
7
- const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)(track, logLevel);
6
+ const canReencodeAudioTrack = async ({ track, audioCodec, bitrate, }) => {
7
+ const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)(track);
8
8
  if (audioCodec === 'wav' && audioDecoderConfig) {
9
9
  return true;
10
10
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * bytes 17,144: 00010 001 | 1 0010 000
3
+ ^^^^^ ^^^ ^ ^^^^ ^
4
+ | | | | padding
5
+ | | |
6
+ | | +-- channelConfiguration (2)
7
+ | +-- samplingFrequencyIndex (3)
8
+ +-- audioConfigType (2)
9
+ */
10
+ export declare const createAacCodecPrivate: ({ audioObjectType, sampleRate, channelConfiguration, }: {
11
+ audioObjectType: number;
12
+ sampleRate: number;
13
+ channelConfiguration: number;
14
+ }) => Uint8Array;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ // codec private, for example [17, 144]
3
+ // audioObjectType = 2 = 'AAC LC'
4
+ // samplingFrequencyIndex = 3 = '48000 Hz'
5
+ // channelConfiguration = 2 = '2 channels'
6
+ /**
7
+ * bytes 17,144: 00010 001 | 1 0010 000
8
+ ^^^^^ ^^^ ^ ^^^^ ^
9
+ | | | | padding
10
+ | | |
11
+ | | +-- channelConfiguration (2)
12
+ | +-- samplingFrequencyIndex (3)
13
+ +-- audioConfigType (2)
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.createAacCodecPrivate = void 0;
17
+ // https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Channel_Configurations
18
+ const getConfigForSampleRate = (sampleRate) => {
19
+ if (sampleRate === 96000) {
20
+ return 0;
21
+ }
22
+ if (sampleRate === 88200) {
23
+ return 1;
24
+ }
25
+ if (sampleRate === 64000) {
26
+ return 2;
27
+ }
28
+ if (sampleRate === 48000) {
29
+ return 3;
30
+ }
31
+ if (sampleRate === 44100) {
32
+ return 4;
33
+ }
34
+ if (sampleRate === 32000) {
35
+ return 5;
36
+ }
37
+ if (sampleRate === 24000) {
38
+ return 6;
39
+ }
40
+ if (sampleRate === 22050) {
41
+ return 7;
42
+ }
43
+ if (sampleRate === 16000) {
44
+ return 8;
45
+ }
46
+ if (sampleRate === 12000) {
47
+ return 9;
48
+ }
49
+ if (sampleRate === 11025) {
50
+ return 10;
51
+ }
52
+ if (sampleRate === 8000) {
53
+ return 11;
54
+ }
55
+ if (sampleRate === 7350) {
56
+ return 12;
57
+ }
58
+ throw new Error(`Unexpected sample rate ${sampleRate}`);
59
+ };
60
+ const createAacCodecPrivate = ({ audioObjectType, sampleRate, channelConfiguration, }) => {
61
+ const bits = `${audioObjectType.toString(2).padStart(5, '0')}${getConfigForSampleRate(sampleRate).toString(2).padStart(4, '0')}${channelConfiguration.toString(2).padStart(4, '0')}000`;
62
+ if (bits.length !== 16) {
63
+ throw new Error('Invalid AAC codec private ' + bits.length);
64
+ }
65
+ if (channelConfiguration === 0 || channelConfiguration > 7) {
66
+ throw new Error('Invalid channel configuration ' + channelConfiguration);
67
+ }
68
+ const firstByte = parseInt(bits.slice(0, 8), 2);
69
+ const secondByte = parseInt(bits.slice(8, 16), 2);
70
+ return new Uint8Array([firstByte, secondByte]);
71
+ };
72
+ exports.createAacCodecPrivate = createAacCodecPrivate;
@@ -492,53 +492,8 @@ var canCopyVideoTrack = ({
492
492
  }
493
493
  throw new Error(`Unhandled codec: ${container}`);
494
494
  };
495
- // src/browser-quirks.ts
496
- var isFirefox = () => {
497
- return navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
498
- };
499
- var isSafari = () => {
500
- return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
501
- };
502
- var isChrome = () => {
503
- return navigator.userAgent.toLowerCase().indexOf("chrome") > -1;
504
- };
505
-
506
495
  // src/audio-decoder-config.ts
507
- var overrideBrowserQuirks = ({
508
- config,
509
- logLevel
510
- }) => {
511
- const bytes = config.description;
512
- if (!bytes) {
513
- return config;
514
- }
515
- if (bytes[0] === 18 && bytes[1] === 8) {
516
- if (isFirefox()) {
517
- return {
518
- ...config,
519
- codec: "mp4a.40.2",
520
- description: bytes
521
- };
522
- }
523
- if (!isChrome()) {
524
- return config;
525
- }
526
- Log.warn(logLevel, "Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330");
527
- return {
528
- ...config,
529
- description: new Uint8Array([18, 16])
530
- };
531
- }
532
- if (bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136) {
533
- Log.warn(logLevel, "Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330");
534
- return {
535
- ...config,
536
- description: new Uint8Array([18, 144])
537
- };
538
- }
539
- return config;
540
- };
541
- var getAudioDecoderConfig = async (config, logLevel) => {
496
+ var getAudioDecoderConfig = async (config) => {
542
497
  if (config.codec === "pcm-s16") {
543
498
  return config;
544
499
  }
@@ -548,12 +503,8 @@ var getAudioDecoderConfig = async (config, logLevel) => {
548
503
  if (typeof EncodedAudioChunk === "undefined") {
549
504
  return null;
550
505
  }
551
- const realConfig = overrideBrowserQuirks({
552
- config,
553
- logLevel
554
- });
555
- if ((await AudioDecoder.isConfigSupported(realConfig)).supported) {
556
- return realConfig;
506
+ if ((await AudioDecoder.isConfigSupported(config)).supported) {
507
+ return config;
557
508
  }
558
509
  return null;
559
510
  };
@@ -592,10 +543,9 @@ var getAudioEncoderConfig = async (config) => {
592
543
  var canReencodeAudioTrack = async ({
593
544
  track,
594
545
  audioCodec,
595
- bitrate,
596
- logLevel = "info"
546
+ bitrate
597
547
  }) => {
598
- const audioDecoderConfig = await getAudioDecoderConfig(track, logLevel);
548
+ const audioDecoderConfig = await getAudioDecoderConfig(track);
599
549
  if (audioCodec === "wav" && audioDecoderConfig) {
600
550
  return true;
601
551
  }
@@ -629,6 +579,14 @@ var getVideoDecoderConfigWithHardwareAcceleration = async (config) => {
629
579
  return null;
630
580
  };
631
581
 
582
+ // src/browser-quirks.ts
583
+ var isFirefox = () => {
584
+ return navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
585
+ };
586
+ var isSafari = () => {
587
+ return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
588
+ };
589
+
632
590
  // src/choose-correct-avc1-profile.ts
633
591
  var chooseCorrectAvc1Profile = ({
634
592
  width,
@@ -713,7 +671,7 @@ var canReencodeVideoTrack = async ({
713
671
  };
714
672
  // src/convert-media.ts
715
673
  import {
716
- MediaParserInternals as MediaParserInternals7,
674
+ MediaParserInternals as MediaParserInternals8,
717
675
  parseMedia
718
676
  } from "@remotion/media-parser";
719
677
 
@@ -756,6 +714,11 @@ var generateOutputFilename = (source, container) => {
756
714
  return `${withoutExtension}.${container}`;
757
715
  };
758
716
 
717
+ // src/on-audio-track.ts
718
+ import {
719
+ MediaParserInternals as MediaParserInternals5
720
+ } from "@remotion/media-parser";
721
+
759
722
  // src/convert-encoded-chunk.ts
760
723
  var convertEncodedChunk = (chunk, trackId) => {
761
724
  const arr = new Uint8Array(chunk.byteLength);
@@ -886,7 +849,7 @@ var makeAudioTrackHandler = ({
886
849
  numberOfChannels: track.numberOfChannels,
887
850
  sampleRate: track.sampleRate,
888
851
  description: track.description
889
- }, logLevel);
852
+ });
890
853
  if (!audioEncoderConfig) {
891
854
  abortConversion(new error_cause_default(`Could not configure audio encoder of track ${track.trackId}`));
892
855
  return null;
@@ -895,7 +858,11 @@ var makeAudioTrackHandler = ({
895
858
  abortConversion(new error_cause_default(`Could not configure audio decoder of track ${track.trackId}`));
896
859
  return null;
897
860
  }
898
- const codecPrivate = audioOperation.audioCodec === "aac" ? new Uint8Array([17, 144]) : null;
861
+ const codecPrivate = audioOperation.audioCodec === "aac" ? MediaParserInternals5.createAacCodecPrivate({
862
+ audioObjectType: 2,
863
+ sampleRate: track.sampleRate,
864
+ channelConfiguration: track.numberOfChannels
865
+ }) : null;
899
866
  const { trackNumber } = await state.addTrack({
900
867
  type: "audio",
901
868
  codec: audioOperation.audioCodec === "wav" ? "pcm-s16" : audioOperation.audioCodec,
@@ -973,7 +940,7 @@ var arrayBufferToUint8Array = (buffer) => {
973
940
  };
974
941
 
975
942
  // src/default-on-video-track-handler.ts
976
- import { MediaParserInternals as MediaParserInternals5 } from "@remotion/media-parser";
943
+ import { MediaParserInternals as MediaParserInternals6 } from "@remotion/media-parser";
977
944
 
978
945
  // src/get-default-video-codec.ts
979
946
  var getDefaultVideoCodec = ({
@@ -1006,12 +973,12 @@ var defaultOnVideoTrackHandler = async ({
1006
973
  rotationToApply: rotate
1007
974
  });
1008
975
  if (canCopy) {
1009
- MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
976
+ MediaParserInternals6.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
1010
977
  return Promise.resolve({ type: "copy" });
1011
978
  }
1012
979
  const videoCodec = defaultVideoCodec ?? getDefaultVideoCodec({ container });
1013
980
  if (videoCodec === null) {
1014
- MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): No default video codec, therefore dropping`);
981
+ MediaParserInternals6.Log.verbose(logLevel, `Track ${track.trackId} (video): No default video codec, therefore dropping`);
1015
982
  return Promise.resolve({ type: "drop" });
1016
983
  }
1017
984
  const canReencode = await canReencodeVideoTrack({
@@ -1019,14 +986,14 @@ var defaultOnVideoTrackHandler = async ({
1019
986
  track
1020
987
  });
1021
988
  if (canReencode) {
1022
- MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Cannot copy, but re-enconde, therefore re-encoding`);
989
+ MediaParserInternals6.Log.verbose(logLevel, `Track ${track.trackId} (video): Cannot copy, but re-enconde, therefore re-encoding`);
1023
990
  return Promise.resolve({
1024
991
  type: "reencode",
1025
992
  videoCodec,
1026
993
  rotation: rotate - track.rotation
1027
994
  });
1028
995
  }
1029
- MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
996
+ MediaParserInternals6.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
1030
997
  return Promise.resolve({ type: "fail" });
1031
998
  };
1032
999
 
@@ -1352,7 +1319,7 @@ var makeVideoTrackHandler = ({
1352
1319
  if (videoOperation.type !== "reencode") {
1353
1320
  throw new error_cause_default(`Video track with ID ${track.trackId} could not be resolved with a valid operation. Received ${JSON.stringify(videoOperation)}, but must be either "copy", "reencode", "drop" or "fail"`);
1354
1321
  }
1355
- const rotation = videoOperation.rotate ?? -track.rotation;
1322
+ const rotation = (videoOperation.rotate ?? rotate) - track.rotation;
1356
1323
  const { height: newHeight, width: newWidth } = calculateNewDimensionsFromDimensions({
1357
1324
  width: track.codedWidth,
1358
1325
  height: track.codedHeight,
@@ -1446,16 +1413,16 @@ var makeVideoTrackHandler = ({
1446
1413
  };
1447
1414
 
1448
1415
  // src/select-container-creator.ts
1449
- import { MediaParserInternals as MediaParserInternals6 } from "@remotion/media-parser";
1416
+ import { MediaParserInternals as MediaParserInternals7 } from "@remotion/media-parser";
1450
1417
  var selectContainerCreator = (container) => {
1451
1418
  if (container === "mp4") {
1452
- return MediaParserInternals6.createIsoBaseMedia;
1419
+ return MediaParserInternals7.createIsoBaseMedia;
1453
1420
  }
1454
1421
  if (container === "wav") {
1455
- return MediaParserInternals6.createWav;
1422
+ return MediaParserInternals7.createWav;
1456
1423
  }
1457
1424
  if (container === "webm") {
1458
- return MediaParserInternals6.createMatroskaMedia;
1425
+ return MediaParserInternals7.createMatroskaMedia;
1459
1426
  }
1460
1427
  throw new Error(`Unsupported container: ${container}`);
1461
1428
  };
@@ -1540,7 +1507,7 @@ var convertMedia = async function({
1540
1507
  if (videoCodec && videoCodec !== "vp8" && videoCodec !== "vp9") {
1541
1508
  return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
1542
1509
  }
1543
- const { resolve, reject, getPromiseToImmediatelyReturn } = MediaParserInternals7.withResolversAndWaitForReturn();
1510
+ const { resolve, reject, getPromiseToImmediatelyReturn } = MediaParserInternals8.withResolversAndWaitForReturn();
1544
1511
  const controller = new AbortController;
1545
1512
  const abortConversion = (errCause) => {
1546
1513
  reject(errCause);
@@ -1558,7 +1525,7 @@ var convertMedia = async function({
1558
1525
  everyMilliseconds: progressIntervalInMs ?? 100,
1559
1526
  signal: controller.signal
1560
1527
  });
1561
- const progressTracker = MediaParserInternals7.makeProgressTracker();
1528
+ const progressTracker = MediaParserInternals8.makeProgressTracker();
1562
1529
  const state = await creator({
1563
1530
  filename: generateOutputFilename(src, container),
1564
1531
  writer: await autoSelectWriter(writer, logLevel),
@@ -1,4 +1,4 @@
1
- import type { LogLevel, MediaFn, OnAudioTrack, ProgressTracker } from '@remotion/media-parser';
1
+ import { type LogLevel, type MediaFn, type OnAudioTrack, type ProgressTracker } from '@remotion/media-parser';
2
2
  import Error from './error-cause';
3
3
  import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
4
4
  import type { ConvertMediaContainer } from './get-available-containers';
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.makeAudioTrackHandler = void 0;
7
+ const media_parser_1 = require("@remotion/media-parser");
7
8
  const audio_decoder_1 = require("./audio-decoder");
8
9
  const audio_decoder_config_1 = require("./audio-decoder-config");
9
10
  const audio_encoder_1 = require("./audio-encoder");
@@ -62,7 +63,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
62
63
  numberOfChannels: track.numberOfChannels,
63
64
  sampleRate: track.sampleRate,
64
65
  description: track.description,
65
- }, logLevel);
66
+ });
66
67
  if (!audioEncoderConfig) {
67
68
  abortConversion(new error_cause_1.default(`Could not configure audio encoder of track ${track.trackId}`));
68
69
  return null;
@@ -71,7 +72,13 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
71
72
  abortConversion(new error_cause_1.default(`Could not configure audio decoder of track ${track.trackId}`));
72
73
  return null;
73
74
  }
74
- const codecPrivate = audioOperation.audioCodec === 'aac' ? new Uint8Array([17, 144]) : null;
75
+ const codecPrivate = audioOperation.audioCodec === 'aac'
76
+ ? media_parser_1.MediaParserInternals.createAacCodecPrivate({
77
+ audioObjectType: 2,
78
+ sampleRate: track.sampleRate,
79
+ channelConfiguration: track.numberOfChannels,
80
+ })
81
+ : null;
75
82
  const { trackNumber } = await state.addTrack({
76
83
  type: 'audio',
77
84
  codec: audioOperation.audioCodec === 'wav'
@@ -63,7 +63,7 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
63
63
  if (videoOperation.type !== 'reencode') {
64
64
  throw new error_cause_1.default(`Video track with ID ${track.trackId} could not be resolved with a valid operation. Received ${JSON.stringify(videoOperation)}, but must be either "copy", "reencode", "drop" or "fail"`);
65
65
  }
66
- const rotation = (_a = videoOperation.rotate) !== null && _a !== void 0 ? _a : -track.rotation;
66
+ const rotation = ((_a = videoOperation.rotate) !== null && _a !== void 0 ? _a : rotate) - track.rotation;
67
67
  const { height: newHeight, width: newWidth } = (0, rotation_1.calculateNewDimensionsFromDimensions)({
68
68
  width: track.codedWidth,
69
69
  height: track.codedHeight,
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const bun_test_1 = require("bun:test");
4
+ const create_aac_codecprivate_1 = require("../create-aac-codecprivate");
5
+ (0, bun_test_1.test)('AACCodecPrivate', () => {
6
+ const codecPrivate = (0, create_aac_codecprivate_1.createAacCodecPrivate)({
7
+ audioObjectType: 2,
8
+ sampleRate: 48000,
9
+ channelConfiguration: 2,
10
+ });
11
+ (0, bun_test_1.expect)(codecPrivate).toEqual(new Uint8Array([17, 144]));
12
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/webcodecs",
3
- "version": "4.0.233",
3
+ "version": "4.0.235",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -17,14 +17,14 @@
17
17
  "author": "Jonny Burger <jonny@remotion.dev>",
18
18
  "license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)",
19
19
  "dependencies": {
20
- "@remotion/media-parser": "4.0.233",
21
- "@remotion/example-videos": "4.0.233"
20
+ "@remotion/media-parser": "4.0.235"
22
21
  },
23
22
  "peerDependencies": {},
24
23
  "devDependencies": {
25
24
  "@types/dom-webcodecs": "0.1.11",
26
25
  "eslint": "9.14.0",
27
- "@remotion/eslint-config-internal": "4.0.233"
26
+ "@remotion/example-videos": "4.0.235",
27
+ "@remotion/eslint-config-internal": "4.0.235"
28
28
  },
29
29
  "keywords": [],
30
30
  "publishConfig": {