@remotion/webcodecs 4.0.286 → 4.0.288
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/dist/audio-data/data-types.d.ts +1 -0
- package/dist/audio-data/data-types.js +26 -0
- package/dist/audio-data/is-planar-format.d.ts +1 -0
- package/dist/audio-data/is-planar-format.js +7 -0
- package/dist/audio-encoder.js +5 -1
- package/dist/can-reencode-audio-track.d.ts +2 -1
- package/dist/can-reencode-audio-track.js +2 -2
- package/dist/convert-audiodata.d.ts +10 -0
- package/dist/convert-audiodata.js +85 -0
- package/dist/convert-media.d.ts +2 -1
- package/dist/convert-media.js +2 -1
- package/dist/create/iso-base-media/codec-specific/create-codec-specific-data.js +8 -0
- package/dist/create/iso-base-media/create-iso-base-media.js +2 -0
- package/dist/create/iso-base-media/example-stts.js +620 -0
- package/dist/create/matroska/create-matroska-media.js +1 -1
- package/dist/create/matroska/matroska-utils.d.ts +1 -1
- package/dist/default-on-audio-track-handler.js +2 -0
- package/dist/esm/index.mjs +183 -24
- package/dist/esm/web-fs.mjs +2 -4
- package/dist/get-wave-audio-decoder.js +29 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/on-audio-track-handler.d.ts +1 -0
- package/dist/on-audio-track.js +3 -3
- package/dist/resample-audiodata.d.ts +4 -0
- package/dist/resample-audiodata.js +35 -0
- package/dist/wav-audio-encoder.d.ts +1 -1
- package/dist/wav-audio-encoder.js +11 -4
- package/package.json +12 -7
- package/dist/test/avc1.test.d.ts +0 -1
- package/dist/test/avc1.test.js +0 -39
- package/dist/test/avcc.test.d.ts +0 -1
- package/dist/test/avcc.test.js +0 -15
- package/dist/test/avi-to-mp4.test.d.ts +0 -1
- package/dist/test/avi-to-mp4.test.js +0 -15
- package/dist/test/cmt.test.d.ts +0 -1
- package/dist/test/cmt.test.js +0 -13
- package/dist/test/colr.test.d.ts +0 -1
- package/dist/test/colr.test.js +0 -16
- package/dist/test/correct-byte-length.test.d.ts +0 -1
- package/dist/test/correct-byte-length.test.js +0 -23
- package/dist/test/create-ftyp.test.d.ts +0 -1
- package/dist/test/create-ftyp.test.js +0 -47
- package/dist/test/create-mvhd.test.d.ts +0 -1
- package/dist/test/create-mvhd.test.js +0 -108
- package/dist/test/ctts.test.d.ts +0 -1
- package/dist/test/ctts.test.js +0 -49
- package/dist/test/dinf.test.d.ts +0 -1
- package/dist/test/dinf.test.js +0 -12
- package/dist/test/ilst.test.d.ts +0 -1
- package/dist/test/ilst.test.js +0 -22
- package/dist/test/mdhd.test.d.ts +0 -1
- package/dist/test/mdhd.test.js +0 -17
- package/dist/test/meta.test.d.ts +0 -1
- package/dist/test/meta.test.js +0 -26
- package/dist/test/mp4-header-length.test.d.ts +0 -1
- package/dist/test/mp4-header-length.test.js +0 -12
- package/dist/test/mp4a.test.d.ts +0 -1
- package/dist/test/mp4a.test.js +0 -24
- package/dist/test/pasp.test.d.ts +0 -1
- package/dist/test/pasp.test.js +0 -12
- package/dist/test/remux-serverside.test.d.ts +0 -1
- package/dist/test/remux-serverside.test.js +0 -23
- package/dist/test/stbl.test.d.ts +0 -0
- package/dist/test/stbl.test.js +0 -176
- package/dist/test/stco.test.d.ts +0 -1
- package/dist/test/stco.test.js +0 -34
- package/dist/test/stsc.test.d.ts +0 -1
- package/dist/test/stsc.test.js +0 -63
- package/dist/test/stss.test.d.ts +0 -1
- package/dist/test/stss.test.js +0 -14
- package/dist/test/stsz.test.d.ts +0 -1
- package/dist/test/stsz.test.js +0 -43
- package/dist/test/stts.test.d.ts +0 -1
- package/dist/test/stts.test.js +0 -12
- package/dist/test/tkhd.test.d.ts +0 -1
- package/dist/test/tkhd.test.js +0 -175
- package/dist/test/too.test.d.ts +0 -1
- package/dist/test/too.test.js +0 -12
- package/dist/test/url.test.d.ts +0 -1
- package/dist/test/url.test.js +0 -11
|
@@ -19,7 +19,7 @@ export type EbmlParsedOrUint8Array<T extends Ebml> = {
|
|
|
19
19
|
value: EbmlValueOrUint8Array<T>;
|
|
20
20
|
minVintWidth: number | null;
|
|
21
21
|
};
|
|
22
|
-
export declare const measureEBMLVarInt: (value: number) => 2 |
|
|
22
|
+
export declare const measureEBMLVarInt: (value: number) => 2 | 4 | 1 | 5 | 3 | 6;
|
|
23
23
|
export declare const getVariableInt: (value: number, minWidth: number | null) => Uint8Array<ArrayBuffer>;
|
|
24
24
|
export declare const makeMatroskaBytes: (fields: PossibleEbmlOrUint8Array) => BytesAndOffset;
|
|
25
25
|
export type PossibleEbmlOrUint8Array = Prettify<{
|
|
@@ -19,6 +19,7 @@ const defaultOnAudioTrackHandler = async ({ track, defaultAudioCodec, logLevel,
|
|
|
19
19
|
audioCodec: defaultAudioCodec,
|
|
20
20
|
track,
|
|
21
21
|
bitrate,
|
|
22
|
+
sampleRate: null,
|
|
22
23
|
});
|
|
23
24
|
if (canReencode) {
|
|
24
25
|
media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (audio): Cannot copy, but re-encode, therefore re-encoding`);
|
|
@@ -26,6 +27,7 @@ const defaultOnAudioTrackHandler = async ({ track, defaultAudioCodec, logLevel,
|
|
|
26
27
|
type: 'reencode',
|
|
27
28
|
bitrate,
|
|
28
29
|
audioCodec: defaultAudioCodec,
|
|
30
|
+
sampleRate: null,
|
|
29
31
|
});
|
|
30
32
|
}
|
|
31
33
|
media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can neither re-encode nor copy, failing render`);
|
package/dist/esm/index.mjs
CHANGED
|
@@ -101,8 +101,7 @@ var createContent = async ({ filename }) => {
|
|
|
101
101
|
await directoryHandle.removeEntry(actualFilename, {
|
|
102
102
|
recursive: true
|
|
103
103
|
});
|
|
104
|
-
} catch {
|
|
105
|
-
}
|
|
104
|
+
} catch {}
|
|
106
105
|
};
|
|
107
106
|
await remove();
|
|
108
107
|
const fileHandle = await directoryHandle.getFileHandle(actualFilename, {
|
|
@@ -129,8 +128,7 @@ var createContent = async ({ filename }) => {
|
|
|
129
128
|
await writPromise;
|
|
130
129
|
try {
|
|
131
130
|
await writable.close();
|
|
132
|
-
} catch {
|
|
133
|
-
}
|
|
131
|
+
} catch {}
|
|
134
132
|
},
|
|
135
133
|
async getBlob() {
|
|
136
134
|
const newHandle = await directoryHandle.getFileHandle(actualFilename, {
|
|
@@ -430,6 +428,33 @@ var setRemotionImported = () => {
|
|
|
430
428
|
};
|
|
431
429
|
|
|
432
430
|
// src/get-wave-audio-decoder.ts
|
|
431
|
+
var getBytesPerSample = (sampleFormat) => {
|
|
432
|
+
if (sampleFormat === "s16") {
|
|
433
|
+
return 2;
|
|
434
|
+
}
|
|
435
|
+
if (sampleFormat === "s32") {
|
|
436
|
+
return 4;
|
|
437
|
+
}
|
|
438
|
+
if (sampleFormat === "f32") {
|
|
439
|
+
return 4;
|
|
440
|
+
}
|
|
441
|
+
if (sampleFormat === "u8") {
|
|
442
|
+
return 1;
|
|
443
|
+
}
|
|
444
|
+
if (sampleFormat === "f32-planar") {
|
|
445
|
+
return 4;
|
|
446
|
+
}
|
|
447
|
+
if (sampleFormat === "s16-planar") {
|
|
448
|
+
return 2;
|
|
449
|
+
}
|
|
450
|
+
if (sampleFormat === "s32-planar") {
|
|
451
|
+
return 4;
|
|
452
|
+
}
|
|
453
|
+
if (sampleFormat === "u8-planar") {
|
|
454
|
+
return 1;
|
|
455
|
+
}
|
|
456
|
+
throw new Error(`Unsupported sample format: ${sampleFormat}`);
|
|
457
|
+
};
|
|
433
458
|
var getWaveAudioDecoder = ({
|
|
434
459
|
onFrame,
|
|
435
460
|
track,
|
|
@@ -437,11 +462,12 @@ var getWaveAudioDecoder = ({
|
|
|
437
462
|
}) => {
|
|
438
463
|
let queue = Promise.resolve();
|
|
439
464
|
const processSample = async (audioSample) => {
|
|
465
|
+
const bytesPerSample = getBytesPerSample(sampleFormat);
|
|
440
466
|
await onFrame(new AudioData({
|
|
441
467
|
data: audioSample.data,
|
|
442
468
|
format: sampleFormat,
|
|
443
469
|
numberOfChannels: track.numberOfChannels,
|
|
444
|
-
numberOfFrames: audioSample.data.byteLength /
|
|
470
|
+
numberOfFrames: audioSample.data.byteLength / bytesPerSample / track.numberOfChannels,
|
|
445
471
|
sampleRate: track.sampleRate,
|
|
446
472
|
timestamp: audioSample.timestamp
|
|
447
473
|
}));
|
|
@@ -766,8 +792,7 @@ var createAudioDecoder = ({
|
|
|
766
792
|
waitForFinish: async () => {
|
|
767
793
|
try {
|
|
768
794
|
await audioDecoder.flush();
|
|
769
|
-
} catch {
|
|
770
|
-
}
|
|
795
|
+
} catch {}
|
|
771
796
|
await queue;
|
|
772
797
|
await ioSynchronizer.waitForFinish(controller);
|
|
773
798
|
await outputQueue;
|
|
@@ -781,25 +806,142 @@ var createAudioDecoder = ({
|
|
|
781
806
|
// src/audio-encoder.ts
|
|
782
807
|
import { MediaParserAbortError } from "@remotion/media-parser";
|
|
783
808
|
|
|
809
|
+
// src/audio-data/data-types.ts
|
|
810
|
+
var getDataTypeForAudioFormat = (format) => {
|
|
811
|
+
switch (format) {
|
|
812
|
+
case "f32":
|
|
813
|
+
return Float32Array;
|
|
814
|
+
case "f32-planar":
|
|
815
|
+
return Float32Array;
|
|
816
|
+
case "s16":
|
|
817
|
+
return Int16Array;
|
|
818
|
+
case "s16-planar":
|
|
819
|
+
return Int16Array;
|
|
820
|
+
case "u8":
|
|
821
|
+
return Uint8Array;
|
|
822
|
+
case "u8-planar":
|
|
823
|
+
return Uint8Array;
|
|
824
|
+
case "s32":
|
|
825
|
+
return Int32Array;
|
|
826
|
+
case "s32-planar":
|
|
827
|
+
return Int32Array;
|
|
828
|
+
default:
|
|
829
|
+
throw new Error(`Unsupported audio format: ${format}`);
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
// src/audio-data/is-planar-format.ts
|
|
834
|
+
var isPlanarFormat = (format) => {
|
|
835
|
+
return format.includes("-planar");
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
// src/convert-audiodata.ts
|
|
839
|
+
var validateRange = (format, value) => {
|
|
840
|
+
if (format === "f32" || format === "f32-planar") {
|
|
841
|
+
if (value < -1 || value > 1) {
|
|
842
|
+
throw new Error("All values in a Float32 array must be between -1 and 1");
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
var convertAudioData = ({
|
|
847
|
+
audioData,
|
|
848
|
+
newSampleRate = audioData.sampleRate,
|
|
849
|
+
format = audioData.format
|
|
850
|
+
}) => {
|
|
851
|
+
const {
|
|
852
|
+
numberOfChannels,
|
|
853
|
+
sampleRate: currentSampleRate,
|
|
854
|
+
numberOfFrames: currentNumberOfFrames
|
|
855
|
+
} = audioData;
|
|
856
|
+
const ratio = currentSampleRate / newSampleRate;
|
|
857
|
+
const newNumberOfFrames = Math.floor(currentNumberOfFrames / ratio);
|
|
858
|
+
if (newNumberOfFrames === 0) {
|
|
859
|
+
throw new Error("Cannot resample - the given sample rate would result in less than 1 sample");
|
|
860
|
+
}
|
|
861
|
+
if (newSampleRate < 3000 || newSampleRate > 768000) {
|
|
862
|
+
throw new Error("newSampleRate must be between 3000 and 768000");
|
|
863
|
+
}
|
|
864
|
+
if (!format) {
|
|
865
|
+
throw new Error("AudioData format is not set");
|
|
866
|
+
}
|
|
867
|
+
if (format === audioData.format && newNumberOfFrames === currentNumberOfFrames) {
|
|
868
|
+
return audioData.clone();
|
|
869
|
+
}
|
|
870
|
+
const DataType = getDataTypeForAudioFormat(format);
|
|
871
|
+
const isPlanar = isPlanarFormat(format);
|
|
872
|
+
const planes = isPlanar ? numberOfChannels : 1;
|
|
873
|
+
const srcChannels = new Array(planes).fill(true).map(() => new DataType((isPlanar ? 1 : numberOfChannels) * currentNumberOfFrames));
|
|
874
|
+
for (let i = 0;i < planes; i++) {
|
|
875
|
+
audioData.clone().copyTo(srcChannels[i], {
|
|
876
|
+
planeIndex: i,
|
|
877
|
+
format
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
const data = new DataType(newNumberOfFrames * numberOfChannels);
|
|
881
|
+
const chunkSize = currentNumberOfFrames / newNumberOfFrames;
|
|
882
|
+
for (let newFrameIndex = 0;newFrameIndex < newNumberOfFrames; newFrameIndex++) {
|
|
883
|
+
const start = Math.floor(newFrameIndex * chunkSize);
|
|
884
|
+
const end = Math.max(Math.floor(start + chunkSize), start + 1);
|
|
885
|
+
if (isPlanar) {
|
|
886
|
+
for (let channelIndex = 0;channelIndex < numberOfChannels; channelIndex++) {
|
|
887
|
+
const chunk = srcChannels[channelIndex].slice(start, end);
|
|
888
|
+
const average = chunk.reduce((a, b) => {
|
|
889
|
+
return a + b;
|
|
890
|
+
}, 0) / chunk.length;
|
|
891
|
+
validateRange(format, average);
|
|
892
|
+
data[newFrameIndex + channelIndex * newNumberOfFrames] = average;
|
|
893
|
+
}
|
|
894
|
+
} else {
|
|
895
|
+
const sampleCountAvg = end - start;
|
|
896
|
+
for (let channelIndex = 0;channelIndex < numberOfChannels; channelIndex++) {
|
|
897
|
+
const items = [];
|
|
898
|
+
for (let k = 0;k < sampleCountAvg; k++) {
|
|
899
|
+
const num = srcChannels[0][(start + k) * numberOfChannels + channelIndex];
|
|
900
|
+
items.push(num);
|
|
901
|
+
}
|
|
902
|
+
const average = items.reduce((a, b) => a + b, 0) / items.length;
|
|
903
|
+
validateRange(format, average);
|
|
904
|
+
data[newFrameIndex * numberOfChannels + channelIndex] = average;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
const newAudioData = new AudioData({
|
|
909
|
+
data,
|
|
910
|
+
format,
|
|
911
|
+
numberOfChannels,
|
|
912
|
+
numberOfFrames: newNumberOfFrames,
|
|
913
|
+
sampleRate: newSampleRate,
|
|
914
|
+
timestamp: audioData.timestamp
|
|
915
|
+
});
|
|
916
|
+
return newAudioData;
|
|
917
|
+
};
|
|
918
|
+
|
|
784
919
|
// src/wav-audio-encoder.ts
|
|
785
920
|
var getWaveAudioEncoder = ({
|
|
786
921
|
onChunk,
|
|
787
|
-
controller
|
|
922
|
+
controller,
|
|
923
|
+
config
|
|
788
924
|
}) => {
|
|
789
925
|
return {
|
|
790
926
|
close: () => {
|
|
791
927
|
return Promise.resolve();
|
|
792
928
|
},
|
|
793
|
-
encodeFrame: (
|
|
929
|
+
encodeFrame: (unconvertedAudioData) => {
|
|
794
930
|
if (controller._internals.signal.aborted) {
|
|
795
931
|
return Promise.resolve();
|
|
796
932
|
}
|
|
933
|
+
const audioData = convertAudioData({
|
|
934
|
+
audioData: unconvertedAudioData,
|
|
935
|
+
newSampleRate: config.sampleRate,
|
|
936
|
+
format: "s16"
|
|
937
|
+
});
|
|
938
|
+
unconvertedAudioData.close();
|
|
797
939
|
const chunk = {
|
|
798
940
|
timestamp: audioData.timestamp,
|
|
799
941
|
duration: audioData.duration,
|
|
800
942
|
type: "key",
|
|
801
|
-
copyTo: (destination) => audioData.copyTo(destination, { planeIndex: 0
|
|
802
|
-
byteLength: audioData.allocationSize({ planeIndex: 0
|
|
943
|
+
copyTo: (destination) => audioData.copyTo(destination, { planeIndex: 0 }),
|
|
944
|
+
byteLength: audioData.allocationSize({ planeIndex: 0 })
|
|
803
945
|
};
|
|
804
946
|
return onChunk(chunk);
|
|
805
947
|
},
|
|
@@ -823,7 +965,11 @@ var createAudioEncoder = ({
|
|
|
823
965
|
throw new MediaParserAbortError("Not creating audio encoder, already aborted");
|
|
824
966
|
}
|
|
825
967
|
if (codec === "wav") {
|
|
826
|
-
return getWaveAudioEncoder({
|
|
968
|
+
return getWaveAudioEncoder({
|
|
969
|
+
onChunk,
|
|
970
|
+
controller,
|
|
971
|
+
config: audioEncoderConfig
|
|
972
|
+
});
|
|
827
973
|
}
|
|
828
974
|
const ioSynchronizer = makeIoSynchronizer({
|
|
829
975
|
logLevel,
|
|
@@ -1020,7 +1166,8 @@ var getAudioEncoderConfig = async (config) => {
|
|
|
1020
1166
|
var canReencodeAudioTrack = async ({
|
|
1021
1167
|
track,
|
|
1022
1168
|
audioCodec,
|
|
1023
|
-
bitrate
|
|
1169
|
+
bitrate,
|
|
1170
|
+
sampleRate
|
|
1024
1171
|
}) => {
|
|
1025
1172
|
const audioDecoderConfig = await getAudioDecoderConfig(track);
|
|
1026
1173
|
if (audioCodec === "wav" && audioDecoderConfig) {
|
|
@@ -1029,7 +1176,7 @@ var canReencodeAudioTrack = async ({
|
|
|
1029
1176
|
const audioEncoderConfig = await getAudioEncoderConfig({
|
|
1030
1177
|
codec: audioCodec,
|
|
1031
1178
|
numberOfChannels: track.numberOfChannels,
|
|
1032
|
-
sampleRate: track.sampleRate,
|
|
1179
|
+
sampleRate: sampleRate ?? track.sampleRate,
|
|
1033
1180
|
bitrate
|
|
1034
1181
|
});
|
|
1035
1182
|
return Boolean(audioDecoderConfig && audioEncoderConfig);
|
|
@@ -1621,14 +1768,16 @@ var defaultOnAudioTrackHandler = async ({
|
|
|
1621
1768
|
const canReencode = await canReencodeAudioTrack({
|
|
1622
1769
|
audioCodec: defaultAudioCodec,
|
|
1623
1770
|
track,
|
|
1624
|
-
bitrate
|
|
1771
|
+
bitrate,
|
|
1772
|
+
sampleRate: null
|
|
1625
1773
|
});
|
|
1626
1774
|
if (canReencode) {
|
|
1627
1775
|
MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Cannot copy, but re-encode, therefore re-encoding`);
|
|
1628
1776
|
return Promise.resolve({
|
|
1629
1777
|
type: "reencode",
|
|
1630
1778
|
bitrate,
|
|
1631
|
-
audioCodec: defaultAudioCodec
|
|
1779
|
+
audioCodec: defaultAudioCodec,
|
|
1780
|
+
sampleRate: null
|
|
1632
1781
|
});
|
|
1633
1782
|
}
|
|
1634
1783
|
MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can neither re-encode nor copy, failing render`);
|
|
@@ -1710,7 +1859,7 @@ var makeAudioTrackHandler = ({
|
|
|
1710
1859
|
}
|
|
1711
1860
|
const audioEncoderConfig = await getAudioEncoderConfig({
|
|
1712
1861
|
numberOfChannels: track.numberOfChannels,
|
|
1713
|
-
sampleRate: track.sampleRate,
|
|
1862
|
+
sampleRate: audioOperation.sampleRate ?? track.sampleRate,
|
|
1714
1863
|
codec: audioOperation.audioCodec,
|
|
1715
1864
|
bitrate: audioOperation.bitrate
|
|
1716
1865
|
});
|
|
@@ -1730,7 +1879,7 @@ var makeAudioTrackHandler = ({
|
|
|
1730
1879
|
}
|
|
1731
1880
|
const codecPrivate = audioOperation.audioCodec === "aac" ? MediaParserInternals3.createAacCodecPrivate({
|
|
1732
1881
|
audioObjectType: 2,
|
|
1733
|
-
sampleRate: audioEncoderConfig.sampleRate,
|
|
1882
|
+
sampleRate: audioOperation.sampleRate ?? audioEncoderConfig.sampleRate,
|
|
1734
1883
|
channelConfiguration: audioEncoderConfig.numberOfChannels,
|
|
1735
1884
|
codecPrivate: null
|
|
1736
1885
|
}) : null;
|
|
@@ -1738,7 +1887,7 @@ var makeAudioTrackHandler = ({
|
|
|
1738
1887
|
type: "audio",
|
|
1739
1888
|
codec: audioOperation.audioCodec === "wav" ? "pcm-s16" : audioOperation.audioCodec,
|
|
1740
1889
|
numberOfChannels: audioEncoderConfig.numberOfChannels,
|
|
1741
|
-
sampleRate: audioEncoderConfig.sampleRate,
|
|
1890
|
+
sampleRate: audioOperation.sampleRate ?? audioEncoderConfig.sampleRate,
|
|
1742
1891
|
codecPrivate,
|
|
1743
1892
|
timescale: track.timescale
|
|
1744
1893
|
});
|
|
@@ -3069,6 +3218,9 @@ var createMp4a = ({
|
|
|
3069
3218
|
var createCodecSpecificData = (track) => {
|
|
3070
3219
|
if (track.type === "video") {
|
|
3071
3220
|
if (track.codec === "h264") {
|
|
3221
|
+
if (!track.codecPrivate) {
|
|
3222
|
+
return new Uint8Array([]);
|
|
3223
|
+
}
|
|
3072
3224
|
return createAvc1Data({
|
|
3073
3225
|
avccBox: createAvccBox(track.codecPrivate),
|
|
3074
3226
|
compressorName: "WebCodecs",
|
|
@@ -3082,6 +3234,9 @@ var createCodecSpecificData = (track) => {
|
|
|
3082
3234
|
});
|
|
3083
3235
|
}
|
|
3084
3236
|
if (track.codec === "h265") {
|
|
3237
|
+
if (!track.codecPrivate) {
|
|
3238
|
+
return new Uint8Array([]);
|
|
3239
|
+
}
|
|
3085
3240
|
return createHvc1Data({
|
|
3086
3241
|
hvccBox: createHvccBox(track.codecPrivate),
|
|
3087
3242
|
compressorName: "WebCodecs",
|
|
@@ -3784,7 +3939,9 @@ var createIsoBaseMedia = async ({
|
|
|
3784
3939
|
cts: Math.round(chunk.cts / 1e6 * currentTrack.timescale),
|
|
3785
3940
|
dts: Math.round(chunk.dts / 1e6 * currentTrack.timescale),
|
|
3786
3941
|
duration: Math.round((chunk.duration ?? 0) / 1e6 * currentTrack.timescale),
|
|
3787
|
-
size: chunk.data.length
|
|
3942
|
+
size: chunk.data.length,
|
|
3943
|
+
bigEndian: false,
|
|
3944
|
+
chunkSize: null
|
|
3788
3945
|
};
|
|
3789
3946
|
lastChunkWasVideo = isVideo;
|
|
3790
3947
|
samplePositions[trackNumber].push(samplePositionToAdd);
|
|
@@ -4591,7 +4748,7 @@ var createMatroskaMedia = async ({
|
|
|
4591
4748
|
}
|
|
4592
4749
|
});
|
|
4593
4750
|
},
|
|
4594
|
-
getBlob:
|
|
4751
|
+
getBlob: () => {
|
|
4595
4752
|
return w.getBlob();
|
|
4596
4753
|
},
|
|
4597
4754
|
remove: async () => {
|
|
@@ -4801,8 +4958,7 @@ var throttledStateUpdate = ({
|
|
|
4801
4958
|
return {
|
|
4802
4959
|
get: () => currentState,
|
|
4803
4960
|
update: null,
|
|
4804
|
-
stopAndGetLastProgress: () => {
|
|
4805
|
-
}
|
|
4961
|
+
stopAndGetLastProgress: () => {}
|
|
4806
4962
|
};
|
|
4807
4963
|
}
|
|
4808
4964
|
let lastUpdated = null;
|
|
@@ -4899,6 +5055,7 @@ var convertMedia = async function({
|
|
|
4899
5055
|
selectM3uStream,
|
|
4900
5056
|
selectM3uAssociatedPlaylists,
|
|
4901
5057
|
expectedDurationInSeconds,
|
|
5058
|
+
seekingHints,
|
|
4902
5059
|
...more
|
|
4903
5060
|
}) {
|
|
4904
5061
|
if (controller._internals.signal.aborted) {
|
|
@@ -5053,7 +5210,8 @@ var convertMedia = async function({
|
|
|
5053
5210
|
selectM3uStream: selectM3uStream ?? defaultSelectM3uStreamFn,
|
|
5054
5211
|
selectM3uAssociatedPlaylists: selectM3uAssociatedPlaylists ?? defaultSelectM3uAssociatedPlaylists,
|
|
5055
5212
|
makeSamplesStartAtZero: false,
|
|
5056
|
-
mp4HeaderSegment: null
|
|
5213
|
+
mp4HeaderSegment: null,
|
|
5214
|
+
seekingHints: seekingHints ?? null
|
|
5057
5215
|
}).then(() => {
|
|
5058
5216
|
return state.waitForFinish();
|
|
5059
5217
|
}).then(() => {
|
|
@@ -5115,6 +5273,7 @@ export {
|
|
|
5115
5273
|
createAudioEncoder,
|
|
5116
5274
|
createAudioDecoder,
|
|
5117
5275
|
convertMedia,
|
|
5276
|
+
convertAudioData,
|
|
5118
5277
|
canReencodeVideoTrack,
|
|
5119
5278
|
canReencodeAudioTrack,
|
|
5120
5279
|
canCopyVideoTrack,
|
package/dist/esm/web-fs.mjs
CHANGED
|
@@ -7,8 +7,7 @@ var createContent = async ({ filename }) => {
|
|
|
7
7
|
await directoryHandle.removeEntry(actualFilename, {
|
|
8
8
|
recursive: true
|
|
9
9
|
});
|
|
10
|
-
} catch {
|
|
11
|
-
}
|
|
10
|
+
} catch {}
|
|
12
11
|
};
|
|
13
12
|
await remove();
|
|
14
13
|
const fileHandle = await directoryHandle.getFileHandle(actualFilename, {
|
|
@@ -35,8 +34,7 @@ var createContent = async ({ filename }) => {
|
|
|
35
34
|
await writPromise;
|
|
36
35
|
try {
|
|
37
36
|
await writable.close();
|
|
38
|
-
} catch {
|
|
39
|
-
}
|
|
37
|
+
} catch {}
|
|
40
38
|
},
|
|
41
39
|
async getBlob() {
|
|
42
40
|
const newHandle = await directoryHandle.getFileHandle(actualFilename, {
|
|
@@ -1,15 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getWaveAudioDecoder = void 0;
|
|
4
|
+
const getBytesPerSample = (sampleFormat) => {
|
|
5
|
+
if (sampleFormat === 's16') {
|
|
6
|
+
return 2;
|
|
7
|
+
}
|
|
8
|
+
if (sampleFormat === 's32') {
|
|
9
|
+
return 4;
|
|
10
|
+
}
|
|
11
|
+
if (sampleFormat === 'f32') {
|
|
12
|
+
return 4;
|
|
13
|
+
}
|
|
14
|
+
if (sampleFormat === 'u8') {
|
|
15
|
+
return 1;
|
|
16
|
+
}
|
|
17
|
+
if (sampleFormat === 'f32-planar') {
|
|
18
|
+
return 4;
|
|
19
|
+
}
|
|
20
|
+
if (sampleFormat === 's16-planar') {
|
|
21
|
+
return 2;
|
|
22
|
+
}
|
|
23
|
+
if (sampleFormat === 's32-planar') {
|
|
24
|
+
return 4;
|
|
25
|
+
}
|
|
26
|
+
if (sampleFormat === 'u8-planar') {
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`Unsupported sample format: ${sampleFormat}`);
|
|
30
|
+
};
|
|
4
31
|
// TODO: Should also be subject to throttling
|
|
5
32
|
const getWaveAudioDecoder = ({ onFrame, track, sampleFormat, }) => {
|
|
6
33
|
let queue = Promise.resolve();
|
|
7
34
|
const processSample = async (audioSample) => {
|
|
35
|
+
const bytesPerSample = getBytesPerSample(sampleFormat);
|
|
8
36
|
await onFrame(new AudioData({
|
|
9
37
|
data: audioSample.data,
|
|
10
38
|
format: sampleFormat,
|
|
11
39
|
numberOfChannels: track.numberOfChannels,
|
|
12
|
-
numberOfFrames: audioSample.data.byteLength /
|
|
40
|
+
numberOfFrames: audioSample.data.byteLength / bytesPerSample / track.numberOfChannels,
|
|
13
41
|
sampleRate: track.sampleRate,
|
|
14
42
|
timestamp: audioSample.timestamp,
|
|
15
43
|
}));
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { canCopyAudioTrack } from './can-copy-audio-track';
|
|
|
6
6
|
export { canCopyVideoTrack } from './can-copy-video-track';
|
|
7
7
|
export { canReencodeAudioTrack } from './can-reencode-audio-track';
|
|
8
8
|
export { canReencodeVideoTrack } from './can-reencode-video-track';
|
|
9
|
+
export { convertAudioData, ConvertAudioDataOptions } from './convert-audiodata';
|
|
9
10
|
export { convertMedia } from './convert-media';
|
|
10
11
|
export type { ConvertMediaOnAudioData, ConvertMediaOnProgress, ConvertMediaOnVideoFrame, ConvertMediaProgress, ConvertMediaResult, } from './convert-media';
|
|
11
12
|
export { defaultOnAudioTrackHandler } from './default-on-audio-track-handler';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WebCodecsInternals = exports.webcodecsController = exports.createVideoEncoder = exports.createVideoDecoder = exports.getDefaultVideoCodec = exports.getDefaultAudioCodec = exports.getAvailableVideoCodecs = exports.getAvailableContainers = exports.getAvailableAudioCodecs = exports.defaultOnVideoTrackHandler = exports.defaultOnAudioTrackHandler = exports.convertMedia = exports.canReencodeVideoTrack = exports.canReencodeAudioTrack = exports.canCopyVideoTrack = exports.canCopyAudioTrack = exports.createAudioEncoder = exports.createAudioDecoder = void 0;
|
|
3
|
+
exports.WebCodecsInternals = exports.webcodecsController = exports.createVideoEncoder = exports.createVideoDecoder = exports.getDefaultVideoCodec = exports.getDefaultAudioCodec = exports.getAvailableVideoCodecs = exports.getAvailableContainers = exports.getAvailableAudioCodecs = exports.defaultOnVideoTrackHandler = exports.defaultOnAudioTrackHandler = exports.convertMedia = exports.convertAudioData = exports.canReencodeVideoTrack = exports.canReencodeAudioTrack = exports.canCopyVideoTrack = exports.canCopyAudioTrack = exports.createAudioEncoder = exports.createAudioDecoder = void 0;
|
|
4
4
|
const rotate_and_resize_video_frame_1 = require("./rotate-and-resize-video-frame");
|
|
5
5
|
const rotation_1 = require("./rotation");
|
|
6
6
|
const set_remotion_imported_1 = require("./set-remotion-imported");
|
|
@@ -16,6 +16,8 @@ var can_reencode_audio_track_1 = require("./can-reencode-audio-track");
|
|
|
16
16
|
Object.defineProperty(exports, "canReencodeAudioTrack", { enumerable: true, get: function () { return can_reencode_audio_track_1.canReencodeAudioTrack; } });
|
|
17
17
|
var can_reencode_video_track_1 = require("./can-reencode-video-track");
|
|
18
18
|
Object.defineProperty(exports, "canReencodeVideoTrack", { enumerable: true, get: function () { return can_reencode_video_track_1.canReencodeVideoTrack; } });
|
|
19
|
+
var convert_audiodata_1 = require("./convert-audiodata");
|
|
20
|
+
Object.defineProperty(exports, "convertAudioData", { enumerable: true, get: function () { return convert_audiodata_1.convertAudioData; } });
|
|
19
21
|
var convert_media_1 = require("./convert-media");
|
|
20
22
|
Object.defineProperty(exports, "convertMedia", { enumerable: true, get: function () { return convert_media_1.convertMedia; } });
|
|
21
23
|
var default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
|
package/dist/on-audio-track.js
CHANGED
|
@@ -58,7 +58,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
58
58
|
}
|
|
59
59
|
const audioEncoderConfig = await (0, audio_encoder_config_1.getAudioEncoderConfig)({
|
|
60
60
|
numberOfChannels: track.numberOfChannels,
|
|
61
|
-
sampleRate: track.sampleRate,
|
|
61
|
+
sampleRate: audioOperation.sampleRate ?? track.sampleRate,
|
|
62
62
|
codec: audioOperation.audioCodec,
|
|
63
63
|
bitrate: audioOperation.bitrate,
|
|
64
64
|
});
|
|
@@ -79,7 +79,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
79
79
|
const codecPrivate = audioOperation.audioCodec === 'aac'
|
|
80
80
|
? media_parser_1.MediaParserInternals.createAacCodecPrivate({
|
|
81
81
|
audioObjectType: 2,
|
|
82
|
-
sampleRate: audioEncoderConfig.sampleRate,
|
|
82
|
+
sampleRate: audioOperation.sampleRate ?? audioEncoderConfig.sampleRate,
|
|
83
83
|
channelConfiguration: audioEncoderConfig.numberOfChannels,
|
|
84
84
|
codecPrivate: null,
|
|
85
85
|
})
|
|
@@ -90,7 +90,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
90
90
|
? 'pcm-s16'
|
|
91
91
|
: audioOperation.audioCodec,
|
|
92
92
|
numberOfChannels: audioEncoderConfig.numberOfChannels,
|
|
93
|
-
sampleRate: audioEncoderConfig.sampleRate,
|
|
93
|
+
sampleRate: audioOperation.sampleRate ?? audioEncoderConfig.sampleRate,
|
|
94
94
|
codecPrivate,
|
|
95
95
|
timescale: track.timescale,
|
|
96
96
|
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resampleAudioData = void 0;
|
|
4
|
+
const resampleAudioData = ({ audioData, newSampleRate, }) => {
|
|
5
|
+
const { numberOfChannels, sampleRate: currentSampleRate, numberOfFrames, } = audioData;
|
|
6
|
+
const ratio = currentSampleRate / newSampleRate;
|
|
7
|
+
const newNumberOfFrames = Math.floor(numberOfFrames / ratio);
|
|
8
|
+
// TODO: Float32Array hardcoded
|
|
9
|
+
const src = new Float32Array(numberOfChannels * numberOfFrames);
|
|
10
|
+
audioData.clone().copyTo(src, {
|
|
11
|
+
// TODO: Plane index hardcoded
|
|
12
|
+
planeIndex: 0,
|
|
13
|
+
});
|
|
14
|
+
const data = new Float32Array(newNumberOfFrames * numberOfChannels);
|
|
15
|
+
const chunkSize = numberOfFrames / newNumberOfFrames;
|
|
16
|
+
for (let i = 0; i < newNumberOfFrames; i++) {
|
|
17
|
+
const start = Math.floor(i * chunkSize);
|
|
18
|
+
const end = Math.max(Math.floor(start + chunkSize), start + 1);
|
|
19
|
+
const chunk = src.slice(start, end);
|
|
20
|
+
const average = chunk.reduce((a, b) => a + b, 0) / chunk.length;
|
|
21
|
+
for (let j = 0; j < numberOfChannels; j++) {
|
|
22
|
+
data[i * numberOfChannels + j] = average;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const newAudioData = new AudioData({
|
|
26
|
+
data,
|
|
27
|
+
format: audioData.format,
|
|
28
|
+
numberOfChannels,
|
|
29
|
+
numberOfFrames: newNumberOfFrames,
|
|
30
|
+
sampleRate: newSampleRate,
|
|
31
|
+
timestamp: audioData.timestamp,
|
|
32
|
+
});
|
|
33
|
+
return newAudioData;
|
|
34
|
+
};
|
|
35
|
+
exports.resampleAudioData = resampleAudioData;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { AudioEncoderInit, WebCodecsAudioEncoder } from './audio-encoder';
|
|
2
|
-
export declare const getWaveAudioEncoder: ({ onChunk, controller, }: Pick<AudioEncoderInit, "onChunk" | "controller">) => WebCodecsAudioEncoder;
|
|
2
|
+
export declare const getWaveAudioEncoder: ({ onChunk, controller, config, }: Pick<AudioEncoderInit, "onChunk" | "controller" | "config">) => WebCodecsAudioEncoder;
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getWaveAudioEncoder = void 0;
|
|
4
|
-
const
|
|
4
|
+
const convert_audiodata_1 = require("./convert-audiodata");
|
|
5
|
+
const getWaveAudioEncoder = ({ onChunk, controller, config, }) => {
|
|
5
6
|
return {
|
|
6
7
|
close: () => {
|
|
7
8
|
return Promise.resolve();
|
|
8
9
|
},
|
|
9
|
-
encodeFrame: (
|
|
10
|
+
encodeFrame: (unconvertedAudioData) => {
|
|
10
11
|
if (controller._internals.signal.aborted) {
|
|
11
12
|
return Promise.resolve();
|
|
12
13
|
}
|
|
14
|
+
const audioData = (0, convert_audiodata_1.convertAudioData)({
|
|
15
|
+
audioData: unconvertedAudioData,
|
|
16
|
+
newSampleRate: config.sampleRate,
|
|
17
|
+
format: 's16',
|
|
18
|
+
});
|
|
19
|
+
unconvertedAudioData.close();
|
|
13
20
|
const chunk = {
|
|
14
21
|
timestamp: audioData.timestamp,
|
|
15
22
|
duration: audioData.duration,
|
|
16
23
|
type: 'key',
|
|
17
|
-
copyTo: (destination) => audioData.copyTo(destination, { planeIndex: 0
|
|
18
|
-
byteLength: audioData.allocationSize({ planeIndex: 0
|
|
24
|
+
copyTo: (destination) => audioData.copyTo(destination, { planeIndex: 0 }),
|
|
25
|
+
byteLength: audioData.allocationSize({ planeIndex: 0 }),
|
|
19
26
|
};
|
|
20
27
|
return onChunk(chunk);
|
|
21
28
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/webcodecs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.288",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -12,20 +12,24 @@
|
|
|
12
12
|
"url": "https://github.com/remotion-dev/remotion/issues"
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
|
-
"dist"
|
|
15
|
+
"dist",
|
|
16
|
+
"!dist/test",
|
|
17
|
+
"!dist/it-tests"
|
|
16
18
|
],
|
|
17
19
|
"author": "Jonny Burger <jonny@remotion.dev>",
|
|
18
20
|
"license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)",
|
|
19
21
|
"dependencies": {
|
|
20
|
-
"@remotion/media-parser": "4.0.
|
|
21
|
-
"@remotion/licensing": "4.0.
|
|
22
|
+
"@remotion/media-parser": "4.0.288",
|
|
23
|
+
"@remotion/licensing": "4.0.288"
|
|
22
24
|
},
|
|
23
25
|
"peerDependencies": {},
|
|
24
26
|
"devDependencies": {
|
|
25
27
|
"@types/dom-webcodecs": "0.1.11",
|
|
28
|
+
"playwright": "1.51.1",
|
|
29
|
+
"@playwright/test": "1.51.1",
|
|
26
30
|
"eslint": "9.19.0",
|
|
27
|
-
"@remotion/
|
|
28
|
-
"@remotion/
|
|
31
|
+
"@remotion/eslint-config-internal": "4.0.288",
|
|
32
|
+
"@remotion/example-videos": "4.0.288"
|
|
29
33
|
},
|
|
30
34
|
"keywords": [],
|
|
31
35
|
"publishConfig": {
|
|
@@ -76,7 +80,8 @@
|
|
|
76
80
|
"scripts": {
|
|
77
81
|
"formatting": "prettier src --check",
|
|
78
82
|
"lint": "eslint src",
|
|
79
|
-
"test": "bun test src",
|
|
83
|
+
"test": "bun test src/test",
|
|
84
|
+
"testwebcodecs": "playwright test src/it-tests",
|
|
80
85
|
"watch": "tsc -w",
|
|
81
86
|
"make": "tsc -d && bun --env-file=../.env.bundle bundle.ts"
|
|
82
87
|
}
|
package/dist/test/avc1.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|