@remotion/webcodecs 4.0.229 → 4.0.230

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 (59) hide show
  1. package/dist/arraybuffer-to-uint8-array.d.ts +1 -0
  2. package/dist/arraybuffer-to-uint8-array.js +7 -0
  3. package/dist/audio-decoder.d.ts +2 -2
  4. package/dist/audio-encoder-config.js +15 -2
  5. package/dist/audio-encoder.d.ts +2 -1
  6. package/dist/audio-encoder.js +16 -4
  7. package/dist/can-copy-audio-track.d.ts +2 -4
  8. package/dist/can-copy-audio-track.js +7 -4
  9. package/dist/can-copy-video-track.d.ts +2 -4
  10. package/dist/can-copy-video-track.js +6 -6
  11. package/dist/can-reencode-audio-track.js +1 -6
  12. package/dist/can-reencode-video-track.js +1 -0
  13. package/dist/choose-correct-avc1-profile.d.ts +5 -0
  14. package/dist/choose-correct-avc1-profile.js +54 -0
  15. package/dist/codec-id.d.ts +7 -4
  16. package/dist/codec-id.js +28 -5
  17. package/dist/convert-encoded-chunk.d.ts +2 -1
  18. package/dist/convert-encoded-chunk.js +25 -2
  19. package/dist/convert-media.d.ts +7 -8
  20. package/dist/convert-media.js +11 -9
  21. package/dist/default-on-audio-track-handler.d.ts +2 -0
  22. package/dist/default-on-audio-track-handler.js +36 -0
  23. package/dist/default-on-video-track-handler.d.ts +2 -0
  24. package/dist/default-on-video-track-handler.js +29 -0
  25. package/dist/esm/index.mjs +277 -106
  26. package/dist/get-default-audio-codec.d.ts +4 -0
  27. package/dist/get-default-audio-codec.js +13 -0
  28. package/dist/get-default-video-codec.d.ts +4 -0
  29. package/dist/get-default-video-codec.js +10 -0
  30. package/dist/index.d.ts +8 -4
  31. package/dist/index.js +10 -1
  32. package/dist/io-manager/io-synchronizer.js +2 -2
  33. package/dist/{resolve-audio-action.d.ts → on-audio-track-handler.d.ts} +5 -5
  34. package/dist/on-audio-track-handler.js +2 -0
  35. package/dist/on-audio-track.d.ts +6 -6
  36. package/dist/on-audio-track.js +37 -10
  37. package/dist/{resolve-video-action.d.ts → on-video-track-handler.d.ts} +5 -5
  38. package/dist/on-video-track-handler.js +2 -0
  39. package/dist/on-video-track.d.ts +6 -6
  40. package/dist/on-video-track.js +35 -9
  41. package/dist/video-decoder.d.ts +2 -2
  42. package/dist/video-decoder.js +5 -0
  43. package/dist/video-encoder-config.d.ts +2 -1
  44. package/dist/video-encoder-config.js +7 -2
  45. package/dist/video-encoder.d.ts +1 -1
  46. package/dist/video-encoder.js +4 -6
  47. package/package.json +3 -3
  48. package/dist/can-reencode-audio.d.ts +0 -7
  49. package/dist/can-reencode-audio.js +0 -21
  50. package/dist/can-reencode-video.d.ts +0 -6
  51. package/dist/can-reencode-video.js +0 -15
  52. package/dist/event-emitter.d.ts +0 -25
  53. package/dist/event-emitter.js +0 -23
  54. package/dist/polyfill-encoded-audio-chunk.d.ts +0 -3
  55. package/dist/polyfill-encoded-audio-chunk.js +0 -5
  56. package/dist/resolve-audio-action.js +0 -32
  57. package/dist/resolve-video-action.js +0 -26
  58. package/dist/wait-until-return.d.ts +0 -4
  59. package/dist/wait-until-return.js +0 -14
@@ -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
@@ -4,9 +4,13 @@ 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';
7
+ export { ConvertMediaAudioCodec, ConvertMediaContainer, ConvertMediaVideoCodec, getAvailableAudioCodecs, getAvailableContainers, getAvailableVideoCodecs, } from './codec-id';
8
+ export { ConvertMediaOnMediaStateUpdate, ConvertMediaOnVideoFrame, ConvertMediaResult, ConvertMediaState, convertMedia, } 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';
11
15
  export { WebCodecsVideoDecoder, createVideoDecoder } from './video-decoder';
12
16
  export { WebCodecsVideoEncoder, createVideoEncoder } from './video-encoder';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
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
4
  var audio_decoder_1 = require("./audio-decoder");
5
5
  Object.defineProperty(exports, "createAudioDecoder", { enumerable: true, get: function () { return audio_decoder_1.createAudioDecoder; } });
6
6
  var audio_encoder_1 = require("./audio-encoder");
@@ -15,9 +15,18 @@ var can_reencode_video_track_1 = require("./can-reencode-video-track");
15
15
  Object.defineProperty(exports, "canReencodeVideoTrack", { enumerable: true, get: function () { return can_reencode_video_track_1.canReencodeVideoTrack; } });
16
16
  var codec_id_1 = require("./codec-id");
17
17
  Object.defineProperty(exports, "getAvailableAudioCodecs", { enumerable: true, get: function () { return codec_id_1.getAvailableAudioCodecs; } });
18
+ Object.defineProperty(exports, "getAvailableContainers", { enumerable: true, get: function () { return codec_id_1.getAvailableContainers; } });
18
19
  Object.defineProperty(exports, "getAvailableVideoCodecs", { enumerable: true, get: function () { return codec_id_1.getAvailableVideoCodecs; } });
19
20
  var convert_media_1 = require("./convert-media");
20
21
  Object.defineProperty(exports, "convertMedia", { enumerable: true, get: function () { return convert_media_1.convertMedia; } });
22
+ var default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
23
+ Object.defineProperty(exports, "defaultOnAudioTrackHandler", { enumerable: true, get: function () { return default_on_audio_track_handler_1.defaultOnAudioTrackHandler; } });
24
+ var default_on_video_track_handler_1 = require("./default-on-video-track-handler");
25
+ Object.defineProperty(exports, "defaultOnVideoTrackHandler", { enumerable: true, get: function () { return default_on_video_track_handler_1.defaultOnVideoTrackHandler; } });
26
+ var get_default_audio_codec_1 = require("./get-default-audio-codec");
27
+ Object.defineProperty(exports, "getDefaultAudioCodec", { enumerable: true, get: function () { return get_default_audio_codec_1.getDefaultAudioCodec; } });
28
+ var get_default_video_codec_1 = require("./get-default-video-codec");
29
+ Object.defineProperty(exports, "getDefaultVideoCodec", { enumerable: true, get: function () { return get_default_video_codec_1.getDefaultVideoCodec; } });
21
30
  var video_decoder_1 = require("./video-decoder");
22
31
  Object.defineProperty(exports, "createVideoDecoder", { enumerable: true, get: function () { return video_decoder_1.createVideoDecoder; } });
23
32
  var video_encoder_1 = require("./video-encoder");
@@ -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,16 @@
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';
3
+ import type { ConvertMediaState } from './convert-media';
4
4
  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, }: {
5
+ import type { ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
6
+ export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, convertMediaState, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, }: {
7
7
  state: MediaFn;
8
- audioCodec: ConvertMediaAudioCodec;
8
+ defaultAudioCodec: ConvertMediaAudioCodec | null;
9
9
  convertMediaState: ConvertMediaState;
10
10
  controller: AbortController;
11
11
  abortConversion: (errCause: Error) => void;
12
12
  onMediaStateUpdate: null | ((state: ConvertMediaState) => void);
13
- onAudioTrack: ResolveAudioActionFn | null;
13
+ onAudioTrack: ConvertMediaOnAudioTrackHandler | null;
14
14
  logLevel: LogLevel;
15
15
  container: ConvertMediaContainer;
16
16
  }) => 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, convertMediaState, 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,16 +22,27 @@ 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);
39
+ await state.addSample({
40
+ chunk: audioSample,
41
+ trackNumber: addedTrack.trackNumber,
42
+ isVideo: false,
43
+ timescale: track.timescale,
44
+ codecPrivate: track.codecPrivate,
45
+ });
34
46
  convertMediaState.encodedAudioFrames++;
35
47
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
36
48
  };
@@ -55,16 +67,31 @@ const makeAudioTrackHandler = ({ state, audioCodec, convertMediaState, controlle
55
67
  abortConversion(new error_cause_1.default(`Could not configure audio decoder of track ${track.trackId}`));
56
68
  return null;
57
69
  }
70
+ const codecPrivate = audioOperation.audioCodec === 'aac' ? new Uint8Array([17, 144]) : null;
58
71
  const { trackNumber } = await state.addTrack({
59
72
  type: 'audio',
60
- codec: audioCodec,
73
+ codec: audioOperation.audioCodec,
61
74
  numberOfChannels: track.numberOfChannels,
62
75
  sampleRate: track.sampleRate,
63
- codecPrivate: null,
76
+ codecPrivate,
77
+ timescale: track.timescale,
64
78
  });
65
79
  const audioEncoder = (0, audio_encoder_1.createAudioEncoder)({
80
+ // This is weird 😵‍💫
81
+ // Chrome completely ignores the sample rate and uses it's own
82
+ // We cannot determine it here because it depends on the system
83
+ // sample rate. Unhardcode then declare it later once we know.
84
+ onNewAudioSampleRate: (sampleRate) => {
85
+ state.updateTrackSampleRate({ sampleRate, trackNumber });
86
+ },
66
87
  onChunk: async (chunk) => {
67
- await state.addSample((0, convert_encoded_chunk_1.convertEncodedChunk)(chunk), trackNumber, false);
88
+ await state.addSample({
89
+ chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
90
+ trackNumber,
91
+ isVideo: false,
92
+ timescale: track.timescale,
93
+ codecPrivate,
94
+ });
68
95
  convertMediaState.encodedAudioFrames++;
69
96
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
70
97
  },
@@ -73,7 +100,7 @@ const makeAudioTrackHandler = ({ state, audioCodec, convertMediaState, controlle
73
100
  cause: err,
74
101
  }));
75
102
  },
76
- codec: audioCodec,
103
+ codec: audioOperation.audioCodec,
77
104
  signal: controller.signal,
78
105
  config: audioEncoderConfig,
79
106
  logLevel,
@@ -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 { ConvertMediaOnMediaStateUpdate, ConvertMediaOnVideoFrame, ConvertMediaState } 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
+ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, convertMediaState, controller, defaultVideoCodec, onVideoTrack, logLevel, container, }: {
7
7
  state: MediaFn;
8
8
  onVideoFrame: null | ConvertMediaOnVideoFrame;
9
9
  onMediaStateUpdate: null | ConvertMediaOnMediaStateUpdate;
10
10
  abortConversion: (errCause: Error) => void;
11
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, convertMediaState, 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,9 +39,16 @@ 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);
45
+ await state.addSample({
46
+ chunk: sample,
47
+ trackNumber: videoTrack.trackNumber,
48
+ isVideo: true,
49
+ timescale: track.timescale,
50
+ codecPrivate: track.codecPrivate,
51
+ });
39
52
  convertMediaState.decodedVideoFrames++;
40
53
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
41
54
  };
@@ -44,6 +57,7 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
44
57
  codec: videoOperation.videoCodec,
45
58
  height: track.displayAspectHeight,
46
59
  width: track.displayAspectWidth,
60
+ fps: track.fps,
47
61
  });
48
62
  const videoDecoderConfig = await (0, video_decoder_config_1.getVideoDecoderConfigWithHardwareAcceleration)(track);
49
63
  if (videoEncoderConfig === null) {
@@ -59,12 +73,21 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
59
73
  color: track.color,
60
74
  width: track.codedWidth,
61
75
  height: track.codedHeight,
62
- codec: videoCodec,
76
+ codec: videoOperation.videoCodec,
63
77
  codecPrivate: null,
78
+ timescale: track.timescale,
64
79
  });
80
+ log_1.Log.verbose(logLevel, `Created new video track with ID ${trackNumber}, codec ${videoOperation.videoCodec} and timescale ${track.timescale}`);
65
81
  const videoEncoder = (0, video_encoder_1.createVideoEncoder)({
66
- onChunk: async (chunk) => {
67
- await state.addSample((0, convert_encoded_chunk_1.convertEncodedChunk)(chunk), trackNumber, true);
82
+ onChunk: async (chunk, metadata) => {
83
+ var _a, _b;
84
+ await state.addSample({
85
+ chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
86
+ trackNumber,
87
+ isVideo: true,
88
+ timescale: track.timescale,
89
+ 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)),
90
+ });
68
91
  convertMediaState.encodedVideoFrames++;
69
92
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate({ ...convertMediaState });
70
93
  },
@@ -98,10 +121,13 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
98
121
  logLevel,
99
122
  });
100
123
  state.addWaitForFinishPromise(async () => {
124
+ log_1.Log.verbose(logLevel, 'Waiting for video decoder to finish');
101
125
  await videoDecoder.waitForFinish();
102
- await videoEncoder.waitForFinish();
103
126
  videoDecoder.close();
127
+ log_1.Log.verbose(logLevel, 'Video decoder finished. Waiting for encoder to finish');
128
+ await videoEncoder.waitForFinish();
104
129
  videoEncoder.close();
130
+ log_1.Log.verbose(logLevel, 'Encoder finished');
105
131
  });
106
132
  return async (chunk) => {
107
133
  await videoDecoder.processSample(chunk);
@@ -1,6 +1,6 @@
1
- import type { LogLevel, VideoSample } from '@remotion/media-parser';
1
+ import type { AudioOrVideoSample, LogLevel } from '@remotion/media-parser';
2
2
  export type WebCodecsVideoDecoder = {
3
- processSample: (videoSample: VideoSample) => Promise<void>;
3
+ processSample: (videoSample: AudioOrVideoSample) => Promise<void>;
4
4
  waitForFinish: () => Promise<void>;
5
5
  close: () => void;
6
6
  flush: () => Promise<void>;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createVideoDecoder = void 0;
4
4
  const io_synchronizer_1 = require("./io-manager/io-synchronizer");
5
+ const log_1 = require("./log");
5
6
  const createVideoDecoder = ({ onFrame, onError, signal, config, logLevel, }) => {
6
7
  const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)(logLevel, 'Video decoder');
7
8
  let outputQueue = Promise.resolve();
@@ -69,9 +70,13 @@ const createVideoDecoder = ({ onFrame, onError, signal, config, logLevel, }) =>
69
70
  },
70
71
  waitForFinish: async () => {
71
72
  await videoDecoder.flush();
73
+ log_1.Log.verbose(logLevel, 'Flushed video decoder');
72
74
  await ioSynchronizer.waitForFinish();
75
+ log_1.Log.verbose(logLevel, 'IO synchro finished');
73
76
  await outputQueue;
77
+ log_1.Log.verbose(logLevel, 'Output queue finished');
74
78
  await inputQueue;
79
+ log_1.Log.verbose(logLevel, 'Input queue finished');
75
80
  },
76
81
  close,
77
82
  flush: async () => {
@@ -1,6 +1,7 @@
1
1
  import type { ConvertMediaVideoCodec } from './codec-id';
2
- export declare const getVideoEncoderConfig: ({ width, height, codec, }: {
2
+ export declare const getVideoEncoderConfig: ({ codec, height, width, fps, }: {
3
3
  width: number;
4
4
  height: number;
5
5
  codec: ConvertMediaVideoCodec;
6
+ fps: number | null;
6
7
  }) => Promise<VideoEncoderConfig | null>;
@@ -1,12 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getVideoEncoderConfig = void 0;
4
- const getVideoEncoderConfig = async ({ width, height, codec, }) => {
4
+ const choose_correct_avc1_profile_1 = require("./choose-correct-avc1-profile");
5
+ const getVideoEncoderConfig = async ({ codec, height, width, fps, }) => {
5
6
  if (typeof VideoEncoder === 'undefined') {
6
7
  return null;
7
8
  }
8
9
  const config = {
9
- codec: codec === 'vp9' ? 'vp09.00.10.08' : codec,
10
+ codec: codec === 'h264'
11
+ ? (0, choose_correct_avc1_profile_1.chooseCorrectAvc1Profile)({ fps, height, width })
12
+ : codec === 'vp9'
13
+ ? 'vp09.00.10.08'
14
+ : codec,
10
15
  height,
11
16
  width,
12
17
  };
@@ -6,7 +6,7 @@ export type WebCodecsVideoEncoder = {
6
6
  flush: () => Promise<void>;
7
7
  };
8
8
  export declare const createVideoEncoder: ({ onChunk, onError, signal, config, logLevel, }: {
9
- onChunk: (chunk: EncodedVideoChunk) => Promise<void>;
9
+ onChunk: (chunk: EncodedVideoChunk, metadata: EncodedVideoChunkMetadata | null) => Promise<void>;
10
10
  onError: (error: DOMException) => void;
11
11
  signal: AbortSignal;
12
12
  config: VideoEncoderConfig;
@@ -12,18 +12,16 @@ const createVideoEncoder = ({ onChunk, onError, signal, config, logLevel, }) =>
12
12
  error(error) {
13
13
  onError(error);
14
14
  },
15
- output(chunk) {
16
- if (chunk.duration === null) {
17
- throw new Error('Duration is null');
18
- }
19
- const timestamp = chunk.timestamp + chunk.duration;
15
+ output(chunk, metadata) {
16
+ var _a;
17
+ const timestamp = chunk.timestamp + ((_a = chunk.duration) !== null && _a !== void 0 ? _a : 0);
20
18
  ioSynchronizer.onOutput(timestamp);
21
19
  outputQueue = outputQueue
22
20
  .then(() => {
23
21
  if (signal.aborted) {
24
22
  return;
25
23
  }
26
- return onChunk(chunk);
24
+ return onChunk(chunk, metadata !== null && metadata !== void 0 ? metadata : null);
27
25
  })
28
26
  .then(() => {
29
27
  ioSynchronizer.onProcessed();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/webcodecs",
3
- "version": "4.0.229",
3
+ "version": "4.0.230",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -17,13 +17,13 @@
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.229"
20
+ "@remotion/media-parser": "4.0.230"
21
21
  },
22
22
  "peerDependencies": {},
23
23
  "devDependencies": {
24
24
  "@types/dom-webcodecs": "0.1.11",
25
25
  "eslint": "9.14.0",
26
- "@remotion/eslint-config-internal": "4.0.229"
26
+ "@remotion/eslint-config-internal": "4.0.230"
27
27
  },
28
28
  "keywords": [],
29
29
  "publishConfig": {
@@ -1,7 +0,0 @@
1
- import type { AudioTrack } from '@remotion/media-parser';
2
- import type { ConvertMediaAudioCodec } from './codec-id';
3
- export declare const canReencodeAudioTrack: ({ track, audioCodec, bitrate, }: {
4
- track: AudioTrack;
5
- audioCodec: ConvertMediaAudioCodec;
6
- bitrate: number;
7
- }) => Promise<boolean>;
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.canReencodeAudioTrack = void 0;
4
- const audio_decoder_config_1 = require("./audio-decoder-config");
5
- const audio_encoder_config_1 = require("./audio-encoder-config");
6
- const canReencodeAudioTrack = async ({ track, audioCodec, bitrate, }) => {
7
- const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)({
8
- codec: track.codec,
9
- numberOfChannels: track.numberOfChannels,
10
- sampleRate: track.sampleRate,
11
- description: track.description,
12
- });
13
- const audioEncoderConfig = await (0, audio_encoder_config_1.getAudioEncoderConfig)({
14
- codec: audioCodec,
15
- numberOfChannels: track.numberOfChannels,
16
- sampleRate: track.sampleRate,
17
- bitrate,
18
- });
19
- return Boolean(audioDecoderConfig && audioEncoderConfig);
20
- };
21
- exports.canReencodeAudioTrack = canReencodeAudioTrack;
@@ -1,6 +0,0 @@
1
- import type { VideoTrack } from '@remotion/media-parser';
2
- import type { ConvertMediaVideoCodec } from './codec-id';
3
- export declare const canReencodeVideoTrack: ({ videoCodec, track, }: {
4
- videoCodec: ConvertMediaVideoCodec;
5
- track: VideoTrack;
6
- }) => Promise<boolean>;
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.canReencodeVideoTrack = void 0;
4
- const video_decoder_config_1 = require("./video-decoder-config");
5
- const video_encoder_config_1 = require("./video-encoder-config");
6
- const canReencodeVideoTrack = async ({ videoCodec, track, }) => {
7
- const videoEncoderConfig = await (0, video_encoder_config_1.getVideoEncoderConfig)({
8
- codec: videoCodec,
9
- height: track.displayAspectHeight,
10
- width: track.displayAspectWidth,
11
- });
12
- const videoDecoderConfig = await (0, video_decoder_config_1.getVideoDecoderConfigWithHardwareAcceleration)(track);
13
- return Boolean(videoDecoderConfig && videoEncoderConfig);
14
- };
15
- exports.canReencodeVideoTrack = canReencodeVideoTrack;
@@ -1,25 +0,0 @@
1
- type Input = {
2
- timestamp: number;
3
- keyframe: boolean;
4
- };
5
- type Output = {
6
- timestamp: number;
7
- };
8
- type IoEventMap = {
9
- input: Input;
10
- output: Output;
11
- };
12
- export type IoEventTypes = keyof IoEventMap;
13
- export type CallbackListener<T extends IoEventTypes> = (data: {
14
- detail: IoEventMap[T];
15
- }) => void;
16
- type IoListeners = {
17
- [EventType in IoEventTypes]: CallbackListener<EventType>[];
18
- };
19
- export declare class IoEventEmitter {
20
- listeners: IoListeners;
21
- addEventListener<Q extends IoEventTypes>(name: Q, callback: CallbackListener<Q>): void;
22
- removeEventListener<Q extends IoEventTypes>(name: Q, callback: CallbackListener<Q>): void;
23
- dispatchEvent<T extends IoEventTypes>(dispatchName: T, context: IoEventMap[T]): void;
24
- }
25
- export {};
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IoEventEmitter = void 0;
4
- class IoEventEmitter {
5
- constructor() {
6
- this.listeners = {
7
- input: [],
8
- output: [],
9
- };
10
- }
11
- addEventListener(name, callback) {
12
- this.listeners[name].push(callback);
13
- }
14
- removeEventListener(name, callback) {
15
- this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
16
- }
17
- dispatchEvent(dispatchName, context) {
18
- this.listeners[dispatchName].forEach((callback) => {
19
- callback({ detail: context });
20
- });
21
- }
22
- }
23
- exports.IoEventEmitter = IoEventEmitter;