@isomp4/parser
Advanced tools
+4
-6
| { | ||
| "name": "@isomp4/parser", | ||
| "version": "0.1.2", | ||
| "version": "0.1.3", | ||
| "description": "", | ||
@@ -39,13 +39,11 @@ "keywords": [ | ||
| "cjs/**/*.js", | ||
| "cjs/**/*.js.map", | ||
| "cjs/**/package.json", | ||
| "dist/**/*.js", | ||
| "dist/**/*.js.map", | ||
| "dist/**/*.d.ts" | ||
| ], | ||
| "dependencies": { | ||
| "@isomp4/core": "^0.1.2" | ||
| "@isomp4/core": "^0.1.3" | ||
| }, | ||
| "devDependencies": { | ||
| "@isomp4/box-moov": "^0.1.2" | ||
| "@isomp4/box-moov": "^0.1.3" | ||
| }, | ||
@@ -59,3 +57,3 @@ "scripts": { | ||
| }, | ||
| "gitHead": "0e1228d97be1b70c4e186be3aa2030e9dbb25430" | ||
| "gitHead": "e9a1443618ef08f11ca714fbccde5ad434d5e2ae" | ||
| } |
-228
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.MP4Parser = exports.AbstractMP4Parser = void 0; | ||
| const buffer_1 = require("buffer"); | ||
| const core_1 = require("@isomp4/core"); | ||
| const EMPTY_BUFFER = buffer_1.Buffer.allocUnsafe(0); | ||
| /** | ||
| * Parses the ISO BMFF box structure of an MP4 stream. | ||
| */ | ||
| class AbstractMP4Parser { | ||
| /** | ||
| * Creates a new parser for an MP4 stream. | ||
| */ | ||
| constructor() { | ||
| this.boxes = new Map(); | ||
| this.boxStack = []; | ||
| this.buffer = EMPTY_BUFFER; | ||
| this.bytesNeeded = 0; | ||
| this.currentBox = null; | ||
| } | ||
| /** | ||
| * | ||
| * @param encodings | ||
| */ | ||
| registerBox(...encodings) { | ||
| for (const encoding of encodings) { | ||
| if (this.boxes.has(encoding.type)) { | ||
| throw new Error("Box type is already registered: " + encoding.type); | ||
| } | ||
| this.boxes.set(encoding.type, encoding); | ||
| } | ||
| } | ||
| /** | ||
| * | ||
| * @param boxType | ||
| */ | ||
| isBoxRegistered(boxType) { | ||
| return this.boxes.has(boxType); | ||
| } | ||
| /** | ||
| * Appends new data to the stream. | ||
| * @param data The new data to append. This data does NOT need to be a complete segment (or even a fragment). | ||
| */ | ||
| append(data) { | ||
| let input = buffer_1.Buffer.from(data.buffer, data.byteOffset, data.byteLength); | ||
| while (input.length > 0) { | ||
| if (this.bytesNeeded > 0) { | ||
| // Ensure that buffer is the correct size | ||
| this.ensureBuffer(this.bytesNeeded); | ||
| // Don't copy more data into the temp buffer than is needed for the next part! | ||
| const needed = this.bytesNeeded - this.buffer.byteOffset; | ||
| if (needed > 0) { | ||
| if (needed <= input.length) { | ||
| // Only copy 'needed' number of bytes into the temp buffer | ||
| input.copy(this.buffer, 0, 0, needed); | ||
| input = input.slice(needed); | ||
| } | ||
| else { | ||
| // All input can be copied into temp buffer | ||
| this.buffer = this.buffer.slice(input.copy(this.buffer)); | ||
| // More input data is needed | ||
| return; | ||
| } | ||
| } | ||
| // Temp buffer now contains all bytes needed | ||
| // Flip buffer | ||
| const bytesNeeded = this.bytesNeeded; | ||
| const buf = buffer_1.Buffer.from(this.buffer.buffer, 0, bytesNeeded); | ||
| this.bytesNeeded = 0; // This must be reset before calling processBuffer() | ||
| const bytesConsumed = this.processBuffer(buf); | ||
| if (this.bytesNeeded > 0) { | ||
| // More bytes are needed | ||
| continue; | ||
| } | ||
| if (bytesConsumed !== bytesNeeded) { | ||
| throw new Error(`bytes consumed(${bytesConsumed}) != bytes needed(${bytesNeeded})`); | ||
| } | ||
| // Reset buffer | ||
| this.buffer = buffer_1.Buffer.from(this.buffer.buffer); | ||
| } | ||
| else { | ||
| // Avoid copying data by using the input buffer directly | ||
| const consumed = this.processBuffer(input); | ||
| if (consumed > 0) { | ||
| input = input.slice(consumed); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ensureBuffer(capacity) { | ||
| if (this.buffer.buffer.byteLength < capacity) { | ||
| const newBuffer = buffer_1.Buffer.alloc(capacity); | ||
| // If the byteOffset is zero, then this indicates that there is no data written to the buffer | ||
| if (this.buffer.byteOffset > 0) { | ||
| // Must copy old buffer to new buffer | ||
| buffer_1.Buffer.from(this.buffer.buffer).copy(newBuffer); | ||
| } | ||
| this.buffer = newBuffer; | ||
| } | ||
| } | ||
| /** | ||
| * Processes the given buffer. | ||
| * @param buffer The input buffer. | ||
| * @return The number of bytes consumed. | ||
| */ | ||
| processBuffer(buffer) { | ||
| stackCheck: if (this.boxStack.length > 0) { | ||
| const top = this.boxStack[this.boxStack.length - 1]; | ||
| const header = top.header; | ||
| const needed = header.size - top.offset; | ||
| if (needed > 0) { | ||
| if (top.children) { | ||
| // Skip and parse children normally | ||
| break stackCheck; | ||
| } | ||
| const available = buffer.length; | ||
| if (needed > available) { | ||
| // Don't have enough data | ||
| this.onBoxData(header, buffer); | ||
| top.offset += available; | ||
| return available; | ||
| } | ||
| // Have enough data | ||
| this.onBoxData(header, buffer.slice(0, needed)); | ||
| } | ||
| // End box | ||
| if (top.box != null) { | ||
| this.onBoxEnded(header, top.box); | ||
| } | ||
| else { | ||
| this.onBoxEnded(header); | ||
| } | ||
| // Pop box state | ||
| this.boxStack.pop(); | ||
| // Check next box state | ||
| if (this.boxStack.length > 0) { | ||
| const next = this.boxStack[this.boxStack.length - 1]; | ||
| next.offset += header.size; | ||
| if (top.box != null && next.box != null && core_1.BoxContainer.isInstance(next.box)) { | ||
| core_1.BoxContainer.add(next.box, top.box); | ||
| } | ||
| } | ||
| // Trigger parsing of next box | ||
| this.currentBox = null; | ||
| return needed; | ||
| } | ||
| if (this.currentBox == null) { | ||
| const header = core_1.BoxHeader.parse(buffer); | ||
| if (typeof header === "number") { | ||
| this.bytesNeeded = header; | ||
| return 0; | ||
| } | ||
| const headerLength = core_1.BoxHeader.decodedBytes; | ||
| // Invoke box started event | ||
| const content = this.onBoxStarted(header, buffer.slice(0, headerLength)); | ||
| // Start box | ||
| this.currentBox = { | ||
| header, | ||
| headerLength, | ||
| content, | ||
| }; | ||
| return headerLength; | ||
| } | ||
| const header = this.currentBox.header; | ||
| if (this.currentBox.content) { | ||
| const encoding = this.boxes.get(header.type); | ||
| if (encoding != null) { | ||
| const box = encoding.decode(buffer, header); | ||
| if (typeof box === "number") { | ||
| this.bytesNeeded = box; | ||
| return 0; | ||
| } | ||
| const consumed = encoding.decodedBytes; | ||
| // Invoke box decoded event | ||
| const children = this.onBoxDecoded(box, buffer.slice(0, consumed)); | ||
| // Push box onto stack (and record whether to parse children) | ||
| this.boxStack.push({ | ||
| header, | ||
| box, | ||
| children, | ||
| offset: this.currentBox.headerLength + consumed, | ||
| }); | ||
| // Trigger parsing of child boxes | ||
| if (children) { | ||
| box.children = {}; | ||
| this.currentBox = null; | ||
| } | ||
| return consumed; | ||
| } | ||
| // No encoding, so reset content boolean | ||
| this.currentBox.content = false; | ||
| } | ||
| // No encoding for box type, must skip entire box and children | ||
| this.boxStack.push({ | ||
| header, | ||
| box: null, | ||
| children: false, | ||
| offset: this.currentBox.headerLength, | ||
| }); | ||
| return this.processBuffer(buffer); | ||
| } | ||
| } | ||
| exports.AbstractMP4Parser = AbstractMP4Parser; | ||
| /** | ||
| * An implementation of {@link AbstractMP4Parser} that delegates to optional function properties. | ||
| */ | ||
| class MP4Parser extends AbstractMP4Parser { | ||
| /** | ||
| * Create a new MP4Parser. | ||
| */ | ||
| constructor() { | ||
| super(); | ||
| } | ||
| onBoxStarted(header, headerData) { | ||
| return this.boxStarted ? this.boxStarted(header, headerData) : true; | ||
| } | ||
| onBoxDecoded(box, boxData) { | ||
| return this.boxDecoded ? this.boxDecoded(box, boxData) : true; | ||
| } | ||
| onBoxData(header, boxData) { | ||
| this.boxData?.(header, boxData); | ||
| } | ||
| onBoxEnded(header, box) { | ||
| this.boxEnded?.(header, box); | ||
| } | ||
| } | ||
| exports.MP4Parser = MP4Parser; | ||
| //# sourceMappingURL=parser.js.map |
| {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"} |
-103
| import { Buffer } from "buffer"; | ||
| import type { Box, BoxEncoding, FourCC } from "@isomp4/core"; | ||
| import { BoxHeader } from "@isomp4/core"; | ||
| /** | ||
| * Parses the ISO BMFF box structure of an MP4 stream. | ||
| */ | ||
| export declare abstract class AbstractMP4Parser { | ||
| /** | ||
| * Registered box encodings. | ||
| */ | ||
| private readonly boxes; | ||
| /** | ||
| * A stack that keeps track of the current state in the MP4 box structure traversal. | ||
| */ | ||
| private readonly boxStack; | ||
| /** | ||
| * A temporary buffer to store appended data before it's parsed. | ||
| * This buffer may be resized if a box requires more space before it can be fully parsed. | ||
| */ | ||
| private buffer; | ||
| /** | ||
| * The number of bytes needed in the buffer to parse the next part. | ||
| */ | ||
| private bytesNeeded; | ||
| /** | ||
| * The current box state. | ||
| * If this is <code>null</code>, then a box header will be parsed next. | ||
| */ | ||
| private currentBox; | ||
| /** | ||
| * Creates a new parser for an MP4 stream. | ||
| */ | ||
| protected constructor(); | ||
| /** | ||
| * | ||
| * @param encodings | ||
| */ | ||
| registerBox(...encodings: BoxEncoding[]): void; | ||
| /** | ||
| * | ||
| * @param boxType | ||
| */ | ||
| isBoxRegistered(boxType: FourCC): boolean; | ||
| /** | ||
| * Appends new data to the stream. | ||
| * @param data The new data to append. This data does NOT need to be a complete segment (or even a fragment). | ||
| */ | ||
| append(data: ArrayBufferView): void; | ||
| private ensureBuffer; | ||
| /** | ||
| * Processes the given buffer. | ||
| * @param buffer The input buffer. | ||
| * @return The number of bytes consumed. | ||
| */ | ||
| private processBuffer; | ||
| /** | ||
| * Invoked when a new box starts from the source. | ||
| * @param header The parsed header data of the box. | ||
| * @param headerData The raw header data of the box. | ||
| * @return Whether to decode the box content (fields). | ||
| */ | ||
| protected abstract onBoxStarted(header: BoxHeader, headerData: Buffer): boolean; | ||
| /** | ||
| * Invoked when the box content is parsed. | ||
| * This will be invoked if {@link onBoxStarted} returns <code>true</code> for a box | ||
| * and there is a registered box encoding for the box type, | ||
| * otherwise {@link onBoxData} will be invoked with the remaining box data. | ||
| * @param box The box that was parsed. | ||
| * @param boxData The raw content data of the box (excluding header and children). | ||
| * @return Whether to decode the children boxes. | ||
| */ | ||
| protected abstract onBoxDecoded(box: Box, boxData: Buffer): boolean; | ||
| /** | ||
| * Invoked when new data is received for the current box. | ||
| * This will be invoked if either {@link onBoxStarted} or {@link onBoxDecoded} return <code>false</code> for a box. | ||
| * @param header The box that the data is for. | ||
| * @param boxData The raw data of the box (excluding header). | ||
| */ | ||
| protected abstract onBoxData(header: BoxHeader, boxData: Buffer): void; | ||
| /** | ||
| * Invoked when a box ends. | ||
| * @param header The header of the box that ended. | ||
| * @param box The box that ended, if it was parsed. | ||
| */ | ||
| protected abstract onBoxEnded(header: BoxHeader, box?: Box): void; | ||
| } | ||
| /** | ||
| * An implementation of {@link AbstractMP4Parser} that delegates to optional function properties. | ||
| */ | ||
| export declare class MP4Parser extends AbstractMP4Parser { | ||
| boxStarted?: typeof MP4Parser.prototype.onBoxStarted; | ||
| boxDecoded?: typeof MP4Parser.prototype.onBoxDecoded; | ||
| boxData?: typeof MP4Parser.prototype.onBoxData; | ||
| boxEnded?: typeof MP4Parser.prototype.onBoxEnded; | ||
| /** | ||
| * Create a new MP4Parser. | ||
| */ | ||
| constructor(); | ||
| protected onBoxStarted(header: BoxHeader, headerData: Buffer): boolean; | ||
| protected onBoxDecoded(box: Box, boxData: Buffer): boolean; | ||
| protected onBoxData(header: BoxHeader, boxData: Buffer): void; | ||
| protected onBoxEnded(header: BoxHeader, box?: Box): void; | ||
| } |
-223
| import { Buffer } from "buffer"; | ||
| import { BoxContainer, BoxHeader } from "@isomp4/core"; | ||
| const EMPTY_BUFFER = Buffer.allocUnsafe(0); | ||
| /** | ||
| * Parses the ISO BMFF box structure of an MP4 stream. | ||
| */ | ||
| export class AbstractMP4Parser { | ||
| /** | ||
| * Creates a new parser for an MP4 stream. | ||
| */ | ||
| constructor() { | ||
| this.boxes = new Map(); | ||
| this.boxStack = []; | ||
| this.buffer = EMPTY_BUFFER; | ||
| this.bytesNeeded = 0; | ||
| this.currentBox = null; | ||
| } | ||
| /** | ||
| * | ||
| * @param encodings | ||
| */ | ||
| registerBox(...encodings) { | ||
| for (const encoding of encodings) { | ||
| if (this.boxes.has(encoding.type)) { | ||
| throw new Error("Box type is already registered: " + encoding.type); | ||
| } | ||
| this.boxes.set(encoding.type, encoding); | ||
| } | ||
| } | ||
| /** | ||
| * | ||
| * @param boxType | ||
| */ | ||
| isBoxRegistered(boxType) { | ||
| return this.boxes.has(boxType); | ||
| } | ||
| /** | ||
| * Appends new data to the stream. | ||
| * @param data The new data to append. This data does NOT need to be a complete segment (or even a fragment). | ||
| */ | ||
| append(data) { | ||
| let input = Buffer.from(data.buffer, data.byteOffset, data.byteLength); | ||
| while (input.length > 0) { | ||
| if (this.bytesNeeded > 0) { | ||
| // Ensure that buffer is the correct size | ||
| this.ensureBuffer(this.bytesNeeded); | ||
| // Don't copy more data into the temp buffer than is needed for the next part! | ||
| const needed = this.bytesNeeded - this.buffer.byteOffset; | ||
| if (needed > 0) { | ||
| if (needed <= input.length) { | ||
| // Only copy 'needed' number of bytes into the temp buffer | ||
| input.copy(this.buffer, 0, 0, needed); | ||
| input = input.slice(needed); | ||
| } | ||
| else { | ||
| // All input can be copied into temp buffer | ||
| this.buffer = this.buffer.slice(input.copy(this.buffer)); | ||
| // More input data is needed | ||
| return; | ||
| } | ||
| } | ||
| // Temp buffer now contains all bytes needed | ||
| // Flip buffer | ||
| const bytesNeeded = this.bytesNeeded; | ||
| const buf = Buffer.from(this.buffer.buffer, 0, bytesNeeded); | ||
| this.bytesNeeded = 0; // This must be reset before calling processBuffer() | ||
| const bytesConsumed = this.processBuffer(buf); | ||
| if (this.bytesNeeded > 0) { | ||
| // More bytes are needed | ||
| continue; | ||
| } | ||
| if (bytesConsumed !== bytesNeeded) { | ||
| throw new Error(`bytes consumed(${bytesConsumed}) != bytes needed(${bytesNeeded})`); | ||
| } | ||
| // Reset buffer | ||
| this.buffer = Buffer.from(this.buffer.buffer); | ||
| } | ||
| else { | ||
| // Avoid copying data by using the input buffer directly | ||
| const consumed = this.processBuffer(input); | ||
| if (consumed > 0) { | ||
| input = input.slice(consumed); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ensureBuffer(capacity) { | ||
| if (this.buffer.buffer.byteLength < capacity) { | ||
| const newBuffer = Buffer.alloc(capacity); | ||
| // If the byteOffset is zero, then this indicates that there is no data written to the buffer | ||
| if (this.buffer.byteOffset > 0) { | ||
| // Must copy old buffer to new buffer | ||
| Buffer.from(this.buffer.buffer).copy(newBuffer); | ||
| } | ||
| this.buffer = newBuffer; | ||
| } | ||
| } | ||
| /** | ||
| * Processes the given buffer. | ||
| * @param buffer The input buffer. | ||
| * @return The number of bytes consumed. | ||
| */ | ||
| processBuffer(buffer) { | ||
| stackCheck: if (this.boxStack.length > 0) { | ||
| const top = this.boxStack[this.boxStack.length - 1]; | ||
| const header = top.header; | ||
| const needed = header.size - top.offset; | ||
| if (needed > 0) { | ||
| if (top.children) { | ||
| // Skip and parse children normally | ||
| break stackCheck; | ||
| } | ||
| const available = buffer.length; | ||
| if (needed > available) { | ||
| // Don't have enough data | ||
| this.onBoxData(header, buffer); | ||
| top.offset += available; | ||
| return available; | ||
| } | ||
| // Have enough data | ||
| this.onBoxData(header, buffer.slice(0, needed)); | ||
| } | ||
| // End box | ||
| if (top.box != null) { | ||
| this.onBoxEnded(header, top.box); | ||
| } | ||
| else { | ||
| this.onBoxEnded(header); | ||
| } | ||
| // Pop box state | ||
| this.boxStack.pop(); | ||
| // Check next box state | ||
| if (this.boxStack.length > 0) { | ||
| const next = this.boxStack[this.boxStack.length - 1]; | ||
| next.offset += header.size; | ||
| if (top.box != null && next.box != null && BoxContainer.isInstance(next.box)) { | ||
| BoxContainer.add(next.box, top.box); | ||
| } | ||
| } | ||
| // Trigger parsing of next box | ||
| this.currentBox = null; | ||
| return needed; | ||
| } | ||
| if (this.currentBox == null) { | ||
| const header = BoxHeader.parse(buffer); | ||
| if (typeof header === "number") { | ||
| this.bytesNeeded = header; | ||
| return 0; | ||
| } | ||
| const headerLength = BoxHeader.decodedBytes; | ||
| // Invoke box started event | ||
| const content = this.onBoxStarted(header, buffer.slice(0, headerLength)); | ||
| // Start box | ||
| this.currentBox = { | ||
| header, | ||
| headerLength, | ||
| content, | ||
| }; | ||
| return headerLength; | ||
| } | ||
| const header = this.currentBox.header; | ||
| if (this.currentBox.content) { | ||
| const encoding = this.boxes.get(header.type); | ||
| if (encoding != null) { | ||
| const box = encoding.decode(buffer, header); | ||
| if (typeof box === "number") { | ||
| this.bytesNeeded = box; | ||
| return 0; | ||
| } | ||
| const consumed = encoding.decodedBytes; | ||
| // Invoke box decoded event | ||
| const children = this.onBoxDecoded(box, buffer.slice(0, consumed)); | ||
| // Push box onto stack (and record whether to parse children) | ||
| this.boxStack.push({ | ||
| header, | ||
| box, | ||
| children, | ||
| offset: this.currentBox.headerLength + consumed, | ||
| }); | ||
| // Trigger parsing of child boxes | ||
| if (children) { | ||
| box.children = {}; | ||
| this.currentBox = null; | ||
| } | ||
| return consumed; | ||
| } | ||
| // No encoding, so reset content boolean | ||
| this.currentBox.content = false; | ||
| } | ||
| // No encoding for box type, must skip entire box and children | ||
| this.boxStack.push({ | ||
| header, | ||
| box: null, | ||
| children: false, | ||
| offset: this.currentBox.headerLength, | ||
| }); | ||
| return this.processBuffer(buffer); | ||
| } | ||
| } | ||
| /** | ||
| * An implementation of {@link AbstractMP4Parser} that delegates to optional function properties. | ||
| */ | ||
| export class MP4Parser extends AbstractMP4Parser { | ||
| /** | ||
| * Create a new MP4Parser. | ||
| */ | ||
| constructor() { | ||
| super(); | ||
| } | ||
| onBoxStarted(header, headerData) { | ||
| return this.boxStarted ? this.boxStarted(header, headerData) : true; | ||
| } | ||
| onBoxDecoded(box, boxData) { | ||
| return this.boxDecoded ? this.boxDecoded(box, boxData) : true; | ||
| } | ||
| onBoxData(header, boxData) { | ||
| this.boxData?.(header, boxData); | ||
| } | ||
| onBoxEnded(header, box) { | ||
| this.boxEnded?.(header, box); | ||
| } | ||
| } | ||
| //# sourceMappingURL=parser.js.map |
| {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"} |
Empty package
Supply chain riskPackage does not contain any code. It may be removed, is name squatting, or the result of a faulty package publish.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
0
-100%18470
-64.52%4
-55.56%0
-100%2
Infinity%Updated