First release
This commit is contained in:
commit
fa6c85266e
2339 changed files with 761050 additions and 0 deletions
581
node_modules/@videojs/vhs-utils/cjs/mp4-helpers.js
generated
vendored
Normal file
581
node_modules/@videojs/vhs-utils/cjs/mp4-helpers.js
generated
vendored
Normal file
|
@ -0,0 +1,581 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.parseMediaInfo = exports.parseTracks = exports.addSampleDescription = exports.buildFrameTable = exports.findNamedBox = exports.findBox = exports.parseDescriptors = void 0;
|
||||
|
||||
var _byteHelpers = require("./byte-helpers.js");
|
||||
|
||||
var _codecHelpers = require("./codec-helpers.js");
|
||||
|
||||
var _opusHelpers = require("./opus-helpers.js");
|
||||
|
||||
var normalizePath = function normalizePath(path) {
|
||||
if (typeof path === 'string') {
|
||||
return (0, _byteHelpers.stringToBytes)(path);
|
||||
}
|
||||
|
||||
if (typeof path === 'number') {
|
||||
return path;
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
var normalizePaths = function normalizePaths(paths) {
|
||||
if (!Array.isArray(paths)) {
|
||||
return [normalizePath(paths)];
|
||||
}
|
||||
|
||||
return paths.map(function (p) {
|
||||
return normalizePath(p);
|
||||
});
|
||||
};
|
||||
|
||||
var DESCRIPTORS;
|
||||
|
||||
var parseDescriptors = function parseDescriptors(bytes) {
|
||||
bytes = (0, _byteHelpers.toUint8)(bytes);
|
||||
var results = [];
|
||||
var i = 0;
|
||||
|
||||
while (bytes.length > i) {
|
||||
var tag = bytes[i];
|
||||
var size = 0;
|
||||
var headerSize = 0; // tag
|
||||
|
||||
headerSize++;
|
||||
var byte = bytes[headerSize]; // first byte
|
||||
|
||||
headerSize++;
|
||||
|
||||
while (byte & 0x80) {
|
||||
size = (byte & 0x7F) << 7;
|
||||
byte = bytes[headerSize];
|
||||
headerSize++;
|
||||
}
|
||||
|
||||
size += byte & 0x7F;
|
||||
|
||||
for (var z = 0; z < DESCRIPTORS.length; z++) {
|
||||
var _DESCRIPTORS$z = DESCRIPTORS[z],
|
||||
id = _DESCRIPTORS$z.id,
|
||||
parser = _DESCRIPTORS$z.parser;
|
||||
|
||||
if (tag === id) {
|
||||
results.push(parser(bytes.subarray(headerSize, headerSize + size)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i += size + headerSize;
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.parseDescriptors = parseDescriptors;
|
||||
DESCRIPTORS = [{
|
||||
id: 0x03,
|
||||
parser: function parser(bytes) {
|
||||
var desc = {
|
||||
tag: 0x03,
|
||||
id: bytes[0] << 8 | bytes[1],
|
||||
flags: bytes[2],
|
||||
size: 3,
|
||||
dependsOnEsId: 0,
|
||||
ocrEsId: 0,
|
||||
descriptors: [],
|
||||
url: ''
|
||||
}; // depends on es id
|
||||
|
||||
if (desc.flags & 0x80) {
|
||||
desc.dependsOnEsId = bytes[desc.size] << 8 | bytes[desc.size + 1];
|
||||
desc.size += 2;
|
||||
} // url
|
||||
|
||||
|
||||
if (desc.flags & 0x40) {
|
||||
var len = bytes[desc.size];
|
||||
desc.url = (0, _byteHelpers.bytesToString)(bytes.subarray(desc.size + 1, desc.size + 1 + len));
|
||||
desc.size += len;
|
||||
} // ocr es id
|
||||
|
||||
|
||||
if (desc.flags & 0x20) {
|
||||
desc.ocrEsId = bytes[desc.size] << 8 | bytes[desc.size + 1];
|
||||
desc.size += 2;
|
||||
}
|
||||
|
||||
desc.descriptors = parseDescriptors(bytes.subarray(desc.size)) || [];
|
||||
return desc;
|
||||
}
|
||||
}, {
|
||||
id: 0x04,
|
||||
parser: function parser(bytes) {
|
||||
// DecoderConfigDescriptor
|
||||
var desc = {
|
||||
tag: 0x04,
|
||||
oti: bytes[0],
|
||||
streamType: bytes[1],
|
||||
bufferSize: bytes[2] << 16 | bytes[3] << 8 | bytes[4],
|
||||
maxBitrate: bytes[5] << 24 | bytes[6] << 16 | bytes[7] << 8 | bytes[8],
|
||||
avgBitrate: bytes[9] << 24 | bytes[10] << 16 | bytes[11] << 8 | bytes[12],
|
||||
descriptors: parseDescriptors(bytes.subarray(13))
|
||||
};
|
||||
return desc;
|
||||
}
|
||||
}, {
|
||||
id: 0x05,
|
||||
parser: function parser(bytes) {
|
||||
// DecoderSpecificInfo
|
||||
return {
|
||||
tag: 0x05,
|
||||
bytes: bytes
|
||||
};
|
||||
}
|
||||
}, {
|
||||
id: 0x06,
|
||||
parser: function parser(bytes) {
|
||||
// SLConfigDescriptor
|
||||
return {
|
||||
tag: 0x06,
|
||||
bytes: bytes
|
||||
};
|
||||
}
|
||||
}];
|
||||
/**
|
||||
* find any number of boxes by name given a path to it in an iso bmff
|
||||
* such as mp4.
|
||||
*
|
||||
* @param {TypedArray} bytes
|
||||
* bytes for the iso bmff to search for boxes in
|
||||
*
|
||||
* @param {Uint8Array[]|string[]|string|Uint8Array} name
|
||||
* An array of paths or a single path representing the name
|
||||
* of boxes to search through in bytes. Paths may be
|
||||
* uint8 (character codes) or strings.
|
||||
*
|
||||
* @param {boolean} [complete=false]
|
||||
* Should we search only for complete boxes on the final path.
|
||||
* This is very useful when you do not want to get back partial boxes
|
||||
* in the case of streaming files.
|
||||
*
|
||||
* @return {Uint8Array[]}
|
||||
* An array of the end paths that we found.
|
||||
*/
|
||||
|
||||
var findBox = function findBox(bytes, paths, complete) {
|
||||
if (complete === void 0) {
|
||||
complete = false;
|
||||
}
|
||||
|
||||
paths = normalizePaths(paths);
|
||||
bytes = (0, _byteHelpers.toUint8)(bytes);
|
||||
var results = [];
|
||||
|
||||
if (!paths.length) {
|
||||
// short-circuit the search for empty paths
|
||||
return results;
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
|
||||
while (i < bytes.length) {
|
||||
var size = (bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]) >>> 0;
|
||||
var type = bytes.subarray(i + 4, i + 8); // invalid box format.
|
||||
|
||||
if (size === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
var end = i + size;
|
||||
|
||||
if (end > bytes.length) {
|
||||
// this box is bigger than the number of bytes we have
|
||||
// and complete is set, we cannot find any more boxes.
|
||||
if (complete) {
|
||||
break;
|
||||
}
|
||||
|
||||
end = bytes.length;
|
||||
}
|
||||
|
||||
var data = bytes.subarray(i + 8, end);
|
||||
|
||||
if ((0, _byteHelpers.bytesMatch)(type, paths[0])) {
|
||||
if (paths.length === 1) {
|
||||
// this is the end of the path and we've found the box we were
|
||||
// looking for
|
||||
results.push(data);
|
||||
} else {
|
||||
// recursively search for the next box along the path
|
||||
results.push.apply(results, findBox(data, paths.slice(1), complete));
|
||||
}
|
||||
}
|
||||
|
||||
i = end;
|
||||
} // we've finished searching all of bytes
|
||||
|
||||
|
||||
return results;
|
||||
};
|
||||
/**
|
||||
* Search for a single matching box by name in an iso bmff format like
|
||||
* mp4. This function is useful for finding codec boxes which
|
||||
* can be placed arbitrarily in sample descriptions depending
|
||||
* on the version of the file or file type.
|
||||
*
|
||||
* @param {TypedArray} bytes
|
||||
* bytes for the iso bmff to search for boxes in
|
||||
*
|
||||
* @param {string|Uint8Array} name
|
||||
* The name of the box to find.
|
||||
*
|
||||
* @return {Uint8Array[]}
|
||||
* a subarray of bytes representing the name boxed we found.
|
||||
*/
|
||||
|
||||
|
||||
exports.findBox = findBox;
|
||||
|
||||
var findNamedBox = function findNamedBox(bytes, name) {
|
||||
name = normalizePath(name);
|
||||
|
||||
if (!name.length) {
|
||||
// short-circuit the search for empty paths
|
||||
return bytes.subarray(bytes.length);
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
|
||||
while (i < bytes.length) {
|
||||
if ((0, _byteHelpers.bytesMatch)(bytes.subarray(i, i + name.length), name)) {
|
||||
var size = (bytes[i - 4] << 24 | bytes[i - 3] << 16 | bytes[i - 2] << 8 | bytes[i - 1]) >>> 0;
|
||||
var end = size > 1 ? i + size : bytes.byteLength;
|
||||
return bytes.subarray(i + 4, end);
|
||||
}
|
||||
|
||||
i++;
|
||||
} // we've finished searching all of bytes
|
||||
|
||||
|
||||
return bytes.subarray(bytes.length);
|
||||
};
|
||||
|
||||
exports.findNamedBox = findNamedBox;
|
||||
|
||||
var parseSamples = function parseSamples(data, entrySize, parseEntry) {
|
||||
if (entrySize === void 0) {
|
||||
entrySize = 4;
|
||||
}
|
||||
|
||||
if (parseEntry === void 0) {
|
||||
parseEntry = function parseEntry(d) {
|
||||
return (0, _byteHelpers.bytesToNumber)(d);
|
||||
};
|
||||
}
|
||||
|
||||
var entries = [];
|
||||
|
||||
if (!data || !data.length) {
|
||||
return entries;
|
||||
}
|
||||
|
||||
var entryCount = (0, _byteHelpers.bytesToNumber)(data.subarray(4, 8));
|
||||
|
||||
for (var i = 8; entryCount; i += entrySize, entryCount--) {
|
||||
entries.push(parseEntry(data.subarray(i, i + entrySize)));
|
||||
}
|
||||
|
||||
return entries;
|
||||
};
|
||||
|
||||
var buildFrameTable = function buildFrameTable(stbl, timescale) {
|
||||
var keySamples = parseSamples(findBox(stbl, ['stss'])[0]);
|
||||
var chunkOffsets = parseSamples(findBox(stbl, ['stco'])[0]);
|
||||
var timeToSamples = parseSamples(findBox(stbl, ['stts'])[0], 8, function (entry) {
|
||||
return {
|
||||
sampleCount: (0, _byteHelpers.bytesToNumber)(entry.subarray(0, 4)),
|
||||
sampleDelta: (0, _byteHelpers.bytesToNumber)(entry.subarray(4, 8))
|
||||
};
|
||||
});
|
||||
var samplesToChunks = parseSamples(findBox(stbl, ['stsc'])[0], 12, function (entry) {
|
||||
return {
|
||||
firstChunk: (0, _byteHelpers.bytesToNumber)(entry.subarray(0, 4)),
|
||||
samplesPerChunk: (0, _byteHelpers.bytesToNumber)(entry.subarray(4, 8)),
|
||||
sampleDescriptionIndex: (0, _byteHelpers.bytesToNumber)(entry.subarray(8, 12))
|
||||
};
|
||||
});
|
||||
var stsz = findBox(stbl, ['stsz'])[0]; // stsz starts with a 4 byte sampleSize which we don't need
|
||||
|
||||
var sampleSizes = parseSamples(stsz && stsz.length && stsz.subarray(4) || null);
|
||||
var frames = [];
|
||||
|
||||
for (var chunkIndex = 0; chunkIndex < chunkOffsets.length; chunkIndex++) {
|
||||
var samplesInChunk = void 0;
|
||||
|
||||
for (var i = 0; i < samplesToChunks.length; i++) {
|
||||
var sampleToChunk = samplesToChunks[i];
|
||||
var isThisOne = chunkIndex + 1 >= sampleToChunk.firstChunk && (i + 1 >= samplesToChunks.length || chunkIndex + 1 < samplesToChunks[i + 1].firstChunk);
|
||||
|
||||
if (isThisOne) {
|
||||
samplesInChunk = sampleToChunk.samplesPerChunk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var chunkOffset = chunkOffsets[chunkIndex];
|
||||
|
||||
for (var _i = 0; _i < samplesInChunk; _i++) {
|
||||
var frameEnd = sampleSizes[frames.length]; // if we don't have key samples every frame is a keyframe
|
||||
|
||||
var keyframe = !keySamples.length;
|
||||
|
||||
if (keySamples.length && keySamples.indexOf(frames.length + 1) !== -1) {
|
||||
keyframe = true;
|
||||
}
|
||||
|
||||
var frame = {
|
||||
keyframe: keyframe,
|
||||
start: chunkOffset,
|
||||
end: chunkOffset + frameEnd
|
||||
};
|
||||
|
||||
for (var k = 0; k < timeToSamples.length; k++) {
|
||||
var _timeToSamples$k = timeToSamples[k],
|
||||
sampleCount = _timeToSamples$k.sampleCount,
|
||||
sampleDelta = _timeToSamples$k.sampleDelta;
|
||||
|
||||
if (frames.length <= sampleCount) {
|
||||
// ms to ns
|
||||
var lastTimestamp = frames.length ? frames[frames.length - 1].timestamp : 0;
|
||||
frame.timestamp = lastTimestamp + sampleDelta / timescale * 1000;
|
||||
frame.duration = sampleDelta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frames.push(frame);
|
||||
chunkOffset += frameEnd;
|
||||
}
|
||||
}
|
||||
|
||||
return frames;
|
||||
};
|
||||
|
||||
exports.buildFrameTable = buildFrameTable;
|
||||
|
||||
var addSampleDescription = function addSampleDescription(track, bytes) {
|
||||
var codec = (0, _byteHelpers.bytesToString)(bytes.subarray(0, 4));
|
||||
|
||||
if (track.type === 'video') {
|
||||
track.info = track.info || {};
|
||||
track.info.width = bytes[28] << 8 | bytes[29];
|
||||
track.info.height = bytes[30] << 8 | bytes[31];
|
||||
} else if (track.type === 'audio') {
|
||||
track.info = track.info || {};
|
||||
track.info.channels = bytes[20] << 8 | bytes[21];
|
||||
track.info.bitDepth = bytes[22] << 8 | bytes[23];
|
||||
track.info.sampleRate = bytes[28] << 8 | bytes[29];
|
||||
}
|
||||
|
||||
if (codec === 'avc1') {
|
||||
var avcC = findNamedBox(bytes, 'avcC'); // AVCDecoderConfigurationRecord
|
||||
|
||||
codec += "." + (0, _codecHelpers.getAvcCodec)(avcC);
|
||||
track.info.avcC = avcC; // TODO: do we need to parse all this?
|
||||
|
||||
/* {
|
||||
configurationVersion: avcC[0],
|
||||
profile: avcC[1],
|
||||
profileCompatibility: avcC[2],
|
||||
level: avcC[3],
|
||||
lengthSizeMinusOne: avcC[4] & 0x3
|
||||
};
|
||||
let spsNalUnitCount = avcC[5] & 0x1F;
|
||||
const spsNalUnits = track.info.avc.spsNalUnits = [];
|
||||
// past spsNalUnitCount
|
||||
let offset = 6;
|
||||
while (spsNalUnitCount--) {
|
||||
const nalLen = avcC[offset] << 8 | avcC[offset + 1];
|
||||
spsNalUnits.push(avcC.subarray(offset + 2, offset + 2 + nalLen));
|
||||
offset += nalLen + 2;
|
||||
}
|
||||
let ppsNalUnitCount = avcC[offset];
|
||||
const ppsNalUnits = track.info.avc.ppsNalUnits = [];
|
||||
// past ppsNalUnitCount
|
||||
offset += 1;
|
||||
while (ppsNalUnitCount--) {
|
||||
const nalLen = avcC[offset] << 8 | avcC[offset + 1];
|
||||
ppsNalUnits.push(avcC.subarray(offset + 2, offset + 2 + nalLen));
|
||||
offset += nalLen + 2;
|
||||
}*/
|
||||
// HEVCDecoderConfigurationRecord
|
||||
} else if (codec === 'hvc1' || codec === 'hev1') {
|
||||
codec += "." + (0, _codecHelpers.getHvcCodec)(findNamedBox(bytes, 'hvcC'));
|
||||
} else if (codec === 'mp4a' || codec === 'mp4v') {
|
||||
var esds = findNamedBox(bytes, 'esds');
|
||||
var esDescriptor = parseDescriptors(esds.subarray(4))[0];
|
||||
var decoderConfig = esDescriptor && esDescriptor.descriptors.filter(function (_ref) {
|
||||
var tag = _ref.tag;
|
||||
return tag === 0x04;
|
||||
})[0];
|
||||
|
||||
if (decoderConfig) {
|
||||
// most codecs do not have a further '.'
|
||||
// such as 0xa5 for ac-3 and 0xa6 for e-ac-3
|
||||
codec += '.' + (0, _byteHelpers.toHexString)(decoderConfig.oti);
|
||||
|
||||
if (decoderConfig.oti === 0x40) {
|
||||
codec += '.' + (decoderConfig.descriptors[0].bytes[0] >> 3).toString();
|
||||
} else if (decoderConfig.oti === 0x20) {
|
||||
codec += '.' + decoderConfig.descriptors[0].bytes[4].toString();
|
||||
} else if (decoderConfig.oti === 0xdd) {
|
||||
codec = 'vorbis';
|
||||
}
|
||||
} else if (track.type === 'audio') {
|
||||
codec += '.40.2';
|
||||
} else {
|
||||
codec += '.20.9';
|
||||
}
|
||||
} else if (codec === 'av01') {
|
||||
// AV1DecoderConfigurationRecord
|
||||
codec += "." + (0, _codecHelpers.getAv1Codec)(findNamedBox(bytes, 'av1C'));
|
||||
} else if (codec === 'vp09') {
|
||||
// VPCodecConfigurationRecord
|
||||
var vpcC = findNamedBox(bytes, 'vpcC'); // https://www.webmproject.org/vp9/mp4/
|
||||
|
||||
var profile = vpcC[0];
|
||||
var level = vpcC[1];
|
||||
var bitDepth = vpcC[2] >> 4;
|
||||
var chromaSubsampling = (vpcC[2] & 0x0F) >> 1;
|
||||
var videoFullRangeFlag = (vpcC[2] & 0x0F) >> 3;
|
||||
var colourPrimaries = vpcC[3];
|
||||
var transferCharacteristics = vpcC[4];
|
||||
var matrixCoefficients = vpcC[5];
|
||||
codec += "." + (0, _byteHelpers.padStart)(profile, 2, '0');
|
||||
codec += "." + (0, _byteHelpers.padStart)(level, 2, '0');
|
||||
codec += "." + (0, _byteHelpers.padStart)(bitDepth, 2, '0');
|
||||
codec += "." + (0, _byteHelpers.padStart)(chromaSubsampling, 2, '0');
|
||||
codec += "." + (0, _byteHelpers.padStart)(colourPrimaries, 2, '0');
|
||||
codec += "." + (0, _byteHelpers.padStart)(transferCharacteristics, 2, '0');
|
||||
codec += "." + (0, _byteHelpers.padStart)(matrixCoefficients, 2, '0');
|
||||
codec += "." + (0, _byteHelpers.padStart)(videoFullRangeFlag, 2, '0');
|
||||
} else if (codec === 'theo') {
|
||||
codec = 'theora';
|
||||
} else if (codec === 'spex') {
|
||||
codec = 'speex';
|
||||
} else if (codec === '.mp3') {
|
||||
codec = 'mp4a.40.34';
|
||||
} else if (codec === 'msVo') {
|
||||
codec = 'vorbis';
|
||||
} else if (codec === 'Opus') {
|
||||
codec = 'opus';
|
||||
var dOps = findNamedBox(bytes, 'dOps');
|
||||
track.info.opus = (0, _opusHelpers.parseOpusHead)(dOps); // TODO: should this go into the webm code??
|
||||
// Firefox requires a codecDelay for opus playback
|
||||
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1276238
|
||||
|
||||
track.info.codecDelay = 6500000;
|
||||
} else {
|
||||
codec = codec.toLowerCase();
|
||||
}
|
||||
/* eslint-enable */
|
||||
// flac, ac-3, ec-3, opus
|
||||
|
||||
|
||||
track.codec = codec;
|
||||
};
|
||||
|
||||
exports.addSampleDescription = addSampleDescription;
|
||||
|
||||
var parseTracks = function parseTracks(bytes, frameTable) {
|
||||
if (frameTable === void 0) {
|
||||
frameTable = true;
|
||||
}
|
||||
|
||||
bytes = (0, _byteHelpers.toUint8)(bytes);
|
||||
var traks = findBox(bytes, ['moov', 'trak'], true);
|
||||
var tracks = [];
|
||||
traks.forEach(function (trak) {
|
||||
var track = {
|
||||
bytes: trak
|
||||
};
|
||||
var mdia = findBox(trak, ['mdia'])[0];
|
||||
var hdlr = findBox(mdia, ['hdlr'])[0];
|
||||
var trakType = (0, _byteHelpers.bytesToString)(hdlr.subarray(8, 12));
|
||||
|
||||
if (trakType === 'soun') {
|
||||
track.type = 'audio';
|
||||
} else if (trakType === 'vide') {
|
||||
track.type = 'video';
|
||||
} else {
|
||||
track.type = trakType;
|
||||
}
|
||||
|
||||
var tkhd = findBox(trak, ['tkhd'])[0];
|
||||
|
||||
if (tkhd) {
|
||||
var view = new DataView(tkhd.buffer, tkhd.byteOffset, tkhd.byteLength);
|
||||
var tkhdVersion = view.getUint8(0);
|
||||
track.number = tkhdVersion === 0 ? view.getUint32(12) : view.getUint32(20);
|
||||
}
|
||||
|
||||
var mdhd = findBox(mdia, ['mdhd'])[0];
|
||||
|
||||
if (mdhd) {
|
||||
// mdhd is a FullBox, meaning it will have its own version as the first byte
|
||||
var version = mdhd[0];
|
||||
var index = version === 0 ? 12 : 20;
|
||||
track.timescale = (mdhd[index] << 24 | mdhd[index + 1] << 16 | mdhd[index + 2] << 8 | mdhd[index + 3]) >>> 0;
|
||||
}
|
||||
|
||||
var stbl = findBox(mdia, ['minf', 'stbl'])[0];
|
||||
var stsd = findBox(stbl, ['stsd'])[0];
|
||||
var descriptionCount = (0, _byteHelpers.bytesToNumber)(stsd.subarray(4, 8));
|
||||
var offset = 8; // add codec and codec info
|
||||
|
||||
while (descriptionCount--) {
|
||||
var len = (0, _byteHelpers.bytesToNumber)(stsd.subarray(offset, offset + 4));
|
||||
var sampleDescriptor = stsd.subarray(offset + 4, offset + 4 + len);
|
||||
addSampleDescription(track, sampleDescriptor);
|
||||
offset += 4 + len;
|
||||
}
|
||||
|
||||
if (frameTable) {
|
||||
track.frameTable = buildFrameTable(stbl, track.timescale);
|
||||
} // codec has no sub parameters
|
||||
|
||||
|
||||
tracks.push(track);
|
||||
});
|
||||
return tracks;
|
||||
};
|
||||
|
||||
exports.parseTracks = parseTracks;
|
||||
|
||||
var parseMediaInfo = function parseMediaInfo(bytes) {
|
||||
var mvhd = findBox(bytes, ['moov', 'mvhd'], true)[0];
|
||||
|
||||
if (!mvhd || !mvhd.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var info = {}; // ms to ns
|
||||
// mvhd v1 has 8 byte duration and other fields too
|
||||
|
||||
if (mvhd[0] === 1) {
|
||||
info.timestampScale = (0, _byteHelpers.bytesToNumber)(mvhd.subarray(20, 24));
|
||||
info.duration = (0, _byteHelpers.bytesToNumber)(mvhd.subarray(24, 32));
|
||||
} else {
|
||||
info.timestampScale = (0, _byteHelpers.bytesToNumber)(mvhd.subarray(12, 16));
|
||||
info.duration = (0, _byteHelpers.bytesToNumber)(mvhd.subarray(16, 20));
|
||||
}
|
||||
|
||||
info.bytes = mvhd;
|
||||
return info;
|
||||
};
|
||||
|
||||
exports.parseMediaInfo = parseMediaInfo;
|
Loading…
Add table
Add a link
Reference in a new issue