webm-muxer
Advanced tools
Comparing version 1.2.1 to 2.0.0
@@ -22,10 +22,4 @@ /** | ||
target: 'buffer' | ((data: Uint8Array, offset: number, done: boolean) => void) | FileSystemWritableFileStream, | ||
/** | ||
* Specifies the docType of the muxed multimedia file. This property is optional and defaults to `'webm'`, which is | ||
* a subset of the more general container format, Matroska. Using `'matroska'` alongside an .mkv extension will | ||
* allow you to use all codecs, not just the ones officially supported by WebM. However, there is generally less | ||
* support for .mkv files than there is for .webm and it is less ubiquitous on the web. | ||
*/ | ||
type?: 'webm' | 'matroska', | ||
/** | ||
* When set, declares the existence of a video track in the WebM file and configures that video track. | ||
@@ -53,2 +47,3 @@ */ | ||
}, | ||
/** | ||
@@ -75,3 +70,25 @@ * When set, declares the existence of an audio track in the WebM file and configures that audio track. | ||
bitDepth?: number | ||
} | ||
}, | ||
/** | ||
* Specifies the docType of the muxed multimedia file. This property is optional and defaults to `'webm'`, which is | ||
* a subset of the more general container format, Matroska. Using `'matroska'` alongside an .mkv extension will | ||
* allow you to use all codecs, not just the ones officially supported by WebM. However, there is generally less | ||
* support for .mkv files than there is for .webm and it is less ubiquitous on the web. | ||
*/ | ||
type?: 'webm' | 'matroska', | ||
/** | ||
* Specifies how to deal with the first chunk in each track having a non-zero timestamp. In the default strict mode, | ||
* timestamps must start with 0 to ensure proper playback. However, when directly pumping video frames or audio data | ||
* from a MediaTrackStream into the encoder and then the muxer, the timestamps are usually relative to the age of | ||
* the document or the computer's clock, which is typically not what we want. Handling of these timestamps must be | ||
* set explicitly: | ||
* | ||
* Use `'offset'` to offset the timestamp of each video track by that track's first chunk's timestamp. This way, it | ||
* starts at 0. | ||
* | ||
* Use `'permissive'` to allow the first timestamp to be non-zero. | ||
*/ | ||
firstTimestampBehavior?: 'strict' | 'offset' | 'permissive' | ||
} | ||
@@ -78,0 +95,0 @@ |
@@ -6,4 +6,18 @@ "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) => { | ||
@@ -428,3 +442,4 @@ for (var name in all) | ||
var CLUSTER_SIZE_BYTES = 5; | ||
var _target, _options, _segment, _segmentInfo, _seekHead, _tracksElement, _segmentDuration, _colourElement, _videoCodecPrivate, _audioCodecPrivate, _cues, _currentCluster, _currentClusterTimestamp, _duration, _videoChunkQueue, _audioChunkQueue, _lastVideoTimestamp, _lastAudioTimestamp, _colorSpace, _finalized, _validateOptions, validateOptions_fn, _createFileHeader, createFileHeader_fn, _writeEBMLHeader, writeEBMLHeader_fn, _createSeekHead, createSeekHead_fn, _createSegmentInfo, createSegmentInfo_fn, _createTracks, createTracks_fn, _createSegment, createSegment_fn, _createCues, createCues_fn, _maybeFlushStreamingTarget, maybeFlushStreamingTarget_fn, _segmentDataOffset, segmentDataOffset_get, _writeVideoDecoderConfig, writeVideoDecoderConfig_fn, _fixVP9ColorSpace, fixVP9ColorSpace_fn, _createInternalChunk, createInternalChunk_fn, _writeSimpleBlock, writeSimpleBlock_fn, _writeCodecPrivate, writeCodecPrivate_fn, _createNewCluster, createNewCluster_fn, _finalizeCurrentCluster, finalizeCurrentCluster_fn, _ensureNotFinalized, ensureNotFinalized_fn; | ||
var FIRST_TIMESTAMP_BEHAVIORS = ["strict", "offset", "permissive"]; | ||
var _target, _options, _segment, _segmentInfo, _seekHead, _tracksElement, _segmentDuration, _colourElement, _videoCodecPrivate, _audioCodecPrivate, _cues, _currentCluster, _currentClusterTimestamp, _duration, _videoChunkQueue, _audioChunkQueue, _firstVideoTimestamp, _firstAudioTimestamp, _lastVideoTimestamp, _lastAudioTimestamp, _colorSpace, _finalized, _validateOptions, validateOptions_fn, _createFileHeader, createFileHeader_fn, _writeEBMLHeader, writeEBMLHeader_fn, _createSeekHead, createSeekHead_fn, _createSegmentInfo, createSegmentInfo_fn, _createTracks, createTracks_fn, _createSegment, createSegment_fn, _createCues, createCues_fn, _maybeFlushStreamingTarget, maybeFlushStreamingTarget_fn, _segmentDataOffset, segmentDataOffset_get, _writeVideoDecoderConfig, writeVideoDecoderConfig_fn, _fixVP9ColorSpace, fixVP9ColorSpace_fn, _createInternalChunk, createInternalChunk_fn, _validateTimestamp, validateTimestamp_fn, _writeSimpleBlock, writeSimpleBlock_fn, _writeCodecPrivate, writeCodecPrivate_fn, _createNewCluster, createNewCluster_fn, _finalizeCurrentCluster, finalizeCurrentCluster_fn, _ensureNotFinalized, ensureNotFinalized_fn; | ||
var WebMMuxer = class { | ||
@@ -445,2 +460,3 @@ constructor(options) { | ||
__privateAdd(this, _createInternalChunk); | ||
__privateAdd(this, _validateTimestamp); | ||
__privateAdd(this, _writeSimpleBlock); | ||
@@ -467,8 +483,13 @@ __privateAdd(this, _writeCodecPrivate); | ||
__privateAdd(this, _audioChunkQueue, []); | ||
__privateAdd(this, _lastVideoTimestamp, 0); | ||
__privateAdd(this, _lastAudioTimestamp, 0); | ||
__privateAdd(this, _firstVideoTimestamp, void 0); | ||
__privateAdd(this, _firstAudioTimestamp, void 0); | ||
__privateAdd(this, _lastVideoTimestamp, -1); | ||
__privateAdd(this, _lastAudioTimestamp, -1); | ||
__privateAdd(this, _colorSpace, void 0); | ||
__privateAdd(this, _finalized, false); | ||
__privateMethod(this, _validateOptions, validateOptions_fn).call(this, options); | ||
__privateSet(this, _options, options); | ||
__privateSet(this, _options, __spreadValues({ | ||
type: "webm", | ||
firstTimestampBehavior: "strict" | ||
}, options)); | ||
if (options.target === "buffer") { | ||
@@ -494,2 +515,4 @@ __privateSet(this, _target, new ArrayBufferWriteTarget()); | ||
throw new Error("No video track declared."); | ||
if (__privateGet(this, _firstVideoTimestamp) === void 0) | ||
__privateSet(this, _firstVideoTimestamp, timestamp); | ||
if (meta) | ||
@@ -521,2 +544,4 @@ __privateMethod(this, _writeVideoDecoderConfig, writeVideoDecoderConfig_fn).call(this, meta); | ||
throw new Error("No audio track declared."); | ||
if (__privateGet(this, _firstAudioTimestamp) === void 0) | ||
__privateSet(this, _firstAudioTimestamp, timestamp); | ||
let internalChunk = __privateMethod(this, _createInternalChunk, createInternalChunk_fn).call(this, data, type, timestamp, AUDIO_TRACK_NUMBER); | ||
@@ -585,2 +610,4 @@ __privateSet(this, _lastAudioTimestamp, internalChunk.timestamp); | ||
_audioChunkQueue = new WeakMap(); | ||
_firstVideoTimestamp = new WeakMap(); | ||
_firstAudioTimestamp = new WeakMap(); | ||
_lastVideoTimestamp = new WeakMap(); | ||
@@ -595,2 +622,5 @@ _lastAudioTimestamp = new WeakMap(); | ||
} | ||
if (options.firstTimestampBehavior && !FIRST_TIMESTAMP_BEHAVIORS.includes(options.firstTimestampBehavior)) { | ||
throw new Error(`Invalid first timestamp behavior: ${options.firstTimestampBehavior}`); | ||
} | ||
}; | ||
@@ -795,6 +825,7 @@ _createFileHeader = new WeakSet(); | ||
createInternalChunk_fn = function(data, type, timestamp, trackNumber) { | ||
let adjustedTimestamp = __privateMethod(this, _validateTimestamp, validateTimestamp_fn).call(this, timestamp, trackNumber); | ||
let internalChunk = { | ||
data, | ||
type, | ||
timestamp, | ||
timestamp: adjustedTimestamp, | ||
trackNumber | ||
@@ -804,2 +835,24 @@ }; | ||
}; | ||
_validateTimestamp = new WeakSet(); | ||
validateTimestamp_fn = function(timestamp, trackNumber) { | ||
let firstTimestamp = trackNumber === VIDEO_TRACK_NUMBER ? __privateGet(this, _firstVideoTimestamp) : __privateGet(this, _firstAudioTimestamp); | ||
let lastTimestamp = trackNumber === VIDEO_TRACK_NUMBER ? __privateGet(this, _lastVideoTimestamp) : __privateGet(this, _lastAudioTimestamp); | ||
if (__privateGet(this, _options).firstTimestampBehavior === "strict" && lastTimestamp === -1 && timestamp !== 0) { | ||
throw new Error( | ||
`The first chunk for your media track must have a timestamp of 0 (received ${timestamp}). Non-zero first timestamps are often caused by directly piping frames or audio data from a MediaStreamTrack into the encoder. Their timestamps are typically relative to the age of the document, which is probably what you want. | ||
If you want to offset all timestamps of a track such that the first one is zero, set firstTimestampBehavior: 'offset' in the options. | ||
If you want to allow non-zero first timestamps, set firstTimestampBehavior: 'permissive'. | ||
` | ||
); | ||
} else if (__privateGet(this, _options).firstTimestampBehavior === "offset") { | ||
timestamp -= firstTimestamp; | ||
} | ||
if (timestamp < lastTimestamp) { | ||
throw new Error( | ||
`Timestamps must be monotonically increasing (went from ${lastTimestamp} to ${timestamp}).` | ||
); | ||
} | ||
return timestamp; | ||
}; | ||
_writeSimpleBlock = new WeakSet(); | ||
@@ -806,0 +859,0 @@ writeSimpleBlock_fn = function(chunk) { |
{ | ||
"name": "webm-muxer", | ||
"version": "1.2.1", | ||
"version": "2.0.0", | ||
"description": "WebM multiplexer in pure TypeScript with support for WebCodecs API, video & audio.", | ||
@@ -5,0 +5,0 @@ "main": "./build/webm-muxer.js", |
@@ -80,4 +80,2 @@ # webm-muxer - JavaScript WebM multiplexer | ||
type?: 'webm' | 'matroska', | ||
video?: { | ||
@@ -95,3 +93,7 @@ codec: string, | ||
bitDepth?: number // Mainly necessary for PCM-coded audio | ||
} | ||
}, | ||
type?: 'webm' | 'matroska', | ||
firstTimestampBehavior?: 'strict' | 'offset' | 'permissive' | ||
} | ||
@@ -163,3 +165,3 @@ ``` | ||
``` | ||
#### `type` | ||
#### `type` (optional) | ||
As WebM is a subset of the more general Matroska multimedia container format, this library muxes both WebM and Matroska | ||
@@ -171,2 +173,11 @@ files. WebM, according to the official specification, supports only a small subset of the codecs supported by Matroska. | ||
extension. | ||
#### `firstTimestampBehavior` (optional) | ||
Specifies how to deal with the first chunk in each track having a non-zero timestamp. In the default strict mode, | ||
timestamps must start with 0 to ensure proper playback. However, when directly pumping video frames or audio data | ||
from a MediaTrackStream into the encoder and then the muxer, the timestamps are usually relative to the age of | ||
the document or the computer's clock, which is typically not what we want. Handling of these timestamps must be | ||
set explicitly: | ||
- Use `'offset'` to offset the timestamp of each video track by that track's first chunk's timestamp. This way, it | ||
starts at 0. | ||
- Use `'permissive'` to allow the first timestamp to be non-zero. | ||
@@ -173,0 +184,0 @@ ### Muxing media chunks |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
62292
1095
259