@remotion/webcodecs 4.0.232 → 4.0.234

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 (48) hide show
  1. package/README.md +2 -2
  2. package/dist/audio-decoder-config.d.ts +2 -1
  3. package/dist/audio-decoder-config.js +44 -3
  4. package/dist/audio-decoder.d.ts +6 -3
  5. package/dist/audio-decoder.js +20 -4
  6. package/dist/audio-encoder.d.ts +3 -2
  7. package/dist/audio-encoder.js +11 -3
  8. package/dist/browser-quirks.d.ts +1 -0
  9. package/dist/browser-quirks.js +5 -1
  10. package/dist/can-copy-video-track.d.ts +3 -1
  11. package/dist/can-copy-video-track.js +6 -1
  12. package/dist/can-reencode-audio-track.d.ts +3 -2
  13. package/dist/can-reencode-audio-track.js +2 -2
  14. package/dist/convert-media.d.ts +2 -1
  15. package/dist/convert-media.js +7 -3
  16. package/dist/convert-to-correct-videoframe.js +4 -0
  17. package/dist/default-on-video-track-handler.js +8 -2
  18. package/dist/esm/index.mjs +352 -137
  19. package/dist/get-wave-audio-decoder.d.ts +2 -0
  20. package/dist/get-wave-audio-decoder.js +29 -0
  21. package/dist/index.d.ts +7 -0
  22. package/dist/index.js +6 -1
  23. package/dist/io-manager/event-emitter.d.ts +4 -0
  24. package/dist/io-manager/event-emitter.js +1 -0
  25. package/dist/io-manager/io-synchronizer.d.ts +8 -2
  26. package/dist/io-manager/io-synchronizer.js +31 -20
  27. package/dist/io-manager/make-timeout-promise.d.ts +4 -0
  28. package/dist/io-manager/make-timeout-promise.js +18 -0
  29. package/dist/on-audio-track.d.ts +3 -2
  30. package/dist/on-audio-track.js +6 -3
  31. package/dist/on-frame.d.ts +2 -1
  32. package/dist/on-frame.js +25 -14
  33. package/dist/on-video-track-handler.d.ts +2 -0
  34. package/dist/on-video-track.d.ts +4 -2
  35. package/dist/on-video-track.js +21 -5
  36. package/dist/rotate-video-frame.d.ts +5 -0
  37. package/dist/rotate-video-frame.js +48 -0
  38. package/dist/rotate-video.d.ts +4 -0
  39. package/dist/rotate-video.js +43 -0
  40. package/dist/rotation.d.ts +8 -0
  41. package/dist/rotation.js +10 -0
  42. package/dist/select-container-creator.d.ts +1 -1
  43. package/dist/test/avi-to-mp4.test.js +15 -0
  44. package/dist/video-decoder.d.ts +3 -2
  45. package/dist/video-decoder.js +11 -3
  46. package/dist/video-encoder.d.ts +3 -2
  47. package/dist/video-encoder.js +7 -2
  48. package/package.json +5 -3
package/README.md CHANGED
@@ -18,7 +18,7 @@ Remove the `^` character from the version number to use the exact version.
18
18
  See the [documentation](https://remotion.dev/webcodecs) for more information.
19
19
 
20
20
  ## License
21
- This package is licensed under the [/docs/license](Remotion License).
21
+ This package is licensed under the [Remotion License](/docs/license).
22
22
  We consider a team of 4 or more people a "company".
23
23
 
24
24
  **For "companies"**: A Remotion Company license needs to be obtained to use this package.
@@ -26,4 +26,4 @@ In a future version of `@remotion/webcodecs`, this package will also require the
26
26
 
27
27
  **For individuals and teams up to 3**: You can use this package for free.
28
28
 
29
- This is a short, non-binding explanation of our license. See the [https://remotion.dev/docs/license](License) itself for more details.
29
+ This is a short, non-binding explanation of our license. See the [License](https://remotion.dev/docs/license) itself for more details.
@@ -1 +1,2 @@
1
- export declare const getAudioDecoderConfig: (config: AudioDecoderConfig) => Promise<AudioDecoderConfig | null>;
1
+ import type { LogLevel } from './log';
2
+ export declare const getAudioDecoderConfig: (config: AudioDecoderConfig, logLevel: LogLevel) => Promise<AudioDecoderConfig | null>;
@@ -1,15 +1,56 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAudioDecoderConfig = void 0;
4
- const getAudioDecoderConfig = async (config) => {
4
+ const browser_quirks_1 = require("./browser-quirks");
5
+ const log_1 = require("./log");
6
+ const overrideBrowserQuirks = ({ config, logLevel, }) => {
7
+ const bytes = config.description;
8
+ if (!bytes) {
9
+ return config;
10
+ }
11
+ if (bytes[0] === 18 && bytes[1] === 8) {
12
+ // riverside_use_cursor_.mp4
13
+ if ((0, browser_quirks_1.isFirefox)()) {
14
+ return {
15
+ ...config,
16
+ codec: 'mp4a.40.2',
17
+ description: bytes,
18
+ };
19
+ }
20
+ if (!(0, browser_quirks_1.isChrome)()) {
21
+ return config;
22
+ }
23
+ log_1.Log.warn(logLevel, 'Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330');
24
+ return {
25
+ ...config,
26
+ description: new Uint8Array([18, 16]),
27
+ };
28
+ }
29
+ if (bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136) {
30
+ log_1.Log.warn(logLevel, 'Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330');
31
+ return {
32
+ ...config,
33
+ description: new Uint8Array([18, 144]),
34
+ };
35
+ }
36
+ return config;
37
+ };
38
+ const getAudioDecoderConfig = async (config, logLevel) => {
39
+ if (config.codec === 'pcm-s16') {
40
+ return config;
41
+ }
5
42
  if (typeof AudioDecoder === 'undefined') {
6
43
  return null;
7
44
  }
8
45
  if (typeof EncodedAudioChunk === 'undefined') {
9
46
  return null;
10
47
  }
11
- if ((await AudioDecoder.isConfigSupported(config)).supported) {
12
- return config;
48
+ const realConfig = overrideBrowserQuirks({
49
+ config,
50
+ logLevel,
51
+ });
52
+ if ((await AudioDecoder.isConfigSupported(realConfig)).supported) {
53
+ return realConfig;
13
54
  }
14
55
  return null;
15
56
  };
@@ -1,14 +1,17 @@
1
- import type { AudioOrVideoSample, LogLevel } from '@remotion/media-parser';
1
+ import type { AudioOrVideoSample, AudioTrack, LogLevel, ProgressTracker } from '@remotion/media-parser';
2
2
  export type WebCodecsAudioDecoder = {
3
3
  processSample: (audioSample: AudioOrVideoSample) => Promise<void>;
4
4
  waitForFinish: () => Promise<void>;
5
5
  close: () => void;
6
6
  flush: () => Promise<void>;
7
7
  };
8
- export declare const createAudioDecoder: ({ onFrame, onError, signal, config, logLevel, }: {
8
+ export type CreateAudioDecoderInit = {
9
9
  onFrame: (frame: AudioData) => Promise<void>;
10
10
  onError: (error: DOMException) => void;
11
11
  signal: AbortSignal;
12
12
  config: AudioDecoderConfig;
13
13
  logLevel: LogLevel;
14
- }) => WebCodecsAudioDecoder;
14
+ track: AudioTrack;
15
+ progressTracker: ProgressTracker;
16
+ };
17
+ export declare const createAudioDecoder: ({ onFrame, onError, signal, config, logLevel, track, progressTracker, }: CreateAudioDecoderInit) => WebCodecsAudioDecoder;
@@ -1,12 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAudioDecoder = void 0;
4
+ const get_wave_audio_decoder_1 = require("./get-wave-audio-decoder");
4
5
  const io_synchronizer_1 = require("./io-manager/io-synchronizer");
5
- const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, }) => {
6
+ const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, track, progressTracker, }) => {
6
7
  if (signal.aborted) {
7
8
  throw new Error('Not creating audio decoder, already aborted');
8
9
  }
9
- const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)(logLevel, 'Audio decoder');
10
+ if (config.codec === 'pcm-s16') {
11
+ return (0, get_wave_audio_decoder_1.getWaveAudioDecoder)({ onFrame, track });
12
+ }
13
+ const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
14
+ logLevel,
15
+ label: 'Audio decoder',
16
+ progress: progressTracker,
17
+ });
10
18
  let outputQueue = Promise.resolve();
11
19
  const audioDecoder = new AudioDecoder({
12
20
  output(inputFrame) {
@@ -53,7 +61,11 @@ const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, }) =>
53
61
  if (audioDecoder.state === 'closed') {
54
62
  return;
55
63
  }
56
- await ioSynchronizer.waitFor({ unemitted: 100, _unprocessed: 2 });
64
+ await ioSynchronizer.waitFor({
65
+ unemitted: 20,
66
+ _unprocessed: 20,
67
+ minimumProgress: audioSample.timestamp - 10000000,
68
+ });
57
69
  // Don't flush, it messes up the audio
58
70
  const chunk = new EncodedAudioChunk(audioSample);
59
71
  audioDecoder.decode(chunk);
@@ -71,7 +83,11 @@ const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, }) =>
71
83
  return queue;
72
84
  },
73
85
  waitForFinish: async () => {
74
- await audioDecoder.flush();
86
+ // Firefox might throw "Needs to be configured first"
87
+ try {
88
+ await audioDecoder.flush();
89
+ }
90
+ catch (_a) { }
75
91
  await queue;
76
92
  await ioSynchronizer.waitForFinish();
77
93
  await outputQueue;
@@ -1,4 +1,4 @@
1
- import type { LogLevel } from '@remotion/media-parser';
1
+ import type { LogLevel, ProgressTracker } from '@remotion/media-parser';
2
2
  import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
3
3
  export type WebCodecsAudioEncoder = {
4
4
  encodeFrame: (audioData: AudioData) => Promise<void>;
@@ -14,5 +14,6 @@ export type AudioEncoderInit = {
14
14
  config: AudioEncoderConfig;
15
15
  logLevel: LogLevel;
16
16
  onNewAudioSampleRate: (sampleRate: number) => void;
17
+ progressTracker: ProgressTracker;
17
18
  };
18
- export declare const createAudioEncoder: ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, }: AudioEncoderInit) => WebCodecsAudioEncoder;
19
+ export declare const createAudioEncoder: ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, progressTracker, }: AudioEncoderInit) => WebCodecsAudioEncoder;
@@ -3,14 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAudioEncoder = void 0;
4
4
  const io_synchronizer_1 = require("./io-manager/io-synchronizer");
5
5
  const wav_audio_encoder_1 = require("./wav-audio-encoder");
6
- const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, }) => {
6
+ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, progressTracker, }) => {
7
7
  if (signal.aborted) {
8
8
  throw new Error('Not creating audio encoder, already aborted');
9
9
  }
10
10
  if (codec === 'wav') {
11
11
  return (0, wav_audio_encoder_1.getWaveAudioEncoder)({ onChunk, signal });
12
12
  }
13
- const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)(logLevel, 'Audio encoder');
13
+ const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
14
+ logLevel,
15
+ label: 'Audio encoder',
16
+ progress: progressTracker,
17
+ });
14
18
  let prom = Promise.resolve();
15
19
  const encoder = new AudioEncoder({
16
20
  output: (chunk) => {
@@ -54,7 +58,11 @@ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEnco
54
58
  if (encoder.state === 'closed') {
55
59
  return;
56
60
  }
57
- await ioSynchronizer.waitFor({ unemitted: 20, _unprocessed: 20 });
61
+ await ioSynchronizer.waitFor({
62
+ unemitted: 20,
63
+ _unprocessed: 20,
64
+ minimumProgress: audioData.timestamp - 10000000,
65
+ });
58
66
  // @ts-expect-error - can have changed in the meanwhile
59
67
  if (encoder.state === 'closed') {
60
68
  return;
@@ -1,2 +1,3 @@
1
1
  export declare const isFirefox: () => boolean;
2
2
  export declare const isSafari: () => boolean;
3
+ export declare const isChrome: () => boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isSafari = exports.isFirefox = void 0;
3
+ exports.isChrome = exports.isSafari = exports.isFirefox = void 0;
4
4
  const isFirefox = () => {
5
5
  return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
6
6
  };
@@ -9,3 +9,7 @@ const isSafari = () => {
9
9
  return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
10
10
  };
11
11
  exports.isSafari = isSafari;
12
+ const isChrome = () => {
13
+ return navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
14
+ };
15
+ exports.isChrome = isChrome;
@@ -1,6 +1,8 @@
1
1
  import type { MediaParserVideoCodec } from '@remotion/media-parser';
2
2
  import type { ConvertMediaContainer } from './get-available-containers';
3
- export declare const canCopyVideoTrack: ({ inputCodec, container, }: {
3
+ export declare const canCopyVideoTrack: ({ inputCodec, container, inputRotation, rotationToApply, }: {
4
4
  inputCodec: MediaParserVideoCodec;
5
+ inputRotation: number;
6
+ rotationToApply: number;
5
7
  container: ConvertMediaContainer;
6
8
  }) => boolean;
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canCopyVideoTrack = void 0;
4
- const canCopyVideoTrack = ({ inputCodec, container, }) => {
4
+ const rotate_video_frame_1 = require("./rotate-video-frame");
5
+ const canCopyVideoTrack = ({ inputCodec, container, inputRotation, rotationToApply, }) => {
6
+ if ((0, rotate_video_frame_1.normalizeVideoRotation)(inputRotation) !==
7
+ (0, rotate_video_frame_1.normalizeVideoRotation)(rotationToApply)) {
8
+ return false;
9
+ }
5
10
  if (container === 'webm') {
6
11
  return inputCodec === 'vp8' || inputCodec === 'vp9';
7
12
  }
@@ -1,7 +1,8 @@
1
- import type { AudioTrack } from '@remotion/media-parser';
1
+ import type { AudioTrack, LogLevel } from '@remotion/media-parser';
2
2
  import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
3
- export declare const canReencodeAudioTrack: ({ track, audioCodec, bitrate, }: {
3
+ export declare const canReencodeAudioTrack: ({ track, audioCodec, bitrate, logLevel, }: {
4
4
  track: AudioTrack;
5
5
  audioCodec: ConvertMediaAudioCodec;
6
6
  bitrate: number;
7
+ logLevel?: LogLevel;
7
8
  }) => Promise<boolean>;
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canReencodeAudioTrack = void 0;
4
4
  const audio_decoder_config_1 = require("./audio-decoder-config");
5
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)(track);
6
+ const canReencodeAudioTrack = async ({ track, audioCodec, bitrate, logLevel = 'info', }) => {
7
+ const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)(track, logLevel);
8
8
  if (audioCodec === 'wav' && audioDecoderConfig) {
9
9
  return true;
10
10
  }
@@ -28,7 +28,7 @@ export type ConvertMediaOnVideoFrame = (options: {
28
28
  frame: VideoFrame;
29
29
  track: VideoTrack;
30
30
  }) => Promise<VideoFrame> | VideoFrame;
31
- export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel, writer, progressIntervalInMs, ...more }: {
31
+ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel, writer, progressIntervalInMs, rotate, ...more }: {
32
32
  src: ParseMediaOptions<F>["src"];
33
33
  container: ConvertMediaContainer;
34
34
  onVideoFrame?: ConvertMediaOnVideoFrame;
@@ -42,4 +42,5 @@ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src,
42
42
  logLevel?: LogLevel;
43
43
  writer?: WriterInterface;
44
44
  progressIntervalInMs?: number;
45
+ rotate?: number;
45
46
  } & ParseMediaDynamicOptions<F>) => Promise<ConvertMediaResult>;
@@ -17,8 +17,7 @@ const on_audio_track_1 = require("./on-audio-track");
17
17
  const on_video_track_1 = require("./on-video-track");
18
18
  const select_container_creator_1 = require("./select-container-creator");
19
19
  const throttled_state_update_1 = require("./throttled-state-update");
20
- const with_resolvers_1 = require("./with-resolvers");
21
- const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, ...more }) {
20
+ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, rotate, ...more }) {
22
21
  var _a, _b;
23
22
  if (userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.aborted) {
24
23
  return Promise.reject(new error_cause_1.default('Aborted'));
@@ -29,7 +28,7 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
29
28
  if (videoCodec && videoCodec !== 'vp8' && videoCodec !== 'vp9') {
30
29
  return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
31
30
  }
32
- const { resolve, reject, getPromiseToImmediatelyReturn } = (0, with_resolvers_1.withResolversAndWaitForReturn)();
31
+ const { resolve, reject, getPromiseToImmediatelyReturn } = media_parser_1.MediaParserInternals.withResolversAndWaitForReturn();
33
32
  const controller = new AbortController();
34
33
  const abortConversion = (errCause) => {
35
34
  reject(errCause);
@@ -47,6 +46,7 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
47
46
  everyMilliseconds: progressIntervalInMs !== null && progressIntervalInMs !== void 0 ? progressIntervalInMs : 100,
48
47
  signal: controller.signal,
49
48
  });
49
+ const progressTracker = media_parser_1.MediaParserInternals.makeProgressTracker();
50
50
  const state = await creator({
51
51
  filename: (0, generate_output_filename_1.generateOutputFilename)(src, container),
52
52
  writer: await (0, auto_select_writer_1.autoSelectWriter)(writer, logLevel),
@@ -76,6 +76,7 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
76
76
  });
77
77
  },
78
78
  logLevel,
79
+ progressTracker,
79
80
  });
80
81
  const onVideoTrack = (0, on_video_track_1.makeVideoTrackHandler)({
81
82
  state,
@@ -87,6 +88,8 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
87
88
  onVideoTrack: userVideoResolver !== null && userVideoResolver !== void 0 ? userVideoResolver : null,
88
89
  logLevel,
89
90
  container,
91
+ rotate: rotate !== null && rotate !== void 0 ? rotate : 0,
92
+ progress: progressTracker,
90
93
  });
91
94
  const onAudioTrack = (0, on_audio_track_1.makeAudioTrackHandler)({
92
95
  abortConversion,
@@ -97,6 +100,7 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
97
100
  onAudioTrack: userAudioResolver !== null && userAudioResolver !== void 0 ? userAudioResolver : null,
98
101
  logLevel,
99
102
  container,
103
+ progressTracker,
100
104
  });
101
105
  (0, media_parser_1.parseMedia)({
102
106
  logLevel,
@@ -7,6 +7,10 @@ const needsToCorrectVideoFrame = ({ videoFrame, outputCodec, }) => {
7
7
  if (videoFrame.format === null) {
8
8
  return true;
9
9
  }
10
+ // copy8f9178c2-e8ab-4538-9591-f8336602e49b-3mp4 - HDR videos
11
+ if (videoFrame.format === 'I420P10') {
12
+ return true;
13
+ }
10
14
  return (0, browser_quirks_1.isFirefox)() && videoFrame.format === 'BGRX' && outputCodec === 'h264';
11
15
  };
12
16
  exports.needsToCorrectVideoFrame = needsToCorrectVideoFrame;
@@ -5,10 +5,12 @@ const media_parser_1 = require("@remotion/media-parser");
5
5
  const can_copy_video_track_1 = require("./can-copy-video-track");
6
6
  const can_reencode_video_track_1 = require("./can-reencode-video-track");
7
7
  const get_default_video_codec_1 = require("./get-default-video-codec");
8
- const defaultOnVideoTrackHandler = async ({ track, defaultVideoCodec, logLevel, container, }) => {
8
+ const defaultOnVideoTrackHandler = async ({ track, defaultVideoCodec, logLevel, container, rotate, }) => {
9
9
  const canCopy = (0, can_copy_video_track_1.canCopyVideoTrack)({
10
10
  inputCodec: track.codecWithoutConfig,
11
11
  container,
12
+ inputRotation: track.rotation,
13
+ rotationToApply: rotate,
12
14
  });
13
15
  if (canCopy) {
14
16
  media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
@@ -25,7 +27,11 @@ const defaultOnVideoTrackHandler = async ({ track, defaultVideoCodec, logLevel,
25
27
  });
26
28
  if (canReencode) {
27
29
  media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): Cannot copy, but re-enconde, therefore re-encoding`);
28
- return Promise.resolve({ type: 'reencode', videoCodec });
30
+ return Promise.resolve({
31
+ type: 'reencode',
32
+ videoCodec,
33
+ rotation: rotate - track.rotation,
34
+ });
29
35
  }
30
36
  media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
31
37
  return Promise.resolve({ type: 'fail' });