@remotion/webcodecs 4.0.264 → 4.0.266

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.
@@ -75,7 +75,14 @@ const createAudioDecoder = ({ onFrame, onError, controller, config, logLevel, tr
75
75
  // Don't flush, it messes up the audio
76
76
  const chunk = new EncodedAudioChunk(audioSample);
77
77
  audioDecoder.decode(chunk);
78
- ioSynchronizer.inputItem(chunk.timestamp, audioSample.type === 'key');
78
+ // https://test-streams.mux.dev/x36xhzz/url_0/url_525/193039199_mp4_h264_aac_hd_7.ts
79
+ // has a 16 byte audio sample at the end which chrome does not decode
80
+ // Might be empty audio
81
+ // For now only reporting chunks that are bigger than that
82
+ // 16 was chosen arbitrarily, can be improved
83
+ if (chunk.byteLength > 16) {
84
+ ioSynchronizer.inputItem(chunk.timestamp, audioSample.type === 'key');
85
+ }
79
86
  };
80
87
  let queue = Promise.resolve();
81
88
  return {
@@ -27,6 +27,13 @@ const getAudioEncoderConfig = async (config) => {
27
27
  if ((await AudioEncoder.isConfigSupported(actualConfig)).supported) {
28
28
  return actualConfig;
29
29
  }
30
+ const maybeItIsTheSampleRateThatIsTheProblem = config.sampleRate !== 48000 && config.sampleRate !== 44100;
31
+ if (maybeItIsTheSampleRateThatIsTheProblem) {
32
+ return (0, exports.getAudioEncoderConfig)({
33
+ ...config,
34
+ sampleRate: config.sampleRate === 22050 ? 44100 : 48000,
35
+ });
36
+ }
30
37
  return null;
31
38
  };
32
39
  exports.getAudioEncoderConfig = getAudioEncoderConfig;
@@ -35,7 +35,7 @@ export type ConvertMediaOnAudioData = (options: {
35
35
  audioData: AudioData;
36
36
  track: AudioTrack;
37
37
  }) => Promise<AudioData> | AudioData;
38
- export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame, onAudioData, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, controller, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel, writer, progressIntervalInMs, rotate, apiKey, resize, onAudioCodec, onContainer, onDimensions, onDurationInSeconds, onFps, onImages, onInternalStats, onIsHdr, onKeyframes, onLocation, onMetadata, onMimeType, onName, onNumberOfAudioChannels, onRotation, onSampleRate, onSize, onSlowAudioBitrate, onSlowDurationInSeconds, onSlowFps, onSlowKeyframes, onSlowNumberOfFrames, onSlowVideoBitrate, onStructure, onTracks, onUnrotatedDimensions, onVideoCodec, ...more }: {
38
+ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame, onAudioData, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, controller, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel, writer, progressIntervalInMs, rotate, apiKey, resize, onAudioCodec, onContainer, onDimensions, onDurationInSeconds, onFps, onImages, onInternalStats, onIsHdr, onKeyframes, onLocation, onMetadata, onMimeType, onName, onNumberOfAudioChannels, onRotation, onSampleRate, onSize, onSlowAudioBitrate, onSlowDurationInSeconds, onSlowFps, onSlowKeyframes, onSlowNumberOfFrames, onSlowVideoBitrate, onStructure, onTracks, onUnrotatedDimensions, onVideoCodec, onM3uStreams, selectM3uStream, ...more }: {
39
39
  src: ParseMediaOptions<F>["src"];
40
40
  container: ConvertMediaContainer;
41
41
  onVideoFrame?: ConvertMediaOnVideoFrame;
@@ -46,6 +46,7 @@ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src,
46
46
  controller?: WebCodecsController;
47
47
  onAudioTrack?: ConvertMediaOnAudioTrackHandler;
48
48
  onVideoTrack?: ConvertMediaOnVideoTrackHandler;
49
+ selectM3uStream?: ParseMediaOptions<F>["selectM3uStream"];
49
50
  reader?: ParseMediaOptions<F>["reader"];
50
51
  logLevel?: LogLevel;
51
52
  writer?: WriterInterface;
@@ -21,7 +21,7 @@ const select_container_creator_1 = require("./select-container-creator");
21
21
  const send_telemetry_event_1 = require("./send-telemetry-event");
22
22
  const throttled_state_update_1 = require("./throttled-state-update");
23
23
  const webcodecs_controller_1 = require("./webcodecs-controller");
24
- const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, controller = (0, webcodecs_controller_1.webcodecsController)(), onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, rotate, apiKey, resize, onAudioCodec, onContainer, onDimensions, onDurationInSeconds, onFps, onImages, onInternalStats, onIsHdr, onKeyframes, onLocation, onMetadata, onMimeType, onName, onNumberOfAudioChannels, onRotation, onSampleRate, onSize, onSlowAudioBitrate, onSlowDurationInSeconds, onSlowFps, onSlowKeyframes, onSlowNumberOfFrames, onSlowVideoBitrate, onStructure, onTracks, onUnrotatedDimensions, onVideoCodec, ...more }) {
24
+ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, controller = (0, webcodecs_controller_1.webcodecsController)(), onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, rotate, apiKey, resize, onAudioCodec, onContainer, onDimensions, onDurationInSeconds, onFps, onImages, onInternalStats, onIsHdr, onKeyframes, onLocation, onMetadata, onMimeType, onName, onNumberOfAudioChannels, onRotation, onSampleRate, onSize, onSlowAudioBitrate, onSlowDurationInSeconds, onSlowFps, onSlowKeyframes, onSlowNumberOfFrames, onSlowVideoBitrate, onStructure, onTracks, onUnrotatedDimensions, onVideoCodec, onM3uStreams, selectM3uStream, ...more }) {
25
25
  var _a, _b;
26
26
  if (controller._internals.signal.aborted) {
27
27
  return Promise.reject(new media_parser_1.MediaParserAbortError('Aborted'));
@@ -173,6 +173,8 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
173
173
  onUnrotatedDimensions: onUnrotatedDimensions !== null && onUnrotatedDimensions !== void 0 ? onUnrotatedDimensions : null,
174
174
  onVideoCodec: onVideoCodec !== null && onVideoCodec !== void 0 ? onVideoCodec : null,
175
175
  apiName: 'convertMedia()',
176
+ onM3uStreams: onM3uStreams !== null && onM3uStreams !== void 0 ? onM3uStreams : null,
177
+ selectM3uStream: selectM3uStream !== null && selectM3uStream !== void 0 ? selectM3uStream : media_parser_1.defaultSelectM3uStreamFn,
176
178
  })
177
179
  .then(() => {
178
180
  return state.waitForFinish();
@@ -13,7 +13,7 @@ const serialize_track_1 = require("./serialize-track");
13
13
  const create_meta_1 = require("./udta/create-meta");
14
14
  const create_hdlr_1 = require("./udta/meta/create-hdlr");
15
15
  // TODO: Creates a header that is way too large
16
- const HEADER_LENGTH = 1024000;
16
+ const HEADER_LENGTH = 2048000;
17
17
  const createPaddedMoovAtom = ({ durationInUnits, trackInfo, timescale, }) => {
18
18
  return (0, primitives_1.padIsoBaseMediaBytes)((0, create_moov_1.createMoov)({
19
19
  mvhd: (0, create_mvhd_1.createMvhd)({
@@ -18,7 +18,10 @@ const createSttsAtom = (samplePositions) => {
18
18
  var _a, _b;
19
19
  // TODO: Why does 0 appear here?
20
20
  if (a[i].duration === undefined || a[i].duration === 0) {
21
- return ((_b = (_a = a[i + 1]) === null || _a === void 0 ? void 0 : _a.dts) !== null && _b !== void 0 ? _b : a[i].dts) - a[i].dts;
21
+ if (a[i + 1] === undefined) {
22
+ return a[i].dts - ((_b = (_a = a[i - 1]) === null || _a === void 0 ? void 0 : _a.dts) !== null && _b !== void 0 ? _b : a[i].dts);
23
+ }
24
+ return a[i + 1].dts - a[i].dts;
22
25
  }
23
26
  return a[i].duration;
24
27
  });
@@ -748,7 +748,9 @@ var createAudioDecoder = ({
748
748
  });
749
749
  const chunk = new EncodedAudioChunk(audioSample);
750
750
  audioDecoder.decode(chunk);
751
- ioSynchronizer.inputItem(chunk.timestamp, audioSample.type === "key");
751
+ if (chunk.byteLength > 16) {
752
+ ioSynchronizer.inputItem(chunk.timestamp, audioSample.type === "key");
753
+ }
752
754
  };
753
755
  let queue = Promise.resolve();
754
756
  return {
@@ -996,6 +998,13 @@ var getAudioEncoderConfig = async (config) => {
996
998
  if ((await AudioEncoder.isConfigSupported(actualConfig)).supported) {
997
999
  return actualConfig;
998
1000
  }
1001
+ const maybeItIsTheSampleRateThatIsTheProblem = config.sampleRate !== 48000 && config.sampleRate !== 44100;
1002
+ if (maybeItIsTheSampleRateThatIsTheProblem) {
1003
+ return getAudioEncoderConfig({
1004
+ ...config,
1005
+ sampleRate: config.sampleRate === 22050 ? 44100 : 48000
1006
+ });
1007
+ }
999
1008
  return null;
1000
1009
  };
1001
1010
 
@@ -1420,6 +1429,7 @@ var canReencodeVideoTrack = async ({
1420
1429
  };
1421
1430
  // src/convert-media.ts
1422
1431
  import {
1432
+ defaultSelectM3uStreamFn,
1423
1433
  MediaParserAbortError as MediaParserAbortError3,
1424
1434
  MediaParserInternals as MediaParserInternals9
1425
1435
  } from "@remotion/media-parser";
@@ -1711,15 +1721,15 @@ var makeAudioTrackHandler = ({
1711
1721
  }
1712
1722
  const codecPrivate = audioOperation.audioCodec === "aac" ? MediaParserInternals3.createAacCodecPrivate({
1713
1723
  audioObjectType: 2,
1714
- sampleRate: track.sampleRate,
1715
- channelConfiguration: track.numberOfChannels,
1724
+ sampleRate: audioEncoderConfig.sampleRate,
1725
+ channelConfiguration: audioEncoderConfig.numberOfChannels,
1716
1726
  codecPrivate: null
1717
1727
  }) : null;
1718
1728
  const { trackNumber } = await state.addTrack({
1719
1729
  type: "audio",
1720
1730
  codec: audioOperation.audioCodec === "wav" ? "pcm-s16" : audioOperation.audioCodec,
1721
- numberOfChannels: track.numberOfChannels,
1722
- sampleRate: track.sampleRate,
1731
+ numberOfChannels: audioEncoderConfig.numberOfChannels,
1732
+ sampleRate: audioEncoderConfig.sampleRate,
1723
1733
  codecPrivate,
1724
1734
  timescale: track.timescale
1725
1735
  });
@@ -3302,7 +3312,10 @@ var createSttsAtom = (samplePositions) => {
3302
3312
  let lastDuration = null;
3303
3313
  const durations = samplePositions.map((_, i, a) => {
3304
3314
  if (a[i].duration === undefined || a[i].duration === 0) {
3305
- return (a[i + 1]?.dts ?? a[i].dts) - a[i].dts;
3315
+ if (a[i + 1] === undefined) {
3316
+ return a[i].dts - (a[i - 1]?.dts ?? a[i].dts);
3317
+ }
3318
+ return a[i + 1].dts - a[i].dts;
3306
3319
  }
3307
3320
  return a[i].duration;
3308
3321
  });
@@ -3505,7 +3518,7 @@ var createMeta = ({
3505
3518
  };
3506
3519
 
3507
3520
  // src/create/iso-base-media/mp4-header.ts
3508
- var HEADER_LENGTH = 1024000;
3521
+ var HEADER_LENGTH = 2048000;
3509
3522
  var createPaddedMoovAtom = ({
3510
3523
  durationInUnits,
3511
3524
  trackInfo,
@@ -4792,6 +4805,8 @@ var convertMedia = async function({
4792
4805
  onTracks,
4793
4806
  onUnrotatedDimensions,
4794
4807
  onVideoCodec,
4808
+ onM3uStreams,
4809
+ selectM3uStream,
4795
4810
  ...more
4796
4811
  }) {
4797
4812
  if (controller._internals.signal.aborted) {
@@ -4940,7 +4955,9 @@ var convertMedia = async function({
4940
4955
  onTracks: onTracks ?? null,
4941
4956
  onUnrotatedDimensions: onUnrotatedDimensions ?? null,
4942
4957
  onVideoCodec: onVideoCodec ?? null,
4943
- apiName: "convertMedia()"
4958
+ apiName: "convertMedia()",
4959
+ onM3uStreams: onM3uStreams ?? null,
4960
+ selectM3uStream: selectM3uStream ?? defaultSelectM3uStreamFn
4944
4961
  }).then(() => {
4945
4962
  return state.waitForFinish();
4946
4963
  }).then(() => {
@@ -4980,6 +4997,7 @@ var getAvailableAudioCodecs = ({
4980
4997
  }
4981
4998
  throw new Error(`Unsupported container: ${container}`);
4982
4999
  };
5000
+
4983
5001
  // src/index.ts
4984
5002
  var WebCodecsInternals = {
4985
5003
  rotateAndResizeVideoFrame,
package/dist/index.d.ts CHANGED
@@ -1,23 +1,32 @@
1
- export { createAudioDecoder, WebCodecsAudioDecoder } from './audio-decoder';
2
- export { createAudioEncoder, WebCodecsAudioEncoder } from './audio-encoder';
1
+ export { createAudioDecoder } from './audio-decoder';
2
+ export type { WebCodecsAudioDecoder } from './audio-decoder';
3
+ export { createAudioEncoder } from './audio-encoder';
4
+ export type { WebCodecsAudioEncoder } from './audio-encoder';
3
5
  export { canCopyAudioTrack } from './can-copy-audio-track';
4
6
  export { canCopyVideoTrack } from './can-copy-video-track';
5
7
  export { canReencodeAudioTrack } from './can-reencode-audio-track';
6
8
  export { canReencodeVideoTrack } from './can-reencode-video-track';
7
- export { convertMedia, ConvertMediaOnAudioData, ConvertMediaOnProgress, ConvertMediaOnVideoFrame, ConvertMediaProgress, ConvertMediaResult, } from './convert-media';
9
+ export { convertMedia } from './convert-media';
10
+ export type { ConvertMediaOnAudioData, ConvertMediaOnProgress, ConvertMediaOnVideoFrame, ConvertMediaProgress, ConvertMediaResult, } from './convert-media';
8
11
  export { defaultOnAudioTrackHandler } from './default-on-audio-track-handler';
9
12
  export { defaultOnVideoTrackHandler } from './default-on-video-track-handler';
10
- export { ConvertMediaAudioCodec, getAvailableAudioCodecs, } from './get-available-audio-codecs';
11
- export { ConvertMediaContainer, getAvailableContainers, } from './get-available-containers';
12
- export { ConvertMediaVideoCodec, getAvailableVideoCodecs, } from './get-available-video-codecs';
13
+ export { getAvailableAudioCodecs } from './get-available-audio-codecs';
14
+ export type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
15
+ export { getAvailableContainers } from './get-available-containers';
16
+ export type { ConvertMediaContainer } from './get-available-containers';
17
+ export { getAvailableVideoCodecs } from './get-available-video-codecs';
18
+ export type { ConvertMediaVideoCodec } from './get-available-video-codecs';
13
19
  export { getDefaultAudioCodec } from './get-default-audio-codec';
14
20
  export { getDefaultVideoCodec } from './get-default-video-codec';
15
- export { AudioOperation, ConvertMediaOnAudioTrackHandler, } from './on-audio-track-handler';
16
- export { ConvertMediaOnVideoTrackHandler, VideoOperation, } from './on-video-track-handler';
21
+ export type { AudioOperation, ConvertMediaOnAudioTrackHandler, } from './on-audio-track-handler';
22
+ export type { ConvertMediaOnVideoTrackHandler, VideoOperation, } from './on-video-track-handler';
17
23
  export type { ResizeOperation } from './resizing/mode';
18
- export { createVideoDecoder, WebCodecsVideoDecoder } from './video-decoder';
19
- export { createVideoEncoder, WebCodecsVideoEncoder } from './video-encoder';
20
- export { webcodecsController, WebCodecsController } from './webcodecs-controller';
24
+ export { createVideoDecoder } from './video-decoder';
25
+ export type { WebCodecsVideoDecoder } from './video-decoder';
26
+ export { createVideoEncoder } from './video-encoder';
27
+ export type { WebCodecsVideoEncoder } from './video-encoder';
28
+ export { webcodecsController } from './webcodecs-controller';
29
+ export type { WebCodecsController } from './webcodecs-controller';
21
30
  export declare const WebCodecsInternals: {
22
31
  rotateAndResizeVideoFrame: ({ frame, rotation, videoCodec, resizeOperation, }: {
23
32
  frame: VideoFrame;
@@ -79,8 +79,8 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
79
79
  const codecPrivate = audioOperation.audioCodec === 'aac'
80
80
  ? media_parser_1.MediaParserInternals.createAacCodecPrivate({
81
81
  audioObjectType: 2,
82
- sampleRate: track.sampleRate,
83
- channelConfiguration: track.numberOfChannels,
82
+ sampleRate: audioEncoderConfig.sampleRate,
83
+ channelConfiguration: audioEncoderConfig.numberOfChannels,
84
84
  codecPrivate: null,
85
85
  })
86
86
  : null;
@@ -89,8 +89,8 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
89
89
  codec: audioOperation.audioCodec === 'wav'
90
90
  ? 'pcm-s16'
91
91
  : audioOperation.audioCodec,
92
- numberOfChannels: track.numberOfChannels,
93
- sampleRate: track.sampleRate,
92
+ numberOfChannels: audioEncoderConfig.numberOfChannels,
93
+ sampleRate: audioEncoderConfig.sampleRate,
94
94
  codecPrivate,
95
95
  timescale: track.timescale,
96
96
  });
@@ -18,6 +18,6 @@ const convert_media_1 = require("../convert-media");
18
18
  writer: (0, node_writer_1.nodeWriter)('outputbun.mp4'),
19
19
  });
20
20
  const data = await save();
21
- (0, bun_test_1.expect)(data.size).toBe(15306323);
21
+ (0, bun_test_1.expect)(data.size).toBe(16330323);
22
22
  (0, node_fs_1.unlinkSync)('outputbun.mp4');
23
23
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/webcodecs",
3
- "version": "4.0.264",
3
+ "version": "4.0.266",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -17,15 +17,15 @@
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.264",
21
- "@remotion/licensing": "4.0.264"
20
+ "@remotion/media-parser": "4.0.266",
21
+ "@remotion/licensing": "4.0.266"
22
22
  },
23
23
  "peerDependencies": {},
24
24
  "devDependencies": {
25
25
  "@types/dom-webcodecs": "0.1.11",
26
26
  "eslint": "9.19.0",
27
- "@remotion/eslint-config-internal": "4.0.264",
28
- "@remotion/example-videos": "4.0.264"
27
+ "@remotion/eslint-config-internal": "4.0.266",
28
+ "@remotion/example-videos": "4.0.266"
29
29
  },
30
30
  "keywords": [],
31
31
  "publishConfig": {