init commit
This commit is contained in:
7
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-duration.d.ts
generated
vendored
Normal file
7
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-duration.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { ParserState } from '../../state/parser-state';
|
||||
import type { XingData } from './parse-xing';
|
||||
export declare const getDurationFromMp3Xing: ({ xingData, samplesPerFrame, }: {
|
||||
xingData: XingData;
|
||||
samplesPerFrame: number;
|
||||
}) => number;
|
||||
export declare const getDurationFromMp3: (state: ParserState) => number | null;
|
||||
55
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-duration.js
generated
vendored
Normal file
55
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-duration.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getDurationFromMp3 = exports.getDurationFromMp3Xing = void 0;
|
||||
const get_frame_length_1 = require("./get-frame-length");
|
||||
const samples_per_mpeg_file_1 = require("./samples-per-mpeg-file");
|
||||
const getDurationFromMp3Xing = ({ xingData, samplesPerFrame, }) => {
|
||||
const xingFrames = xingData.numberOfFrames;
|
||||
if (!xingFrames) {
|
||||
throw new Error('Cannot get duration of VBR MP3 file - no frames');
|
||||
}
|
||||
const { sampleRate } = xingData;
|
||||
if (!sampleRate) {
|
||||
throw new Error('Cannot get duration of VBR MP3 file - no sample rate');
|
||||
}
|
||||
const xingSamples = xingFrames * samplesPerFrame;
|
||||
return xingSamples / sampleRate;
|
||||
};
|
||||
exports.getDurationFromMp3Xing = getDurationFromMp3Xing;
|
||||
const getDurationFromMp3 = (state) => {
|
||||
const mp3Info = state.mp3.getMp3Info();
|
||||
const mp3BitrateInfo = state.mp3.getMp3BitrateInfo();
|
||||
if (!mp3Info || !mp3BitrateInfo) {
|
||||
return null;
|
||||
}
|
||||
const samplesPerFrame = (0, samples_per_mpeg_file_1.getSamplesPerMpegFrame)({
|
||||
layer: mp3Info.layer,
|
||||
mpegVersion: mp3Info.mpegVersion,
|
||||
});
|
||||
if (mp3BitrateInfo.type === 'variable') {
|
||||
return (0, exports.getDurationFromMp3Xing)({
|
||||
xingData: mp3BitrateInfo.xingData,
|
||||
samplesPerFrame,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* sonnet: The variation between 1044 and 1045 bytes in MP3 frames occurs due to the bit reservoir mechanism in MP3 encoding. Here's the typical distribution:
|
||||
* • 1044 bytes (99% of frames)
|
||||
* • 1045 bytes (1% of frames)
|
||||
*/
|
||||
// we ignore that fact for now
|
||||
const frameLengthInBytes = (0, get_frame_length_1.getMpegFrameLength)({
|
||||
bitrateKbit: mp3BitrateInfo.bitrateInKbit,
|
||||
padding: false,
|
||||
samplesPerFrame,
|
||||
samplingFrequency: mp3Info.sampleRate,
|
||||
layer: mp3Info.layer,
|
||||
});
|
||||
const frames = Math.floor((state.contentLength -
|
||||
state.mediaSection.getMediaSectionAssertOnlyOne().start) /
|
||||
frameLengthInBytes);
|
||||
const samples = frames * samplesPerFrame;
|
||||
const durationInSeconds = samples / mp3Info.sampleRate;
|
||||
return durationInSeconds;
|
||||
};
|
||||
exports.getDurationFromMp3 = getDurationFromMp3;
|
||||
13
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-frame-length.d.ts
generated
vendored
Normal file
13
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-frame-length.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
export declare const getAverageMpegFrameLength: ({ samplesPerFrame, bitrateKbit, samplingFrequency, layer, }: {
|
||||
samplesPerFrame: number;
|
||||
bitrateKbit: number;
|
||||
samplingFrequency: number;
|
||||
layer: number;
|
||||
}) => number;
|
||||
export declare const getMpegFrameLength: ({ samplesPerFrame, bitrateKbit, samplingFrequency, padding, layer, }: {
|
||||
samplesPerFrame: number;
|
||||
bitrateKbit: number;
|
||||
samplingFrequency: number;
|
||||
padding: boolean;
|
||||
layer: number;
|
||||
}) => number;
|
||||
33
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-frame-length.js
generated
vendored
Normal file
33
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-frame-length.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getMpegFrameLength = exports.getAverageMpegFrameLength = void 0;
|
||||
const getUnroundedMpegFrameLength = ({ samplesPerFrame, bitrateKbit, samplingFrequency, padding, layer, }) => {
|
||||
if (layer === 1) {
|
||||
throw new Error('MPEG Layer I is not supported');
|
||||
}
|
||||
return ((((samplesPerFrame / 8) * bitrateKbit) / samplingFrequency) * 1000 +
|
||||
(padding ? (layer === 1 ? 4 : 1) : 0));
|
||||
};
|
||||
const getAverageMpegFrameLength = ({ samplesPerFrame, bitrateKbit, samplingFrequency, layer, }) => {
|
||||
const withoutPadding = getUnroundedMpegFrameLength({
|
||||
bitrateKbit,
|
||||
layer,
|
||||
padding: false,
|
||||
samplesPerFrame,
|
||||
samplingFrequency,
|
||||
});
|
||||
const rounded = Math.floor(withoutPadding);
|
||||
const rest = withoutPadding % 1;
|
||||
return rest * (rounded + 1) + (1 - rest) * rounded;
|
||||
};
|
||||
exports.getAverageMpegFrameLength = getAverageMpegFrameLength;
|
||||
const getMpegFrameLength = ({ samplesPerFrame, bitrateKbit, samplingFrequency, padding, layer, }) => {
|
||||
return Math.floor(getUnroundedMpegFrameLength({
|
||||
bitrateKbit,
|
||||
layer,
|
||||
padding,
|
||||
samplesPerFrame,
|
||||
samplingFrequency,
|
||||
}));
|
||||
};
|
||||
exports.getMpegFrameLength = getMpegFrameLength;
|
||||
3
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-metadata-from-mp3.d.ts
generated
vendored
Normal file
3
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-metadata-from-mp3.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { MediaParserMetadataEntry } from '../../metadata/get-metadata';
|
||||
import type { Mp3Structure } from '../../parse-result';
|
||||
export declare const getMetadataFromMp3: (mp3Structure: Mp3Structure) => MediaParserMetadataEntry[] | null;
|
||||
8
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-metadata-from-mp3.js
generated
vendored
Normal file
8
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-metadata-from-mp3.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getMetadataFromMp3 = void 0;
|
||||
const getMetadataFromMp3 = (mp3Structure) => {
|
||||
const findHeader = mp3Structure.boxes.find((b) => b.type === 'id3-header');
|
||||
return findHeader ? findHeader.metatags : null;
|
||||
};
|
||||
exports.getMetadataFromMp3 = getMetadataFromMp3;
|
||||
6
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-seeking-byte.d.ts
generated
vendored
Normal file
6
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-seeking-byte.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { SeekResolution } from '../../work-on-seek-request';
|
||||
import type { Mp3SeekingHints } from './seeking-hints';
|
||||
export declare const getSeekingByteForMp3: ({ time, info, }: {
|
||||
time: number;
|
||||
info: Mp3SeekingHints;
|
||||
}) => SeekResolution;
|
||||
52
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-seeking-byte.js
generated
vendored
Normal file
52
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/get-seeking-byte.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getSeekingByteForMp3 = void 0;
|
||||
const get_approximate_byte_from_bitrate_1 = require("./seek/get-approximate-byte-from-bitrate");
|
||||
const get_byte_from_observed_samples_1 = require("./seek/get-byte-from-observed-samples");
|
||||
const get_seek_point_from_xing_1 = require("./seek/get-seek-point-from-xing");
|
||||
const getSeekingByteForMp3 = ({ time, info, }) => {
|
||||
var _a;
|
||||
if (info.mp3BitrateInfo === null ||
|
||||
info.mp3Info === null ||
|
||||
info.mediaSection === null) {
|
||||
return {
|
||||
type: 'valid-but-must-wait',
|
||||
};
|
||||
}
|
||||
const approximateByte = (0, get_approximate_byte_from_bitrate_1.getApproximateByteFromBitrate)({
|
||||
mp3BitrateInfo: info.mp3BitrateInfo,
|
||||
timeInSeconds: time,
|
||||
mp3Info: info.mp3Info,
|
||||
mediaSection: info.mediaSection,
|
||||
contentLength: info.contentLength,
|
||||
});
|
||||
const bestAudioSample = (0, get_byte_from_observed_samples_1.getByteFromObservedSamples)({
|
||||
info,
|
||||
timeInSeconds: time,
|
||||
});
|
||||
const xingSeekPoint = info.mp3BitrateInfo.type === 'variable'
|
||||
? (0, get_seek_point_from_xing_1.getSeekPointFromXing)({
|
||||
mp3Info: info.mp3Info,
|
||||
timeInSeconds: time,
|
||||
xingData: info.mp3BitrateInfo.xingData,
|
||||
})
|
||||
: null;
|
||||
const candidates = [
|
||||
approximateByte,
|
||||
(_a = bestAudioSample === null || bestAudioSample === void 0 ? void 0 : bestAudioSample.offset) !== null && _a !== void 0 ? _a : null,
|
||||
xingSeekPoint,
|
||||
].filter((b) => b !== null);
|
||||
if (candidates.length === 0) {
|
||||
return {
|
||||
type: 'valid-but-must-wait',
|
||||
};
|
||||
}
|
||||
const byte = Math.max(...candidates);
|
||||
const timeInSeconds = byte === (bestAudioSample === null || bestAudioSample === void 0 ? void 0 : bestAudioSample.offset) ? bestAudioSample.timeInSeconds : time;
|
||||
return {
|
||||
type: 'do-seek',
|
||||
byte,
|
||||
timeInSeconds,
|
||||
};
|
||||
};
|
||||
exports.getSeekingByteForMp3 = getSeekingByteForMp3;
|
||||
2
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/id3-v1.d.ts
generated
vendored
Normal file
2
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/id3-v1.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import type { BufferIterator } from '../../iterator/buffer-iterator';
|
||||
export declare const parseID3V1: (iterator: BufferIterator) => void;
|
||||
12
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/id3-v1.js
generated
vendored
Normal file
12
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/id3-v1.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseID3V1 = void 0;
|
||||
const parseID3V1 = (iterator) => {
|
||||
if (iterator.bytesRemaining() < 128) {
|
||||
return;
|
||||
}
|
||||
// we drop ID3v1 because usually there is also ID3v2 and ID3v3 which are superior.
|
||||
// Better than have duplicated data.
|
||||
iterator.discard(128);
|
||||
};
|
||||
exports.parseID3V1 = parseID3V1;
|
||||
4
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/id3.d.ts
generated
vendored
Normal file
4
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/id3.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { ParserState } from '../../state/parser-state';
|
||||
export declare const parseId3: ({ state }: {
|
||||
state: ParserState;
|
||||
}) => void;
|
||||
83
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/id3.js
generated
vendored
Normal file
83
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/id3.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseId3 = void 0;
|
||||
function combine28Bits(a, b, c, d) {
|
||||
// Mask each number to ignore first bit (& 0x7F)
|
||||
const val1 = a & 0x7f; // 7 bits from first byte
|
||||
const val2 = b & 0x7f; // 7 bits from second byte
|
||||
const val3 = c & 0x7f; // 7 bits from third byte
|
||||
const val4 = d & 0x7f; // 7 bits from fourth byte
|
||||
// Combine all values using bitwise operations
|
||||
return (val1 << 21) | (val2 << 14) | (val3 << 7) | val4;
|
||||
}
|
||||
const parseId3 = ({ state }) => {
|
||||
const { iterator } = state;
|
||||
if (iterator.bytesRemaining() < 9) {
|
||||
return;
|
||||
}
|
||||
const { returnToCheckpoint } = iterator.startCheckpoint();
|
||||
iterator.discard(3);
|
||||
const versionMajor = iterator.getUint8();
|
||||
const versionMinor = iterator.getUint8();
|
||||
const flags = iterator.getUint8();
|
||||
const sizeArr = iterator.getSlice(4);
|
||||
const size = combine28Bits(sizeArr[0], sizeArr[1], sizeArr[2], sizeArr[3]);
|
||||
if (iterator.bytesRemaining() < size) {
|
||||
returnToCheckpoint();
|
||||
return;
|
||||
}
|
||||
const entries = [];
|
||||
const initial = iterator.counter.getOffset();
|
||||
while (iterator.counter.getOffset() < size + initial) {
|
||||
const name = versionMajor === 3 || versionMajor === 4
|
||||
? iterator.getByteString(4, true)
|
||||
: iterator.getByteString(3, true);
|
||||
if (name === '') {
|
||||
iterator.discard(size + initial - iterator.counter.getOffset());
|
||||
break;
|
||||
}
|
||||
const s = versionMajor === 4
|
||||
? iterator.getSyncSafeInt32()
|
||||
: versionMajor === 3
|
||||
? iterator.getUint32()
|
||||
: iterator.getUint24();
|
||||
if (versionMajor === 3 || versionMajor === 4) {
|
||||
iterator.getUint16(); // flags
|
||||
}
|
||||
let subtract = 0;
|
||||
if (!name.startsWith('W')) {
|
||||
iterator.getUint8(); // encoding
|
||||
subtract += 1;
|
||||
}
|
||||
if (name === 'APIC') {
|
||||
const { discardRest } = iterator.planBytes(s - subtract);
|
||||
const mimeType = iterator.readUntilNullTerminator();
|
||||
iterator.getUint16(); // picture type
|
||||
const description = iterator.readUntilNullTerminator();
|
||||
iterator.discard(1);
|
||||
const data = discardRest();
|
||||
state.images.addImage({
|
||||
data,
|
||||
description,
|
||||
mimeType,
|
||||
});
|
||||
}
|
||||
else {
|
||||
const information = iterator.getByteString(s - subtract, true);
|
||||
entries.push({
|
||||
key: name,
|
||||
value: information,
|
||||
trackId: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
state.structure.getMp3Structure().boxes.push({
|
||||
type: 'id3-header',
|
||||
flags,
|
||||
size,
|
||||
versionMajor,
|
||||
versionMinor,
|
||||
metatags: entries,
|
||||
});
|
||||
};
|
||||
exports.parseId3 = parseId3;
|
||||
3
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-mp3.d.ts
generated
vendored
Normal file
3
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-mp3.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { ParseResult } from '../../parse-result';
|
||||
import type { ParserState } from '../../state/parser-state';
|
||||
export declare const parseMp3: (state: ParserState) => Promise<ParseResult>;
|
||||
42
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-mp3.js
generated
vendored
Normal file
42
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-mp3.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseMp3 = void 0;
|
||||
const id3_1 = require("./id3");
|
||||
const id3_v1_1 = require("./id3-v1");
|
||||
const parse_mpeg_header_1 = require("./parse-mpeg-header");
|
||||
const wait_until_syncword_1 = require("./seek/wait-until-syncword");
|
||||
const parseMp3 = async (state) => {
|
||||
const { iterator } = state;
|
||||
if (iterator.bytesRemaining() < 3) {
|
||||
return null;
|
||||
}
|
||||
// When coming from a seek, we need to discard until the syncword
|
||||
if (state.mediaSection.isCurrentByteInMediaSection(iterator) === 'in-section') {
|
||||
(0, wait_until_syncword_1.discardUntilSyncword)({ iterator });
|
||||
await (0, parse_mpeg_header_1.parseMpegHeader)({
|
||||
state,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
const { returnToCheckpoint } = iterator.startCheckpoint();
|
||||
const bytes = iterator.getSlice(3);
|
||||
returnToCheckpoint();
|
||||
// ID3 v1
|
||||
if (bytes[0] === 0x54 && bytes[1] === 0x41 && bytes[2] === 0x47) {
|
||||
(0, id3_v1_1.parseID3V1)(iterator);
|
||||
return null;
|
||||
}
|
||||
// ID3 v2 or v3
|
||||
if (bytes[0] === 0x49 && bytes[1] === 0x44 && bytes[2] === 0x33) {
|
||||
(0, id3_1.parseId3)({ state });
|
||||
return null;
|
||||
}
|
||||
if (bytes[0] === 0xff) {
|
||||
await (0, parse_mpeg_header_1.parseMpegHeader)({
|
||||
state,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
throw new Error('Unknown MP3 header ' + JSON.stringify(bytes));
|
||||
};
|
||||
exports.parseMp3 = parseMp3;
|
||||
4
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-mpeg-header.d.ts
generated
vendored
Normal file
4
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-mpeg-header.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { ParserState } from '../../state/parser-state';
|
||||
export declare const parseMpegHeader: ({ state, }: {
|
||||
state: ParserState;
|
||||
}) => Promise<void>;
|
||||
117
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-mpeg-header.js
generated
vendored
Normal file
117
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-mpeg-header.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
"use strict";
|
||||
// spec: http://www.mp3-tech.org/programmer/frame_header.html
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseMpegHeader = void 0;
|
||||
const log_1 = require("../../log");
|
||||
const register_track_1 = require("../../register-track");
|
||||
const webcodecs_timescale_1 = require("../../webcodecs-timescale");
|
||||
const parse_packet_header_1 = require("./parse-packet-header");
|
||||
const parse_xing_1 = require("./parse-xing");
|
||||
const audio_sample_from_cbr_1 = require("./seek/audio-sample-from-cbr");
|
||||
const audio_sample_from_vbr_1 = require("./seek/audio-sample-from-vbr");
|
||||
const parseMpegHeader = async ({ state, }) => {
|
||||
const { iterator } = state;
|
||||
const initialOffset = iterator.counter.getOffset();
|
||||
if (iterator.bytesRemaining() < 32) {
|
||||
return;
|
||||
}
|
||||
// parse header
|
||||
const { frameLength, bitrateInKbit, layer, mpegVersion, numberOfChannels, sampleRate, samplesPerFrame, } = (0, parse_packet_header_1.parseMp3PacketHeader)(iterator);
|
||||
const cbrMp3Info = state.mp3.getMp3BitrateInfo();
|
||||
if (cbrMp3Info && cbrMp3Info.type === 'constant') {
|
||||
if (bitrateInKbit !== cbrMp3Info.bitrateInKbit) {
|
||||
throw new Error(`Bitrate mismatch at offset ${initialOffset}: ${bitrateInKbit} !== ${cbrMp3Info.bitrateInKbit}`);
|
||||
}
|
||||
}
|
||||
const offsetNow = iterator.counter.getOffset();
|
||||
iterator.counter.decrement(offsetNow - initialOffset);
|
||||
const data = iterator.getSlice(frameLength);
|
||||
if (state.callbacks.tracks.getTracks().length === 0) {
|
||||
const info = {
|
||||
layer,
|
||||
mpegVersion,
|
||||
sampleRate,
|
||||
};
|
||||
const asText = new TextDecoder().decode(data);
|
||||
if (asText.includes('VBRI')) {
|
||||
throw new Error('MP3 files with VBRI are currently unsupported because we have no sample file. Submit this file at remotion.dev/report if you would like us to support this file.');
|
||||
}
|
||||
if (asText.includes('Info')) {
|
||||
return;
|
||||
}
|
||||
const isVbr = asText.includes('Xing');
|
||||
if (isVbr) {
|
||||
const xingData = (0, parse_xing_1.parseXing)(data);
|
||||
log_1.Log.verbose(state.logLevel, 'MP3 has variable bit rate. Requiring whole file to be read');
|
||||
state.mp3.setMp3BitrateInfo({
|
||||
type: 'variable',
|
||||
xingData,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!state.mp3.getMp3BitrateInfo()) {
|
||||
state.mp3.setMp3BitrateInfo({
|
||||
bitrateInKbit,
|
||||
type: 'constant',
|
||||
});
|
||||
}
|
||||
state.mp3.setMp3Info(info);
|
||||
await (0, register_track_1.registerAudioTrack)({
|
||||
container: 'mp3',
|
||||
track: {
|
||||
type: 'audio',
|
||||
codec: 'mp3',
|
||||
codecData: null,
|
||||
codecEnum: 'mp3',
|
||||
description: undefined,
|
||||
numberOfChannels,
|
||||
sampleRate,
|
||||
originalTimescale: 1000000,
|
||||
trackId: 0,
|
||||
startInSeconds: 0,
|
||||
timescale: webcodecs_timescale_1.WEBCODECS_TIMESCALE,
|
||||
trackMediaTimeOffsetInTrackTimescale: 0,
|
||||
},
|
||||
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
||||
tracks: state.callbacks.tracks,
|
||||
logLevel: state.logLevel,
|
||||
onAudioTrack: state.onAudioTrack,
|
||||
});
|
||||
state.callbacks.tracks.setIsDone(state.logLevel);
|
||||
state.mediaSection.addMediaSection({
|
||||
start: initialOffset,
|
||||
size: state.contentLength - initialOffset,
|
||||
});
|
||||
}
|
||||
const bitrateInfo = state.mp3.getMp3BitrateInfo();
|
||||
if (!bitrateInfo) {
|
||||
throw new Error('No bitrate info');
|
||||
}
|
||||
const sample = bitrateInfo.type === 'constant'
|
||||
? (0, audio_sample_from_cbr_1.getAudioSampleFromCbr)({
|
||||
bitrateInKbit,
|
||||
data,
|
||||
initialOffset,
|
||||
layer,
|
||||
sampleRate,
|
||||
samplesPerFrame,
|
||||
state,
|
||||
})
|
||||
: (0, audio_sample_from_vbr_1.getAudioSampleFromVbr)({
|
||||
data,
|
||||
info: bitrateInfo,
|
||||
mp3Info: state.mp3.getMp3Info(),
|
||||
position: initialOffset,
|
||||
});
|
||||
const { audioSample, timeInSeconds, durationInSeconds } = sample;
|
||||
state.mp3.audioSamples.addSample({
|
||||
timeInSeconds,
|
||||
offset: initialOffset,
|
||||
durationInSeconds,
|
||||
});
|
||||
await state.callbacks.onAudioSample({
|
||||
audioSample,
|
||||
trackId: 0,
|
||||
});
|
||||
};
|
||||
exports.parseMpegHeader = parseMpegHeader;
|
||||
30
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-packet-header.d.ts
generated
vendored
Normal file
30
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-packet-header.d.ts
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { BufferIterator } from '../../iterator/buffer-iterator';
|
||||
type MpegVersion = 1 | 2;
|
||||
export declare const parseMp3PacketHeader: (iterator: BufferIterator) => {
|
||||
frameLength: number;
|
||||
bitrateInKbit: number;
|
||||
layer: number;
|
||||
mpegVersion: MpegVersion;
|
||||
numberOfChannels: number;
|
||||
sampleRate: number;
|
||||
samplesPerFrame: number;
|
||||
};
|
||||
export declare const isMp3PacketHeaderHere: (iterator: BufferIterator) => false | {
|
||||
frameLength: number;
|
||||
bitrateInKbit: number;
|
||||
layer: number;
|
||||
mpegVersion: MpegVersion;
|
||||
numberOfChannels: number;
|
||||
sampleRate: number;
|
||||
samplesPerFrame: number;
|
||||
};
|
||||
export declare const isMp3PacketHeaderHereAndInNext: (iterator: BufferIterator) => boolean | {
|
||||
frameLength: number;
|
||||
bitrateInKbit: number;
|
||||
layer: number;
|
||||
mpegVersion: MpegVersion;
|
||||
numberOfChannels: number;
|
||||
sampleRate: number;
|
||||
samplesPerFrame: number;
|
||||
};
|
||||
export {};
|
||||
258
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-packet-header.js
generated
vendored
Normal file
258
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-packet-header.js
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isMp3PacketHeaderHereAndInNext = exports.isMp3PacketHeaderHere = exports.parseMp3PacketHeader = void 0;
|
||||
const get_frame_length_1 = require("./get-frame-length");
|
||||
const samples_per_mpeg_file_1 = require("./samples-per-mpeg-file");
|
||||
function getSamplingFrequency({ bits, mpegVersion, }) {
|
||||
const samplingTable = {
|
||||
0b00: { MPEG1: 44100, MPEG2: 22050 },
|
||||
0b01: { MPEG1: 48000, MPEG2: 24000 },
|
||||
0b10: { MPEG1: 32000, MPEG2: 16000 },
|
||||
0b11: { MPEG1: 'reserved', MPEG2: 'reserved' },
|
||||
};
|
||||
const key = `MPEG${mpegVersion}`;
|
||||
const value = samplingTable[bits][key];
|
||||
if (value === 'reserved') {
|
||||
throw new Error('Reserved sampling frequency');
|
||||
}
|
||||
if (!value) {
|
||||
throw new Error('Invalid sampling frequency for MPEG version: ' +
|
||||
JSON.stringify({ bits, version: mpegVersion }));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function getBitrateKB({ bits, mpegVersion, level, }) {
|
||||
const bitrateTable = {
|
||||
0b0000: {
|
||||
'V1,L1': 'free',
|
||||
'V1,L2': 'free',
|
||||
'V1,L3': 'free',
|
||||
'V2,L1': 'free',
|
||||
'V2,L2&L3': 'free',
|
||||
},
|
||||
0b0001: { 'V1,L1': 32, 'V1,L2': 32, 'V1,L3': 32, 'V2,L1': 32, 'V2,L2&L3': 8 },
|
||||
0b0010: {
|
||||
'V1,L1': 64,
|
||||
'V1,L2': 48,
|
||||
'V1,L3': 40,
|
||||
'V2,L1': 48,
|
||||
'V2,L2&L3': 16,
|
||||
},
|
||||
0b0011: {
|
||||
'V1,L1': 96,
|
||||
'V1,L2': 56,
|
||||
'V1,L3': 48,
|
||||
'V2,L1': 56,
|
||||
'V2,L2&L3': 24,
|
||||
},
|
||||
0b0100: {
|
||||
'V1,L1': 128,
|
||||
'V1,L2': 64,
|
||||
'V1,L3': 56,
|
||||
'V2,L1': 64,
|
||||
'V2,L2&L3': 32,
|
||||
},
|
||||
0b0101: {
|
||||
'V1,L1': 160,
|
||||
'V1,L2': 80,
|
||||
'V1,L3': 64,
|
||||
'V2,L1': 80,
|
||||
'V2,L2&L3': 40,
|
||||
},
|
||||
0b0110: {
|
||||
'V1,L1': 192,
|
||||
'V1,L2': 96,
|
||||
'V1,L3': 80,
|
||||
'V2,L1': 96,
|
||||
'V2,L2&L3': 48,
|
||||
},
|
||||
0b0111: {
|
||||
'V1,L1': 224,
|
||||
'V1,L2': 112,
|
||||
'V1,L3': 96,
|
||||
'V2,L1': 112,
|
||||
'V2,L2&L3': 56,
|
||||
},
|
||||
0b1000: {
|
||||
'V1,L1': 256,
|
||||
'V1,L2': 128,
|
||||
'V1,L3': 112,
|
||||
'V2,L1': 128,
|
||||
'V2,L2&L3': 64,
|
||||
},
|
||||
0b1001: {
|
||||
'V1,L1': 288,
|
||||
'V1,L2': 160,
|
||||
'V1,L3': 128,
|
||||
'V2,L1': 144,
|
||||
'V2,L2&L3': 80,
|
||||
},
|
||||
0b1010: {
|
||||
'V1,L1': 320,
|
||||
'V1,L2': 192,
|
||||
'V1,L3': 160,
|
||||
'V2,L1': 160,
|
||||
'V2,L2&L3': 96,
|
||||
},
|
||||
0b1011: {
|
||||
'V1,L1': 352,
|
||||
'V1,L2': 224,
|
||||
'V1,L3': 192,
|
||||
'V2,L1': 176,
|
||||
'V2,L2&L3': 112,
|
||||
},
|
||||
0b1100: {
|
||||
'V1,L1': 384,
|
||||
'V1,L2': 256,
|
||||
'V1,L3': 224,
|
||||
'V2,L1': 192,
|
||||
'V2,L2&L3': 128,
|
||||
},
|
||||
0b1101: {
|
||||
'V1,L1': 416,
|
||||
'V1,L2': 320,
|
||||
'V1,L3': 256,
|
||||
'V2,L1': 224,
|
||||
'V2,L2&L3': 144,
|
||||
},
|
||||
0b1110: {
|
||||
'V1,L1': 448,
|
||||
'V1,L2': 384,
|
||||
'V1,L3': 320,
|
||||
'V2,L1': 256,
|
||||
'V2,L2&L3': 160,
|
||||
},
|
||||
0b1111: {
|
||||
'V1,L1': 'bad',
|
||||
'V1,L2': 'bad',
|
||||
'V1,L3': 'bad',
|
||||
'V2,L1': 'bad',
|
||||
'V2,L2&L3': 'bad',
|
||||
},
|
||||
};
|
||||
// Determine the correct key based on version and level
|
||||
let key;
|
||||
if (mpegVersion === 2 && (level === 2 || level === 3)) {
|
||||
key = 'V2,L2&L3';
|
||||
}
|
||||
else {
|
||||
key = `V${mpegVersion},L${level}`;
|
||||
}
|
||||
// Return the corresponding bitrate
|
||||
return bitrateTable[bits][key];
|
||||
}
|
||||
const innerParseMp3PacketHeader = (iterator) => {
|
||||
for (let i = 0; i < 11; i++) {
|
||||
const expectToBe1 = iterator.getBits(1);
|
||||
if (expectToBe1 !== 1) {
|
||||
throw new Error('Expected 1');
|
||||
}
|
||||
}
|
||||
const audioVersionId = iterator.getBits(2);
|
||||
/**
|
||||
* 00 - MPEG Version 2.5 (later extension of MPEG 2)
|
||||
01 - reserved
|
||||
10 - MPEG Version 2 (ISO/IEC 13818-3)
|
||||
11 - MPEG Version 1 (ISO/IEC 11172-3)
|
||||
*/
|
||||
if (audioVersionId !== 0b11 &&
|
||||
audioVersionId !== 0b10 &&
|
||||
audioVersionId !== 0b00) {
|
||||
throw new Error('Expected MPEG Version 1 or 2');
|
||||
}
|
||||
const mpegVersion = audioVersionId === 0b11 ? 1 : 2;
|
||||
const layerBits = iterator.getBits(2);
|
||||
/**
|
||||
* 00 - reserved
|
||||
01 - Layer III
|
||||
10 - Layer II
|
||||
11 - Layer I
|
||||
*/
|
||||
if (layerBits === 0b00) {
|
||||
throw new Error('Expected Layer I, II or III');
|
||||
}
|
||||
const layer = layerBits === 0b11 ? 1 : layerBits === 0b10 ? 2 : 3;
|
||||
iterator.getBits(1); // 0b1 means that there is no CRC, 0b0 means there is. Not validating checksum though
|
||||
const bitrateIndex = iterator.getBits(4);
|
||||
const bitrateInKbit = getBitrateKB({
|
||||
bits: bitrateIndex,
|
||||
mpegVersion,
|
||||
level: layer,
|
||||
});
|
||||
if (bitrateInKbit === 'bad') {
|
||||
throw new Error('Invalid bitrate');
|
||||
}
|
||||
if (bitrateInKbit === 'free') {
|
||||
throw new Error('Free bitrate not supported');
|
||||
}
|
||||
const samplingFrequencyIndex = iterator.getBits(2);
|
||||
const baseSampleRate = getSamplingFrequency({
|
||||
bits: samplingFrequencyIndex,
|
||||
mpegVersion,
|
||||
});
|
||||
const sampleRate = audioVersionId === 0b00 ? baseSampleRate / 2 : baseSampleRate;
|
||||
const padding = Boolean(iterator.getBits(1));
|
||||
iterator.getBits(1); // private bit
|
||||
const channelMode = iterator.getBits(2); // channel mode
|
||||
iterator.getBits(2); // mode extension
|
||||
iterator.getBits(1); // copyright
|
||||
iterator.getBits(1); // original
|
||||
iterator.getBits(2); // emphasis
|
||||
const numberOfChannels = channelMode === 0b11 ? 1 : 2;
|
||||
const samplesPerFrame = (0, samples_per_mpeg_file_1.getSamplesPerMpegFrame)({ mpegVersion, layer });
|
||||
const frameLength = (0, get_frame_length_1.getMpegFrameLength)({
|
||||
bitrateKbit: bitrateInKbit,
|
||||
padding,
|
||||
samplesPerFrame,
|
||||
samplingFrequency: sampleRate,
|
||||
layer,
|
||||
});
|
||||
return {
|
||||
frameLength,
|
||||
bitrateInKbit,
|
||||
layer,
|
||||
mpegVersion,
|
||||
numberOfChannels,
|
||||
sampleRate,
|
||||
samplesPerFrame,
|
||||
};
|
||||
};
|
||||
const parseMp3PacketHeader = (iterator) => {
|
||||
iterator.startReadingBits();
|
||||
const d = innerParseMp3PacketHeader(iterator);
|
||||
iterator.stopReadingBits();
|
||||
return d;
|
||||
};
|
||||
exports.parseMp3PacketHeader = parseMp3PacketHeader;
|
||||
const isMp3PacketHeaderHere = (iterator) => {
|
||||
const offset = iterator.counter.getOffset();
|
||||
iterator.startReadingBits();
|
||||
try {
|
||||
const res = innerParseMp3PacketHeader(iterator);
|
||||
iterator.stopReadingBits();
|
||||
iterator.counter.decrement(iterator.counter.getOffset() - offset);
|
||||
return res;
|
||||
}
|
||||
catch (_a) {
|
||||
iterator.stopReadingBits();
|
||||
iterator.counter.decrement(iterator.counter.getOffset() - offset);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
exports.isMp3PacketHeaderHere = isMp3PacketHeaderHere;
|
||||
const isMp3PacketHeaderHereAndInNext = (iterator) => {
|
||||
const offset = iterator.counter.getOffset();
|
||||
const res = (0, exports.isMp3PacketHeaderHere)(iterator);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
// cannot check here because we don't have enough data, let's hope for the best
|
||||
if (iterator.bytesRemaining() <= res.frameLength) {
|
||||
return true;
|
||||
}
|
||||
iterator.counter.increment(res.frameLength);
|
||||
const isHere = (0, exports.isMp3PacketHeaderHere)(iterator);
|
||||
iterator.counter.decrement(iterator.counter.getOffset() - offset);
|
||||
return isHere;
|
||||
};
|
||||
exports.isMp3PacketHeaderHereAndInNext = isMp3PacketHeaderHereAndInNext;
|
||||
19
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-xing.d.ts
generated
vendored
Normal file
19
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-xing.d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export type XingData = {
|
||||
sampleRate: number;
|
||||
numberOfFrames: number | null;
|
||||
fileSize: number | null;
|
||||
tableOfContents: number[] | null;
|
||||
vbrScale: number | null;
|
||||
};
|
||||
export declare const parseXing: (data: Uint8Array) => XingData;
|
||||
export declare const getSeekPointInBytes: ({ fileSize, percentBetween0And100, tableOfContents, }: {
|
||||
tableOfContents: number[];
|
||||
fileSize: number;
|
||||
percentBetween0And100: number;
|
||||
}) => number;
|
||||
export declare const getTimeFromPosition: ({ position, fileSize, tableOfContents, durationInSeconds, }: {
|
||||
position: number;
|
||||
fileSize: number;
|
||||
tableOfContents: number[];
|
||||
durationInSeconds: number;
|
||||
}) => number;
|
||||
121
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-xing.js
generated
vendored
Normal file
121
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/parse-xing.js
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
"use strict";
|
||||
// implementation of http://www.mp3-tech.org/programmer/sources/vbrheadersdk.zip
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getTimeFromPosition = exports.getSeekPointInBytes = exports.parseXing = void 0;
|
||||
const SAMPLE_RATES = [44100, 48000, 32000, 99999];
|
||||
const FRAMES_FLAG = 0x0001;
|
||||
const BYTES_FLAG = 0x0002;
|
||||
const TOC_FLAG = 0x0004;
|
||||
const VBR_SCALE_FLAG = 0x0008;
|
||||
const extractI4 = (data, offset) => {
|
||||
let x = 0;
|
||||
x = data[offset];
|
||||
x <<= 8;
|
||||
x |= data[offset + 1];
|
||||
x <<= 8;
|
||||
x |= data[offset + 2];
|
||||
x <<= 8;
|
||||
x |= data[offset + 3];
|
||||
return x;
|
||||
};
|
||||
const parseXing = (data) => {
|
||||
const h_id = (data[1] >> 3) & 1;
|
||||
const h_sr_index = (data[2] >> 2) & 3;
|
||||
const h_mode = (data[3] >> 6) & 3;
|
||||
let xingOffset = 0;
|
||||
if (h_id) {
|
||||
// mpeg1
|
||||
if (h_mode !== 3) {
|
||||
xingOffset += 32 + 4;
|
||||
}
|
||||
else {
|
||||
xingOffset += 17 + 4;
|
||||
}
|
||||
}
|
||||
else if (h_mode !== 3) {
|
||||
xingOffset += 17 + 4;
|
||||
}
|
||||
else {
|
||||
xingOffset += 9 + 4;
|
||||
}
|
||||
const expectXing = new TextDecoder('utf8').decode(data.slice(xingOffset, xingOffset + 4));
|
||||
if (expectXing !== 'Xing') {
|
||||
throw new Error('Invalid Xing header');
|
||||
}
|
||||
let sampleRate = SAMPLE_RATES[h_sr_index];
|
||||
if (h_id === 0) {
|
||||
sampleRate >>= 1;
|
||||
}
|
||||
let offset = xingOffset + 4;
|
||||
const flags = extractI4(data, offset);
|
||||
offset += 4;
|
||||
let numberOfFrames;
|
||||
let fileSize;
|
||||
let tableOfContents;
|
||||
let vbrScale;
|
||||
if (flags & FRAMES_FLAG) {
|
||||
numberOfFrames = extractI4(data, offset);
|
||||
offset += 4;
|
||||
}
|
||||
if (flags & BYTES_FLAG) {
|
||||
fileSize = extractI4(data, offset);
|
||||
offset += 4;
|
||||
}
|
||||
if (flags & TOC_FLAG) {
|
||||
tableOfContents = data.slice(offset, offset + 100);
|
||||
offset += 100;
|
||||
}
|
||||
if (flags & VBR_SCALE_FLAG) {
|
||||
vbrScale = extractI4(data, offset);
|
||||
offset += 4;
|
||||
}
|
||||
// Allow extra data after the standard Xing fields, as some encoders add additional information
|
||||
if (offset > data.length) {
|
||||
throw new Error('xing header was parsed wrong: read beyond available data');
|
||||
}
|
||||
return {
|
||||
sampleRate,
|
||||
numberOfFrames: numberOfFrames !== null && numberOfFrames !== void 0 ? numberOfFrames : null,
|
||||
fileSize: fileSize !== null && fileSize !== void 0 ? fileSize : null,
|
||||
tableOfContents: tableOfContents
|
||||
? Array.from(tableOfContents.slice(0, 100))
|
||||
: null,
|
||||
vbrScale: vbrScale !== null && vbrScale !== void 0 ? vbrScale : null,
|
||||
};
|
||||
};
|
||||
exports.parseXing = parseXing;
|
||||
const getSeekPointInBytes = ({ fileSize, percentBetween0And100, tableOfContents, }) => {
|
||||
let index = Math.floor(percentBetween0And100);
|
||||
if (index > 99) {
|
||||
index = 99;
|
||||
}
|
||||
const fa = tableOfContents[index];
|
||||
let fb;
|
||||
if (index < 99) {
|
||||
fb = tableOfContents[index + 1];
|
||||
}
|
||||
else {
|
||||
fb = 256;
|
||||
}
|
||||
const fx = fa + (fb - fa) * (percentBetween0And100 - index);
|
||||
const seekPoint = (1 / 256) * fx * fileSize;
|
||||
return Math.floor(seekPoint);
|
||||
};
|
||||
exports.getSeekPointInBytes = getSeekPointInBytes;
|
||||
const getTimeFromPosition = ({ position, fileSize, tableOfContents, durationInSeconds, }) => {
|
||||
// Convert position to a value between 0-256
|
||||
const positionNormalized = (position / fileSize) * 256;
|
||||
// Find the closest indices in the table of contents
|
||||
let index = 0;
|
||||
while (index < 99 && tableOfContents[index + 1] <= positionNormalized) {
|
||||
index++;
|
||||
}
|
||||
const fa = tableOfContents[index];
|
||||
const fb = index < 99 ? tableOfContents[index + 1] : 256;
|
||||
// Interpolate between the two points
|
||||
const percentWithinSegment = (positionNormalized - fa) / (fb - fa);
|
||||
const percentBetween0And100 = index + percentWithinSegment;
|
||||
// Convert percentage to time
|
||||
return (percentBetween0And100 / 100) * durationInSeconds;
|
||||
};
|
||||
exports.getTimeFromPosition = getTimeFromPosition;
|
||||
4
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/samples-per-mpeg-file.d.ts
generated
vendored
Normal file
4
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/samples-per-mpeg-file.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export declare const getSamplesPerMpegFrame: ({ mpegVersion, layer, }: {
|
||||
mpegVersion: 1 | 2;
|
||||
layer: number;
|
||||
}) => 384 | 1152 | 576;
|
||||
26
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/samples-per-mpeg-file.js
generated
vendored
Normal file
26
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/samples-per-mpeg-file.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getSamplesPerMpegFrame = void 0;
|
||||
const getSamplesPerMpegFrame = ({ mpegVersion, layer, }) => {
|
||||
if (mpegVersion === 1) {
|
||||
if (layer === 1) {
|
||||
return 384;
|
||||
}
|
||||
if (layer === 2 || layer === 3) {
|
||||
return 1152;
|
||||
}
|
||||
}
|
||||
if (mpegVersion === 2) {
|
||||
if (layer === 1) {
|
||||
return 384;
|
||||
}
|
||||
if (layer === 2) {
|
||||
return 1152;
|
||||
}
|
||||
if (layer === 3) {
|
||||
return 576;
|
||||
}
|
||||
}
|
||||
throw new Error('Invalid MPEG layer');
|
||||
};
|
||||
exports.getSamplesPerMpegFrame = getSamplesPerMpegFrame;
|
||||
16
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/audio-sample-from-cbr.d.ts
generated
vendored
Normal file
16
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/audio-sample-from-cbr.d.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { ParserState } from '../../../state/parser-state';
|
||||
import type { MediaParserAudioSample } from '../../../webcodec-sample-types';
|
||||
export declare const getAudioSampleFromCbr: ({ bitrateInKbit, initialOffset, layer, sampleRate, samplesPerFrame, data, state, }: {
|
||||
bitrateInKbit: number;
|
||||
layer: number;
|
||||
samplesPerFrame: number;
|
||||
sampleRate: number;
|
||||
initialOffset: number;
|
||||
data: Uint8Array;
|
||||
state: ParserState;
|
||||
}) => {
|
||||
audioSample: MediaParserAudioSample;
|
||||
timeInSeconds: number;
|
||||
durationInSeconds: number;
|
||||
};
|
||||
export type AudioSampleFromCbr = ReturnType<typeof getAudioSampleFromCbr>;
|
||||
35
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/audio-sample-from-cbr.js
generated
vendored
Normal file
35
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/audio-sample-from-cbr.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAudioSampleFromCbr = void 0;
|
||||
const webcodecs_timescale_1 = require("../../../webcodecs-timescale");
|
||||
const get_frame_length_1 = require("../get-frame-length");
|
||||
const getAudioSampleFromCbr = ({ bitrateInKbit, initialOffset, layer, sampleRate, samplesPerFrame, data, state, }) => {
|
||||
const avgLength = (0, get_frame_length_1.getAverageMpegFrameLength)({
|
||||
bitrateKbit: bitrateInKbit,
|
||||
layer,
|
||||
samplesPerFrame,
|
||||
samplingFrequency: sampleRate,
|
||||
});
|
||||
const mp3Info = state.mp3.getMp3Info();
|
||||
if (!mp3Info) {
|
||||
throw new Error('No MP3 info');
|
||||
}
|
||||
const nthFrame = Math.round((initialOffset - state.mediaSection.getMediaSectionAssertOnlyOne().start) /
|
||||
avgLength);
|
||||
const durationInSeconds = samplesPerFrame / sampleRate;
|
||||
const timeInSeconds = (nthFrame * samplesPerFrame) / sampleRate;
|
||||
// Important that we round down, otherwise WebCodecs might stall, e.g.
|
||||
// Last input = 30570667 Last output = 30570666 -> stuck
|
||||
const timestamp = Math.floor(timeInSeconds * webcodecs_timescale_1.WEBCODECS_TIMESCALE);
|
||||
const duration = Math.floor(durationInSeconds * webcodecs_timescale_1.WEBCODECS_TIMESCALE);
|
||||
const audioSample = {
|
||||
data,
|
||||
decodingTimestamp: timestamp,
|
||||
duration,
|
||||
offset: initialOffset,
|
||||
timestamp,
|
||||
type: 'key',
|
||||
};
|
||||
return { audioSample, timeInSeconds, durationInSeconds };
|
||||
};
|
||||
exports.getAudioSampleFromCbr = getAudioSampleFromCbr;
|
||||
8
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/audio-sample-from-vbr.d.ts
generated
vendored
Normal file
8
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/audio-sample-from-vbr.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { Mp3Info, VariableMp3BitrateInfo } from '../../../state/mp3';
|
||||
import type { AudioSampleFromCbr } from './audio-sample-from-cbr';
|
||||
export declare const getAudioSampleFromVbr: ({ info, position, mp3Info, data, }: {
|
||||
position: number;
|
||||
info: VariableMp3BitrateInfo;
|
||||
mp3Info: Mp3Info | null;
|
||||
data: Uint8Array;
|
||||
}) => AudioSampleFromCbr;
|
||||
45
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/audio-sample-from-vbr.js
generated
vendored
Normal file
45
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/audio-sample-from-vbr.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAudioSampleFromVbr = void 0;
|
||||
const webcodecs_timescale_1 = require("../../../webcodecs-timescale");
|
||||
const get_duration_1 = require("../get-duration");
|
||||
const parse_xing_1 = require("../parse-xing");
|
||||
const samples_per_mpeg_file_1 = require("../samples-per-mpeg-file");
|
||||
const getAudioSampleFromVbr = ({ info, position, mp3Info, data, }) => {
|
||||
if (!mp3Info) {
|
||||
throw new Error('No MP3 info');
|
||||
}
|
||||
const samplesPerFrame = (0, samples_per_mpeg_file_1.getSamplesPerMpegFrame)({
|
||||
layer: mp3Info.layer,
|
||||
mpegVersion: mp3Info.mpegVersion,
|
||||
});
|
||||
const wholeFileDuration = (0, get_duration_1.getDurationFromMp3Xing)({
|
||||
samplesPerFrame,
|
||||
xingData: info.xingData,
|
||||
});
|
||||
if (!info.xingData.fileSize) {
|
||||
throw new Error('file size');
|
||||
}
|
||||
if (!info.xingData.tableOfContents) {
|
||||
throw new Error('table of contents');
|
||||
}
|
||||
const timeInSeconds = (0, parse_xing_1.getTimeFromPosition)({
|
||||
durationInSeconds: wholeFileDuration,
|
||||
fileSize: info.xingData.fileSize,
|
||||
position,
|
||||
tableOfContents: info.xingData.tableOfContents,
|
||||
});
|
||||
const durationInSeconds = samplesPerFrame / info.xingData.sampleRate;
|
||||
const timestamp = Math.floor(timeInSeconds * webcodecs_timescale_1.WEBCODECS_TIMESCALE);
|
||||
const duration = Math.floor(durationInSeconds * webcodecs_timescale_1.WEBCODECS_TIMESCALE);
|
||||
const audioSample = {
|
||||
data,
|
||||
decodingTimestamp: timestamp,
|
||||
duration,
|
||||
offset: position,
|
||||
timestamp,
|
||||
type: 'key',
|
||||
};
|
||||
return { timeInSeconds, audioSample, durationInSeconds };
|
||||
};
|
||||
exports.getAudioSampleFromVbr = getAudioSampleFromVbr;
|
||||
9
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-approximate-byte-from-bitrate.d.ts
generated
vendored
Normal file
9
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-approximate-byte-from-bitrate.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { Mp3BitrateInfo, Mp3Info } from '../../../state/mp3';
|
||||
import type { MediaSection } from '../../../state/video-section';
|
||||
export declare const getApproximateByteFromBitrate: ({ mp3BitrateInfo, timeInSeconds, mp3Info, mediaSection, contentLength, }: {
|
||||
mp3BitrateInfo: Mp3BitrateInfo;
|
||||
mp3Info: Mp3Info;
|
||||
timeInSeconds: number;
|
||||
mediaSection: MediaSection;
|
||||
contentLength: number;
|
||||
}) => number | null;
|
||||
28
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-approximate-byte-from-bitrate.js
generated
vendored
Normal file
28
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-approximate-byte-from-bitrate.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getApproximateByteFromBitrate = void 0;
|
||||
const get_frame_length_1 = require("../get-frame-length");
|
||||
const samples_per_mpeg_file_1 = require("../samples-per-mpeg-file");
|
||||
const getApproximateByteFromBitrate = ({ mp3BitrateInfo, timeInSeconds, mp3Info, mediaSection, contentLength, }) => {
|
||||
if (mp3BitrateInfo.type === 'variable') {
|
||||
return null;
|
||||
}
|
||||
const samplesPerFrame = (0, samples_per_mpeg_file_1.getSamplesPerMpegFrame)({
|
||||
layer: mp3Info.layer,
|
||||
mpegVersion: mp3Info.mpegVersion,
|
||||
});
|
||||
const frameLengthInBytes = (0, get_frame_length_1.getMpegFrameLength)({
|
||||
bitrateKbit: mp3BitrateInfo.bitrateInKbit,
|
||||
padding: false,
|
||||
samplesPerFrame,
|
||||
samplingFrequency: mp3Info.sampleRate,
|
||||
layer: mp3Info.layer,
|
||||
});
|
||||
const frameIndexUnclamped = Math.floor((timeInSeconds * mp3Info.sampleRate) / samplesPerFrame);
|
||||
const frames = Math.floor((contentLength - mediaSection.start) / frameLengthInBytes);
|
||||
const frameIndex = Math.min(frames - 1, frameIndexUnclamped);
|
||||
const byteRelativeToMediaSection = frameIndex * frameLengthInBytes;
|
||||
const byteBeforeFrame = byteRelativeToMediaSection + mediaSection.start;
|
||||
return byteBeforeFrame;
|
||||
};
|
||||
exports.getApproximateByteFromBitrate = getApproximateByteFromBitrate;
|
||||
6
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-byte-from-observed-samples.d.ts
generated
vendored
Normal file
6
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-byte-from-observed-samples.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { AudioSampleOffset } from '../../../state/audio-sample-map';
|
||||
import type { Mp3SeekingHints } from '../seeking-hints';
|
||||
export declare const getByteFromObservedSamples: ({ info, timeInSeconds, }: {
|
||||
info: Mp3SeekingHints;
|
||||
timeInSeconds: number;
|
||||
}) => AudioSampleOffset | undefined;
|
||||
27
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-byte-from-observed-samples.js
generated
vendored
Normal file
27
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-byte-from-observed-samples.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getByteFromObservedSamples = void 0;
|
||||
const getByteFromObservedSamples = ({ info, timeInSeconds, }) => {
|
||||
let bestAudioSample;
|
||||
for (const hint of info.audioSampleMap) {
|
||||
if (hint.timeInSeconds > timeInSeconds) {
|
||||
continue;
|
||||
}
|
||||
// Everything is a keyframe in mp3, so if this sample does not cover the time, it's not a good candidate.
|
||||
// Let's go to the next one. Exception: If we already saw the last sample, we use it so we find can at least
|
||||
// find the closest one.
|
||||
if (hint.timeInSeconds + hint.durationInSeconds < timeInSeconds &&
|
||||
!info.lastSampleObserved) {
|
||||
continue;
|
||||
}
|
||||
if (!bestAudioSample) {
|
||||
bestAudioSample = hint;
|
||||
continue;
|
||||
}
|
||||
if (bestAudioSample.timeInSeconds < hint.timeInSeconds) {
|
||||
bestAudioSample = hint;
|
||||
}
|
||||
}
|
||||
return bestAudioSample;
|
||||
};
|
||||
exports.getByteFromObservedSamples = getByteFromObservedSamples;
|
||||
7
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-seek-point-from-xing.d.ts
generated
vendored
Normal file
7
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-seek-point-from-xing.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Mp3Info } from '../../../state/mp3';
|
||||
import { type XingData } from '../parse-xing';
|
||||
export declare const getSeekPointFromXing: ({ timeInSeconds, xingData, mp3Info, }: {
|
||||
timeInSeconds: number;
|
||||
xingData: XingData;
|
||||
mp3Info: Mp3Info;
|
||||
}) => number;
|
||||
29
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-seek-point-from-xing.js
generated
vendored
Normal file
29
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/get-seek-point-from-xing.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getSeekPointFromXing = void 0;
|
||||
const get_duration_1 = require("../get-duration");
|
||||
const parse_xing_1 = require("../parse-xing");
|
||||
const samples_per_mpeg_file_1 = require("../samples-per-mpeg-file");
|
||||
const getSeekPointFromXing = ({ timeInSeconds, xingData, mp3Info, }) => {
|
||||
const samplesPerFrame = (0, samples_per_mpeg_file_1.getSamplesPerMpegFrame)({
|
||||
layer: mp3Info.layer,
|
||||
mpegVersion: mp3Info.mpegVersion,
|
||||
});
|
||||
const duration = (0, get_duration_1.getDurationFromMp3Xing)({
|
||||
xingData,
|
||||
samplesPerFrame,
|
||||
});
|
||||
const totalSamples = timeInSeconds * xingData.sampleRate;
|
||||
// -1 frame so we are sure to be before the target
|
||||
const oneFrameSubtracted = totalSamples - samplesPerFrame;
|
||||
const timeToTarget = Math.max(0, oneFrameSubtracted / xingData.sampleRate);
|
||||
if (!xingData.fileSize || !xingData.tableOfContents) {
|
||||
throw new Error('Cannot seek of VBR MP3 file');
|
||||
}
|
||||
return (0, parse_xing_1.getSeekPointInBytes)({
|
||||
fileSize: xingData.fileSize,
|
||||
percentBetween0And100: (timeToTarget / duration) * 100,
|
||||
tableOfContents: xingData.tableOfContents,
|
||||
});
|
||||
};
|
||||
exports.getSeekPointFromXing = getSeekPointFromXing;
|
||||
4
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/wait-until-syncword.d.ts
generated
vendored
Normal file
4
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/wait-until-syncword.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { BufferIterator } from '../../../iterator/buffer-iterator';
|
||||
export declare const discardUntilSyncword: ({ iterator, }: {
|
||||
iterator: BufferIterator;
|
||||
}) => void;
|
||||
28
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/wait-until-syncword.js
generated
vendored
Normal file
28
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seek/wait-until-syncword.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.discardUntilSyncword = void 0;
|
||||
const parse_packet_header_1 = require("../parse-packet-header");
|
||||
const discardUntilSyncword = ({ iterator, }) => {
|
||||
while (true) {
|
||||
const next2Bytes = iterator.getUint8();
|
||||
if (next2Bytes !== 0xff) {
|
||||
continue;
|
||||
}
|
||||
if (iterator.bytesRemaining() === 0) {
|
||||
break;
|
||||
}
|
||||
const nextByte = iterator.getUint8();
|
||||
const mask = 0xe0; // 1110 0000
|
||||
if ((nextByte & mask) !== mask) {
|
||||
continue;
|
||||
}
|
||||
iterator.counter.decrement(2);
|
||||
if ((0, parse_packet_header_1.isMp3PacketHeaderHereAndInNext)(iterator)) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
iterator.counter.increment(2);
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.discardUntilSyncword = discardUntilSyncword;
|
||||
24
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seeking-hints.d.ts
generated
vendored
Normal file
24
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seeking-hints.d.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { AudioSampleOffset } from '../../state/audio-sample-map';
|
||||
import type { Mp3BitrateInfo, Mp3Info, Mp3State } from '../../state/mp3';
|
||||
import type { ParserState } from '../../state/parser-state';
|
||||
import type { SamplesObservedState } from '../../state/samples-observed/slow-duration-fps';
|
||||
import type { MediaSection, MediaSectionState } from '../../state/video-section';
|
||||
export type Mp3SeekingHints = {
|
||||
type: 'mp3-seeking-hints';
|
||||
audioSampleMap: AudioSampleOffset[];
|
||||
lastSampleObserved: boolean;
|
||||
mp3BitrateInfo: Mp3BitrateInfo | null;
|
||||
mp3Info: Mp3Info | null;
|
||||
mediaSection: MediaSection | null;
|
||||
contentLength: number;
|
||||
};
|
||||
export declare const getSeekingHintsForMp3: ({ mp3State, samplesObserved, mediaSectionState, contentLength, }: {
|
||||
mp3State: Mp3State;
|
||||
mediaSectionState: MediaSectionState;
|
||||
samplesObserved: SamplesObservedState;
|
||||
contentLength: number;
|
||||
}) => Mp3SeekingHints;
|
||||
export declare const setSeekingHintsForMp3: ({ hints, state, }: {
|
||||
hints: Mp3SeekingHints;
|
||||
state: ParserState;
|
||||
}) => void;
|
||||
21
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seeking-hints.js
generated
vendored
Normal file
21
remotion/node_modules/@remotion/media-parser/dist/containers/mp3/seeking-hints.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.setSeekingHintsForMp3 = exports.getSeekingHintsForMp3 = void 0;
|
||||
const getSeekingHintsForMp3 = ({ mp3State, samplesObserved, mediaSectionState, contentLength, }) => {
|
||||
var _a;
|
||||
return {
|
||||
type: 'mp3-seeking-hints',
|
||||
audioSampleMap: mp3State.audioSamples.getSamples(),
|
||||
lastSampleObserved: samplesObserved.getLastSampleObserved(),
|
||||
mp3BitrateInfo: mp3State.getMp3BitrateInfo(),
|
||||
mp3Info: mp3State.getMp3Info(),
|
||||
mediaSection: (_a = mediaSectionState.getMediaSections()[0]) !== null && _a !== void 0 ? _a : null,
|
||||
contentLength,
|
||||
};
|
||||
};
|
||||
exports.getSeekingHintsForMp3 = getSeekingHintsForMp3;
|
||||
// TODO: could set xing data in the hints
|
||||
const setSeekingHintsForMp3 = ({ hints, state, }) => {
|
||||
state.mp3.audioSamples.setFromSeekingHints(hints.audioSampleMap);
|
||||
};
|
||||
exports.setSeekingHintsForMp3 = setSeekingHintsForMp3;
|
||||
Reference in New Issue
Block a user