@remotion/webcodecs 4.0.240 → 4.0.242

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/dist/audio-decoder.js +0 -5
  2. package/dist/can-copy-video-track.d.ts +5 -4
  3. package/dist/can-copy-video-track.js +19 -6
  4. package/dist/convert-encoded-chunk.js +2 -0
  5. package/dist/convert-media.d.ts +4 -1
  6. package/dist/convert-media.js +12 -1
  7. package/dist/default-on-video-track-handler.js +3 -2
  8. package/dist/esm/index.mjs +318 -43
  9. package/dist/index.d.ts +11 -1
  10. package/dist/index.js +5 -3
  11. package/dist/io-manager/io-synchronizer.js +4 -4
  12. package/dist/io-manager/make-timeout-promise.d.ts +1 -1
  13. package/dist/io-manager/make-timeout-promise.js +1 -1
  14. package/dist/on-frame.d.ts +3 -1
  15. package/dist/on-frame.js +5 -3
  16. package/dist/on-video-track-handler.d.ts +3 -0
  17. package/dist/on-video-track.d.ts +3 -1
  18. package/dist/on-video-track.js +10 -5
  19. package/dist/resizing/calculate-new-size.d.ts +8 -0
  20. package/dist/resizing/calculate-new-size.js +89 -0
  21. package/dist/resizing/mode.d.ts +24 -0
  22. package/dist/resizing/mode.js +2 -0
  23. package/dist/resizing/resizing.d.ts +13 -0
  24. package/dist/resizing/resizing.js +2 -0
  25. package/dist/resizing.d.ts +13 -0
  26. package/dist/resizing.js +2 -0
  27. package/dist/rotate-and-resize-video-frame.d.ts +9 -0
  28. package/dist/rotate-and-resize-video-frame.js +67 -0
  29. package/dist/rotate-video-frame.d.ts +5 -1
  30. package/dist/rotate-video-frame.js +9 -4
  31. package/dist/rotation.d.ts +11 -3
  32. package/dist/rotation.js +24 -5
  33. package/dist/scaling.d.ts +13 -0
  34. package/dist/scaling.js +2 -0
  35. package/dist/send-telemetry-event.d.ts +4 -0
  36. package/dist/send-telemetry-event.js +22 -0
  37. package/package.json +5 -4
package/dist/index.d.ts CHANGED
@@ -14,12 +14,22 @@ export { getDefaultAudioCodec } from './get-default-audio-codec';
14
14
  export { getDefaultVideoCodec } from './get-default-video-codec';
15
15
  export { AudioOperation, ConvertMediaOnAudioTrackHandler, } from './on-audio-track-handler';
16
16
  export { ConvertMediaOnVideoTrackHandler, VideoOperation, } from './on-video-track-handler';
17
+ export type { ResizeOperation } from './resizing/mode';
17
18
  export { createVideoDecoder, WebCodecsVideoDecoder } from './video-decoder';
18
19
  export { createVideoEncoder, WebCodecsVideoEncoder } from './video-encoder';
19
20
  export declare const WebCodecsInternals: {
20
- rotateVideoFrame: ({ frame, rotation, }: {
21
+ rotateAndResizeVideoFrame: ({ frame, rotation, videoCodec, resizeOperation, }: {
21
22
  frame: VideoFrame;
22
23
  rotation: number;
24
+ videoCodec: import("./get-available-video-codecs").ConvertMediaVideoCodec;
25
+ resizeOperation: import("./resizing/mode").ResizeOperation | null;
23
26
  }) => VideoFrame;
24
27
  normalizeVideoRotation: (rotation: number) => number;
28
+ calculateNewDimensionsFromDimensions: ({ width, height, rotation, resizeOperation, videoCodec, }: {
29
+ width: number;
30
+ height: number;
31
+ rotation: number;
32
+ resizeOperation: import("./resizing/mode").ResizeOperation | null;
33
+ videoCodec: import("./get-available-video-codecs").ConvertMediaVideoCodec | import("@remotion/media-parser").MediaParserVideoCodec;
34
+ }) => import("./resizing/mode").Dimensions;
25
35
  };
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WebCodecsInternals = exports.createVideoEncoder = exports.createVideoDecoder = exports.getDefaultVideoCodec = exports.getDefaultAudioCodec = exports.getAvailableVideoCodecs = exports.getAvailableContainers = exports.getAvailableAudioCodecs = exports.defaultOnVideoTrackHandler = exports.defaultOnAudioTrackHandler = exports.convertMedia = exports.canReencodeVideoTrack = exports.canReencodeAudioTrack = exports.canCopyVideoTrack = exports.canCopyAudioTrack = exports.createAudioEncoder = exports.createAudioDecoder = void 0;
4
- const rotate_video_frame_1 = require("./rotate-video-frame");
4
+ const rotate_and_resize_video_frame_1 = require("./rotate-and-resize-video-frame");
5
+ const rotation_1 = require("./rotation");
5
6
  const set_remotion_imported_1 = require("./set-remotion-imported");
6
7
  var audio_decoder_1 = require("./audio-decoder");
7
8
  Object.defineProperty(exports, "createAudioDecoder", { enumerable: true, get: function () { return audio_decoder_1.createAudioDecoder; } });
@@ -36,7 +37,8 @@ Object.defineProperty(exports, "createVideoDecoder", { enumerable: true, get: fu
36
37
  var video_encoder_1 = require("./video-encoder");
37
38
  Object.defineProperty(exports, "createVideoEncoder", { enumerable: true, get: function () { return video_encoder_1.createVideoEncoder; } });
38
39
  exports.WebCodecsInternals = {
39
- rotateVideoFrame: rotate_video_frame_1.rotateVideoFrame,
40
- normalizeVideoRotation: rotate_video_frame_1.normalizeVideoRotation,
40
+ rotateAndResizeVideoFrame: rotate_and_resize_video_frame_1.rotateAndResizeVideoFrame,
41
+ normalizeVideoRotation: rotate_and_resize_video_frame_1.normalizeVideoRotation,
42
+ calculateNewDimensionsFromDimensions: rotation_1.calculateNewDimensionsFromRotateAndScale,
41
43
  };
42
44
  (0, set_remotion_imported_1.setRemotionImported)();
@@ -69,14 +69,14 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
69
69
  return promise;
70
70
  };
71
71
  const waitFor = async ({ unprocessed, unemitted, minimumProgress, signal, }) => {
72
- const { timeoutPromise, clear } = (0, make_timeout_promise_1.makeTimeoutPromise)([
73
- `Waited too long for ${label}:`,
72
+ const { timeoutPromise, clear } = (0, make_timeout_promise_1.makeTimeoutPromise)(() => [
73
+ `Waited too long for ${label} to finish:`,
74
74
  `${getUnemittedItems()} unemitted items`,
75
- `${getUnprocessed()} unprocessed items`,
76
- `minimum progress ${minimumProgress}`,
75
+ `${getUnprocessed()} unprocessed items: ${JSON.stringify(_unprocessed)}`,
77
76
  `smallest progress: ${progress.getSmallestProgress()}`,
78
77
  `inputs: ${JSON.stringify(inputs)}`,
79
78
  `last output: ${lastOutput}`,
79
+ `wanted: ${unemitted} unemitted items, ${unprocessed} unprocessed items, minimum progress ${minimumProgress}`,
80
80
  ].join('\n'), 10000);
81
81
  signal.addEventListener('abort', clear);
82
82
  await Promise.race([
@@ -1,4 +1,4 @@
1
- export declare const makeTimeoutPromise: (label: string, ms: number) => {
1
+ export declare const makeTimeoutPromise: (label: () => string, ms: number) => {
2
2
  timeoutPromise: Promise<void>;
3
3
  clear: () => void;
4
4
  };
@@ -5,7 +5,7 @@ const media_parser_1 = require("@remotion/media-parser");
5
5
  const makeTimeoutPromise = (label, ms) => {
6
6
  const { promise, reject, resolve } = media_parser_1.MediaParserInternals.withResolvers();
7
7
  const timeout = setTimeout(() => {
8
- reject(new Error(`${label} (timed out after ${ms}ms)`));
8
+ reject(new Error(`${label()} (timed out after ${ms}ms)`));
9
9
  }, ms);
10
10
  return {
11
11
  timeoutPromise: promise,
@@ -1,12 +1,14 @@
1
1
  import type { VideoTrack } from '@remotion/media-parser';
2
2
  import type { ConvertMediaOnVideoFrame } from './convert-media';
3
3
  import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
4
+ import type { ResizeOperation } from './resizing/mode';
4
5
  import type { WebCodecsVideoEncoder } from './video-encoder';
5
- export declare const onFrame: ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, }: {
6
+ export declare const onFrame: ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, resizeOperation, }: {
6
7
  frame: VideoFrame;
7
8
  onVideoFrame: ConvertMediaOnVideoFrame | null;
8
9
  videoEncoder: WebCodecsVideoEncoder;
9
10
  track: VideoTrack;
10
11
  outputCodec: ConvertMediaVideoCodec;
11
12
  rotation: number;
13
+ resizeOperation: ResizeOperation | null;
12
14
  }) => Promise<void>;
package/dist/on-frame.js CHANGED
@@ -3,12 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.onFrame = void 0;
4
4
  const browser_quirks_1 = require("./browser-quirks");
5
5
  const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
6
- const rotate_video_frame_1 = require("./rotate-video-frame");
7
- const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, }) => {
6
+ const rotate_and_resize_video_frame_1 = require("./rotate-and-resize-video-frame");
7
+ const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, resizeOperation, }) => {
8
8
  var _a, _b;
9
- const rotated = (0, rotate_video_frame_1.rotateVideoFrame)({
9
+ const rotated = (0, rotate_and_resize_video_frame_1.rotateAndResizeVideoFrame)({
10
10
  rotation,
11
11
  frame: unrotatedFrame,
12
+ resizeOperation,
13
+ videoCodec: outputCodec,
12
14
  });
13
15
  if (unrotatedFrame !== rotated) {
14
16
  unrotatedFrame.close();
@@ -1,10 +1,12 @@
1
1
  import type { LogLevel, ParseMediaContainer, VideoTrack } from '@remotion/media-parser';
2
2
  import type { ConvertMediaContainer } from './get-available-containers';
3
3
  import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
4
+ import type { ResizeOperation } from './resizing/mode';
4
5
  export type VideoOperation = {
5
6
  type: 'reencode';
6
7
  videoCodec: ConvertMediaVideoCodec;
7
8
  rotate?: number;
9
+ resize?: ResizeOperation | null;
8
10
  } | {
9
11
  type: 'copy';
10
12
  } | {
@@ -18,6 +20,7 @@ export type ConvertMediaOnVideoTrackHandler = (options: {
18
20
  logLevel: LogLevel;
19
21
  outputContainer: ConvertMediaContainer;
20
22
  rotate: number;
23
+ resizeOperation: ResizeOperation | null;
21
24
  inputContainer: ParseMediaContainer;
22
25
  canCopyTrack: boolean;
23
26
  }) => VideoOperation | Promise<VideoOperation>;
@@ -4,8 +4,9 @@ import Error from './error-cause';
4
4
  import type { ConvertMediaContainer } from './get-available-containers';
5
5
  import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
6
6
  import type { ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
7
+ import type { ResizeOperation } from './resizing/mode';
7
8
  import type { ConvertMediaProgressFn } from './throttled-state-update';
8
- export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, }: {
9
+ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, resizeOperation, }: {
9
10
  state: MediaFn;
10
11
  onVideoFrame: null | ConvertMediaOnVideoFrame;
11
12
  onMediaStateUpdate: null | ConvertMediaProgressFn;
@@ -17,4 +18,5 @@ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaState
17
18
  outputContainer: ConvertMediaContainer;
18
19
  rotate: number;
19
20
  progress: ProgressTracker;
21
+ resizeOperation: ResizeOperation | null;
20
22
  }) => OnVideoTrack;
@@ -17,17 +17,17 @@ const video_decoder_1 = require("./video-decoder");
17
17
  const video_decoder_config_1 = require("./video-decoder-config");
18
18
  const video_encoder_1 = require("./video-encoder");
19
19
  const video_encoder_config_1 = require("./video-encoder-config");
20
- const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, }) => async ({ track, container: inputContainer }) => {
21
- var _a;
20
+ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, resizeOperation, }) => async ({ track, container: inputContainer }) => {
21
+ var _a, _b;
22
22
  if (controller.signal.aborted) {
23
23
  throw new error_cause_1.default('Aborted');
24
24
  }
25
25
  const canCopyTrack = (0, can_copy_video_track_1.canCopyVideoTrack)({
26
- inputCodec: track.codecWithoutConfig,
27
26
  inputContainer,
28
- inputRotation: track.rotation,
29
27
  outputContainer,
30
28
  rotationToApply: rotate,
29
+ inputTrack: track,
30
+ resizeOperation,
31
31
  });
32
32
  const videoOperation = await (onVideoTrack !== null && onVideoTrack !== void 0 ? onVideoTrack : default_on_video_track_handler_1.defaultOnVideoTrackHandler)({
33
33
  track,
@@ -37,6 +37,7 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
37
37
  rotate,
38
38
  inputContainer,
39
39
  canCopyTrack,
40
+ resizeOperation,
40
41
  });
41
42
  if (videoOperation.type === 'drop') {
42
43
  return null;
@@ -74,10 +75,12 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
74
75
  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"`);
75
76
  }
76
77
  const rotation = ((_a = videoOperation.rotate) !== null && _a !== void 0 ? _a : rotate) - track.rotation;
77
- const { height: newHeight, width: newWidth } = (0, rotation_1.calculateNewDimensionsFromDimensions)({
78
+ const { height: newHeight, width: newWidth } = (0, rotation_1.calculateNewDimensionsFromRotateAndScale)({
78
79
  width: track.codedWidth,
79
80
  height: track.codedHeight,
80
81
  rotation,
82
+ videoCodec: videoOperation.videoCodec,
83
+ resizeOperation: (_b = videoOperation.resize) !== null && _b !== void 0 ? _b : null,
81
84
  });
82
85
  const videoEncoderConfig = await (0, video_encoder_config_1.getVideoEncoderConfig)({
83
86
  codec: videoOperation.videoCodec,
@@ -134,6 +137,7 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
134
137
  const videoDecoder = (0, video_decoder_1.createVideoDecoder)({
135
138
  config: videoDecoderConfig,
136
139
  onFrame: async (frame) => {
140
+ var _a;
137
141
  await (0, on_frame_1.onFrame)({
138
142
  frame,
139
143
  track,
@@ -141,6 +145,7 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
141
145
  onVideoFrame,
142
146
  outputCodec: videoOperation.videoCodec,
143
147
  rotation,
148
+ resizeOperation: (_a = videoOperation.resize) !== null && _a !== void 0 ? _a : null,
144
149
  });
145
150
  },
146
151
  onError: (err) => {
@@ -0,0 +1,8 @@
1
+ import type { MediaParserVideoCodec } from '@remotion/media-parser';
2
+ import type { ConvertMediaVideoCodec } from '../get-available-video-codecs';
3
+ import type { Dimensions, ResizeOperation } from './mode';
4
+ export declare const calculateNewSizeAfterResizing: ({ dimensions, resizeOperation, videoCodec, }: {
5
+ dimensions: Dimensions;
6
+ resizeOperation: ResizeOperation | null;
7
+ videoCodec: ConvertMediaVideoCodec | MediaParserVideoCodec;
8
+ }) => Dimensions;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateNewSizeAfterResizing = void 0;
4
+ const ensureMultipleOfTwo = ({ dimensions, needsToBeMultipleOfTwo, }) => {
5
+ if (!needsToBeMultipleOfTwo) {
6
+ return dimensions;
7
+ }
8
+ return {
9
+ width: Math.floor(dimensions.width / 2) * 2,
10
+ height: Math.floor(dimensions.height / 2) * 2,
11
+ };
12
+ };
13
+ const calculateNewSizeAfterResizing = ({ dimensions, resizeOperation, videoCodec, }) => {
14
+ const needsToBeMultipleOfTwo = videoCodec === 'h264';
15
+ if (resizeOperation === null) {
16
+ return ensureMultipleOfTwo({
17
+ dimensions,
18
+ needsToBeMultipleOfTwo,
19
+ });
20
+ }
21
+ if (resizeOperation.mode === 'width') {
22
+ return ensureMultipleOfTwo({
23
+ dimensions: {
24
+ width: resizeOperation.width,
25
+ height: Math.round((resizeOperation.width / dimensions.width) * dimensions.height),
26
+ },
27
+ needsToBeMultipleOfTwo,
28
+ });
29
+ }
30
+ if (resizeOperation.mode === 'height') {
31
+ return ensureMultipleOfTwo({
32
+ dimensions: {
33
+ width: Math.round((resizeOperation.height / dimensions.height) * dimensions.width),
34
+ height: resizeOperation.height,
35
+ },
36
+ needsToBeMultipleOfTwo,
37
+ });
38
+ }
39
+ if (resizeOperation.mode === 'max-height') {
40
+ const height = Math.min(dimensions.height, resizeOperation.maxHeight);
41
+ return ensureMultipleOfTwo({
42
+ dimensions: {
43
+ width: Math.round((height / dimensions.height) * dimensions.width),
44
+ height,
45
+ },
46
+ needsToBeMultipleOfTwo,
47
+ });
48
+ }
49
+ if (resizeOperation.mode === 'max-width') {
50
+ const width = Math.min(dimensions.width, resizeOperation.maxWidth);
51
+ return ensureMultipleOfTwo({
52
+ dimensions: {
53
+ width,
54
+ height: Math.round((width / dimensions.width) * dimensions.height),
55
+ },
56
+ needsToBeMultipleOfTwo,
57
+ });
58
+ }
59
+ if (resizeOperation.mode === 'max-height-width') {
60
+ const height = Math.min(dimensions.height, resizeOperation.maxHeight);
61
+ const width = Math.min(dimensions.width, resizeOperation.maxWidth);
62
+ const scale = Math.min(width / dimensions.width, height / dimensions.height);
63
+ const actualWidth = Math.round(dimensions.width * scale);
64
+ const actualHeight = Math.round(dimensions.height * scale);
65
+ return ensureMultipleOfTwo({
66
+ dimensions: {
67
+ height: actualHeight,
68
+ width: actualWidth,
69
+ },
70
+ needsToBeMultipleOfTwo,
71
+ });
72
+ }
73
+ if (resizeOperation.mode === 'scale') {
74
+ if (resizeOperation.scale <= 0) {
75
+ throw new Error('Scale must be greater than 0');
76
+ }
77
+ const width = Math.round(dimensions.width * resizeOperation.scale);
78
+ const height = Math.round(dimensions.height * resizeOperation.scale);
79
+ return ensureMultipleOfTwo({
80
+ dimensions: {
81
+ width,
82
+ height,
83
+ },
84
+ needsToBeMultipleOfTwo,
85
+ });
86
+ }
87
+ throw new Error('Invalid resizing mode ' + resizeOperation);
88
+ };
89
+ exports.calculateNewSizeAfterResizing = calculateNewSizeAfterResizing;
@@ -0,0 +1,24 @@
1
+ export type Dimensions = {
2
+ width: number;
3
+ height: number;
4
+ };
5
+ export type ResizeOperation = {
6
+ mode: 'width';
7
+ width: number;
8
+ } | {
9
+ mode: 'height';
10
+ height: number;
11
+ } | {
12
+ mode: 'max-height';
13
+ maxHeight: number;
14
+ } | {
15
+ mode: 'max-width';
16
+ maxWidth: number;
17
+ } | {
18
+ mode: 'max-height-width';
19
+ maxHeight: number;
20
+ maxWidth: number;
21
+ } | {
22
+ mode: 'scale';
23
+ scale: number;
24
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ export type ResizingMode = {
2
+ type: 'width';
3
+ width: number;
4
+ } | {
5
+ type: 'height';
6
+ height: number;
7
+ } | {
8
+ type: 'max-height';
9
+ height: number;
10
+ } | {
11
+ type: 'max-width';
12
+ width: number;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ export type ResizingMode = {
2
+ type: 'width';
3
+ width: number;
4
+ } | {
5
+ type: 'height';
6
+ height: number;
7
+ } | {
8
+ type: 'max-height';
9
+ height: number;
10
+ } | {
11
+ type: 'max-width';
12
+ width: number;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
2
+ import type { ResizeOperation } from './resizing/mode';
3
+ export declare const normalizeVideoRotation: (rotation: number) => number;
4
+ export declare const rotateAndResizeVideoFrame: ({ frame, rotation, videoCodec, resizeOperation, }: {
5
+ frame: VideoFrame;
6
+ rotation: number;
7
+ videoCodec: ConvertMediaVideoCodec;
8
+ resizeOperation: ResizeOperation | null;
9
+ }) => VideoFrame;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rotateAndResizeVideoFrame = exports.normalizeVideoRotation = void 0;
4
+ const rotation_1 = require("./rotation");
5
+ const normalizeVideoRotation = (rotation) => {
6
+ return ((rotation % 360) + 360) % 360;
7
+ };
8
+ exports.normalizeVideoRotation = normalizeVideoRotation;
9
+ const rotateAndResizeVideoFrame = ({ frame, rotation, videoCodec, resizeOperation, }) => {
10
+ var _a;
11
+ const normalized = ((rotation % 360) + 360) % 360;
12
+ // No resize, no rotation
13
+ if (normalized === 0 && resizeOperation === null) {
14
+ return frame;
15
+ }
16
+ if (normalized % 90 !== 0) {
17
+ throw new Error('Only 90 degree rotations are supported');
18
+ }
19
+ const { height, width } = (0, rotation_1.calculateNewDimensionsFromRotateAndScale)({
20
+ height: frame.displayHeight,
21
+ width: frame.displayWidth,
22
+ rotation,
23
+ videoCodec,
24
+ resizeOperation,
25
+ });
26
+ // No rotation, and resize turned out to be same dimensions
27
+ if (normalized === 0 &&
28
+ height === frame.displayHeight &&
29
+ width === frame.displayWidth) {
30
+ return frame;
31
+ }
32
+ const canvas = new OffscreenCanvas(width, height);
33
+ const ctx = canvas.getContext('2d');
34
+ if (!ctx) {
35
+ throw new Error('Could not get 2d context');
36
+ }
37
+ canvas.width = width;
38
+ canvas.height = height;
39
+ if (normalized === 90) {
40
+ ctx.translate(width, 0);
41
+ }
42
+ else if (normalized === 180) {
43
+ ctx.translate(width, height);
44
+ }
45
+ else if (normalized === 270) {
46
+ ctx.translate(0, height);
47
+ }
48
+ if (normalized !== 0) {
49
+ ctx.rotate(normalized * (Math.PI / 180));
50
+ }
51
+ if (frame.displayHeight !== height || frame.displayWidth !== width) {
52
+ const dimensionsAfterRotate = (0, rotation_1.calculateNewDimensionsFromRotate)({
53
+ height: frame.displayHeight,
54
+ rotation,
55
+ width: frame.displayWidth,
56
+ });
57
+ ctx.scale(width / dimensionsAfterRotate.width, height / dimensionsAfterRotate.height);
58
+ }
59
+ ctx.drawImage(frame, 0, 0);
60
+ return new VideoFrame(canvas, {
61
+ displayHeight: height,
62
+ displayWidth: width,
63
+ duration: (_a = frame.duration) !== null && _a !== void 0 ? _a : undefined,
64
+ timestamp: frame.timestamp,
65
+ });
66
+ };
67
+ exports.rotateAndResizeVideoFrame = rotateAndResizeVideoFrame;
@@ -1,5 +1,9 @@
1
+ import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
2
+ import type { ResizingMode } from './resizing/mode';
1
3
  export declare const normalizeVideoRotation: (rotation: number) => number;
2
- export declare const rotateVideoFrame: ({ frame, rotation, }: {
4
+ export declare const rotateAndResizeVideoFrame: ({ frame, rotation, videoCodec, resizingMode, }: {
3
5
  frame: VideoFrame;
4
6
  rotation: number;
7
+ videoCodec: ConvertMediaVideoCodec;
8
+ resizingMode: ResizingMode | null;
5
9
  }) => VideoFrame;
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.rotateVideoFrame = exports.normalizeVideoRotation = void 0;
3
+ exports.rotateAndResizeVideoFrame = exports.normalizeVideoRotation = void 0;
4
4
  const rotation_1 = require("./rotation");
5
5
  const normalizeVideoRotation = (rotation) => {
6
6
  return ((rotation % 360) + 360) % 360;
7
7
  };
8
8
  exports.normalizeVideoRotation = normalizeVideoRotation;
9
- const rotateVideoFrame = ({ frame, rotation, }) => {
9
+ const rotateAndResizeVideoFrame = ({ frame, rotation, videoCodec, resizingMode, }) => {
10
10
  var _a;
11
11
  const normalized = ((rotation % 360) + 360) % 360;
12
- if (normalized % 360 === 0) {
12
+ if (normalized % 360 === 0 && resizingMode === null) {
13
13
  return frame;
14
14
  }
15
15
  if (normalized % 90 !== 0) {
@@ -19,6 +19,8 @@ const rotateVideoFrame = ({ frame, rotation, }) => {
19
19
  height: frame.displayHeight,
20
20
  width: frame.displayWidth,
21
21
  rotation,
22
+ videoCodec,
23
+ resizingMode,
22
24
  });
23
25
  const canvas = new OffscreenCanvas(width, height);
24
26
  const ctx = canvas.getContext('2d');
@@ -37,6 +39,9 @@ const rotateVideoFrame = ({ frame, rotation, }) => {
37
39
  ctx.translate(0, height);
38
40
  }
39
41
  ctx.rotate(normalized * (Math.PI / 180));
42
+ if (frame.displayHeight !== height || frame.displayWidth !== width) {
43
+ ctx.scale(width / frame.displayWidth, height / frame.displayHeight);
44
+ }
40
45
  ctx.drawImage(frame, 0, 0);
41
46
  return new VideoFrame(canvas, {
42
47
  displayHeight: height,
@@ -45,4 +50,4 @@ const rotateVideoFrame = ({ frame, rotation, }) => {
45
50
  timestamp: frame.timestamp,
46
51
  });
47
52
  };
48
- exports.rotateVideoFrame = rotateVideoFrame;
53
+ exports.rotateAndResizeVideoFrame = rotateAndResizeVideoFrame;
@@ -1,8 +1,16 @@
1
- export declare const calculateNewDimensionsFromDimensions: ({ width, height, rotation, }: {
2
- width: number;
3
- height: number;
1
+ import type { Dimensions, MediaParserVideoCodec } from '@remotion/media-parser';
2
+ import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
3
+ import type { ResizeOperation } from './resizing/mode';
4
+ export declare const calculateNewDimensionsFromRotate: ({ height, width, rotation, }: Dimensions & {
4
5
  rotation: number;
5
6
  }) => {
6
7
  height: number;
7
8
  width: number;
8
9
  };
10
+ export declare const calculateNewDimensionsFromRotateAndScale: ({ width, height, rotation, resizeOperation, videoCodec, }: {
11
+ width: number;
12
+ height: number;
13
+ rotation: number;
14
+ resizeOperation: ResizeOperation | null;
15
+ videoCodec: ConvertMediaVideoCodec | MediaParserVideoCodec;
16
+ }) => import("./resizing/mode").Dimensions;
package/dist/rotation.js CHANGED
@@ -1,10 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateNewDimensionsFromDimensions = void 0;
4
- const calculateNewDimensionsFromDimensions = ({ width, height, rotation, }) => {
5
- const switchDimensions = rotation % 90 === 0 && rotation % 180 !== 0;
3
+ exports.calculateNewDimensionsFromRotateAndScale = exports.calculateNewDimensionsFromRotate = void 0;
4
+ const calculate_new_size_1 = require("./resizing/calculate-new-size");
5
+ const rotate_and_resize_video_frame_1 = require("./rotate-and-resize-video-frame");
6
+ const calculateNewDimensionsFromRotate = ({ height, width, rotation, }) => {
7
+ const normalized = (0, rotate_and_resize_video_frame_1.normalizeVideoRotation)(rotation);
8
+ const switchDimensions = normalized % 90 === 0 && normalized % 180 !== 0;
6
9
  const newHeight = switchDimensions ? width : height;
7
10
  const newWidth = switchDimensions ? height : width;
8
- return { height: newHeight, width: newWidth };
11
+ return {
12
+ height: newHeight,
13
+ width: newWidth,
14
+ };
9
15
  };
10
- exports.calculateNewDimensionsFromDimensions = calculateNewDimensionsFromDimensions;
16
+ exports.calculateNewDimensionsFromRotate = calculateNewDimensionsFromRotate;
17
+ const calculateNewDimensionsFromRotateAndScale = ({ width, height, rotation, resizeOperation, videoCodec, }) => {
18
+ const { height: newHeight, width: newWidth } = (0, exports.calculateNewDimensionsFromRotate)({
19
+ height,
20
+ rotation,
21
+ width,
22
+ });
23
+ return (0, calculate_new_size_1.calculateNewSizeAfterResizing)({
24
+ dimensions: { height: newHeight, width: newWidth },
25
+ resizeOperation,
26
+ videoCodec,
27
+ });
28
+ };
29
+ exports.calculateNewDimensionsFromRotateAndScale = calculateNewDimensionsFromRotateAndScale;
@@ -0,0 +1,13 @@
1
+ export type ScalingMode = {
2
+ type: 'width';
3
+ width: number;
4
+ } | {
5
+ type: 'height';
6
+ height: number;
7
+ } | {
8
+ type: 'max-height';
9
+ height: number;
10
+ } | {
11
+ type: 'max-width';
12
+ width: number;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ export declare const sendUsageEvent: ({ apiKey, succeeded, }: {
2
+ apiKey: string | null;
3
+ succeeded: boolean;
4
+ }) => Promise<void>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendUsageEvent = void 0;
4
+ const licensing_1 = require("@remotion/licensing");
5
+ const sendUsageEvent = async ({ apiKey, succeeded, }) => {
6
+ var _a;
7
+ const host = typeof window === 'undefined'
8
+ ? null
9
+ : typeof window.location === 'undefined'
10
+ ? null
11
+ : ((_a = window.location.origin) !== null && _a !== void 0 ? _a : null);
12
+ if (host === null) {
13
+ return;
14
+ }
15
+ await (0, licensing_1.registerUsageEvent)({
16
+ apiKey,
17
+ event: 'webcodec-conversion',
18
+ host,
19
+ succeeded,
20
+ });
21
+ };
22
+ exports.sendUsageEvent = sendUsageEvent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/webcodecs",
3
- "version": "4.0.240",
3
+ "version": "4.0.242",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -17,14 +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.240"
20
+ "@remotion/licensing": "4.0.242",
21
+ "@remotion/media-parser": "4.0.242"
21
22
  },
22
23
  "peerDependencies": {},
23
24
  "devDependencies": {
24
25
  "@types/dom-webcodecs": "0.1.11",
25
26
  "eslint": "9.14.0",
26
- "@remotion/example-videos": "4.0.240",
27
- "@remotion/eslint-config-internal": "4.0.240"
27
+ "@remotion/example-videos": "4.0.242",
28
+ "@remotion/eslint-config-internal": "4.0.242"
28
29
  },
29
30
  "keywords": [],
30
31
  "publishConfig": {