@remotion/media-utils 4.0.398 → 4.0.400

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.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/media-utils"
4
4
  },
5
5
  "name": "@remotion/media-utils",
6
- "version": "4.0.398",
6
+ "version": "4.0.400",
7
7
  "description": "Utilities for working with media files",
8
8
  "main": "dist/index.js",
9
9
  "sideEffects": false,
@@ -18,17 +18,17 @@
18
18
  "url": "https://github.com/remotion-dev/remotion/issues"
19
19
  },
20
20
  "dependencies": {
21
- "@remotion/media-parser": "4.0.398",
22
- "@remotion/webcodecs": "4.0.398",
23
- "remotion": "4.0.398",
24
- "mediabunny": "1.27.2"
21
+ "@remotion/media-parser": "4.0.400",
22
+ "@remotion/webcodecs": "4.0.400",
23
+ "remotion": "4.0.400",
24
+ "mediabunny": "1.27.3"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "react": ">=16.8.0",
28
28
  "react-dom": ">=16.8.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@remotion/eslint-config-internal": "4.0.398",
31
+ "@remotion/eslint-config-internal": "4.0.400",
32
32
  "eslint": "9.19.0"
33
33
  },
34
34
  "keywords": [
@@ -1,7 +0,0 @@
1
- export declare const getPartialMediaData: ({ src, fromSeconds, toSeconds, channelIndex, signal, }: {
2
- src: string;
3
- fromSeconds: number;
4
- toSeconds: number;
5
- channelIndex: number;
6
- signal: AbortSignal;
7
- }) => Promise<Float32Array>;
@@ -1,104 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPartialMediaData = void 0;
4
- const media_parser_1 = require("@remotion/media-parser");
5
- const webcodecs_1 = require("@remotion/webcodecs");
6
- const getPartialMediaData = async ({ src, fromSeconds, toSeconds, channelIndex, signal, }) => {
7
- const controller = (0, media_parser_1.mediaParserController)();
8
- // Collect audio samples
9
- const audioSamples = [];
10
- // Abort if the signal is already aborted
11
- if (signal.aborted) {
12
- throw new Error('Operation was aborted');
13
- }
14
- try {
15
- if (fromSeconds > 0) {
16
- controller.seek(fromSeconds);
17
- }
18
- await (0, media_parser_1.parseMedia)({
19
- src,
20
- controller,
21
- onAudioTrack: ({ track }) => {
22
- if (!track) {
23
- throw new Error('No audio track found');
24
- }
25
- const audioDecoder = (0, webcodecs_1.createAudioDecoder)({
26
- track,
27
- onFrame: (sample) => {
28
- if (signal.aborted) {
29
- sample.close();
30
- return;
31
- }
32
- // For multi-channel audio, we need to handle channels properly
33
- const { numberOfChannels } = sample;
34
- const samplesPerChannel = sample.numberOfFrames;
35
- let data;
36
- if (numberOfChannels === 1) {
37
- // Mono audio
38
- data = new Float32Array(sample.allocationSize({ format: 'f32', planeIndex: 0 }));
39
- sample.copyTo(data, { format: 'f32', planeIndex: 0 });
40
- }
41
- else {
42
- // Multi-channel audio: extract specific channel
43
- const allChannelsData = new Float32Array(sample.allocationSize({ format: 'f32', planeIndex: 0 }));
44
- sample.copyTo(allChannelsData, { format: 'f32', planeIndex: 0 });
45
- // Extract the specific channel (interleaved audio)
46
- data = new Float32Array(samplesPerChannel);
47
- for (let i = 0; i < samplesPerChannel; i++) {
48
- data[i] = allChannelsData[i * numberOfChannels + channelIndex];
49
- }
50
- }
51
- audioSamples.push(data);
52
- sample.close();
53
- },
54
- onError(error) {
55
- throw error;
56
- },
57
- });
58
- // Listen for abort signal
59
- const onAbort = () => {
60
- controller.abort();
61
- if (audioDecoder) {
62
- audioDecoder.close();
63
- }
64
- };
65
- signal.addEventListener('abort', onAbort, { once: true });
66
- return async (sample) => {
67
- if (signal.aborted) {
68
- return;
69
- }
70
- // Convert timestamp using the track's timescale
71
- const time = sample.timestamp / track.timescale;
72
- console.log(time);
73
- // Stop immediately when we reach our target time
74
- if (time >= toSeconds) {
75
- // abort media parsing, we reached the point where we want to stop
76
- controller.abort();
77
- return;
78
- }
79
- // Decode the sample using the sample directly
80
- await audioDecoder.waitForQueueToBeLessThan(10);
81
- // we're waiting for the queue above anyway, enqueue in sync mode
82
- audioDecoder.decode(sample);
83
- };
84
- },
85
- });
86
- }
87
- catch (err) {
88
- const isAbortedByTimeCutoff = (0, media_parser_1.hasBeenAborted)(err);
89
- // Don't throw if we stopped the parsing ourselves
90
- if (!isAbortedByTimeCutoff && !signal.aborted) {
91
- throw err;
92
- }
93
- }
94
- // Simply concatenate all audio data since windowing handles the time ranges
95
- const totalSamples = audioSamples.reduce((sum, sample) => sum + sample.length, 0);
96
- const result = new Float32Array(totalSamples);
97
- let offset = 0;
98
- for (const audioSample of audioSamples) {
99
- result.set(audioSample, offset);
100
- offset += audioSample.length;
101
- }
102
- return result;
103
- };
104
- exports.getPartialMediaData = getPartialMediaData;
@@ -1,7 +0,0 @@
1
- export declare const getPartialMediaData: ({ src, fromSeconds, toSeconds, channelIndex, signal, }: {
2
- src: string;
3
- fromSeconds: number;
4
- toSeconds: number;
5
- channelIndex: number;
6
- signal: AbortSignal;
7
- }) => Promise<Float32Array>;
@@ -1,105 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPartialMediaData = void 0;
4
- const media_parser_1 = require("@remotion/media-parser");
5
- const worker_1 = require("@remotion/media-parser/worker");
6
- const webcodecs_1 = require("@remotion/webcodecs");
7
- const getPartialMediaData = async ({ src, fromSeconds, toSeconds, channelIndex, signal, }) => {
8
- const controller = (0, media_parser_1.mediaParserController)();
9
- // Collect audio samples
10
- const audioSamples = [];
11
- // Abort if the signal is already aborted
12
- if (signal.aborted) {
13
- throw new Error('Operation was aborted');
14
- }
15
- try {
16
- if (fromSeconds > 0) {
17
- controller.seek(fromSeconds);
18
- }
19
- await (0, worker_1.parseMediaOnWebWorker)({
20
- src,
21
- controller,
22
- onAudioTrack: ({ track }) => {
23
- if (!track) {
24
- throw new Error('No audio track found');
25
- }
26
- const audioDecoder = (0, webcodecs_1.createAudioDecoder)({
27
- track,
28
- onFrame: (sample) => {
29
- if (signal.aborted) {
30
- sample.close();
31
- return;
32
- }
33
- // For multi-channel audio, we need to handle channels properly
34
- const { numberOfChannels } = sample;
35
- const samplesPerChannel = sample.numberOfFrames;
36
- let data;
37
- if (numberOfChannels === 1) {
38
- // Mono audio
39
- data = new Float32Array(sample.allocationSize({ format: 'f32', planeIndex: 0 }));
40
- sample.copyTo(data, { format: 'f32', planeIndex: 0 });
41
- }
42
- else {
43
- // Multi-channel audio: extract specific channel
44
- const allChannelsData = new Float32Array(sample.allocationSize({ format: 'f32', planeIndex: 0 }));
45
- sample.copyTo(allChannelsData, { format: 'f32', planeIndex: 0 });
46
- // Extract the specific channel (interleaved audio)
47
- data = new Float32Array(samplesPerChannel);
48
- for (let i = 0; i < samplesPerChannel; i++) {
49
- data[i] = allChannelsData[i * numberOfChannels + channelIndex];
50
- }
51
- }
52
- audioSamples.push(data);
53
- sample.close();
54
- },
55
- onError(error) {
56
- throw error;
57
- },
58
- });
59
- // Listen for abort signal
60
- const onAbort = () => {
61
- controller.abort();
62
- if (audioDecoder) {
63
- audioDecoder.close();
64
- }
65
- };
66
- signal.addEventListener('abort', onAbort, { once: true });
67
- return async (sample) => {
68
- if (signal.aborted) {
69
- return;
70
- }
71
- // Convert timestamp using the track's timescale
72
- const time = sample.timestamp / track.timescale;
73
- // Stop immediately when we reach our target time
74
- if (time >= toSeconds) {
75
- // abort media parsing, we reached the point where we want to stop
76
- controller.abort();
77
- await audioDecoder.flush();
78
- return;
79
- }
80
- // Decode the sample using the sample directly
81
- await audioDecoder.waitForQueueToBeLessThan(10);
82
- // we're waiting for the queue above anyway, enqueue in sync mode
83
- audioDecoder.decode(sample);
84
- };
85
- },
86
- });
87
- }
88
- catch (err) {
89
- const isAbortedByTimeCutoff = (0, media_parser_1.hasBeenAborted)(err);
90
- // Don't throw if we stopped the parsing ourselves
91
- if (!isAbortedByTimeCutoff && !signal.aborted) {
92
- throw err;
93
- }
94
- }
95
- // Simply concatenate all audio data since windowing handles the time ranges
96
- const totalSamples = audioSamples.reduce((sum, sample) => sum + sample.length, 0);
97
- const result = new Float32Array(totalSamples);
98
- let offset = 0;
99
- for (const audioSample of audioSamples) {
100
- result.set(audioSample, offset);
101
- offset += audioSample.length;
102
- }
103
- return result;
104
- };
105
- exports.getPartialMediaData = getPartialMediaData;
@@ -1,12 +0,0 @@
1
- export declare const getPartialWaveData: ({ dataOffset, src, bitsPerSample, channelIndex, sampleRate, fromSeconds, toSeconds, blockAlign, fileSize, signal, }: {
2
- dataOffset: number;
3
- src: string;
4
- bitsPerSample: number;
5
- channelIndex: number;
6
- sampleRate: number;
7
- fromSeconds: number;
8
- toSeconds: number;
9
- blockAlign: number;
10
- fileSize: number;
11
- signal: AbortSignal;
12
- }) => Promise<Float32Array<ArrayBuffer>>;
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPartialWaveData = void 0;
4
- const fetch_with_cors_catch_1 = require("./fetch-with-cors-catch");
5
- const probe_wave_file_1 = require("./probe-wave-file");
6
- const getPartialWaveData = async ({ dataOffset, src, bitsPerSample, channelIndex, sampleRate, fromSeconds, toSeconds, blockAlign, fileSize, signal, }) => {
7
- const startByte = dataOffset + Math.floor(fromSeconds * sampleRate) * blockAlign;
8
- const endByte = Math.min(fileSize, (dataOffset + Math.floor(toSeconds * sampleRate)) * blockAlign) - 1;
9
- const response = await (0, fetch_with_cors_catch_1.fetchWithCorsCatch)(src, {
10
- headers: {
11
- range: `bytes=${startByte}-${endByte}`,
12
- },
13
- signal,
14
- });
15
- if (response.status === 416) {
16
- throw new Error(`Tried to read bytes ${startByte}-${endByte} from ${src}, but the response status code was 416 "Range Not Satisfiable". Were too many bytes requested? The file is ${fileSize} bytes long.`);
17
- }
18
- if (response.status !== 206) {
19
- throw new Error(`Tried to read bytes ${startByte}-${endByte} from ${src}, but the response status code was ${response.status} (expected was 206). This means the server might not support returning a partial response.`);
20
- }
21
- const arrayBuffer = await response.arrayBuffer();
22
- const uintArray = new Uint8Array(arrayBuffer);
23
- const samples = new Float32Array(uintArray.length / blockAlign);
24
- for (let i = 0; i < uintArray.length; i += blockAlign) {
25
- const sampleStart = i + channelIndex * (bitsPerSample / 8);
26
- let sample;
27
- if (bitsPerSample === 16) {
28
- sample = (0, probe_wave_file_1.getInt16AsFloat)(uintArray, sampleStart);
29
- }
30
- else if (bitsPerSample === 8) {
31
- sample = (0, probe_wave_file_1.getInt8AsFloat)(uintArray, sampleStart);
32
- }
33
- else {
34
- throw new Error(`Unsupported bits per sample: ${bitsPerSample}`);
35
- }
36
- samples[i / blockAlign] = sample;
37
- }
38
- return samples;
39
- };
40
- exports.getPartialWaveData = getPartialWaveData;
@@ -1,12 +0,0 @@
1
- export declare const getInt16AsFloat: (bytes: Uint8Array, offset: number) => number;
2
- export declare const getInt8AsFloat: (bytes: Uint8Array, offset: number) => number;
3
- export type WaveProbe = {
4
- dataOffset: number;
5
- bitsPerSample: number;
6
- numberOfChannels: number;
7
- sampleRate: number;
8
- blockAlign: number;
9
- fileSize: number;
10
- durationInSeconds: number;
11
- };
12
- export declare const probeWaveFile: (src: string, probeSize?: number) => Promise<WaveProbe>;
@@ -1,95 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.probeWaveFile = exports.getInt8AsFloat = exports.getInt16AsFloat = void 0;
4
- const fetch_with_cors_catch_1 = require("./fetch-with-cors-catch");
5
- const getUint32 = (bytes, offset) => {
6
- const val1 = bytes[offset + 3];
7
- const val2 = bytes[offset + 2];
8
- const val3 = bytes[offset + 1];
9
- const val4 = bytes[offset];
10
- return (val1 << 24) | (val2 << 16) | (val3 << 8) | val4;
11
- };
12
- const getUint16 = (bytes, offset) => {
13
- const val1 = bytes[offset + 1];
14
- const val2 = bytes[offset];
15
- return (val1 << 8) | val2;
16
- };
17
- const getInt16AsFloat = (bytes, offset) => {
18
- if (offset >= bytes.length) {
19
- throw new Error(`Tried to read a 16-bit integer from offset ${offset} but the array length is ${bytes.length}`);
20
- }
21
- const val1 = bytes[offset + 1];
22
- const val2 = bytes[offset];
23
- const int16 = (val1 << 8) | val2;
24
- return ((int16 << 16) >> 16) / 32768;
25
- };
26
- exports.getInt16AsFloat = getInt16AsFloat;
27
- const getInt8AsFloat = (bytes, offset) => {
28
- if (offset >= bytes.length) {
29
- throw new Error(`Tried to read an 8-bit integer from offset ${offset} but the array length is ${bytes.length}`);
30
- }
31
- return bytes[offset] / 128;
32
- };
33
- exports.getInt8AsFloat = getInt8AsFloat;
34
- const probeWaveFile = async (src, probeSize = 1024) => {
35
- const response = await (0, fetch_with_cors_catch_1.fetchWithCorsCatch)(src, {
36
- headers: {
37
- range: `bytes=0-${probeSize - 1}`,
38
- },
39
- });
40
- if (response.status === 416) {
41
- throw new Error(`Tried to read bytes 0-1024 from ${src}, but the response status code was 416 "Range Not Satisfiable". Is the file at least 256 bytes long?`);
42
- }
43
- if (response.status !== 206) {
44
- throw new Error(`Tried to read bytes 0-1024 from ${src}, but the response status code was ${response.status} (expected was 206). This means the server might not support returning a partial response.`);
45
- }
46
- const buffer = await response.arrayBuffer();
47
- const uintArray = new Uint8Array(buffer);
48
- const shouldBeRiff = new TextDecoder().decode(uintArray.slice(0, 4));
49
- if (shouldBeRiff !== 'RIFF') {
50
- throw new Error('getPartialAudioData() requires a WAVE file, but the first bytes are not RIFF. ');
51
- }
52
- const size = getUint32(uintArray, 4);
53
- const shouldBeWAVE = new TextDecoder().decode(uintArray.slice(8, 12));
54
- if (shouldBeWAVE !== 'WAVE') {
55
- throw new Error('getPartialAudioData() requires a WAVE file, but the bytes 8-11 are not "WAVE". ');
56
- }
57
- const shouldBeFmt = new TextDecoder().decode(uintArray.slice(12, 16));
58
- if (shouldBeFmt !== 'fmt ') {
59
- throw new Error('getPartialAudioData() requires a WAVE file, but the bytes 12-15 are not "fmt ". ');
60
- }
61
- // const chunkSize = toUint32(uintArray.slice(16, 20));
62
- const audioFormat = getUint16(uintArray, 20);
63
- if (audioFormat !== 1) {
64
- throw new Error('getPartialAudioData() supports only a WAVE file with PCM audio format, but the audio format is not PCM. ');
65
- }
66
- const numberOfChannels = getUint16(uintArray, 22);
67
- const sampleRate = getUint32(uintArray, 24);
68
- const blockAlign = getUint16(uintArray, 32);
69
- const bitsPerSample = getUint16(uintArray, 34);
70
- let offset = 36;
71
- const shouldBeDataOrList = new TextDecoder().decode(uintArray.slice(offset, offset + 4));
72
- if (shouldBeDataOrList === 'LIST') {
73
- const listSize = getUint32(uintArray, 40);
74
- offset += listSize;
75
- offset += 8;
76
- }
77
- if (offset + 4 > probeSize) {
78
- return (0, exports.probeWaveFile)(src, offset + 4);
79
- }
80
- const shouldBeData = new TextDecoder().decode(uintArray.slice(offset, offset + 4));
81
- if (shouldBeData !== 'data') {
82
- throw new Error(`getPartialAudioData() requires a WAVE file, but the bytes ${offset}-${offset + 4} are not "data". `);
83
- }
84
- const dataSize = getUint32(uintArray, offset + 4);
85
- return {
86
- dataOffset: offset + 8,
87
- bitsPerSample,
88
- numberOfChannels,
89
- sampleRate,
90
- blockAlign,
91
- fileSize: size,
92
- durationInSeconds: dataSize / (sampleRate * blockAlign),
93
- };
94
- };
95
- exports.probeWaveFile = probeWaveFile;