@remotion/webcodecs 4.0.287 → 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/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 +176 -15
- 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
|
@@ -428,6 +428,33 @@ var setRemotionImported = () => {
|
|
|
428
428
|
};
|
|
429
429
|
|
|
430
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
|
+
};
|
|
431
458
|
var getWaveAudioDecoder = ({
|
|
432
459
|
onFrame,
|
|
433
460
|
track,
|
|
@@ -435,11 +462,12 @@ var getWaveAudioDecoder = ({
|
|
|
435
462
|
}) => {
|
|
436
463
|
let queue = Promise.resolve();
|
|
437
464
|
const processSample = async (audioSample) => {
|
|
465
|
+
const bytesPerSample = getBytesPerSample(sampleFormat);
|
|
438
466
|
await onFrame(new AudioData({
|
|
439
467
|
data: audioSample.data,
|
|
440
468
|
format: sampleFormat,
|
|
441
469
|
numberOfChannels: track.numberOfChannels,
|
|
442
|
-
numberOfFrames: audioSample.data.byteLength /
|
|
470
|
+
numberOfFrames: audioSample.data.byteLength / bytesPerSample / track.numberOfChannels,
|
|
443
471
|
sampleRate: track.sampleRate,
|
|
444
472
|
timestamp: audioSample.timestamp
|
|
445
473
|
}));
|
|
@@ -778,25 +806,142 @@ var createAudioDecoder = ({
|
|
|
778
806
|
// src/audio-encoder.ts
|
|
779
807
|
import { MediaParserAbortError } from "@remotion/media-parser";
|
|
780
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
|
+
|
|
781
919
|
// src/wav-audio-encoder.ts
|
|
782
920
|
var getWaveAudioEncoder = ({
|
|
783
921
|
onChunk,
|
|
784
|
-
controller
|
|
922
|
+
controller,
|
|
923
|
+
config
|
|
785
924
|
}) => {
|
|
786
925
|
return {
|
|
787
926
|
close: () => {
|
|
788
927
|
return Promise.resolve();
|
|
789
928
|
},
|
|
790
|
-
encodeFrame: (
|
|
929
|
+
encodeFrame: (unconvertedAudioData) => {
|
|
791
930
|
if (controller._internals.signal.aborted) {
|
|
792
931
|
return Promise.resolve();
|
|
793
932
|
}
|
|
933
|
+
const audioData = convertAudioData({
|
|
934
|
+
audioData: unconvertedAudioData,
|
|
935
|
+
newSampleRate: config.sampleRate,
|
|
936
|
+
format: "s16"
|
|
937
|
+
});
|
|
938
|
+
unconvertedAudioData.close();
|
|
794
939
|
const chunk = {
|
|
795
940
|
timestamp: audioData.timestamp,
|
|
796
941
|
duration: audioData.duration,
|
|
797
942
|
type: "key",
|
|
798
|
-
copyTo: (destination) => audioData.copyTo(destination, { planeIndex: 0
|
|
799
|
-
byteLength: audioData.allocationSize({ planeIndex: 0
|
|
943
|
+
copyTo: (destination) => audioData.copyTo(destination, { planeIndex: 0 }),
|
|
944
|
+
byteLength: audioData.allocationSize({ planeIndex: 0 })
|
|
800
945
|
};
|
|
801
946
|
return onChunk(chunk);
|
|
802
947
|
},
|
|
@@ -820,7 +965,11 @@ var createAudioEncoder = ({
|
|
|
820
965
|
throw new MediaParserAbortError("Not creating audio encoder, already aborted");
|
|
821
966
|
}
|
|
822
967
|
if (codec === "wav") {
|
|
823
|
-
return getWaveAudioEncoder({
|
|
968
|
+
return getWaveAudioEncoder({
|
|
969
|
+
onChunk,
|
|
970
|
+
controller,
|
|
971
|
+
config: audioEncoderConfig
|
|
972
|
+
});
|
|
824
973
|
}
|
|
825
974
|
const ioSynchronizer = makeIoSynchronizer({
|
|
826
975
|
logLevel,
|
|
@@ -1017,7 +1166,8 @@ var getAudioEncoderConfig = async (config) => {
|
|
|
1017
1166
|
var canReencodeAudioTrack = async ({
|
|
1018
1167
|
track,
|
|
1019
1168
|
audioCodec,
|
|
1020
|
-
bitrate
|
|
1169
|
+
bitrate,
|
|
1170
|
+
sampleRate
|
|
1021
1171
|
}) => {
|
|
1022
1172
|
const audioDecoderConfig = await getAudioDecoderConfig(track);
|
|
1023
1173
|
if (audioCodec === "wav" && audioDecoderConfig) {
|
|
@@ -1026,7 +1176,7 @@ var canReencodeAudioTrack = async ({
|
|
|
1026
1176
|
const audioEncoderConfig = await getAudioEncoderConfig({
|
|
1027
1177
|
codec: audioCodec,
|
|
1028
1178
|
numberOfChannels: track.numberOfChannels,
|
|
1029
|
-
sampleRate: track.sampleRate,
|
|
1179
|
+
sampleRate: sampleRate ?? track.sampleRate,
|
|
1030
1180
|
bitrate
|
|
1031
1181
|
});
|
|
1032
1182
|
return Boolean(audioDecoderConfig && audioEncoderConfig);
|
|
@@ -1618,14 +1768,16 @@ var defaultOnAudioTrackHandler = async ({
|
|
|
1618
1768
|
const canReencode = await canReencodeAudioTrack({
|
|
1619
1769
|
audioCodec: defaultAudioCodec,
|
|
1620
1770
|
track,
|
|
1621
|
-
bitrate
|
|
1771
|
+
bitrate,
|
|
1772
|
+
sampleRate: null
|
|
1622
1773
|
});
|
|
1623
1774
|
if (canReencode) {
|
|
1624
1775
|
MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Cannot copy, but re-encode, therefore re-encoding`);
|
|
1625
1776
|
return Promise.resolve({
|
|
1626
1777
|
type: "reencode",
|
|
1627
1778
|
bitrate,
|
|
1628
|
-
audioCodec: defaultAudioCodec
|
|
1779
|
+
audioCodec: defaultAudioCodec,
|
|
1780
|
+
sampleRate: null
|
|
1629
1781
|
});
|
|
1630
1782
|
}
|
|
1631
1783
|
MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can neither re-encode nor copy, failing render`);
|
|
@@ -1707,7 +1859,7 @@ var makeAudioTrackHandler = ({
|
|
|
1707
1859
|
}
|
|
1708
1860
|
const audioEncoderConfig = await getAudioEncoderConfig({
|
|
1709
1861
|
numberOfChannels: track.numberOfChannels,
|
|
1710
|
-
sampleRate: track.sampleRate,
|
|
1862
|
+
sampleRate: audioOperation.sampleRate ?? track.sampleRate,
|
|
1711
1863
|
codec: audioOperation.audioCodec,
|
|
1712
1864
|
bitrate: audioOperation.bitrate
|
|
1713
1865
|
});
|
|
@@ -1727,7 +1879,7 @@ var makeAudioTrackHandler = ({
|
|
|
1727
1879
|
}
|
|
1728
1880
|
const codecPrivate = audioOperation.audioCodec === "aac" ? MediaParserInternals3.createAacCodecPrivate({
|
|
1729
1881
|
audioObjectType: 2,
|
|
1730
|
-
sampleRate: audioEncoderConfig.sampleRate,
|
|
1882
|
+
sampleRate: audioOperation.sampleRate ?? audioEncoderConfig.sampleRate,
|
|
1731
1883
|
channelConfiguration: audioEncoderConfig.numberOfChannels,
|
|
1732
1884
|
codecPrivate: null
|
|
1733
1885
|
}) : null;
|
|
@@ -1735,7 +1887,7 @@ var makeAudioTrackHandler = ({
|
|
|
1735
1887
|
type: "audio",
|
|
1736
1888
|
codec: audioOperation.audioCodec === "wav" ? "pcm-s16" : audioOperation.audioCodec,
|
|
1737
1889
|
numberOfChannels: audioEncoderConfig.numberOfChannels,
|
|
1738
|
-
sampleRate: audioEncoderConfig.sampleRate,
|
|
1890
|
+
sampleRate: audioOperation.sampleRate ?? audioEncoderConfig.sampleRate,
|
|
1739
1891
|
codecPrivate,
|
|
1740
1892
|
timescale: track.timescale
|
|
1741
1893
|
});
|
|
@@ -3066,6 +3218,9 @@ var createMp4a = ({
|
|
|
3066
3218
|
var createCodecSpecificData = (track) => {
|
|
3067
3219
|
if (track.type === "video") {
|
|
3068
3220
|
if (track.codec === "h264") {
|
|
3221
|
+
if (!track.codecPrivate) {
|
|
3222
|
+
return new Uint8Array([]);
|
|
3223
|
+
}
|
|
3069
3224
|
return createAvc1Data({
|
|
3070
3225
|
avccBox: createAvccBox(track.codecPrivate),
|
|
3071
3226
|
compressorName: "WebCodecs",
|
|
@@ -3079,6 +3234,9 @@ var createCodecSpecificData = (track) => {
|
|
|
3079
3234
|
});
|
|
3080
3235
|
}
|
|
3081
3236
|
if (track.codec === "h265") {
|
|
3237
|
+
if (!track.codecPrivate) {
|
|
3238
|
+
return new Uint8Array([]);
|
|
3239
|
+
}
|
|
3082
3240
|
return createHvc1Data({
|
|
3083
3241
|
hvccBox: createHvccBox(track.codecPrivate),
|
|
3084
3242
|
compressorName: "WebCodecs",
|
|
@@ -3781,7 +3939,9 @@ var createIsoBaseMedia = async ({
|
|
|
3781
3939
|
cts: Math.round(chunk.cts / 1e6 * currentTrack.timescale),
|
|
3782
3940
|
dts: Math.round(chunk.dts / 1e6 * currentTrack.timescale),
|
|
3783
3941
|
duration: Math.round((chunk.duration ?? 0) / 1e6 * currentTrack.timescale),
|
|
3784
|
-
size: chunk.data.length
|
|
3942
|
+
size: chunk.data.length,
|
|
3943
|
+
bigEndian: false,
|
|
3944
|
+
chunkSize: null
|
|
3785
3945
|
};
|
|
3786
3946
|
lastChunkWasVideo = isVideo;
|
|
3787
3947
|
samplePositions[trackNumber].push(samplePositionToAdd);
|
|
@@ -4588,7 +4748,7 @@ var createMatroskaMedia = async ({
|
|
|
4588
4748
|
}
|
|
4589
4749
|
});
|
|
4590
4750
|
},
|
|
4591
|
-
getBlob:
|
|
4751
|
+
getBlob: () => {
|
|
4592
4752
|
return w.getBlob();
|
|
4593
4753
|
},
|
|
4594
4754
|
remove: async () => {
|
|
@@ -5113,6 +5273,7 @@ export {
|
|
|
5113
5273
|
createAudioEncoder,
|
|
5114
5274
|
createAudioDecoder,
|
|
5115
5275
|
convertMedia,
|
|
5276
|
+
convertAudioData,
|
|
5116
5277
|
canReencodeVideoTrack,
|
|
5117
5278
|
canReencodeAudioTrack,
|
|
5118
5279
|
canCopyVideoTrack,
|
|
@@ -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/eslint-config-internal": "4.0.
|
|
28
|
-
"@remotion/example-videos": "4.0.
|
|
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 {};
|
package/dist/test/avc1.test.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const bun_test_1 = require("bun:test");
|
|
4
|
-
const avc1_1 = require("../create/iso-base-media/codec-specific/avc1");
|
|
5
|
-
const create_avcc_1 = require("../create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avcc");
|
|
6
|
-
const create_pasp_1 = require("../create/iso-base-media/trak/mdia/minf/stbl/stsd/create-pasp");
|
|
7
|
-
// bun segfaults here
|
|
8
|
-
if (process.platform !== 'win32') {
|
|
9
|
-
const reference = new Uint8Array([
|
|
10
|
-
0, 0, 0, 161, 97, 118, 99, 49, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
|
11
|
-
0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 128, 1, 104, 0, 72, 0, 0, 0, 72, 0, 0, 0, 0,
|
|
12
|
-
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
13
|
-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 255, 255, 0, 0, 0, 59, 97, 118, 99,
|
|
14
|
-
67, 1, 100, 0, 30, 255, 225, 0, 30, 103, 100, 0, 30, 172, 217, 64, 160, 47,
|
|
15
|
-
249, 112, 22, 224, 64, 64, 180, 160, 0, 0, 3, 0, 32, 0, 0, 7, 129, 226, 197,
|
|
16
|
-
178, 192, 1, 0, 6, 104, 235, 224, 140, 178, 44, 253, 248, 248, 0, 0, 0, 0,
|
|
17
|
-
16, 112, 97, 115, 112, 0, 0, 0, 1, 0, 0, 0, 1,
|
|
18
|
-
]);
|
|
19
|
-
(0, bun_test_1.test)('create avc1box', () => {
|
|
20
|
-
const privateData = new Uint8Array([
|
|
21
|
-
0x01, 0x64, 0x00, 0x1e, 0xff, 0xe1, 0x00, 0x1e, 0x67, 0x64, 0x00, 0x1e,
|
|
22
|
-
0xac, 0xd9, 0x40, 0xa0, 0x2f, 0xf9, 0x70, 0x16, 0xe0, 0x40, 0x40, 0xb4,
|
|
23
|
-
0xa0, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x07, 0x81, 0xe2, 0xc5,
|
|
24
|
-
0xb2, 0xc0, 0x01, 0x00, 0x06, 0x68, 0xeb, 0xe0, 0x8c, 0xb2, 0x2c, 0xfd,
|
|
25
|
-
0xf8, 0xf8, 0x00,
|
|
26
|
-
]);
|
|
27
|
-
(0, bun_test_1.expect)((0, avc1_1.createAvc1Data)({
|
|
28
|
-
pasp: (0, create_pasp_1.createPasp)(1, 1),
|
|
29
|
-
avccBox: (0, create_avcc_1.createAvccBox)(privateData),
|
|
30
|
-
width: 640,
|
|
31
|
-
height: 360,
|
|
32
|
-
horizontalResolution: 72,
|
|
33
|
-
verticalResolution: 72,
|
|
34
|
-
compressorName: '',
|
|
35
|
-
depth: 24,
|
|
36
|
-
type: 'avc1-data',
|
|
37
|
-
})).toEqual(reference);
|
|
38
|
-
});
|
|
39
|
-
}
|
package/dist/test/avcc.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/test/avcc.test.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const bun_test_1 = require("bun:test");
|
|
4
|
-
const create_avcc_1 = require("../create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avcc");
|
|
5
|
-
(0, bun_test_1.test)('avcc box', () => {
|
|
6
|
-
(0, bun_test_1.expect)((0, create_avcc_1.createAvccBox)(new Uint8Array([
|
|
7
|
-
1, 100, 0, 32, 255, 225, 0, 27, 103, 100, 0, 32, 172, 217, 64, 68, 2,
|
|
8
|
-
39, 150, 92, 4, 64, 0, 0, 3, 0, 64, 0, 0, 12, 3, 198, 12, 101, 128, 1,
|
|
9
|
-
0, 6, 104, 235, 224, 140, 178, 44, 253, 248, 248, 0,
|
|
10
|
-
]))).toEqual(new Uint8Array([
|
|
11
|
-
0, 0, 0, 56, 97, 118, 99, 67, 1, 100, 0, 32, 255, 225, 0, 27, 103, 100, 0,
|
|
12
|
-
32, 172, 217, 64, 68, 2, 39, 150, 92, 4, 64, 0, 0, 3, 0, 64, 0, 0, 12, 3,
|
|
13
|
-
198, 12, 101, 128, 1, 0, 6, 104, 235, 224, 140, 178, 44, 253, 248, 248, 0,
|
|
14
|
-
]));
|
|
15
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|