@remotion/media 4.0.393 → 4.0.395

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.
@@ -38,17 +38,17 @@ const extractAudioInternal = async ({ src, timeInSeconds: unloopedTimeInSeconds,
38
38
  if (timeInSeconds === null) {
39
39
  return { data: null, durationInSeconds: mediaDurationInSeconds };
40
40
  }
41
- const sampleIterator = await audioManager.getIterator({
42
- src,
43
- timeInSeconds,
44
- audioSampleSink: audio.sampleSink,
45
- isMatroska,
46
- actualMatroskaTimestamps,
47
- logLevel,
48
- maxCacheSize,
49
- });
50
- const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
51
41
  try {
42
+ const sampleIterator = await audioManager.getIterator({
43
+ src,
44
+ timeInSeconds,
45
+ audioSampleSink: audio.sampleSink,
46
+ isMatroska,
47
+ actualMatroskaTimestamps,
48
+ logLevel,
49
+ maxCacheSize,
50
+ });
51
+ const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
52
52
  const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
53
53
  audioManager.logOpenFrames();
54
54
  const audioDataArray = [];
@@ -3085,17 +3085,17 @@ var extractAudioInternal = async ({
3085
3085
  if (timeInSeconds === null) {
3086
3086
  return { data: null, durationInSeconds: mediaDurationInSeconds };
3087
3087
  }
3088
- const sampleIterator = await audioManager.getIterator({
3089
- src,
3090
- timeInSeconds,
3091
- audioSampleSink: audio.sampleSink,
3092
- isMatroska,
3093
- actualMatroskaTimestamps,
3094
- logLevel,
3095
- maxCacheSize
3096
- });
3097
- const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
3098
3088
  try {
3089
+ const sampleIterator = await audioManager.getIterator({
3090
+ src,
3091
+ timeInSeconds,
3092
+ audioSampleSink: audio.sampleSink,
3093
+ isMatroska,
3094
+ actualMatroskaTimestamps,
3095
+ logLevel,
3096
+ maxCacheSize
3097
+ });
3098
+ const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
3099
3099
  const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
3100
3100
  audioManager.logOpenFrames();
3101
3101
  const audioDataArray = [];
@@ -3387,8 +3387,26 @@ var extractFrameAndAudio = async ({
3387
3387
  }
3388
3388
  };
3389
3389
 
3390
- // src/video-extraction/extract-frame-via-broadcast-channel.ts
3391
- if (typeof window !== "undefined" && window.remotion_broadcastChannel && window.remotion_isMainTab) {
3390
+ // src/video-extraction/add-broadcast-channel-listener.ts
3391
+ var emitReadiness = (channel) => {
3392
+ channel.postMessage({
3393
+ type: "main-tab-ready"
3394
+ });
3395
+ let times = 0;
3396
+ const interval = setInterval(() => {
3397
+ channel.postMessage({
3398
+ type: "main-tab-ready"
3399
+ });
3400
+ times++;
3401
+ if (times > 30) {
3402
+ clearInterval(interval);
3403
+ }
3404
+ }, 300);
3405
+ };
3406
+ var addBroadcastChannelListener = () => {
3407
+ if (!(typeof window !== "undefined" && window.remotion_broadcastChannel && window.remotion_isMainTab)) {
3408
+ return;
3409
+ }
3392
3410
  window.remotion_broadcastChannel.addEventListener("message", async (event) => {
3393
3411
  const data = event.data;
3394
3412
  if (data.type === "request") {
@@ -3467,8 +3485,29 @@ if (typeof window !== "undefined" && window.remotion_broadcastChannel && window.
3467
3485
  throw new Error("Invalid message: " + JSON.stringify(data));
3468
3486
  }
3469
3487
  });
3470
- }
3471
- var extractFrameViaBroadcastChannel = ({
3488
+ emitReadiness(window.remotion_broadcastChannel);
3489
+ };
3490
+ var mainTabIsReadyProm = null;
3491
+ var waitForMainTabToBeReady = (channel) => {
3492
+ if (mainTabIsReadyProm) {
3493
+ return mainTabIsReadyProm;
3494
+ }
3495
+ mainTabIsReadyProm = new Promise((resolve) => {
3496
+ const onMessage = (event) => {
3497
+ const data = event.data;
3498
+ if (data.type === "main-tab-ready") {
3499
+ resolve();
3500
+ channel.removeEventListener("message", onMessage);
3501
+ }
3502
+ };
3503
+ channel.addEventListener("message", onMessage);
3504
+ });
3505
+ return mainTabIsReadyProm;
3506
+ };
3507
+
3508
+ // src/video-extraction/extract-frame-via-broadcast-channel.ts
3509
+ addBroadcastChannelListener();
3510
+ var extractFrameViaBroadcastChannel = async ({
3472
3511
  src,
3473
3512
  timeInSeconds,
3474
3513
  logLevel,
@@ -3501,6 +3540,7 @@ var extractFrameViaBroadcastChannel = ({
3501
3540
  maxCacheSize
3502
3541
  });
3503
3542
  }
3543
+ await waitForMainTabToBeReady(window.remotion_broadcastChannel);
3504
3544
  const requestId = crypto.randomUUID();
3505
3545
  const resolvePromise = new Promise((resolve, reject) => {
3506
3546
  const onMessage = (event) => {
@@ -3508,6 +3548,9 @@ var extractFrameViaBroadcastChannel = ({
3508
3548
  if (!data) {
3509
3549
  return;
3510
3550
  }
3551
+ if (data.type === "main-tab-ready") {
3552
+ return;
3553
+ }
3511
3554
  if (data.id !== requestId) {
3512
3555
  return;
3513
3556
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Utility to check if error is network error
3
+ * @param error
4
+ * @returns
5
+ */
6
+ export declare function isNetworkError(error: Error): boolean;
@@ -0,0 +1,17 @@
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
+ }
@@ -0,0 +1,48 @@
1
+ import type { LogLevel } from 'remotion';
2
+ import type { PcmS16AudioData } from '../convert-audiodata/convert-audiodata';
3
+ export type MessageFromMainTab = {
4
+ type: 'response-success';
5
+ id: string;
6
+ frame: ImageBitmap | null;
7
+ audio: PcmS16AudioData | null;
8
+ durationInSeconds: number | null;
9
+ } | {
10
+ type: 'response-error';
11
+ id: string;
12
+ errorStack: string;
13
+ } | {
14
+ type: 'response-cannot-decode';
15
+ id: string;
16
+ durationInSeconds: number | null;
17
+ } | {
18
+ type: 'response-cannot-decode-alpha';
19
+ id: string;
20
+ durationInSeconds: number | null;
21
+ } | {
22
+ type: 'response-network-error';
23
+ id: string;
24
+ } | {
25
+ type: 'response-unknown-container-format';
26
+ id: string;
27
+ } | {
28
+ type: 'main-tab-ready';
29
+ };
30
+ export type ExtractFrameRequest = {
31
+ type: 'request';
32
+ src: string;
33
+ timeInSeconds: number;
34
+ durationInSeconds: number;
35
+ playbackRate: number;
36
+ id: string;
37
+ logLevel: LogLevel;
38
+ includeAudio: boolean;
39
+ includeVideo: boolean;
40
+ loop: boolean;
41
+ audioStreamIndex: number;
42
+ trimAfter: number | undefined;
43
+ trimBefore: number | undefined;
44
+ fps: number;
45
+ maxCacheSize: number;
46
+ };
47
+ export declare const addBroadcastChannelListener: () => void;
48
+ export declare const waitForMainTabToBeReady: (channel: BroadcastChannel) => Promise<void>;
@@ -0,0 +1,125 @@
1
+ import { extractFrameAndAudio } from '../extract-frame-and-audio';
2
+ // Send to other channels a message to let them know that the
3
+ // tab was loaded and is ready to receive requests.
4
+ // Emit "readiness" messages for approximately 10 seconds.
5
+ const emitReadiness = (channel) => {
6
+ channel.postMessage({
7
+ type: 'main-tab-ready',
8
+ });
9
+ let times = 0;
10
+ const interval = setInterval(() => {
11
+ channel.postMessage({
12
+ type: 'main-tab-ready',
13
+ });
14
+ times++;
15
+ if (times > 30) {
16
+ clearInterval(interval);
17
+ }
18
+ }, 300);
19
+ };
20
+ export const addBroadcastChannelListener = () => {
21
+ // Doesn't exist in studio
22
+ if (!(typeof window !== 'undefined' &&
23
+ window.remotion_broadcastChannel &&
24
+ window.remotion_isMainTab)) {
25
+ return;
26
+ }
27
+ window.remotion_broadcastChannel.addEventListener('message', async (event) => {
28
+ const data = event.data;
29
+ if (data.type === 'request') {
30
+ try {
31
+ const result = await extractFrameAndAudio({
32
+ src: data.src,
33
+ timeInSeconds: data.timeInSeconds,
34
+ logLevel: data.logLevel,
35
+ durationInSeconds: data.durationInSeconds,
36
+ playbackRate: data.playbackRate,
37
+ includeAudio: data.includeAudio,
38
+ includeVideo: data.includeVideo,
39
+ loop: data.loop,
40
+ audioStreamIndex: data.audioStreamIndex,
41
+ trimAfter: data.trimAfter,
42
+ trimBefore: data.trimBefore,
43
+ fps: data.fps,
44
+ maxCacheSize: data.maxCacheSize,
45
+ });
46
+ if (result.type === 'cannot-decode') {
47
+ const cannotDecodeResponse = {
48
+ type: 'response-cannot-decode',
49
+ id: data.id,
50
+ durationInSeconds: result.durationInSeconds,
51
+ };
52
+ window.remotion_broadcastChannel.postMessage(cannotDecodeResponse);
53
+ return;
54
+ }
55
+ if (result.type === 'cannot-decode-alpha') {
56
+ const cannotDecodeAlphaResponse = {
57
+ type: 'response-cannot-decode-alpha',
58
+ id: data.id,
59
+ durationInSeconds: result.durationInSeconds,
60
+ };
61
+ window.remotion_broadcastChannel.postMessage(cannotDecodeAlphaResponse);
62
+ return;
63
+ }
64
+ if (result.type === 'network-error') {
65
+ const networkErrorResponse = {
66
+ type: 'response-network-error',
67
+ id: data.id,
68
+ };
69
+ window.remotion_broadcastChannel.postMessage(networkErrorResponse);
70
+ return;
71
+ }
72
+ if (result.type === 'unknown-container-format') {
73
+ const unknownContainerFormatResponse = {
74
+ type: 'response-unknown-container-format',
75
+ id: data.id,
76
+ };
77
+ window.remotion_broadcastChannel.postMessage(unknownContainerFormatResponse);
78
+ return;
79
+ }
80
+ const { frame, audio, durationInSeconds } = result;
81
+ const imageBitmap = frame ? await createImageBitmap(frame) : null;
82
+ if (frame) {
83
+ frame.close();
84
+ }
85
+ const response = {
86
+ type: 'response-success',
87
+ id: data.id,
88
+ frame: imageBitmap,
89
+ audio,
90
+ durationInSeconds: durationInSeconds ?? null,
91
+ };
92
+ window.remotion_broadcastChannel.postMessage(response);
93
+ }
94
+ catch (error) {
95
+ const response = {
96
+ type: 'response-error',
97
+ id: data.id,
98
+ errorStack: error.stack ?? 'No stack trace',
99
+ };
100
+ window.remotion_broadcastChannel.postMessage(response);
101
+ }
102
+ }
103
+ else {
104
+ throw new Error('Invalid message: ' + JSON.stringify(data));
105
+ }
106
+ });
107
+ emitReadiness(window.remotion_broadcastChannel);
108
+ };
109
+ let mainTabIsReadyProm = null;
110
+ export const waitForMainTabToBeReady = (channel) => {
111
+ if (mainTabIsReadyProm) {
112
+ return mainTabIsReadyProm;
113
+ }
114
+ mainTabIsReadyProm = new Promise((resolve) => {
115
+ const onMessage = (event) => {
116
+ const data = event.data;
117
+ if (data.type === 'main-tab-ready') {
118
+ resolve();
119
+ channel.removeEventListener('message', onMessage);
120
+ }
121
+ };
122
+ channel.addEventListener('message', onMessage);
123
+ });
124
+ return mainTabIsReadyProm;
125
+ };
@@ -1,90 +1,7 @@
1
1
  import { extractFrameAndAudio } from '../extract-frame-and-audio';
2
- // Doesn't exist in studio
3
- if (typeof window !== 'undefined' &&
4
- window.remotion_broadcastChannel &&
5
- window.remotion_isMainTab) {
6
- window.remotion_broadcastChannel.addEventListener('message', async (event) => {
7
- const data = event.data;
8
- if (data.type === 'request') {
9
- try {
10
- const result = await extractFrameAndAudio({
11
- src: data.src,
12
- timeInSeconds: data.timeInSeconds,
13
- logLevel: data.logLevel,
14
- durationInSeconds: data.durationInSeconds,
15
- playbackRate: data.playbackRate,
16
- includeAudio: data.includeAudio,
17
- includeVideo: data.includeVideo,
18
- loop: data.loop,
19
- audioStreamIndex: data.audioStreamIndex,
20
- trimAfter: data.trimAfter,
21
- trimBefore: data.trimBefore,
22
- fps: data.fps,
23
- maxCacheSize: data.maxCacheSize,
24
- });
25
- if (result.type === 'cannot-decode') {
26
- const cannotDecodeResponse = {
27
- type: 'response-cannot-decode',
28
- id: data.id,
29
- durationInSeconds: result.durationInSeconds,
30
- };
31
- window.remotion_broadcastChannel.postMessage(cannotDecodeResponse);
32
- return;
33
- }
34
- if (result.type === 'cannot-decode-alpha') {
35
- const cannotDecodeAlphaResponse = {
36
- type: 'response-cannot-decode-alpha',
37
- id: data.id,
38
- durationInSeconds: result.durationInSeconds,
39
- };
40
- window.remotion_broadcastChannel.postMessage(cannotDecodeAlphaResponse);
41
- return;
42
- }
43
- if (result.type === 'network-error') {
44
- const networkErrorResponse = {
45
- type: 'response-network-error',
46
- id: data.id,
47
- };
48
- window.remotion_broadcastChannel.postMessage(networkErrorResponse);
49
- return;
50
- }
51
- if (result.type === 'unknown-container-format') {
52
- const unknownContainerFormatResponse = {
53
- type: 'response-unknown-container-format',
54
- id: data.id,
55
- };
56
- window.remotion_broadcastChannel.postMessage(unknownContainerFormatResponse);
57
- return;
58
- }
59
- const { frame, audio, durationInSeconds } = result;
60
- const imageBitmap = frame ? await createImageBitmap(frame) : null;
61
- if (frame) {
62
- frame.close();
63
- }
64
- const response = {
65
- type: 'response-success',
66
- id: data.id,
67
- frame: imageBitmap,
68
- audio,
69
- durationInSeconds: durationInSeconds ?? null,
70
- };
71
- window.remotion_broadcastChannel.postMessage(response);
72
- }
73
- catch (error) {
74
- const response = {
75
- type: 'response-error',
76
- id: data.id,
77
- errorStack: error.stack ?? 'No stack trace',
78
- };
79
- window.remotion_broadcastChannel.postMessage(response);
80
- }
81
- }
82
- else {
83
- throw new Error('Invalid message: ' + JSON.stringify(data));
84
- }
85
- });
86
- }
87
- export const extractFrameViaBroadcastChannel = ({ src, timeInSeconds, logLevel, durationInSeconds, playbackRate, includeAudio, includeVideo, isClientSideRendering, loop, audioStreamIndex, trimAfter, trimBefore, fps, maxCacheSize, }) => {
2
+ import { addBroadcastChannelListener, waitForMainTabToBeReady, } from './add-broadcast-channel-listener';
3
+ addBroadcastChannelListener();
4
+ export const extractFrameViaBroadcastChannel = async ({ src, timeInSeconds, logLevel, durationInSeconds, playbackRate, includeAudio, includeVideo, isClientSideRendering, loop, audioStreamIndex, trimAfter, trimBefore, fps, maxCacheSize, }) => {
88
5
  if (isClientSideRendering || window.remotion_isMainTab) {
89
6
  return extractFrameAndAudio({
90
7
  logLevel,
@@ -102,6 +19,7 @@ export const extractFrameViaBroadcastChannel = ({ src, timeInSeconds, logLevel,
102
19
  maxCacheSize,
103
20
  });
104
21
  }
22
+ await waitForMainTabToBeReady(window.remotion_broadcastChannel);
105
23
  const requestId = crypto.randomUUID();
106
24
  const resolvePromise = new Promise((resolve, reject) => {
107
25
  const onMessage = (event) => {
@@ -109,6 +27,9 @@ export const extractFrameViaBroadcastChannel = ({ src, timeInSeconds, logLevel,
109
27
  if (!data) {
110
28
  return;
111
29
  }
30
+ if (data.type === 'main-tab-ready') {
31
+ return;
32
+ }
112
33
  if (data.id !== requestId) {
113
34
  return;
114
35
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/media",
3
- "version": "4.0.393",
3
+ "version": "4.0.395",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -21,15 +21,15 @@
21
21
  "make": "tsc -d && bun --env-file=../.env.bundle bundle.ts"
22
22
  },
23
23
  "dependencies": {
24
- "mediabunny": "1.27.0",
25
- "remotion": "4.0.393"
24
+ "mediabunny": "1.27.2",
25
+ "remotion": "4.0.395"
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.393",
32
+ "@remotion/eslint-config-internal": "4.0.395",
33
33
  "@vitest/browser-webdriverio": "4.0.9",
34
34
  "eslint": "9.19.0",
35
35
  "react": "19.2.3",