securityos/node_modules/music-metadata/lib/asf/AsfParser.js

136 lines
7.0 KiB
JavaScript
Raw Normal View History

2024-09-06 15:32:35 +00:00
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsfParser = void 0;
const debug_1 = require("debug");
const type_1 = require("../type");
const GUID_1 = require("./GUID");
const AsfObject = require("./AsfObject");
const BasicParser_1 = require("../common/BasicParser");
const debug = (0, debug_1.default)('music-metadata:parser:ASF');
const headerType = 'asf';
/**
* Windows Media Metadata Usage Guidelines
* - Ref: https://msdn.microsoft.com/en-us/library/ms867702.aspx
*
* Ref:
* - https://tools.ietf.org/html/draft-fleischman-asf-01
* - https://hwiegman.home.xs4all.nl/fileformats/asf/ASF_Specification.pdf
* - http://drang.s4.xrea.com/program/tips/id3tag/wmp/index.html
* - https://msdn.microsoft.com/en-us/library/windows/desktop/ee663575(v=vs.85).aspx
*/
class AsfParser extends BasicParser_1.BasicParser {
async parse() {
const header = await this.tokenizer.readToken(AsfObject.TopLevelHeaderObjectToken);
if (!header.objectId.equals(GUID_1.default.HeaderObject)) {
throw new Error('expected asf header; but was not found; got: ' + header.objectId.str);
}
try {
await this.parseObjectHeader(header.numberOfHeaderObjects);
}
catch (err) {
debug('Error while parsing ASF: %s', err);
}
}
async parseObjectHeader(numberOfObjectHeaders) {
let tags;
do {
// Parse common header of the ASF Object (3.1)
const header = await this.tokenizer.readToken(AsfObject.HeaderObjectToken);
// Parse data part of the ASF Object
debug('header GUID=%s', header.objectId.str);
switch (header.objectId.str) {
case AsfObject.FilePropertiesObject.guid.str: // 3.2
const fpo = await this.tokenizer.readToken(new AsfObject.FilePropertiesObject(header));
this.metadata.setFormat('duration', Number(fpo.playDuration / BigInt(1000)) / 10000 - Number(fpo.preroll) / 1000);
this.metadata.setFormat('bitrate', fpo.maximumBitrate);
break;
case AsfObject.StreamPropertiesObject.guid.str: // 3.3
const spo = await this.tokenizer.readToken(new AsfObject.StreamPropertiesObject(header));
this.metadata.setFormat('container', 'ASF/' + spo.streamType);
break;
case AsfObject.HeaderExtensionObject.guid.str: // 3.4
const extHeader = await this.tokenizer.readToken(new AsfObject.HeaderExtensionObject());
await this.parseExtensionObject(extHeader.extensionDataSize);
break;
case AsfObject.ContentDescriptionObjectState.guid.str: // 3.10
tags = await this.tokenizer.readToken(new AsfObject.ContentDescriptionObjectState(header));
this.addTags(tags);
break;
case AsfObject.ExtendedContentDescriptionObjectState.guid.str: // 3.11
tags = await this.tokenizer.readToken(new AsfObject.ExtendedContentDescriptionObjectState(header));
this.addTags(tags);
break;
case GUID_1.default.CodecListObject.str:
const codecs = await AsfObject.readCodecEntries(this.tokenizer);
codecs.forEach(codec => {
this.metadata.addStreamInfo({
type: codec.type.videoCodec ? type_1.TrackType.video : type_1.TrackType.audio,
codecName: codec.codecName
});
});
const audioCodecs = codecs.filter(codec => codec.type.audioCodec).map(codec => codec.codecName).join('/');
this.metadata.setFormat('codec', audioCodecs);
break;
case GUID_1.default.StreamBitratePropertiesObject.str:
// ToDo?
await this.tokenizer.ignore(header.objectSize - AsfObject.HeaderObjectToken.len);
break;
case GUID_1.default.PaddingObject.str:
// ToDo: register bytes pad
debug('Padding: %s bytes', header.objectSize - AsfObject.HeaderObjectToken.len);
await this.tokenizer.ignore(header.objectSize - AsfObject.HeaderObjectToken.len);
break;
default:
this.metadata.addWarning('Ignore ASF-Object-GUID: ' + header.objectId.str);
debug('Ignore ASF-Object-GUID: %s', header.objectId.str);
await this.tokenizer.readToken(new AsfObject.IgnoreObjectState(header));
}
} while (--numberOfObjectHeaders);
// done
}
addTags(tags) {
tags.forEach(tag => {
this.metadata.addTag(headerType, tag.id, tag.value);
});
}
async parseExtensionObject(extensionSize) {
do {
// Parse common header of the ASF Object (3.1)
const header = await this.tokenizer.readToken(AsfObject.HeaderObjectToken);
const remaining = header.objectSize - AsfObject.HeaderObjectToken.len;
// Parse data part of the ASF Object
switch (header.objectId.str) {
case AsfObject.ExtendedStreamPropertiesObjectState.guid.str: // 4.1
// ToDo: extended stream header properties are ignored
await this.tokenizer.readToken(new AsfObject.ExtendedStreamPropertiesObjectState(header));
break;
case AsfObject.MetadataObjectState.guid.str: // 4.7
const moTags = await this.tokenizer.readToken(new AsfObject.MetadataObjectState(header));
this.addTags(moTags);
break;
case AsfObject.MetadataLibraryObjectState.guid.str: // 4.8
const mlTags = await this.tokenizer.readToken(new AsfObject.MetadataLibraryObjectState(header));
this.addTags(mlTags);
break;
case GUID_1.default.PaddingObject.str:
// ToDo: register bytes pad
await this.tokenizer.ignore(remaining);
break;
case GUID_1.default.CompatibilityObject.str:
this.tokenizer.ignore(remaining);
break;
case GUID_1.default.ASF_Index_Placeholder_Object.str:
await this.tokenizer.ignore(remaining);
break;
default:
this.metadata.addWarning('Ignore ASF-Object-GUID: ' + header.objectId.str);
// console.log("Ignore ASF-Object-GUID: %s", header.objectId.str);
await this.tokenizer.readToken(new AsfObject.IgnoreObjectState(header));
break;
}
extensionSize -= header.objectSize;
} while (extensionSize > 0);
}
}
exports.AsfParser = AsfParser;