New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

mp4-muxer

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mp4-muxer - npm Package Compare versions

Comparing version 2.3.0 to 3.0.0

98

build/mp4-muxer.d.ts

@@ -0,5 +1,45 @@

declare interface VideoOptions {
/**
* The codec of the encoded video chunks.
*/
codec: 'avc' | 'hevc' | 'vp9' | 'av1',
/**
* The width of the video in pixels.
*/
width: number,
/**
* The height of the video in pixels.
*/
height: number,
/**
* The clockwise rotation of the video in degrees.
*/
rotation?: 0 | 90 | 180 | 270
}
declare interface AudioOptions {
/**
* The codec of the encoded audio chunks.
*/
codec: 'aac' | 'opus',
/**
* The number of audio channels in the audio track.
*/
numberOfChannels: number,
/**
* The sample rate of the audio track in samples per second per channel.
*/
sampleRate: number
}
type NoInfer<T> = T extends infer S ? S : never;
/**
* Describes the properties used to configure an instance of `Muxer`.
*/
declare interface MuxerOptions<T extends Target> {
declare type MuxerOptions<
T extends Target,
V extends VideoOptions | undefined = undefined,
A extends AudioOptions | undefined = undefined
> = {
/**

@@ -13,20 +53,3 @@ * Specifies what happens with the data created by the muxer.

*/
video?: {
/**
* The codec of the encoded video chunks.
*/
codec: 'avc' | 'hevc' | 'vp9' | 'av1',
/**
* The width of the video in pixels.
*/
width: number,
/**
* The height of the video in pixels.
*/
height: number,
/**
* The clockwise rotation of the video in degrees.
*/
rotation?: 0 | 90 | 180 | 270
},
video?: V,

@@ -36,18 +59,25 @@ /**

*/
audio?: {
/**
* The codec of the encoded audio chunks.
*/
codec: 'aac' | 'opus',
/**
* The number of audio channels in the audio track.
*/
numberOfChannels: number,
/**
* The sample rate of the audio track in samples per second per channel.
*/
sampleRate: number
},
audio?: A,
/**
* Controls the placement of metadata in the file. Placing metadata at the start of the file is known as "Fast
* Start", which results in better playback at the cost of more required processing or memory.
*
* Use `false` to disable Fast Start, placing the metadata at the end of the file. Fastest and uses the least
* memory.
*
* Use `'in-memory'` to produce a file with Fast Start by keeping all media chunks in memory until the file is
* finalized. This produces a high-quality and compact output at the cost of a more expensive finalization step and
* higher memory requirements.
*
* Use an object to produce a file with Fast Start by reserving space for metadata when muxing starts. In order to
* know how much space needs to be reserved, you'll need to tell it the upper bound of how many media chunks will be
* muxed. Do this by setting `expectedVideoChunks` and/or `expectedAudioChunks`.
*/
fastStart: false | 'in-memory' | (
(NoInfer<V> extends undefined ? { expectedVideoChunks?: never } : { expectedVideoChunks: number })
& (NoInfer<A> extends undefined ? { expectedAudioChunks?: never } : { expectedAudioChunks: number })
),
/**
* Specifies how to deal with the first chunk in each track having a non-zero timestamp. In the default strict mode,

@@ -63,3 +93,3 @@ * timestamps must start with 0 to ensure proper playback. However, when directly piping video frames or audio data

firstTimestampBehavior?: 'strict' | 'offset'
}
};

@@ -66,0 +96,0 @@ declare type Target = ArrayBufferTarget | StreamTarget | FileSystemWritableFileStreamTarget;

@@ -6,18 +6,3 @@ "use strict";

var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __pow = Math.pow;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b ||= {})
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __export = (target, all) => {

@@ -91,3 +76,3 @@ for (var name in all)

var u64 = (value) => {
view.setUint32(0, Math.floor(value / __pow(2, 32)), false);
view.setUint32(0, Math.floor(value / 2 ** 32), false);
view.setUint32(4, value, false);

@@ -97,11 +82,11 @@ return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]];

var fixed_8_8 = (value) => {
view.setInt16(0, __pow(2, 8) * value, false);
view.setInt16(0, 2 ** 8 * value, false);
return [bytes[0], bytes[1]];
};
var fixed_16_16 = (value) => {
view.setInt32(0, __pow(2, 16) * value, false);
view.setInt32(0, 2 ** 16 * value, false);
return [bytes[0], bytes[1], bytes[2], bytes[3]];
};
var fixed_2_30 = (value) => {
view.setInt32(0, __pow(2, 30) * value, false);
view.setInt32(0, 2 ** 30 * value, false);
return [bytes[0], bytes[1], bytes[2], bytes[3]];

@@ -152,2 +137,11 @@ };

};
var deepClone = (x) => {
if (!x)
return x;
if (typeof x !== "object")
return x;
if (Array.isArray(x))
return x.map(deepClone);
return Object.fromEntries(Object.entries(x).map(([key, value]) => [key, deepClone(value)]));
};

@@ -162,3 +156,3 @@ // src/box.ts

type,
[u8(version), u24(flags), contents != null ? contents : []],
[u8(version), u24(flags), contents ?? []],
children

@@ -191,3 +185,4 @@ );

};
var mdat = () => ({ type: "mdat", largeSize: true });
var mdat = (reserveLargeSize) => ({ type: "mdat", largeSize: reserveLargeSize });
var free = (size) => ({ type: "free", size });
var moov = (tracks, creationTime) => box("moov", null, [

@@ -514,7 +509,7 @@ mvhd(creationTime, tracks),

var stco = (track) => {
if (track.writtenChunks.length > 0 && last(track.writtenChunks).offset >= __pow(2, 32)) {
if (track.finalizedChunks.length > 0 && last(track.finalizedChunks).offset >= 2 ** 32) {
return fullBox("co64", 0, 0, [
u32(track.writtenChunks.length),
u32(track.finalizedChunks.length),
// Number of entries
track.writtenChunks.map((x) => u64(x.offset))
track.finalizedChunks.map((x) => u64(x.offset))
// Chunk offset table

@@ -524,5 +519,5 @@ ]);

return fullBox("stco", 0, 0, [
u32(track.writtenChunks.length),
u32(track.finalizedChunks.length),
// Number of entries
track.writtenChunks.map((x) => u32(x.offset))
track.finalizedChunks.map((x) => u32(x.offset))
// Chunk offset table

@@ -594,3 +589,3 @@ ]);

writeU64(value) {
__privateGet(this, _helperView).setUint32(0, Math.floor(value / __pow(2, 32)), false);
__privateGet(this, _helperView).setUint32(0, Math.floor(value / 2 ** 32), false);
__privateGet(this, _helperView).setUint32(4, value, false);

@@ -610,6 +605,5 @@ this.write(__privateGet(this, _helper).subarray(0, 8));

writeBox(box2) {
var _a, _b;
this.offsets.set(box2, this.pos);
if (box2.contents && !box2.children) {
this.writeBoxHeader(box2, (_a = box2.size) != null ? _a : box2.contents.byteLength + 8);
this.writeBoxHeader(box2, box2.size ?? box2.contents.byteLength + 8);
this.write(box2.contents);

@@ -627,3 +621,3 @@ } else {

let endPos = this.pos;
let size = (_b = box2.size) != null ? _b : endPos - startPos;
let size = box2.size ?? endPos - startPos;
this.seek(startPos);

@@ -640,2 +634,5 @@ this.writeBoxHeader(box2, size);

}
measureBoxHeader(box2) {
return 8 + (box2.largeSize ? 8 : 0);
}
patchBox(box2) {

@@ -647,6 +644,22 @@ let endPos = this.pos;

}
measureBox(box2) {
if (box2.contents && !box2.children) {
let headerSize = this.measureBoxHeader(box2);
return headerSize + box2.contents.byteLength;
} else {
let result = this.measureBoxHeader(box2);
if (box2.contents)
result += box2.contents.byteLength;
if (box2.children) {
for (let child of box2.children)
if (child)
result += this.measureBox(child);
}
return result;
}
}
};
_helper = new WeakMap();
_helperView = new WeakMap();
var _target, _buffer, _bytes, _ensureSize, ensureSize_fn;
var _target, _buffer, _bytes, _maxPos, _ensureSize, ensureSize_fn;
var ArrayBufferTargetWriter = class extends Writer {

@@ -657,4 +670,5 @@ constructor(target) {

__privateAdd(this, _target, void 0);
__privateAdd(this, _buffer, new ArrayBuffer(__pow(2, 16)));
__privateAdd(this, _buffer, new ArrayBuffer(2 ** 16));
__privateAdd(this, _bytes, new Uint8Array(__privateGet(this, _buffer)));
__privateAdd(this, _maxPos, 0);
__privateSet(this, _target, target);

@@ -666,6 +680,7 @@ }

this.pos += data.byteLength;
__privateSet(this, _maxPos, Math.max(__privateGet(this, _maxPos), this.pos));
}
finalize() {
__privateMethod(this, _ensureSize, ensureSize_fn).call(this, this.pos);
__privateGet(this, _target).buffer = __privateGet(this, _buffer).slice(0, this.pos);
__privateGet(this, _target).buffer = __privateGet(this, _buffer).slice(0, Math.max(__privateGet(this, _maxPos), this.pos));
}

@@ -676,2 +691,3 @@ };

_bytes = new WeakMap();
_maxPos = new WeakMap();
_ensureSize = new WeakSet();

@@ -738,4 +754,3 @@ ensureSize_fn = function(size) {

finalize() {
var _a, _b;
(_b = (_a = __privateGet(this, _target2)).onDone) == null ? void 0 : _b.call(_a);
__privateGet(this, _target2).onDone?.();
}

@@ -745,3 +760,3 @@ };

_sections = new WeakMap();
var DEFAULT_CHUNK_SIZE = __pow(2, 24);
var DEFAULT_CHUNK_SIZE = 2 ** 24;
var MAX_CHUNKS_AT_ONCE = 2;

@@ -751,3 +766,2 @@ var _target3, _chunkSize, _chunks, _writeDataIntoChunks, writeDataIntoChunks_fn, _insertSectionIntoChunk, insertSectionIntoChunk_fn, _createChunk, createChunk_fn, _flushChunks, flushChunks_fn;

constructor(target) {
var _a, _b;
super();

@@ -766,4 +780,4 @@ __privateAdd(this, _writeDataIntoChunks);

__privateSet(this, _target3, target);
__privateSet(this, _chunkSize, (_b = (_a = target.options) == null ? void 0 : _a.chunkSize) != null ? _b : DEFAULT_CHUNK_SIZE);
if (!Number.isInteger(__privateGet(this, _chunkSize)) || __privateGet(this, _chunkSize) < __pow(2, 10)) {
__privateSet(this, _chunkSize, target.options?.chunkSize ?? DEFAULT_CHUNK_SIZE);
if (!Number.isInteger(__privateGet(this, _chunkSize)) || __privateGet(this, _chunkSize) < 2 ** 10) {
throw new Error("Invalid StreamTarget options: chunkSize must be an integer not smaller than 1024.");

@@ -778,5 +792,4 @@ }

finalize() {
var _a, _b;
__privateMethod(this, _flushChunks, flushChunks_fn).call(this, true);
(_b = (_a = __privateGet(this, _target3)).onDone) == null ? void 0 : _b.call(_a);
__privateGet(this, _target3).onDone?.();
}

@@ -866,3 +879,2 @@ };

constructor(target) {
var _a;
super(new StreamTarget(

@@ -875,3 +887,3 @@ (data, position) => target.stream.write({

void 0,
{ chunkSize: (_a = target.options) == null ? void 0 : _a.chunkSize }
{ chunkSize: target.options?.chunkSize }
));

@@ -888,3 +900,3 @@ }

var FIRST_TIMESTAMP_BEHAVIORS = ["strict", "offset"];
var _options, _writer, _mdat, _videoTrack, _audioTrack, _creationTime, _finalized, _validateOptions, validateOptions_fn, _writeHeader, writeHeader_fn, _prepareTracks, prepareTracks_fn, _generateMpeg4AudioSpecificConfig, generateMpeg4AudioSpecificConfig_fn, _addSampleToTrack, addSampleToTrack_fn, _validateTimestamp, validateTimestamp_fn, _writeCurrentChunk, writeCurrentChunk_fn, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn, _ensureNotFinalized, ensureNotFinalized_fn;
var _options, _writer, _ftypSize, _mdat, _videoTrack, _audioTrack, _creationTime, _finalizedChunks, _finalized, _validateOptions, validateOptions_fn, _writeHeader, writeHeader_fn, _computeMoovSizeUpperBound, computeMoovSizeUpperBound_fn, _prepareTracks, prepareTracks_fn, _generateMpeg4AudioSpecificConfig, generateMpeg4AudioSpecificConfig_fn, _addSampleToTrack, addSampleToTrack_fn, _validateTimestamp, validateTimestamp_fn, _finalizeCurrentChunk, finalizeCurrentChunk_fn, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn, _ensureNotFinalized, ensureNotFinalized_fn;
var Muxer = class {

@@ -894,2 +906,3 @@ constructor(options) {

__privateAdd(this, _writeHeader);
__privateAdd(this, _computeMoovSizeUpperBound);
__privateAdd(this, _prepareTracks);

@@ -900,3 +913,3 @@ // https://wiki.multimedia.cx/index.php/MPEG-4_Audio

__privateAdd(this, _validateTimestamp);
__privateAdd(this, _writeCurrentChunk);
__privateAdd(this, _finalizeCurrentChunk);
__privateAdd(this, _maybeFlushStreamingTargetWriter);

@@ -906,2 +919,3 @@ __privateAdd(this, _ensureNotFinalized);

__privateAdd(this, _writer, void 0);
__privateAdd(this, _ftypSize, void 0);
__privateAdd(this, _mdat, void 0);

@@ -911,13 +925,17 @@ __privateAdd(this, _videoTrack, null);

__privateAdd(this, _creationTime, Math.floor(Date.now() / 1e3) + TIMESTAMP_OFFSET);
__privateAdd(this, _finalizedChunks, []);
__privateAdd(this, _finalized, false);
var _a;
__privateMethod(this, _validateOptions, validateOptions_fn).call(this, options);
options.video = deepClone(options.video);
options.audio = deepClone(options.audio);
options.fastStart = deepClone(options.fastStart);
this.target = options.target;
__privateSet(this, _options, __spreadValues({
firstTimestampBehavior: "strict"
}, options));
__privateSet(this, _options, {
firstTimestampBehavior: "strict",
...options
});
if (options.target instanceof ArrayBufferTarget) {
__privateSet(this, _writer, new ArrayBufferTargetWriter(options.target));
} else if (options.target instanceof StreamTarget) {
__privateSet(this, _writer, ((_a = options.target.options) == null ? void 0 : _a.chunked) ? new ChunkedStreamTargetWriter(options.target) : new StreamTargetWriter(options.target));
__privateSet(this, _writer, options.target.options?.chunked ? new ChunkedStreamTargetWriter(options.target) : new StreamTargetWriter(options.target));
} else if (options.target instanceof FileSystemWritableFileStreamTarget) {

@@ -934,3 +952,3 @@ __privateSet(this, _writer, new FileSystemWritableFileStreamTargetWriter(options.target));

sample.copyTo(data);
this.addVideoChunkRaw(data, sample.type, timestamp != null ? timestamp : sample.timestamp, sample.duration, meta);
this.addVideoChunkRaw(data, sample.type, timestamp ?? sample.timestamp, sample.duration, meta);
}

@@ -941,2 +959,5 @@ addVideoChunkRaw(data, type, timestamp, duration, meta) {

throw new Error("No video track declared.");
if (typeof __privateGet(this, _options).fastStart === "object" && __privateGet(this, _videoTrack).samples.length === __privateGet(this, _options).fastStart.expectedVideoChunks) {
throw new Error(`Cannot add more video chunks than specified in 'fastStart' (${__privateGet(this, _options).fastStart.expectedVideoChunks}).`);
}
__privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _videoTrack), data, type, timestamp, duration, meta);

@@ -947,3 +968,3 @@ }

sample.copyTo(data);
this.addAudioChunkRaw(data, sample.type, timestamp != null ? timestamp : sample.timestamp, sample.duration, meta);
this.addAudioChunkRaw(data, sample.type, timestamp ?? sample.timestamp, sample.duration, meta);
}

@@ -954,2 +975,5 @@ addAudioChunkRaw(data, type, timestamp, duration, meta) {

throw new Error("No audio track declared.");
if (typeof __privateGet(this, _options).fastStart === "object" && __privateGet(this, _audioTrack).samples.length === __privateGet(this, _options).fastStart.expectedAudioChunks) {
throw new Error(`Cannot add more audio chunks than specified in 'fastStart' (${__privateGet(this, _options).fastStart.expectedAudioChunks}).`);
}
__privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _audioTrack), data, type, timestamp, duration, meta);

@@ -960,11 +984,50 @@ }

if (__privateGet(this, _videoTrack))
__privateMethod(this, _writeCurrentChunk, writeCurrentChunk_fn).call(this, __privateGet(this, _videoTrack));
__privateMethod(this, _finalizeCurrentChunk, finalizeCurrentChunk_fn).call(this, __privateGet(this, _videoTrack));
if (__privateGet(this, _audioTrack))
__privateMethod(this, _writeCurrentChunk, writeCurrentChunk_fn).call(this, __privateGet(this, _audioTrack));
let mdatPos = __privateGet(this, _writer).offsets.get(__privateGet(this, _mdat));
let mdatSize = __privateGet(this, _writer).pos - mdatPos;
__privateGet(this, _mdat).size = mdatSize;
__privateGet(this, _writer).patchBox(__privateGet(this, _mdat));
let movieBox = moov([__privateGet(this, _videoTrack), __privateGet(this, _audioTrack)].filter(Boolean), __privateGet(this, _creationTime));
__privateGet(this, _writer).writeBox(movieBox);
__privateMethod(this, _finalizeCurrentChunk, finalizeCurrentChunk_fn).call(this, __privateGet(this, _audioTrack));
let tracks = [__privateGet(this, _videoTrack), __privateGet(this, _audioTrack)].filter(Boolean);
if (__privateGet(this, _options).fastStart === "in-memory") {
let mdatSize;
for (let i = 0; i < 2; i++) {
let movieBox2 = moov(tracks, __privateGet(this, _creationTime));
let movieBoxSize = __privateGet(this, _writer).measureBox(movieBox2);
mdatSize = __privateGet(this, _writer).measureBox(__privateGet(this, _mdat));
let currentChunkPos = __privateGet(this, _writer).pos + movieBoxSize + mdatSize;
for (let chunk of __privateGet(this, _finalizedChunks)) {
chunk.offset = currentChunkPos;
for (let bytes2 of chunk.sampleData) {
currentChunkPos += bytes2.byteLength;
mdatSize += bytes2.byteLength;
}
}
if (currentChunkPos < 2 ** 32)
break;
if (mdatSize >= 2 ** 32)
__privateGet(this, _mdat).largeSize = true;
}
let movieBox = moov(tracks, __privateGet(this, _creationTime));
__privateGet(this, _writer).writeBox(movieBox);
__privateGet(this, _mdat).size = mdatSize;
__privateGet(this, _writer).writeBox(__privateGet(this, _mdat));
for (let chunk of __privateGet(this, _finalizedChunks)) {
for (let bytes2 of chunk.sampleData)
__privateGet(this, _writer).write(bytes2);
chunk.sampleData = null;
}
} else {
let mdatPos = __privateGet(this, _writer).offsets.get(__privateGet(this, _mdat));
let mdatSize = __privateGet(this, _writer).pos - mdatPos;
__privateGet(this, _mdat).size = mdatSize;
__privateGet(this, _mdat).largeSize = mdatSize >= 2 ** 32;
__privateGet(this, _writer).patchBox(__privateGet(this, _mdat));
let movieBox = moov(tracks, __privateGet(this, _creationTime));
if (typeof __privateGet(this, _options).fastStart === "object") {
__privateGet(this, _writer).seek(__privateGet(this, _ftypSize));
__privateGet(this, _writer).writeBox(movieBox);
let remainingBytes = mdatPos - __privateGet(this, _writer).pos;
__privateGet(this, _writer).writeBox(free(remainingBytes));
} else {
__privateGet(this, _writer).writeBox(movieBox);
}
}
__privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);

@@ -977,2 +1040,3 @@ __privateGet(this, _writer).finalize();

_writer = new WeakMap();
_ftypSize = new WeakMap();
_mdat = new WeakMap();

@@ -982,2 +1046,3 @@ _videoTrack = new WeakMap();

_creationTime = new WeakMap();
_finalizedChunks = new WeakMap();
_finalized = new WeakMap();

@@ -1000,15 +1065,53 @@ _validateOptions = new WeakSet();

}
if (typeof options.fastStart === "object") {
if (options.video && options.fastStart.expectedVideoChunks === void 0) {
throw new Error(`'fastStart' is an object but is missing property 'expectedVideoChunks'.`);
}
if (options.audio && options.fastStart.expectedAudioChunks === void 0) {
throw new Error(`'fastStart' is an object but is missing property 'expectedAudioChunks'.`);
}
} else if (![false, "in-memory"].includes(options.fastStart)) {
throw new Error(`'fastStart' option must be false, 'in-memory' or an object.`);
}
};
_writeHeader = new WeakSet();
writeHeader_fn = function() {
var _a;
let holdsHevc = ((_a = __privateGet(this, _options).video) == null ? void 0 : _a.codec) === "hevc";
let holdsHevc = __privateGet(this, _options).video?.codec === "hevc";
__privateGet(this, _writer).writeBox(ftyp(holdsHevc));
__privateSet(this, _mdat, mdat());
__privateGet(this, _writer).writeBox(__privateGet(this, _mdat));
__privateSet(this, _ftypSize, __privateGet(this, _writer).pos);
if (__privateGet(this, _options).fastStart === "in-memory") {
__privateSet(this, _mdat, mdat(false));
} else {
if (typeof __privateGet(this, _options).fastStart === "object") {
let moovSizeUpperBound = __privateMethod(this, _computeMoovSizeUpperBound, computeMoovSizeUpperBound_fn).call(this);
__privateGet(this, _writer).seek(__privateGet(this, _writer).pos + moovSizeUpperBound);
}
__privateSet(this, _mdat, mdat(true));
__privateGet(this, _writer).writeBox(__privateGet(this, _mdat));
}
__privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);
};
_computeMoovSizeUpperBound = new WeakSet();
computeMoovSizeUpperBound_fn = function() {
if (typeof __privateGet(this, _options).fastStart !== "object")
return;
let upperBound = 0;
let sampleCounts = [
__privateGet(this, _options).fastStart.expectedVideoChunks,
__privateGet(this, _options).fastStart.expectedAudioChunks
];
for (let n of sampleCounts) {
if (!n)
continue;
upperBound += (4 + 4) * Math.ceil(2 / 3 * n);
upperBound += 4 * n;
upperBound += (4 + 4 + 4) * Math.ceil(2 / 3 * n);
upperBound += 4 * n;
upperBound += 8 * n;
}
upperBound += 4096;
return upperBound;
};
_prepareTracks = new WeakSet();
prepareTracks_fn = function() {
var _a;
if (__privateGet(this, _options).video) {

@@ -1022,3 +1125,3 @@ __privateSet(this, _videoTrack, {

height: __privateGet(this, _options).video.height,
rotation: (_a = __privateGet(this, _options).video.rotation) != null ? _a : 0
rotation: __privateGet(this, _options).video.rotation ?? 0
},

@@ -1029,3 +1132,3 @@ timescale: 720,

samples: [],
writtenChunks: [],
finalizedChunks: [],
currentChunk: null,

@@ -1058,3 +1161,3 @@ firstTimestamp: void 0,

samples: [],
writtenChunks: [],
finalizedChunks: [],
currentChunk: null,

@@ -1090,3 +1193,2 @@ firstTimestamp: void 0,

addSampleToTrack_fn = function(track, data, type, timestamp, duration, meta) {
var _a;
let timestampInSeconds = timestamp / 1e6;

@@ -1100,3 +1202,3 @@ let durationInSeconds = duration / 1e6;

if (track.currentChunk)
__privateMethod(this, _writeCurrentChunk, writeCurrentChunk_fn).call(this, track);
__privateMethod(this, _finalizeCurrentChunk, finalizeCurrentChunk_fn).call(this, track);
track.currentChunk = {

@@ -1110,3 +1212,3 @@ startTimestamp: timestampInSeconds,

track.currentChunk.sampleCount++;
if ((_a = meta == null ? void 0 : meta.decoderConfig) == null ? void 0 : _a.description) {
if (meta?.decoderConfig?.description) {
track.codecPrivate = new Uint8Array(meta.decoderConfig.description);

@@ -1164,13 +1266,9 @@ }

};
_writeCurrentChunk = new WeakSet();
writeCurrentChunk_fn = function(track) {
_finalizeCurrentChunk = new WeakSet();
finalizeCurrentChunk_fn = function(track) {
if (!track.currentChunk)
return;
track.currentChunk.offset = __privateGet(this, _writer).pos;
for (let bytes2 of track.currentChunk.sampleData)
__privateGet(this, _writer).write(bytes2);
track.currentChunk.sampleData = null;
if (track.compactlyCodedChunkTable.length === 0 || last(track.compactlyCodedChunkTable).samplesPerChunk !== track.currentChunk.sampleCount) {
track.compactlyCodedChunkTable.push({
firstChunk: track.writtenChunks.length + 1,
firstChunk: track.finalizedChunks.length + 1,
// 1-indexed

@@ -1180,3 +1278,12 @@ samplesPerChunk: track.currentChunk.sampleCount

}
track.writtenChunks.push(track.currentChunk);
track.finalizedChunks.push(track.currentChunk);
__privateGet(this, _finalizedChunks).push(track.currentChunk);
if (__privateGet(this, _options).fastStart === "in-memory") {
track.currentChunk.offset = 0;
return;
}
track.currentChunk.offset = __privateGet(this, _writer).pos;
for (let bytes2 of track.currentChunk.sampleData)
__privateGet(this, _writer).write(bytes2);
track.currentChunk.sampleData = null;
__privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);

@@ -1183,0 +1290,0 @@ };

{
"name": "mp4-muxer",
"version": "2.3.0",
"version": "3.0.0",
"description": "MP4 multiplexer in pure TypeScript with support for WebCodecs API, video & audio.",

@@ -5,0 +5,0 @@ "main": "./build/mp4-muxer.js",

@@ -5,5 +5,6 @@ # mp4-muxer - JavaScript MP4 multiplexer

[![](https://img.shields.io/bundlephobia/minzip/mp4-muxer)](https://bundlephobia.com/package/mp4-muxer)
[![](https://img.shields.io/npm/dm/mp4-muxer)](https://www.npmjs.com/package/mp4-muxer)
The WebCodecs API provides low-level access to media codecs, but provides no way of actually packaging (multiplexing)
the encoded media into a playable file. This project implements an MP4 multiplexer in pure TypeScript, which is
the encoded media into a playable file. This project implements an MP4 multiplexer in pure TypeScript which is
high-quality, fast and tiny, and supports both video and audio.

@@ -16,2 +17,4 @@

> Consider [donating](https://ko-fi.com/vanilagy) if you've found this library useful and wish to support it ❤️
## Quick start

@@ -28,3 +31,4 @@ The following is an example for a common usage of this library:

height: 720
}
},
fastStart: 'in-memory'
});

@@ -102,2 +106,7 @@

fastStart:
| false
| 'in-memory'
| { expectedVideoChunks?: number, expectedAudioChunks?: number }
firstTimestampBehavior?: 'strict' | 'offset'

@@ -107,3 +116,3 @@ }

Codecs currently supported by this library are AVC/H.264, HEVC/H.265, VP9 and AV1 for video, and AAC and Opus for audio.
#### `target`
#### `target` (required)
This option specifies where the data created by the muxer will be written. The options are:

@@ -117,2 +126,3 @@ - `ArrayBufferTarget`: The file data will be written into a single large buffer, which is then stored in the target.

target: new ArrayBufferTarget(),
fastStart: 'in-memory',
// ...

@@ -155,2 +165,3 @@ });

),
fastStart: false,
// ...

@@ -185,2 +196,3 @@ });

target: new FileSystemWritableFileStreamTarget(fileStream),
fastStart: false,
// ...

@@ -194,2 +206,27 @@ });

```
#### `fastStart` (required)
By default, MP4 metadata is stored at the end of the file in the `moov` box - this makes writing the file faster and
easier. However, placing this `moov` box at the _start_ of the file instead (known as "Fast Start") provides certain
benefits: The file becomes easier to stream over the web without range requests, and sites like YouTube can start
processing the video while it's uploading. This library provides full control over the placement of the `moov` box by
setting `fastStart` to one of these options:
- `false`: Disables Fast Start, placing metadata at the end of the file. This option is the fastest and uses the least
memory. This option is recommended for large, unbounded files that are streamed directly to disk.
- `'in-memory'`: Produces a file with Fast Start by keeping all media chunks in memory until the file is finalized. This
option produces the most compact output possible at the cost of a more expensive finalization step and higher memory
requirements. You should _always_ use this option when using `ArrayBufferTarget` as it will result in a
higher-quality output with no change in memory footprint.
- `object`: Produces a file with Fast Start by reserving space for metadata when muxing begins. To know
how many bytes need to be reserved to be safe, you'll have to provide the following data:
```ts
{
expectedVideoChunks?: number,
expectedAudioChunks?: number
}
```
Note that the property `expectedVideoChunks` is _required_ if you have a video track - the same goes for audio. With
this option set, you cannot mux more chunks than the number you've specified (although less is fine).
This option is faster than `'in-memory'` and uses no additional memory, but results in a slightly larger output,
making it useful for when you want to stream the file to disk while still retaining Fast Start.
#### `firstTimestampBehavior` (optional)

@@ -196,0 +233,0 @@ Specifies how to deal with the first chunk in each track having a non-zero timestamp. In the default strict mode,

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc