@remotion/webcodecs 4.0.229 → 4.0.231

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 (72) hide show
  1. package/README.md +12 -1
  2. package/dist/arraybuffer-to-uint8-array.d.ts +1 -0
  3. package/dist/arraybuffer-to-uint8-array.js +7 -0
  4. package/dist/audio-decoder.d.ts +2 -2
  5. package/dist/audio-encoder-config.js +15 -2
  6. package/dist/audio-encoder.d.ts +2 -1
  7. package/dist/audio-encoder.js +17 -5
  8. package/dist/browser-quirks.d.ts +2 -0
  9. package/dist/browser-quirks.js +11 -0
  10. package/dist/can-copy-audio-track.d.ts +2 -4
  11. package/dist/can-copy-audio-track.js +7 -4
  12. package/dist/can-copy-video-track.d.ts +2 -4
  13. package/dist/can-copy-video-track.js +6 -6
  14. package/dist/can-reencode-audio-track.js +1 -6
  15. package/dist/can-reencode-video-track.js +1 -0
  16. package/dist/choose-correct-avc1-profile.d.ts +5 -0
  17. package/dist/choose-correct-avc1-profile.js +54 -0
  18. package/dist/codec-id.d.ts +7 -4
  19. package/dist/codec-id.js +28 -5
  20. package/dist/convert-encoded-chunk.d.ts +2 -1
  21. package/dist/convert-encoded-chunk.js +25 -2
  22. package/dist/convert-media.d.ts +13 -12
  23. package/dist/convert-media.js +62 -46
  24. package/dist/convert-to-correct-videoframe.d.ts +9 -0
  25. package/dist/convert-to-correct-videoframe.js +28 -0
  26. package/dist/default-on-audio-track-handler.d.ts +2 -0
  27. package/dist/default-on-audio-track-handler.js +36 -0
  28. package/dist/default-on-video-track-handler.d.ts +2 -0
  29. package/dist/default-on-video-track-handler.js +29 -0
  30. package/dist/esm/index.mjs +493 -174
  31. package/dist/generate-output-filename.d.ts +2 -0
  32. package/dist/generate-output-filename.js +14 -0
  33. package/dist/get-default-audio-codec.d.ts +4 -0
  34. package/dist/get-default-audio-codec.js +13 -0
  35. package/dist/get-default-video-codec.d.ts +4 -0
  36. package/dist/get-default-video-codec.js +10 -0
  37. package/dist/index.d.ts +12 -8
  38. package/dist/index.js +12 -1
  39. package/dist/io-manager/io-synchronizer.js +2 -2
  40. package/dist/{resolve-audio-action.d.ts → on-audio-track-handler.d.ts} +5 -5
  41. package/dist/on-audio-track-handler.js +2 -0
  42. package/dist/on-audio-track.d.ts +7 -8
  43. package/dist/on-audio-track.js +55 -16
  44. package/dist/on-frame.d.ts +4 -4
  45. package/dist/on-frame.js +15 -9
  46. package/dist/{resolve-video-action.d.ts → on-video-track-handler.d.ts} +5 -5
  47. package/dist/on-video-track-handler.js +2 -0
  48. package/dist/on-video-track.d.ts +8 -8
  49. package/dist/on-video-track.js +49 -15
  50. package/dist/set-remotion-imported.d.ts +6 -0
  51. package/dist/set-remotion-imported.js +25 -0
  52. package/dist/throttled-state-update.d.ts +13 -0
  53. package/dist/throttled-state-update.js +49 -0
  54. package/dist/video-decoder.d.ts +2 -2
  55. package/dist/video-decoder.js +5 -0
  56. package/dist/video-encoder-config.d.ts +2 -1
  57. package/dist/video-encoder-config.js +9 -2
  58. package/dist/video-encoder.d.ts +4 -2
  59. package/dist/video-encoder.js +12 -10
  60. package/package.json +4 -3
  61. package/dist/can-reencode-audio.d.ts +0 -7
  62. package/dist/can-reencode-audio.js +0 -21
  63. package/dist/can-reencode-video.d.ts +0 -6
  64. package/dist/can-reencode-video.js +0 -15
  65. package/dist/event-emitter.d.ts +0 -25
  66. package/dist/event-emitter.js +0 -23
  67. package/dist/polyfill-encoded-audio-chunk.d.ts +0 -3
  68. package/dist/polyfill-encoded-audio-chunk.js +0 -5
  69. package/dist/resolve-audio-action.js +0 -32
  70. package/dist/resolve-video-action.js +0 -26
  71. package/dist/wait-until-return.d.ts +0 -4
  72. package/dist/wait-until-return.js +0 -14
@@ -0,0 +1,2 @@
1
+ import type { ConvertMediaContainer } from './codec-id';
2
+ export declare const generateOutputFilename: (source: string | Blob, container: ConvertMediaContainer) => string;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateOutputFilename = void 0;
4
+ const generateOutputFilename = (source, container) => {
5
+ const filename = typeof source === 'string'
6
+ ? source
7
+ : source instanceof File
8
+ ? source.name
9
+ : 'converted';
10
+ const behindSlash = filename.split('/').pop();
11
+ const withoutExtension = behindSlash.split('.').slice(0, -1).join('.');
12
+ return `${withoutExtension}.${container}`;
13
+ };
14
+ exports.generateOutputFilename = generateOutputFilename;
@@ -0,0 +1,4 @@
1
+ import type { ConvertMediaAudioCodec, ConvertMediaContainer } from './codec-id';
2
+ export declare const getDefaultAudioCodec: ({ container, }: {
3
+ container: ConvertMediaContainer;
4
+ }) => ConvertMediaAudioCodec;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDefaultAudioCodec = void 0;
4
+ const getDefaultAudioCodec = ({ container, }) => {
5
+ if (container === 'webm') {
6
+ return 'opus';
7
+ }
8
+ if (container === 'mp4') {
9
+ return 'aac';
10
+ }
11
+ throw new Error(`Unhandled container: ${container}`);
12
+ };
13
+ exports.getDefaultAudioCodec = getDefaultAudioCodec;
@@ -0,0 +1,4 @@
1
+ import type { ConvertMediaContainer, ConvertMediaVideoCodec } from './codec-id';
2
+ export declare const getDefaultVideoCodec: ({ container, }: {
3
+ container: ConvertMediaContainer;
4
+ }) => ConvertMediaVideoCodec;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDefaultVideoCodec = void 0;
4
+ const getDefaultVideoCodec = ({ container, }) => {
5
+ if (container === 'webm') {
6
+ return 'vp8';
7
+ }
8
+ throw new Error(`Unhandled container: ${container} satisfies never`);
9
+ };
10
+ exports.getDefaultVideoCodec = getDefaultVideoCodec;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,16 @@
1
- export { WebCodecsAudioDecoder, createAudioDecoder } from './audio-decoder';
2
- export { WebCodecsAudioEncoder, createAudioEncoder } from './audio-encoder';
1
+ export { createAudioDecoder, WebCodecsAudioDecoder } from './audio-decoder';
2
+ export { createAudioEncoder, WebCodecsAudioEncoder } from './audio-encoder';
3
3
  export { canCopyAudioTrack } from './can-copy-audio-track';
4
4
  export { canCopyVideoTrack } from './can-copy-video-track';
5
5
  export { canReencodeAudioTrack } from './can-reencode-audio-track';
6
6
  export { canReencodeVideoTrack } from './can-reencode-video-track';
7
- export { ConvertMediaAudioCodec, ConvertMediaVideoCodec, getAvailableAudioCodecs, getAvailableVideoCodecs, } from './codec-id';
8
- export { ConvertMediaContainer, ConvertMediaOnMediaStateUpdate, ConvertMediaOnVideoFrame, ConvertMediaResult, ConvertMediaState, convertMedia, } from './convert-media';
9
- export { AudioOperation, ResolveAudioActionFn } from './resolve-audio-action';
10
- export { ResolveVideoActionFn, VideoOperation } from './resolve-video-action';
11
- export { WebCodecsVideoDecoder, createVideoDecoder } from './video-decoder';
12
- export { WebCodecsVideoEncoder, createVideoEncoder } from './video-encoder';
7
+ export { ConvertMediaAudioCodec, ConvertMediaContainer, ConvertMediaVideoCodec, getAvailableAudioCodecs, getAvailableContainers, getAvailableVideoCodecs, } from './codec-id';
8
+ export { convertMedia, ConvertMediaOnProgress, ConvertMediaOnVideoFrame, ConvertMediaProgress, ConvertMediaResult, } from './convert-media';
9
+ export { defaultOnAudioTrackHandler } from './default-on-audio-track-handler';
10
+ export { defaultOnVideoTrackHandler } from './default-on-video-track-handler';
11
+ export { getDefaultAudioCodec } from './get-default-audio-codec';
12
+ export { getDefaultVideoCodec } from './get-default-video-codec';
13
+ export { AudioOperation, ConvertMediaOnAudioTrackHandler, } from './on-audio-track-handler';
14
+ export { ConvertMediaOnVideoTrackHandler, VideoOperation, } from './on-video-track-handler';
15
+ export { createVideoDecoder, WebCodecsVideoDecoder } from './video-decoder';
16
+ export { createVideoEncoder, WebCodecsVideoEncoder } from './video-encoder';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createVideoEncoder = exports.createVideoDecoder = exports.convertMedia = exports.getAvailableVideoCodecs = exports.getAvailableAudioCodecs = exports.canReencodeVideoTrack = exports.canReencodeAudioTrack = exports.canCopyVideoTrack = exports.canCopyAudioTrack = exports.createAudioEncoder = exports.createAudioDecoder = void 0;
3
+ exports.createVideoEncoder = exports.createVideoDecoder = exports.getDefaultVideoCodec = exports.getDefaultAudioCodec = exports.defaultOnVideoTrackHandler = exports.defaultOnAudioTrackHandler = exports.convertMedia = exports.getAvailableVideoCodecs = exports.getAvailableContainers = exports.getAvailableAudioCodecs = exports.canReencodeVideoTrack = exports.canReencodeAudioTrack = exports.canCopyVideoTrack = exports.canCopyAudioTrack = exports.createAudioEncoder = exports.createAudioDecoder = void 0;
4
+ const set_remotion_imported_1 = require("./set-remotion-imported");
4
5
  var audio_decoder_1 = require("./audio-decoder");
5
6
  Object.defineProperty(exports, "createAudioDecoder", { enumerable: true, get: function () { return audio_decoder_1.createAudioDecoder; } });
6
7
  var audio_encoder_1 = require("./audio-encoder");
@@ -15,10 +16,20 @@ var can_reencode_video_track_1 = require("./can-reencode-video-track");
15
16
  Object.defineProperty(exports, "canReencodeVideoTrack", { enumerable: true, get: function () { return can_reencode_video_track_1.canReencodeVideoTrack; } });
16
17
  var codec_id_1 = require("./codec-id");
17
18
  Object.defineProperty(exports, "getAvailableAudioCodecs", { enumerable: true, get: function () { return codec_id_1.getAvailableAudioCodecs; } });
19
+ Object.defineProperty(exports, "getAvailableContainers", { enumerable: true, get: function () { return codec_id_1.getAvailableContainers; } });
18
20
  Object.defineProperty(exports, "getAvailableVideoCodecs", { enumerable: true, get: function () { return codec_id_1.getAvailableVideoCodecs; } });
19
21
  var convert_media_1 = require("./convert-media");
20
22
  Object.defineProperty(exports, "convertMedia", { enumerable: true, get: function () { return convert_media_1.convertMedia; } });
23
+ var default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
24
+ Object.defineProperty(exports, "defaultOnAudioTrackHandler", { enumerable: true, get: function () { return default_on_audio_track_handler_1.defaultOnAudioTrackHandler; } });
25
+ var default_on_video_track_handler_1 = require("./default-on-video-track-handler");
26
+ Object.defineProperty(exports, "defaultOnVideoTrackHandler", { enumerable: true, get: function () { return default_on_video_track_handler_1.defaultOnVideoTrackHandler; } });
27
+ var get_default_audio_codec_1 = require("./get-default-audio-codec");
28
+ Object.defineProperty(exports, "getDefaultAudioCodec", { enumerable: true, get: function () { return get_default_audio_codec_1.getDefaultAudioCodec; } });
29
+ var get_default_video_codec_1 = require("./get-default-video-codec");
30
+ Object.defineProperty(exports, "getDefaultVideoCodec", { enumerable: true, get: function () { return get_default_video_codec_1.getDefaultVideoCodec; } });
21
31
  var video_decoder_1 = require("./video-decoder");
22
32
  Object.defineProperty(exports, "createVideoDecoder", { enumerable: true, get: function () { return video_decoder_1.createVideoDecoder; } });
23
33
  var video_encoder_1 = require("./video-encoder");
24
34
  Object.defineProperty(exports, "createVideoEncoder", { enumerable: true, get: function () { return video_encoder_1.createVideoEncoder; } });
35
+ (0, set_remotion_imported_1.setRemotionImported)();
@@ -17,11 +17,11 @@ const makeIoSynchronizer = (logLevel, label) => {
17
17
  let unprocessed = 0;
18
18
  const getUnprocessed = () => unprocessed;
19
19
  const getUnemittedItems = () => {
20
- inputs = inputs.filter((input) => input > lastOutput);
20
+ inputs = inputs.filter((input) => Math.floor(input) > Math.floor(lastOutput));
21
21
  return inputs.length;
22
22
  };
23
23
  const getUnemittedKeyframes = () => {
24
- keyframes = keyframes.filter((keyframe) => keyframe > lastOutput);
24
+ keyframes = keyframes.filter((keyframe) => Math.floor(keyframe) > Math.floor(lastOutput));
25
25
  return keyframes.length;
26
26
  };
27
27
  const printState = (prefix) => {
@@ -1,19 +1,19 @@
1
1
  import type { AudioTrack, LogLevel } from '@remotion/media-parser';
2
- import type { ConvertMediaAudioCodec } from './codec-id';
3
- import type { ConvertMediaContainer } from './convert-media';
2
+ import type { ConvertMediaAudioCodec, ConvertMediaContainer } from './codec-id';
4
3
  export type AudioOperation = {
5
4
  type: 'reencode';
6
5
  bitrate: number;
7
6
  audioCodec: ConvertMediaAudioCodec;
8
7
  } | {
9
8
  type: 'copy';
9
+ } | {
10
+ type: 'fail';
10
11
  } | {
11
12
  type: 'drop';
12
13
  };
13
- export type ResolveAudioActionFn = (options: {
14
+ export type ConvertMediaOnAudioTrackHandler = (options: {
14
15
  track: AudioTrack;
15
- audioCodec: ConvertMediaAudioCodec;
16
+ defaultAudioCodec: ConvertMediaAudioCodec | null;
16
17
  logLevel: LogLevel;
17
18
  container: ConvertMediaContainer;
18
19
  }) => AudioOperation | Promise<AudioOperation>;
19
- export declare const defaultResolveAudioAction: ResolveAudioActionFn;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,16 +1,15 @@
1
1
  import type { LogLevel, MediaFn, OnAudioTrack } from '@remotion/media-parser';
2
- import type { ConvertMediaAudioCodec } from './codec-id';
3
- import type { ConvertMediaContainer, ConvertMediaState } from './convert-media';
2
+ import type { ConvertMediaAudioCodec, ConvertMediaContainer } from './codec-id';
4
3
  import Error from './error-cause';
5
- import type { ResolveAudioActionFn } from './resolve-audio-action';
6
- export declare const makeAudioTrackHandler: ({ state, audioCodec, convertMediaState, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, }: {
4
+ import type { ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
5
+ import type { ConvertMediaProgressFn } from './throttled-state-update';
6
+ export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, }: {
7
7
  state: MediaFn;
8
- audioCodec: ConvertMediaAudioCodec;
9
- convertMediaState: ConvertMediaState;
8
+ defaultAudioCodec: ConvertMediaAudioCodec | null;
10
9
  controller: AbortController;
11
10
  abortConversion: (errCause: Error) => void;
12
- onMediaStateUpdate: null | ((state: ConvertMediaState) => void);
13
- onAudioTrack: ResolveAudioActionFn | null;
11
+ onMediaStateUpdate: null | ConvertMediaProgressFn;
12
+ onAudioTrack: ConvertMediaOnAudioTrackHandler | null;
14
13
  logLevel: LogLevel;
15
14
  container: ConvertMediaContainer;
16
15
  }) => OnAudioTrack;
@@ -9,11 +9,12 @@ const audio_decoder_config_1 = require("./audio-decoder-config");
9
9
  const audio_encoder_1 = require("./audio-encoder");
10
10
  const audio_encoder_config_1 = require("./audio-encoder-config");
11
11
  const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
12
+ const default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
12
13
  const error_cause_1 = __importDefault(require("./error-cause"));
13
- const resolve_audio_action_1 = require("./resolve-audio-action");
14
- const makeAudioTrackHandler = ({ state, audioCodec, convertMediaState, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, }) => async (track) => {
15
- const audioOperation = await (onAudioTrack !== null && onAudioTrack !== void 0 ? onAudioTrack : resolve_audio_action_1.defaultResolveAudioAction)({
16
- audioCodec,
14
+ const log_1 = require("./log");
15
+ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, }) => async (track) => {
16
+ const audioOperation = await (onAudioTrack !== null && onAudioTrack !== void 0 ? onAudioTrack : default_on_audio_track_handler_1.defaultOnAudioTrackHandler)({
17
+ defaultAudioCodec: audioCodec,
17
18
  track,
18
19
  logLevel,
19
20
  container,
@@ -21,18 +22,33 @@ const makeAudioTrackHandler = ({ state, audioCodec, convertMediaState, controlle
21
22
  if (audioOperation.type === 'drop') {
22
23
  return null;
23
24
  }
25
+ if (audioOperation.type === 'fail') {
26
+ throw new error_cause_1.default(`Audio track with ID ${track.trackId} could resolved with {"type": "fail"}. This could mean that this audio track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
27
+ }
24
28
  if (audioOperation.type === 'copy') {
25
29
  const addedTrack = await state.addTrack({
26
30
  type: 'audio',
27
- codec: audioCodec,
31
+ codec: track.codecWithoutConfig,
28
32
  numberOfChannels: track.numberOfChannels,
29
33
  sampleRate: track.sampleRate,
30
34
  codecPrivate: track.codecPrivate,
35
+ timescale: track.timescale,
31
36
  });
37
+ log_1.Log.verbose(logLevel, `Copying audio track ${track.trackId} as track ${addedTrack.trackNumber}. Timescale = ${track.timescale}, codec = ${track.codecWithoutConfig} (${track.codec}) `);
32
38
  return async (audioSample) => {
33
- await state.addSample(audioSample, addedTrack.trackNumber, false);
34
- convertMediaState.encodedAudioFrames++;
35
- onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
39
+ await state.addSample({
40
+ chunk: audioSample,
41
+ trackNumber: addedTrack.trackNumber,
42
+ isVideo: false,
43
+ timescale: track.timescale,
44
+ codecPrivate: track.codecPrivate,
45
+ });
46
+ onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
47
+ return {
48
+ ...prevState,
49
+ encodedAudioFrames: prevState.encodedAudioFrames + 1,
50
+ };
51
+ });
36
52
  };
37
53
  }
38
54
  const audioEncoderConfig = await (0, audio_encoder_config_1.getAudioEncoderConfig)({
@@ -55,25 +71,44 @@ const makeAudioTrackHandler = ({ state, audioCodec, convertMediaState, controlle
55
71
  abortConversion(new error_cause_1.default(`Could not configure audio decoder of track ${track.trackId}`));
56
72
  return null;
57
73
  }
74
+ const codecPrivate = audioOperation.audioCodec === 'aac' ? new Uint8Array([17, 144]) : null;
58
75
  const { trackNumber } = await state.addTrack({
59
76
  type: 'audio',
60
- codec: audioCodec,
77
+ codec: audioOperation.audioCodec,
61
78
  numberOfChannels: track.numberOfChannels,
62
79
  sampleRate: track.sampleRate,
63
- codecPrivate: null,
80
+ codecPrivate,
81
+ timescale: track.timescale,
64
82
  });
65
83
  const audioEncoder = (0, audio_encoder_1.createAudioEncoder)({
84
+ // This is weird 😵‍💫
85
+ // Chrome completely ignores the sample rate and uses it's own
86
+ // We cannot determine it here because it depends on the system
87
+ // sample rate. Unhardcode then declare it later once we know.
88
+ onNewAudioSampleRate: (sampleRate) => {
89
+ state.updateTrackSampleRate({ sampleRate, trackNumber });
90
+ },
66
91
  onChunk: async (chunk) => {
67
- await state.addSample((0, convert_encoded_chunk_1.convertEncodedChunk)(chunk), trackNumber, false);
68
- convertMediaState.encodedAudioFrames++;
69
- onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
92
+ await state.addSample({
93
+ chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
94
+ trackNumber,
95
+ isVideo: false,
96
+ timescale: track.timescale,
97
+ codecPrivate,
98
+ });
99
+ onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
100
+ return {
101
+ ...prevState,
102
+ encodedAudioFrames: prevState.encodedAudioFrames + 1,
103
+ };
104
+ });
70
105
  },
71
106
  onError: (err) => {
72
107
  abortConversion(new error_cause_1.default(`Audio encoder of ${track.trackId} failed (see .cause of this error)`, {
73
108
  cause: err,
74
109
  }));
75
110
  },
76
- codec: audioCodec,
111
+ codec: audioOperation.audioCodec,
77
112
  signal: controller.signal,
78
113
  config: audioEncoderConfig,
79
114
  logLevel,
@@ -81,8 +116,12 @@ const makeAudioTrackHandler = ({ state, audioCodec, convertMediaState, controlle
81
116
  const audioDecoder = (0, audio_decoder_1.createAudioDecoder)({
82
117
  onFrame: async (frame) => {
83
118
  await audioEncoder.encodeFrame(frame);
84
- convertMediaState.decodedAudioFrames++;
85
- onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate(convertMediaState);
119
+ onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
120
+ return {
121
+ ...prevState,
122
+ decodedAudioFrames: prevState.decodedAudioFrames + 1,
123
+ };
124
+ });
86
125
  frame.close();
87
126
  },
88
127
  onError(error) {
@@ -1,11 +1,11 @@
1
1
  import type { VideoTrack } from '@remotion/media-parser';
2
- import type { ConvertMediaOnMediaStateUpdate, ConvertMediaOnVideoFrame, ConvertMediaState } from './convert-media';
2
+ import type { ConvertMediaVideoCodec } from './codec-id';
3
+ import type { ConvertMediaOnVideoFrame } from './convert-media';
3
4
  import type { WebCodecsVideoEncoder } from './video-encoder';
4
- export declare const onFrame: ({ frame, onVideoFrame, videoEncoder, onMediaStateUpdate, track, convertMediaState, }: {
5
+ export declare const onFrame: ({ frame, onVideoFrame, videoEncoder, track, outputCodec, }: {
5
6
  frame: VideoFrame;
6
7
  onVideoFrame: ConvertMediaOnVideoFrame | null;
7
8
  videoEncoder: WebCodecsVideoEncoder;
8
- onMediaStateUpdate: ConvertMediaOnMediaStateUpdate | null;
9
9
  track: VideoTrack;
10
- convertMediaState: ConvertMediaState;
10
+ outputCodec: ConvertMediaVideoCodec;
11
11
  }) => Promise<void>;
package/dist/on-frame.js CHANGED
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.onFrame = void 0;
4
- const onFrame = async ({ frame, onVideoFrame, videoEncoder, onMediaStateUpdate, track, convertMediaState, }) => {
4
+ const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
5
+ const onFrame = async ({ frame, onVideoFrame, videoEncoder, track, outputCodec, }) => {
5
6
  const newFrame = onVideoFrame ? await onVideoFrame({ frame, track }) : frame;
6
- if (newFrame.codedHeight !== frame.codedHeight) {
7
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedHeight (${newFrame.codedHeight}) than the input frame (${frame.codedHeight})`);
7
+ if (newFrame.codedHeight !== frame.displayHeight) {
8
+ throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedHeight (${newFrame.codedHeight}) than the input frame displayHeight (${frame.displayHeight})`);
8
9
  }
9
- if (newFrame.codedWidth !== frame.codedWidth) {
10
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedWidth (${newFrame.codedWidth}) than the input frame (${frame.codedWidth})`);
10
+ if (newFrame.codedWidth !== frame.displayWidth) {
11
+ throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedWidth (${newFrame.codedWidth}) than the input frame displayWidth (${frame.displayWidth})`);
11
12
  }
12
13
  if (newFrame.displayWidth !== frame.displayWidth) {
13
14
  throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayWidth (${newFrame.displayWidth}) than the input frame (${newFrame.displayHeight})`);
@@ -21,12 +22,17 @@ const onFrame = async ({ frame, onVideoFrame, videoEncoder, onMediaStateUpdate,
21
22
  if (newFrame.duration !== frame.duration) {
22
23
  throw new Error(`Returned VideoFrame of track ${track.trackId} has different duration (${newFrame.duration}) than the input frame (${newFrame.duration}). When calling new VideoFrame(), pass {duration: frame.duration} as second argument`);
23
24
  }
24
- await videoEncoder.encodeFrame(newFrame, newFrame.timestamp);
25
- convertMediaState.decodedVideoFrames++;
26
- onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
27
- newFrame.close();
25
+ const fixedFrame = (0, convert_to_correct_videoframe_1.convertToCorrectVideoFrame)({
26
+ videoFrame: newFrame,
27
+ outputCodec,
28
+ });
29
+ await videoEncoder.encodeFrame(fixedFrame, fixedFrame.timestamp);
30
+ fixedFrame.close();
28
31
  if (frame !== newFrame) {
29
32
  frame.close();
30
33
  }
34
+ if (fixedFrame !== newFrame) {
35
+ fixedFrame.close();
36
+ }
31
37
  };
32
38
  exports.onFrame = onFrame;
@@ -1,6 +1,5 @@
1
1
  import type { LogLevel, VideoTrack } from '@remotion/media-parser';
2
- import type { ConvertMediaVideoCodec } from './codec-id';
3
- import type { ConvertMediaContainer } from './convert-media';
2
+ import type { ConvertMediaContainer, ConvertMediaVideoCodec } from './codec-id';
4
3
  export type VideoOperation = {
5
4
  type: 'reencode';
6
5
  videoCodec: ConvertMediaVideoCodec;
@@ -8,11 +7,12 @@ export type VideoOperation = {
8
7
  type: 'copy';
9
8
  } | {
10
9
  type: 'drop';
10
+ } | {
11
+ type: 'fail';
11
12
  };
12
- export type ResolveVideoActionFn = (options: {
13
- videoCodec: ConvertMediaVideoCodec;
13
+ export type ConvertMediaOnVideoTrackHandler = (options: {
14
+ defaultVideoCodec: ConvertMediaVideoCodec | null;
14
15
  track: VideoTrack;
15
16
  logLevel: LogLevel;
16
17
  container: ConvertMediaContainer;
17
18
  }) => VideoOperation | Promise<VideoOperation>;
18
- export declare const defaultResolveVideoAction: ResolveVideoActionFn;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,17 +1,17 @@
1
1
  import type { LogLevel, MediaFn, OnVideoTrack } from '@remotion/media-parser';
2
- import type { ConvertMediaVideoCodec } from './codec-id';
3
- import type { ConvertMediaContainer, ConvertMediaOnMediaStateUpdate, ConvertMediaOnVideoFrame, ConvertMediaState } from './convert-media';
2
+ import type { ConvertMediaContainer, ConvertMediaVideoCodec } from './codec-id';
3
+ import type { ConvertMediaOnVideoFrame } from './convert-media';
4
4
  import Error from './error-cause';
5
- import type { ResolveVideoActionFn } from './resolve-video-action';
6
- export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, convertMediaState, controller, videoCodec, onVideoTrack, logLevel, container, }: {
5
+ import type { ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
6
+ import type { ConvertMediaProgressFn } from './throttled-state-update';
7
+ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, container, }: {
7
8
  state: MediaFn;
8
9
  onVideoFrame: null | ConvertMediaOnVideoFrame;
9
- onMediaStateUpdate: null | ConvertMediaOnMediaStateUpdate;
10
+ onMediaStateUpdate: null | ConvertMediaProgressFn;
10
11
  abortConversion: (errCause: Error) => void;
11
- convertMediaState: ConvertMediaState;
12
12
  controller: AbortController;
13
- videoCodec: ConvertMediaVideoCodec;
14
- onVideoTrack: ResolveVideoActionFn | null;
13
+ defaultVideoCodec: ConvertMediaVideoCodec | null;
14
+ onVideoTrack: ConvertMediaOnVideoTrackHandler | null;
15
15
  logLevel: LogLevel;
16
16
  container: ConvertMediaContainer;
17
17
  }) => OnVideoTrack;
@@ -4,28 +4,34 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.makeVideoTrackHandler = void 0;
7
+ const arraybuffer_to_uint8_array_1 = require("./arraybuffer-to-uint8-array");
7
8
  const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
9
+ const default_on_video_track_handler_1 = require("./default-on-video-track-handler");
8
10
  const error_cause_1 = __importDefault(require("./error-cause"));
11
+ const log_1 = require("./log");
9
12
  const on_frame_1 = require("./on-frame");
10
- const resolve_video_action_1 = require("./resolve-video-action");
11
13
  const video_decoder_1 = require("./video-decoder");
12
14
  const video_decoder_config_1 = require("./video-decoder-config");
13
15
  const video_encoder_1 = require("./video-encoder");
14
16
  const video_encoder_config_1 = require("./video-encoder-config");
15
- const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, convertMediaState, controller, videoCodec, onVideoTrack, logLevel, container, }) => async (track) => {
17
+ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, container, }) => async (track) => {
16
18
  if (controller.signal.aborted) {
17
19
  throw new error_cause_1.default('Aborted');
18
20
  }
19
- const videoOperation = await (onVideoTrack !== null && onVideoTrack !== void 0 ? onVideoTrack : resolve_video_action_1.defaultResolveVideoAction)({
21
+ const videoOperation = await (onVideoTrack !== null && onVideoTrack !== void 0 ? onVideoTrack : default_on_video_track_handler_1.defaultOnVideoTrackHandler)({
20
22
  track,
21
- videoCodec,
23
+ defaultVideoCodec,
22
24
  logLevel,
23
25
  container,
24
26
  });
25
27
  if (videoOperation.type === 'drop') {
26
28
  return null;
27
29
  }
30
+ if (videoOperation.type === 'fail') {
31
+ throw new error_cause_1.default(`Video track with ID ${track.trackId} could resolved with {"type": "fail"}. This could mean that this video track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
32
+ }
28
33
  if (videoOperation.type === 'copy') {
34
+ log_1.Log.verbose(logLevel, `Copying video track with codec ${track.codec} and timescale ${track.timescale}`);
29
35
  const videoTrack = await state.addTrack({
30
36
  type: 'video',
31
37
  color: track.color,
@@ -33,17 +39,29 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
33
39
  height: track.codedHeight,
34
40
  codec: track.codecWithoutConfig,
35
41
  codecPrivate: track.codecPrivate,
42
+ timescale: track.timescale,
36
43
  });
37
44
  return async (sample) => {
38
- await state.addSample(sample, videoTrack.trackNumber, true);
39
- convertMediaState.decodedVideoFrames++;
40
- onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
45
+ await state.addSample({
46
+ chunk: sample,
47
+ trackNumber: videoTrack.trackNumber,
48
+ isVideo: true,
49
+ timescale: track.timescale,
50
+ codecPrivate: track.codecPrivate,
51
+ });
52
+ onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
53
+ return {
54
+ ...prevState,
55
+ decodedVideoFrames: prevState.decodedVideoFrames + 1,
56
+ };
57
+ });
41
58
  };
42
59
  }
43
60
  const videoEncoderConfig = await (0, video_encoder_config_1.getVideoEncoderConfig)({
44
61
  codec: videoOperation.videoCodec,
45
62
  height: track.displayAspectHeight,
46
63
  width: track.displayAspectWidth,
64
+ fps: track.fps,
47
65
  });
48
66
  const videoDecoderConfig = await (0, video_decoder_config_1.getVideoDecoderConfigWithHardwareAcceleration)(track);
49
67
  if (videoEncoderConfig === null) {
@@ -59,14 +77,27 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
59
77
  color: track.color,
60
78
  width: track.codedWidth,
61
79
  height: track.codedHeight,
62
- codec: videoCodec,
80
+ codec: videoOperation.videoCodec,
63
81
  codecPrivate: null,
82
+ timescale: track.timescale,
64
83
  });
84
+ log_1.Log.verbose(logLevel, `Created new video track with ID ${trackNumber}, codec ${videoOperation.videoCodec} and timescale ${track.timescale}`);
65
85
  const videoEncoder = (0, video_encoder_1.createVideoEncoder)({
66
- onChunk: async (chunk) => {
67
- await state.addSample((0, convert_encoded_chunk_1.convertEncodedChunk)(chunk), trackNumber, true);
68
- convertMediaState.encodedVideoFrames++;
69
- onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
86
+ onChunk: async (chunk, metadata) => {
87
+ var _a, _b;
88
+ await state.addSample({
89
+ chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
90
+ trackNumber,
91
+ isVideo: true,
92
+ timescale: track.timescale,
93
+ codecPrivate: (0, arraybuffer_to_uint8_array_1.arrayBufferToUint8Array)(((_b = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.decoderConfig) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null)),
94
+ });
95
+ onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
96
+ return {
97
+ ...prevState,
98
+ encodedVideoFrames: prevState.encodedVideoFrames + 1,
99
+ };
100
+ });
70
101
  },
71
102
  onError: (err) => {
72
103
  abortConversion(new error_cause_1.default(`Video encoder of track ${track.trackId} failed (see .cause of this error)`, {
@@ -76,17 +107,17 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
76
107
  signal: controller.signal,
77
108
  config: videoEncoderConfig,
78
109
  logLevel,
110
+ outputCodec: videoOperation.videoCodec,
79
111
  });
80
112
  const videoDecoder = (0, video_decoder_1.createVideoDecoder)({
81
113
  config: videoDecoderConfig,
82
114
  onFrame: async (frame) => {
83
115
  await (0, on_frame_1.onFrame)({
84
- convertMediaState,
85
116
  frame,
86
- onMediaStateUpdate,
87
117
  track,
88
118
  videoEncoder,
89
119
  onVideoFrame,
120
+ outputCodec: videoOperation.videoCodec,
90
121
  });
91
122
  },
92
123
  onError: (err) => {
@@ -98,10 +129,13 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
98
129
  logLevel,
99
130
  });
100
131
  state.addWaitForFinishPromise(async () => {
132
+ log_1.Log.verbose(logLevel, 'Waiting for video decoder to finish');
101
133
  await videoDecoder.waitForFinish();
102
- await videoEncoder.waitForFinish();
103
134
  videoDecoder.close();
135
+ log_1.Log.verbose(logLevel, 'Video decoder finished. Waiting for encoder to finish');
136
+ await videoEncoder.waitForFinish();
104
137
  videoEncoder.close();
138
+ log_1.Log.verbose(logLevel, 'Encoder finished');
105
139
  });
106
140
  return async (chunk) => {
107
141
  await videoDecoder.processSample(chunk);
@@ -0,0 +1,6 @@
1
+ declare global {
2
+ interface Window {
3
+ remotion_imported: string | boolean;
4
+ }
5
+ }
6
+ export declare const setRemotionImported: () => void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setRemotionImported = void 0;
4
+ const media_parser_1 = require("@remotion/media-parser");
5
+ // We set the `window.remotion_imported` variable for the sole purpose
6
+ // of being picked up by Wappalyzer.
7
+ // The Wappalyzer Chrome extension is used to detect the technologies
8
+ // used on websites, and it looks for this variable.
9
+ // Remotion is a customer of Wappalyzer and buys a list of domains
10
+ // where Remotion is used from time to time.
11
+ // Remotion uses this data to ensure companies which are required to get
12
+ // a company license for this pacakge are actually doing so.
13
+ const setRemotionImported = () => {
14
+ if (typeof globalThis === 'undefined') {
15
+ return;
16
+ }
17
+ if (globalThis.remotion_imported) {
18
+ return;
19
+ }
20
+ globalThis.remotion_imported = media_parser_1.VERSION;
21
+ if (typeof window !== 'undefined') {
22
+ window.remotion_imported = `${media_parser_1.VERSION}-webcodecs`;
23
+ }
24
+ };
25
+ exports.setRemotionImported = setRemotionImported;
@@ -0,0 +1,13 @@
1
+ import type { ConvertMediaOnProgress, ConvertMediaProgress } from './convert-media';
2
+ export type ConvertMediaProgressFn = (state: (prevState: ConvertMediaProgress) => ConvertMediaProgress) => void;
3
+ type ReturnType = {
4
+ get: () => ConvertMediaProgress;
5
+ update: ConvertMediaProgressFn | null;
6
+ stopAndGetLastProgress: () => void;
7
+ };
8
+ export declare const throttledStateUpdate: ({ updateFn, everyMilliseconds, signal, }: {
9
+ updateFn: ConvertMediaOnProgress | null;
10
+ everyMilliseconds: number;
11
+ signal: AbortSignal;
12
+ }) => ReturnType;
13
+ export {};