@remotion/webcodecs 4.0.293 → 4.0.295

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.
@@ -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, onM3uStreams, selectM3uStream, selectM3uAssociatedPlaylists, expectedDurationInSeconds, seekingHints, ...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, selectM3uAssociatedPlaylists, expectedDurationInSeconds, expectedFrameRate, seekingHints, ...more }: {
39
39
  src: ParseMediaOptions<F>["src"];
40
40
  container: ConvertMediaContainer;
41
41
  onVideoFrame?: ConvertMediaOnVideoFrame;
@@ -49,6 +49,7 @@ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src,
49
49
  selectM3uStream?: ParseMediaOptions<F>["selectM3uStream"];
50
50
  selectM3uAssociatedPlaylists?: ParseMediaOptions<F>["selectM3uAssociatedPlaylists"];
51
51
  expectedDurationInSeconds?: number | null;
52
+ expectedFrameRate?: number | null;
52
53
  reader?: ParseMediaOptions<F>["reader"];
53
54
  logLevel?: LogLevel;
54
55
  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, onM3uStreams, selectM3uStream, selectM3uAssociatedPlaylists, expectedDurationInSeconds, seekingHints, ...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, selectM3uAssociatedPlaylists, expectedDurationInSeconds, expectedFrameRate, seekingHints, ...more }) {
25
25
  if (controller._internals.signal.aborted) {
26
26
  return Promise.reject(new media_parser_1.MediaParserAbortError('Aborted'));
27
27
  }
@@ -78,6 +78,7 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
78
78
  logLevel,
79
79
  progressTracker,
80
80
  expectedDurationInSeconds: expectedDurationInSeconds ?? null,
81
+ expectedFrameRate: expectedFrameRate ?? null,
81
82
  });
82
83
  const onVideoTrack = (0, on_video_track_1.makeVideoTrackHandler)({
83
84
  state,
@@ -1,2 +1,2 @@
1
1
  import type { MediaFn, MediaFnGeneratorInput } from '../media-fn';
2
- export declare const createIsoBaseMedia: ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, }: MediaFnGeneratorInput) => Promise<MediaFn>;
2
+ export declare const createIsoBaseMedia: ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, expectedFrameRate, }: MediaFnGeneratorInput) => Promise<MediaFn>;
@@ -7,7 +7,7 @@ const create_ftyp_1 = require("./create-ftyp");
7
7
  const mp4_header_1 = require("./mp4-header");
8
8
  const primitives_1 = require("./primitives");
9
9
  const CONTAINER_TIMESCALE = 1000;
10
- const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, }) => {
10
+ const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, expectedFrameRate, }) => {
11
11
  const header = (0, create_ftyp_1.createIsoBaseMediaFtyp)({
12
12
  compatibleBrands: ['isom', 'iso2', 'avc1', 'mp42'],
13
13
  majorBrand: 'isom',
@@ -40,6 +40,7 @@ const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgr
40
40
  timescale: CONTAINER_TIMESCALE,
41
41
  expectedDurationInSeconds,
42
42
  logLevel,
43
+ expectedFrameRate,
43
44
  });
44
45
  };
45
46
  await w.write(getPaddedMoovAtom());
@@ -1 +1,4 @@
1
- export declare const calculateAReasonableMp4HeaderLength: (expectedDurationInSeconds: number | null) => number;
1
+ export declare const calculateAReasonableMp4HeaderLength: ({ expectedDurationInSeconds, expectedFrameRate, }: {
2
+ expectedDurationInSeconds: number | null;
3
+ expectedFrameRate: number | null;
4
+ }) => number;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.calculateAReasonableMp4HeaderLength = void 0;
4
- const calculateAReasonableMp4HeaderLength = (expectedDurationInSeconds) => {
4
+ const calculateAReasonableMp4HeaderLength = ({ expectedDurationInSeconds, expectedFrameRate, }) => {
5
5
  if (expectedDurationInSeconds === null) {
6
6
  return 2048000;
7
7
  }
@@ -9,11 +9,15 @@ const calculateAReasonableMp4HeaderLength = (expectedDurationInSeconds) => {
9
9
  * we had a video that was 1 hour 40 minutes long and the header ended up being 3.7MB. the header approximately grows linearly to the video length in seconds, but we should reserve enough, like at least 50KB in any case.
10
10
  * it's better to be safe than to fail, so let's add a 30% safety margin
11
11
  */
12
+ // This was however with 30fps, and there can also be 60fps videos, so let's
13
+ // estimate even more conservatively and estimate 60fps
14
+ const assumedFrameRate = expectedFrameRate ?? 60;
15
+ const frameRateMultiplier = assumedFrameRate / 30;
12
16
  // 1h40m = 6000 seconds resulted in 3.7MB header
13
17
  // So bytes per second = 3.7MB / 6000 = ~616 bytes/second
14
18
  const bytesPerSecond = (3.7 * 1024 * 1024) / 6000;
15
- // Add 20% safety margin
16
- const bytesWithSafetyMargin = bytesPerSecond * 1.2;
19
+ // Add 20% safety margin and multiply by frame rate multiplier
20
+ const bytesWithSafetyMargin = bytesPerSecond * 1.2 * frameRateMultiplier;
17
21
  // Calculate based on duration, with minimum 50KB
18
22
  const calculatedBytes = Math.max(50 * 1024, Math.ceil(expectedDurationInSeconds * bytesWithSafetyMargin));
19
23
  return calculatedBytes;
@@ -1,9 +1,10 @@
1
1
  import type { LogLevel } from '@remotion/media-parser';
2
2
  import type { IsoBaseMediaTrackData } from './serialize-track';
3
- export declare const createPaddedMoovAtom: ({ durationInUnits, trackInfo, timescale, expectedDurationInSeconds, logLevel, }: {
3
+ export declare const createPaddedMoovAtom: ({ durationInUnits, trackInfo, timescale, expectedDurationInSeconds, logLevel, expectedFrameRate, }: {
4
4
  durationInUnits: number;
5
5
  trackInfo: IsoBaseMediaTrackData[];
6
6
  timescale: number;
7
7
  expectedDurationInSeconds: number | null;
8
8
  logLevel: LogLevel;
9
+ expectedFrameRate: number | null;
9
10
  }) => Uint8Array<ArrayBufferLike>;
@@ -14,8 +14,11 @@ const primitives_1 = require("./primitives");
14
14
  const serialize_track_1 = require("./serialize-track");
15
15
  const create_meta_1 = require("./udta/create-meta");
16
16
  const create_hdlr_1 = require("./udta/meta/create-hdlr");
17
- const createPaddedMoovAtom = ({ durationInUnits, trackInfo, timescale, expectedDurationInSeconds, logLevel, }) => {
18
- const headerLength = (0, header_length_1.calculateAReasonableMp4HeaderLength)(expectedDurationInSeconds);
17
+ const createPaddedMoovAtom = ({ durationInUnits, trackInfo, timescale, expectedDurationInSeconds, logLevel, expectedFrameRate, }) => {
18
+ const headerLength = (0, header_length_1.calculateAReasonableMp4HeaderLength)({
19
+ expectedDurationInSeconds,
20
+ expectedFrameRate,
21
+ });
19
22
  if (expectedDurationInSeconds !== null) {
20
23
  log_1.Log.verbose(logLevel, `Expecting duration of the video to be ${expectedDurationInSeconds} seconds, allocating ${headerLength} bytes for the MP4 header.`);
21
24
  }
@@ -29,4 +29,5 @@ export type MediaFnGeneratorInput = {
29
29
  filename: string;
30
30
  progressTracker: ProgressTracker;
31
31
  expectedDurationInSeconds: number | null;
32
+ expectedFrameRate: number | null;
32
33
  };
@@ -3031,12 +3031,17 @@ var createUdta = (children) => {
3031
3031
  };
3032
3032
 
3033
3033
  // src/create/iso-base-media/header-length.ts
3034
- var calculateAReasonableMp4HeaderLength = (expectedDurationInSeconds) => {
3034
+ var calculateAReasonableMp4HeaderLength = ({
3035
+ expectedDurationInSeconds,
3036
+ expectedFrameRate
3037
+ }) => {
3035
3038
  if (expectedDurationInSeconds === null) {
3036
3039
  return 2048000;
3037
3040
  }
3041
+ const assumedFrameRate = expectedFrameRate ?? 60;
3042
+ const frameRateMultiplier = assumedFrameRate / 30;
3038
3043
  const bytesPerSecond = 3.7 * 1024 * 1024 / 6000;
3039
- const bytesWithSafetyMargin = bytesPerSecond * 1.2;
3044
+ const bytesWithSafetyMargin = bytesPerSecond * 1.2 * frameRateMultiplier;
3040
3045
  const calculatedBytes = Math.max(50 * 1024, Math.ceil(expectedDurationInSeconds * bytesWithSafetyMargin));
3041
3046
  return calculatedBytes;
3042
3047
  };
@@ -3782,9 +3787,13 @@ var createPaddedMoovAtom = ({
3782
3787
  trackInfo,
3783
3788
  timescale,
3784
3789
  expectedDurationInSeconds,
3785
- logLevel
3790
+ logLevel,
3791
+ expectedFrameRate
3786
3792
  }) => {
3787
- const headerLength = calculateAReasonableMp4HeaderLength(expectedDurationInSeconds);
3793
+ const headerLength = calculateAReasonableMp4HeaderLength({
3794
+ expectedDurationInSeconds,
3795
+ expectedFrameRate
3796
+ });
3788
3797
  if (expectedDurationInSeconds !== null) {
3789
3798
  Log.verbose(logLevel, `Expecting duration of the video to be ${expectedDurationInSeconds} seconds, allocating ${headerLength} bytes for the MP4 header.`);
3790
3799
  } else {
@@ -3828,7 +3837,8 @@ var createIsoBaseMedia = async ({
3828
3837
  logLevel,
3829
3838
  filename,
3830
3839
  progressTracker,
3831
- expectedDurationInSeconds
3840
+ expectedDurationInSeconds,
3841
+ expectedFrameRate
3832
3842
  }) => {
3833
3843
  const header = createIsoBaseMediaFtyp({
3834
3844
  compatibleBrands: ["isom", "iso2", "avc1", "mp42"],
@@ -3861,7 +3871,8 @@ var createIsoBaseMedia = async ({
3861
3871
  }),
3862
3872
  timescale: CONTAINER_TIMESCALE,
3863
3873
  expectedDurationInSeconds,
3864
- logLevel
3874
+ logLevel,
3875
+ expectedFrameRate
3865
3876
  });
3866
3877
  };
3867
3878
  await w.write(getPaddedMoovAtom());
@@ -5060,6 +5071,7 @@ var convertMedia = async function({
5060
5071
  selectM3uStream,
5061
5072
  selectM3uAssociatedPlaylists,
5062
5073
  expectedDurationInSeconds,
5074
+ expectedFrameRate,
5063
5075
  seekingHints,
5064
5076
  ...more
5065
5077
  }) {
@@ -5118,7 +5130,8 @@ var convertMedia = async function({
5118
5130
  },
5119
5131
  logLevel,
5120
5132
  progressTracker,
5121
- expectedDurationInSeconds: expectedDurationInSeconds ?? null
5133
+ expectedDurationInSeconds: expectedDurationInSeconds ?? null,
5134
+ expectedFrameRate: expectedFrameRate ?? null
5122
5135
  });
5123
5136
  const onVideoTrack = makeVideoTrackHandler({
5124
5137
  state,
@@ -5,7 +5,7 @@ const choose_correct_avc1_profile_1 = require("./choose-correct-avc1-profile");
5
5
  const choose_correct_hevc_profile_1 = require("./choose-correct-hevc-profile");
6
6
  const getCodecStringForEncoder = ({ codec, fps, height, width, }) => {
7
7
  if (codec === 'h264') {
8
- return (0, choose_correct_avc1_profile_1.chooseCorrectAvc1Profile)({ fps, height, width });
8
+ return (0, choose_correct_avc1_profile_1.chooseCorrectAvc1Profile)({ fps, height, width }); // return chooseCorrectAvc1Profile({fps, height, width});
9
9
  }
10
10
  if (codec === 'h265') {
11
11
  return (0, choose_correct_hevc_profile_1.chooseCorrectHevcProfile)({ fps, height, width });
@@ -1,2 +1,2 @@
1
1
  import type { ConvertMediaContainer } from './get-available-containers';
2
- export declare const selectContainerCreator: (container: ConvertMediaContainer) => ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, }: import("./create/media-fn").MediaFnGeneratorInput) => Promise<import("./create/media-fn").MediaFn>;
2
+ export declare const selectContainerCreator: (container: ConvertMediaContainer) => ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, expectedFrameRate, }: import("./create/media-fn").MediaFnGeneratorInput) => Promise<import("./create/media-fn").MediaFn>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/webcodecs",
3
- "version": "4.0.293",
3
+ "version": "4.0.295",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -19,8 +19,8 @@
19
19
  "author": "Jonny Burger <jonny@remotion.dev>",
20
20
  "license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)",
21
21
  "dependencies": {
22
- "@remotion/media-parser": "4.0.293",
23
- "@remotion/licensing": "4.0.293"
22
+ "@remotion/media-parser": "4.0.295",
23
+ "@remotion/licensing": "4.0.295"
24
24
  },
25
25
  "peerDependencies": {},
26
26
  "devDependencies": {
@@ -28,8 +28,8 @@
28
28
  "playwright": "1.51.1",
29
29
  "@playwright/test": "1.51.1",
30
30
  "eslint": "9.19.0",
31
- "@remotion/example-videos": "4.0.293",
32
- "@remotion/eslint-config-internal": "4.0.293"
31
+ "@remotion/example-videos": "4.0.295",
32
+ "@remotion/eslint-config-internal": "4.0.295"
33
33
  },
34
34
  "keywords": [],
35
35
  "publishConfig": {