@remotion/media 4.0.382 → 4.0.383

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.
@@ -4,6 +4,7 @@ import { convertAudioData, fixFloatingPoint, } from '../convert-audiodata/conver
4
4
  import { TARGET_NUMBER_OF_CHANNELS, TARGET_SAMPLE_RATE, } from '../convert-audiodata/resample-audiodata';
5
5
  import { getSink } from '../get-sink';
6
6
  import { getTimeInSeconds } from '../get-time-in-seconds';
7
+ import { isNetworkError, isUnsupportedConfigurationError, } from '../is-type-of-error';
7
8
  const extractAudioInternal = async ({ src, timeInSeconds: unloopedTimeInSeconds, durationInSeconds: durationNotYetApplyingPlaybackRate, logLevel, loop, playbackRate, audioStreamIndex, trimBefore, trimAfter, fps, maxCacheSize, }) => {
8
9
  const { getAudio, actualMatroskaTimestamps, isMatroska, getDuration } = await getSink(src, logLevel);
9
10
  let mediaDurationInSeconds = null;
@@ -47,70 +48,82 @@ const extractAudioInternal = async ({ src, timeInSeconds: unloopedTimeInSeconds,
47
48
  maxCacheSize,
48
49
  });
49
50
  const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
50
- const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
51
- audioManager.logOpenFrames();
52
- const audioDataArray = [];
53
- for (let i = 0; i < samples.length; i++) {
54
- const sample = samples[i];
55
- // Less than 1 sample would be included - we did not need it after all!
56
- if (Math.abs(sample.timestamp - (timeInSeconds + durationInSeconds)) *
57
- sample.sampleRate <
58
- 1) {
59
- continue;
60
- }
61
- // Less than 1 sample would be included - we did not need it after all!
62
- if (sample.timestamp + sample.duration <= timeInSeconds) {
63
- continue;
64
- }
65
- const isFirstSample = i === 0;
66
- const isLastSample = i === samples.length - 1;
67
- const audioDataRaw = sample.toAudioData();
68
- // amount of samples to shave from start and end
69
- let trimStartInSeconds = 0;
70
- let trimEndInSeconds = 0;
71
- let leadingSilence = null;
72
- if (isFirstSample) {
73
- trimStartInSeconds = fixFloatingPoint(timeInSeconds - sample.timestamp);
74
- if (trimStartInSeconds < 0) {
75
- const silenceFrames = Math.ceil(fixFloatingPoint(-trimStartInSeconds * TARGET_SAMPLE_RATE));
76
- leadingSilence = {
77
- data: new Int16Array(silenceFrames * TARGET_NUMBER_OF_CHANNELS),
78
- numberOfFrames: silenceFrames,
79
- timestamp: timeInSeconds * 1000000,
80
- durationInMicroSeconds: (silenceFrames / TARGET_SAMPLE_RATE) * 1000000,
81
- };
82
- trimStartInSeconds = 0;
51
+ try {
52
+ const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
53
+ audioManager.logOpenFrames();
54
+ const audioDataArray = [];
55
+ for (let i = 0; i < samples.length; i++) {
56
+ const sample = samples[i];
57
+ // Less than 1 sample would be included - we did not need it after all!
58
+ if (Math.abs(sample.timestamp - (timeInSeconds + durationInSeconds)) *
59
+ sample.sampleRate <
60
+ 1) {
61
+ continue;
62
+ }
63
+ // Less than 1 sample would be included - we did not need it after all!
64
+ if (sample.timestamp + sample.duration <= timeInSeconds) {
65
+ continue;
66
+ }
67
+ const isFirstSample = i === 0;
68
+ const isLastSample = i === samples.length - 1;
69
+ const audioDataRaw = sample.toAudioData();
70
+ // amount of samples to shave from start and end
71
+ let trimStartInSeconds = 0;
72
+ let trimEndInSeconds = 0;
73
+ let leadingSilence = null;
74
+ if (isFirstSample) {
75
+ trimStartInSeconds = fixFloatingPoint(timeInSeconds - sample.timestamp);
76
+ if (trimStartInSeconds < 0) {
77
+ const silenceFrames = Math.ceil(fixFloatingPoint(-trimStartInSeconds * TARGET_SAMPLE_RATE));
78
+ leadingSilence = {
79
+ data: new Int16Array(silenceFrames * TARGET_NUMBER_OF_CHANNELS),
80
+ numberOfFrames: silenceFrames,
81
+ timestamp: timeInSeconds * 1000000,
82
+ durationInMicroSeconds: (silenceFrames / TARGET_SAMPLE_RATE) * 1000000,
83
+ };
84
+ trimStartInSeconds = 0;
85
+ }
86
+ }
87
+ if (isLastSample) {
88
+ trimEndInSeconds =
89
+ // clamp to 0 in case the audio ends early
90
+ Math.max(0, sample.timestamp +
91
+ sample.duration -
92
+ (timeInSeconds + durationInSeconds));
83
93
  }
94
+ const audioData = convertAudioData({
95
+ audioData: audioDataRaw,
96
+ trimStartInSeconds,
97
+ trimEndInSeconds,
98
+ playbackRate,
99
+ audioDataTimestamp: sample.timestamp,
100
+ isLast: isLastSample,
101
+ });
102
+ audioDataRaw.close();
103
+ if (audioData.numberOfFrames === 0) {
104
+ continue;
105
+ }
106
+ if (leadingSilence) {
107
+ audioDataArray.push(leadingSilence);
108
+ }
109
+ audioDataArray.push(audioData);
84
110
  }
85
- if (isLastSample) {
86
- trimEndInSeconds =
87
- // clamp to 0 in case the audio ends early
88
- Math.max(0, sample.timestamp +
89
- sample.duration -
90
- (timeInSeconds + durationInSeconds));
111
+ if (audioDataArray.length === 0) {
112
+ return { data: null, durationInSeconds: mediaDurationInSeconds };
91
113
  }
92
- const audioData = convertAudioData({
93
- audioData: audioDataRaw,
94
- trimStartInSeconds,
95
- trimEndInSeconds,
96
- playbackRate,
97
- audioDataTimestamp: sample.timestamp,
98
- isLast: isLastSample,
99
- });
100
- audioDataRaw.close();
101
- if (audioData.numberOfFrames === 0) {
102
- continue;
114
+ const combined = combineAudioDataAndClosePrevious(audioDataArray);
115
+ return { data: combined, durationInSeconds: mediaDurationInSeconds };
116
+ }
117
+ catch (err) {
118
+ const error = err;
119
+ if (isNetworkError(error)) {
120
+ return 'network-error';
103
121
  }
104
- if (leadingSilence) {
105
- audioDataArray.push(leadingSilence);
122
+ if (isUnsupportedConfigurationError(error)) {
123
+ return 'cannot-decode';
106
124
  }
107
- audioDataArray.push(audioData);
108
- }
109
- if (audioDataArray.length === 0) {
110
- return { data: null, durationInSeconds: mediaDurationInSeconds };
125
+ throw err;
111
126
  }
112
- const combined = combineAudioDataAndClosePrevious(audioDataArray);
113
- return { data: combined, durationInSeconds: mediaDurationInSeconds };
114
127
  };
115
128
  let queue = Promise.resolve(undefined);
116
129
  export const extractAudio = (params) => {
@@ -538,13 +538,16 @@ var drawPreviewOverlay = ({
538
538
  }
539
539
  };
540
540
 
541
- // src/is-network-error.ts
541
+ // src/is-type-of-error.ts
542
542
  function isNetworkError(error) {
543
543
  if (error.message.includes("Failed to fetch") || error.message.includes("Load failed") || error.message.includes("NetworkError when attempting to fetch resource")) {
544
544
  return true;
545
545
  }
546
546
  return false;
547
547
  }
548
+ function isUnsupportedConfigurationError(error) {
549
+ return error.message.includes("Unsupported configuration");
550
+ }
548
551
 
549
552
  // src/nonce-manager.ts
550
553
  var makeNonceManager = () => {
@@ -2902,61 +2905,72 @@ var extractAudioInternal = async ({
2902
2905
  maxCacheSize
2903
2906
  });
2904
2907
  const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
2905
- const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
2906
- audioManager.logOpenFrames();
2907
- const audioDataArray = [];
2908
- for (let i = 0;i < samples.length; i++) {
2909
- const sample = samples[i];
2910
- if (Math.abs(sample.timestamp - (timeInSeconds + durationInSeconds)) * sample.sampleRate < 1) {
2911
- continue;
2912
- }
2913
- if (sample.timestamp + sample.duration <= timeInSeconds) {
2914
- continue;
2915
- }
2916
- const isFirstSample = i === 0;
2917
- const isLastSample = i === samples.length - 1;
2918
- const audioDataRaw = sample.toAudioData();
2919
- let trimStartInSeconds = 0;
2920
- let trimEndInSeconds = 0;
2921
- let leadingSilence = null;
2922
- if (isFirstSample) {
2923
- trimStartInSeconds = fixFloatingPoint2(timeInSeconds - sample.timestamp);
2924
- if (trimStartInSeconds < 0) {
2925
- const silenceFrames = Math.ceil(fixFloatingPoint2(-trimStartInSeconds * TARGET_SAMPLE_RATE));
2926
- leadingSilence = {
2927
- data: new Int16Array(silenceFrames * TARGET_NUMBER_OF_CHANNELS),
2928
- numberOfFrames: silenceFrames,
2929
- timestamp: timeInSeconds * 1e6,
2930
- durationInMicroSeconds: silenceFrames / TARGET_SAMPLE_RATE * 1e6
2931
- };
2932
- trimStartInSeconds = 0;
2908
+ try {
2909
+ const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
2910
+ audioManager.logOpenFrames();
2911
+ const audioDataArray = [];
2912
+ for (let i = 0;i < samples.length; i++) {
2913
+ const sample = samples[i];
2914
+ if (Math.abs(sample.timestamp - (timeInSeconds + durationInSeconds)) * sample.sampleRate < 1) {
2915
+ continue;
2933
2916
  }
2917
+ if (sample.timestamp + sample.duration <= timeInSeconds) {
2918
+ continue;
2919
+ }
2920
+ const isFirstSample = i === 0;
2921
+ const isLastSample = i === samples.length - 1;
2922
+ const audioDataRaw = sample.toAudioData();
2923
+ let trimStartInSeconds = 0;
2924
+ let trimEndInSeconds = 0;
2925
+ let leadingSilence = null;
2926
+ if (isFirstSample) {
2927
+ trimStartInSeconds = fixFloatingPoint2(timeInSeconds - sample.timestamp);
2928
+ if (trimStartInSeconds < 0) {
2929
+ const silenceFrames = Math.ceil(fixFloatingPoint2(-trimStartInSeconds * TARGET_SAMPLE_RATE));
2930
+ leadingSilence = {
2931
+ data: new Int16Array(silenceFrames * TARGET_NUMBER_OF_CHANNELS),
2932
+ numberOfFrames: silenceFrames,
2933
+ timestamp: timeInSeconds * 1e6,
2934
+ durationInMicroSeconds: silenceFrames / TARGET_SAMPLE_RATE * 1e6
2935
+ };
2936
+ trimStartInSeconds = 0;
2937
+ }
2938
+ }
2939
+ if (isLastSample) {
2940
+ trimEndInSeconds = Math.max(0, sample.timestamp + sample.duration - (timeInSeconds + durationInSeconds));
2941
+ }
2942
+ const audioData = convertAudioData({
2943
+ audioData: audioDataRaw,
2944
+ trimStartInSeconds,
2945
+ trimEndInSeconds,
2946
+ playbackRate,
2947
+ audioDataTimestamp: sample.timestamp,
2948
+ isLast: isLastSample
2949
+ });
2950
+ audioDataRaw.close();
2951
+ if (audioData.numberOfFrames === 0) {
2952
+ continue;
2953
+ }
2954
+ if (leadingSilence) {
2955
+ audioDataArray.push(leadingSilence);
2956
+ }
2957
+ audioDataArray.push(audioData);
2934
2958
  }
2935
- if (isLastSample) {
2936
- trimEndInSeconds = Math.max(0, sample.timestamp + sample.duration - (timeInSeconds + durationInSeconds));
2959
+ if (audioDataArray.length === 0) {
2960
+ return { data: null, durationInSeconds: mediaDurationInSeconds };
2937
2961
  }
2938
- const audioData = convertAudioData({
2939
- audioData: audioDataRaw,
2940
- trimStartInSeconds,
2941
- trimEndInSeconds,
2942
- playbackRate,
2943
- audioDataTimestamp: sample.timestamp,
2944
- isLast: isLastSample
2945
- });
2946
- audioDataRaw.close();
2947
- if (audioData.numberOfFrames === 0) {
2948
- continue;
2962
+ const combined = combineAudioDataAndClosePrevious(audioDataArray);
2963
+ return { data: combined, durationInSeconds: mediaDurationInSeconds };
2964
+ } catch (err) {
2965
+ const error = err;
2966
+ if (isNetworkError(error)) {
2967
+ return "network-error";
2949
2968
  }
2950
- if (leadingSilence) {
2951
- audioDataArray.push(leadingSilence);
2969
+ if (isUnsupportedConfigurationError(error)) {
2970
+ return "cannot-decode";
2952
2971
  }
2953
- audioDataArray.push(audioData);
2954
- }
2955
- if (audioDataArray.length === 0) {
2956
- return { data: null, durationInSeconds: mediaDurationInSeconds };
2972
+ throw err;
2957
2973
  }
2958
- const combined = combineAudioDataAndClosePrevious(audioDataArray);
2959
- return { data: combined, durationInSeconds: mediaDurationInSeconds };
2960
2974
  };
2961
2975
  var queue = Promise.resolve(undefined);
2962
2976
  var extractAudio = (params) => {
@@ -4115,7 +4129,7 @@ var VideoForRendering = ({
4115
4129
  cancelRender3(new Error(`Cannot decode ${src}, and 'disallowFallbackToOffthreadVideo' was set. Failing the render.`));
4116
4130
  }
4117
4131
  if (window.remotion_isMainTab) {
4118
- Internals16.Log.info({ logLevel, tag: "@remotion/media" }, `Cannot decode ${src}, falling back to <OffthreadVideo>`);
4132
+ Internals16.Log.warn({ logLevel, tag: "@remotion/media" }, `Cannot decode ${src}, falling back to <OffthreadVideo>`);
4119
4133
  }
4120
4134
  setReplaceWithOffthreadVideo({
4121
4135
  durationInSeconds: result.durationInSeconds
@@ -1,5 +1,5 @@
1
1
  import { extractAudio } from './audio-extraction/extract-audio';
2
- import { isNetworkError } from './is-network-error';
2
+ import { isNetworkError } from './is-type-of-error';
3
3
  import { extractFrame } from './video-extraction/extract-frame';
4
4
  import { rotateFrame } from './video-extraction/rotate-frame';
5
5
  export const extractFrameAndAudio = async ({ src, timeInSeconds, logLevel, durationInSeconds, playbackRate, includeAudio, includeVideo, loop, audioStreamIndex, trimAfter, trimBefore, fps, maxCacheSize, }) => {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Utility to check if error is network error
3
+ * @param error
4
+ * @returns
5
+ */
6
+ export declare function isNetworkError(error: Error): boolean;
7
+ export declare function isUnsupportedConfigurationError(error: Error): boolean;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Utility to check if error is network error
3
+ * @param error
4
+ * @returns
5
+ */
6
+ export function isNetworkError(error) {
7
+ if (
8
+ // Chrome
9
+ error.message.includes('Failed to fetch') ||
10
+ // Safari
11
+ error.message.includes('Load failed') ||
12
+ // Firefox
13
+ error.message.includes('NetworkError when attempting to fetch resource')) {
14
+ return true;
15
+ }
16
+ return false;
17
+ }
18
+ export function isUnsupportedConfigurationError(error) {
19
+ return error.message.includes('Unsupported configuration');
20
+ }
@@ -4,7 +4,7 @@ import { audioIteratorManager, } from './audio-iterator-manager';
4
4
  import { calculatePlaybackTime } from './calculate-playbacktime';
5
5
  import { drawPreviewOverlay } from './debug-overlay/preview-overlay';
6
6
  import { getTimeInSeconds } from './get-time-in-seconds';
7
- import { isNetworkError } from './is-network-error';
7
+ import { isNetworkError } from './is-type-of-error';
8
8
  import { makeNonceManager } from './nonce-manager';
9
9
  import { videoIteratorManager } from './video-iterator-manager';
10
10
  export class MediaPlayer {
@@ -92,7 +92,7 @@ export const VideoForRendering = ({ volume: volumeProp, playbackRate, src, muted
92
92
  cancelRender(new Error(`Cannot decode ${src}, and 'disallowFallbackToOffthreadVideo' was set. Failing the render.`));
93
93
  }
94
94
  if (window.remotion_isMainTab) {
95
- Internals.Log.info({ logLevel, tag: '@remotion/media' }, `Cannot decode ${src}, falling back to <OffthreadVideo>`);
95
+ Internals.Log.warn({ logLevel, tag: '@remotion/media' }, `Cannot decode ${src}, falling back to <OffthreadVideo>`);
96
96
  }
97
97
  setReplaceWithOffthreadVideo({
98
98
  durationInSeconds: result.durationInSeconds,
@@ -1,5 +1,5 @@
1
1
  import { ALL_FORMATS, AudioSampleSink, EncodedPacketSink, Input, MATROSKA, UrlSource, VideoSampleSink, WEBM, } from 'mediabunny';
2
- import { isNetworkError } from '../is-network-error';
2
+ import { isNetworkError } from '../is-type-of-error';
3
3
  import { makeKeyframeBank } from './keyframe-bank';
4
4
  import { rememberActualMatroskaTimestamps } from './remember-actual-matroska-timestamps';
5
5
  const getRetryDelay = (() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/media",
3
- "version": "4.0.382",
3
+ "version": "4.0.383",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -22,14 +22,14 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "mediabunny": "1.25.3",
25
- "remotion": "4.0.382"
25
+ "remotion": "4.0.383"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "react": ">=16.8.0",
29
29
  "react-dom": ">=16.8.0"
30
30
  },
31
31
  "devDependencies": {
32
- "@remotion/eslint-config-internal": "4.0.382",
32
+ "@remotion/eslint-config-internal": "4.0.383",
33
33
  "@vitest/browser-webdriverio": "4.0.7",
34
34
  "eslint": "9.19.0",
35
35
  "react": "19.2.1",