arib-subtitle-timedmetadater
Version:
ARIB subtitle copy as id3 timed-metadata
278 lines (277 loc) • 17.2 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FFmpegID3PaddingTransform = void 0;
var stream_1 = require("stream");
var arib_mpeg2ts_parser_1 = require("arib-mpeg2ts-parser");
var arib_mpeg2ts_parser_2 = require("arib-mpeg2ts-parser");
var arib_mpeg2ts_parser_3 = require("arib-mpeg2ts-parser");
var id3_1 = __importDefault(require("./id3"));
var ffmpeg_id3_padding_transform_1 = require("./ffmpeg-id3-padding-transform");
Object.defineProperty(exports, "FFmpegID3PaddingTransform", { enumerable: true, get: function () { return __importDefault(ffmpeg_id3_padding_transform_1).default; } });
var MetadataTransform = /** @class */ (function (_super) {
__extends(MetadataTransform, _super);
function MetadataTransform() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.packetQueue = new arib_mpeg2ts_parser_1.TSPacketQueue();
_this.PAT_TSSectionQueue = new arib_mpeg2ts_parser_2.TSSectionQueue();
_this.PMT_TSSectionQueues = new Map();
_this.PMT_SubtitlePids = new Map();
_this.PMT_ID3Pids = new Map();
_this.PMT_ContinuityCounters = new Map();
_this.Subtitle_TSPESQueues = new Map();
_this.Subtitle_PMTPids = new Map();
_this.Metadata_ContinuityCounters = new Map();
return _this;
}
MetadataTransform.prototype._transform = function (chunk, encoding, callback) {
var _a, _b, _c, _d, _e;
this.packetQueue.push(chunk);
while (!this.packetQueue.isEmpty()) {
var packet = this.packetQueue.pop();
var pid = arib_mpeg2ts_parser_1.TSPacket.pid(packet);
if (pid == 0x00) {
this.PAT_TSSectionQueue.push(packet);
while (!this.PAT_TSSectionQueue.isEmpty()) {
var PAT = this.PAT_TSSectionQueue.pop();
if (arib_mpeg2ts_parser_2.TSSection.CRC32(PAT) != 0) {
continue;
}
var begin = arib_mpeg2ts_parser_2.TSSection.EXTENDED_HEADER_SIZE;
while (begin < arib_mpeg2ts_parser_2.TSSection.BASIC_HEADER_SIZE + arib_mpeg2ts_parser_2.TSSection.section_length(PAT) - arib_mpeg2ts_parser_2.TSSection.CRC_SIZE) {
var program_number = (PAT[begin + 0] << 8) | PAT[begin + 1];
var program_map_PID = ((PAT[begin + 2] & 0x1F) << 8) | PAT[begin + 3];
if (program_map_PID === 0x10) {
begin += 4;
continue;
} // NIT
if (!this.PMT_TSSectionQueues.has(program_map_PID)) {
this.PMT_TSSectionQueues.set(program_map_PID, new arib_mpeg2ts_parser_2.TSSectionQueue());
this.PMT_ContinuityCounters.set(program_map_PID, 0);
}
begin += 4;
}
}
this.push(packet);
}
else if (this.PMT_TSSectionQueues.has(pid)) {
var PMT_TSSectionQueue = this.PMT_TSSectionQueues.get(pid);
PMT_TSSectionQueue.push(packet);
while (!PMT_TSSectionQueue.isEmpty()) {
var PMT = PMT_TSSectionQueue.pop();
if (arib_mpeg2ts_parser_2.TSSection.CRC32(PMT) != 0) {
continue;
}
var newPMT = Buffer.from(PMT.slice(0, arib_mpeg2ts_parser_2.TSSection.EXTENDED_HEADER_SIZE + 2));
var program_info_length = ((PMT[arib_mpeg2ts_parser_2.TSSection.EXTENDED_HEADER_SIZE + 2] & 0x0F) << 8) | PMT[arib_mpeg2ts_parser_2.TSSection.EXTENDED_HEADER_SIZE + 3];
var newPMT_program_info = Buffer.from([]);
var begin = arib_mpeg2ts_parser_2.TSSection.EXTENDED_HEADER_SIZE + 4;
while (begin < arib_mpeg2ts_parser_2.TSSection.EXTENDED_HEADER_SIZE + 4 + program_info_length) {
var descriptor_tag = PMT[begin + 0];
var descriptor_length = PMT[begin + 1];
newPMT_program_info = Buffer.concat([
newPMT_program_info,
PMT.slice(begin, begin + 2 + descriptor_length),
]);
begin += 2 + descriptor_length;
}
newPMT_program_info = Buffer.concat([
newPMT_program_info,
id3_1.default.metadata_pointer_descriptor(arib_mpeg2ts_parser_2.TSSection.table_id_extension(PMT))
]);
var newPMT_program_info_length = Buffer.from([
((newPMT_program_info.length & 0xFF00) >> 8), ((newPMT_program_info.length & 0x00FF) >> 0),
]);
var newPMT_descriptor_loop = Buffer.from([]);
var subtitlePid = -1;
var PMT_PIDs = new Set();
PMT_PIDs.add(pid);
begin = arib_mpeg2ts_parser_2.TSSection.EXTENDED_HEADER_SIZE + 4 + program_info_length;
while (begin < arib_mpeg2ts_parser_2.TSSection.BASIC_HEADER_SIZE + arib_mpeg2ts_parser_2.TSSection.section_length(PMT) - arib_mpeg2ts_parser_2.TSSection.CRC_SIZE) {
var stream_type = PMT[begin + 0];
var elementary_PID = ((PMT[begin + 1] & 0x1F) << 8) | PMT[begin + 2];
var ES_info_length = ((PMT[begin + 3] & 0x0F) << 8) | PMT[begin + 4];
var descriptor = begin + 5;
while (descriptor < begin + 5 + ES_info_length) {
var descriptor_tag = PMT[descriptor + 0];
var descriptor_length = PMT[descriptor + 1];
if (descriptor_tag == 0x52) {
var component_tag = PMT[descriptor + 2];
if (0x30 <= component_tag && component_tag <= 0x37 || component_tag == 0x87) {
subtitlePid = elementary_PID;
}
}
descriptor += 2 + descriptor_length;
}
PMT_PIDs.add(elementary_PID);
begin += 5 + ES_info_length;
}
var id3_PID = 0x1FFE; // TODO: いい感じのPIDを見つけたい。ここがアドホックでトラブルの元。
{
var already_ID3Pids = new Set(this.PMT_ID3Pids.values());
if (this.PMT_ID3Pids.has(pid)) {
already_ID3Pids.delete(this.PMT_ID3Pids.get(pid));
}
for (;; id3_PID--) {
if (PMT_PIDs.has(id3_PID)) {
continue;
}
if (already_ID3Pids.has(id3_PID)) {
continue;
}
break;
}
}
if (!this.PMT_ID3Pids.has(pid)) {
this.PMT_ID3Pids.set(pid, id3_PID);
this.Metadata_ContinuityCounters.set(id3_PID, 0);
}
else if (this.PMT_ID3Pids.get(pid) !== id3_PID) {
this.Metadata_ContinuityCounters.delete(id3_PID);
this.PMT_ID3Pids.set(pid, id3_PID);
this.Metadata_ContinuityCounters.set(id3_PID, 0);
}
newPMT_descriptor_loop = Buffer.concat([
PMT.slice(arib_mpeg2ts_parser_2.TSSection.EXTENDED_HEADER_SIZE + 4 + program_info_length, arib_mpeg2ts_parser_2.TSSection.BASIC_HEADER_SIZE + arib_mpeg2ts_parser_2.TSSection.section_length(PMT) - arib_mpeg2ts_parser_2.TSSection.CRC_SIZE),
id3_1.default.metadata_elementary_stream(id3_PID),
]);
if (subtitlePid >= 0) {
if (!this.PMT_SubtitlePids.has(pid)) {
this.PMT_SubtitlePids.set(pid, subtitlePid);
this.Subtitle_TSPESQueues.set(subtitlePid, new arib_mpeg2ts_parser_3.TSPESQueue());
var PMTs = (_a = this.Subtitle_PMTPids.get(subtitlePid)) !== null && _a !== void 0 ? _a : new Set();
PMTs.add(pid);
this.Subtitle_PMTPids.set(subtitlePid, PMTs);
}
else {
var oldSubtitlePid = this.PMT_SubtitlePids.get(pid);
if (subtitlePid !== oldSubtitlePid) {
var oldPMTs = (_b = this.Subtitle_PMTPids.get(oldSubtitlePid)) !== null && _b !== void 0 ? _b : new Set();
oldPMTs.delete(pid);
this.Subtitle_PMTPids.set(oldSubtitlePid, oldPMTs);
var newPMTs = (_c = this.Subtitle_PMTPids.get(subtitlePid)) !== null && _c !== void 0 ? _c : new Set();
newPMTs.add(pid);
this.Subtitle_PMTPids.set(subtitlePid, newPMTs);
this.PMT_SubtitlePids.set(pid, subtitlePid);
this.Subtitle_TSPESQueues.set(subtitlePid, new arib_mpeg2ts_parser_3.TSPESQueue());
if (!this.Subtitle_PMTPids.has(oldSubtitlePid) || this.Subtitle_PMTPids.get(oldSubtitlePid).size === 0) {
this.Subtitle_TSPESQueues.delete(oldSubtitlePid);
}
}
}
}
else if (this.PMT_SubtitlePids.has(pid)) {
var oldSubtitlePid = this.PMT_SubtitlePids.get(pid);
this.PMT_SubtitlePids.delete(pid);
var oldPMTs = (_d = this.Subtitle_PMTPids.get(oldSubtitlePid)) !== null && _d !== void 0 ? _d : new Set();
oldPMTs.delete(pid);
this.Subtitle_PMTPids.set(oldSubtitlePid, oldPMTs);
if (!this.Subtitle_PMTPids.has(oldSubtitlePid) || this.Subtitle_PMTPids.get(oldSubtitlePid).size === 0) {
this.Subtitle_TSPESQueues.delete(oldSubtitlePid);
}
}
newPMT = Buffer.concat([
newPMT,
newPMT_program_info_length,
newPMT_program_info,
newPMT_descriptor_loop,
]);
var newPMT_length = newPMT.length + arib_mpeg2ts_parser_2.TSSection.CRC_SIZE - arib_mpeg2ts_parser_2.TSSection.BASIC_HEADER_SIZE;
newPMT[1] = (PMT[1] & 0xF0) | ((newPMT_length & 0x0F00) >> 8);
newPMT[2] = (newPMT_length & 0x00FF);
var newPMT_CRC = arib_mpeg2ts_parser_2.TSSection.CRC32(newPMT);
newPMT = Buffer.concat([newPMT, Buffer.from([
(newPMT_CRC & 0xFF000000) >> 24,
(newPMT_CRC & 0x00FF0000) >> 16,
(newPMT_CRC & 0x0000FF00) >> 8,
(newPMT_CRC & 0x000000FF) >> 0,
])]);
var packets = arib_mpeg2ts_parser_2.TSSectionPacketizer.packetize(newPMT, arib_mpeg2ts_parser_1.TSPacket.transport_error_indicator(packet), arib_mpeg2ts_parser_1.TSPacket.transport_priority(packet), pid, arib_mpeg2ts_parser_1.TSPacket.transport_scrambling_control(packet), this.PMT_ContinuityCounters.get(pid));
for (var i = 0; i < packets.length; i++) {
this.push(packets[i]);
}
this.PMT_ContinuityCounters.set(pid, (this.PMT_ContinuityCounters.get(pid) + packets.length) & 0x0F);
}
}
else if (this.Subtitle_TSPESQueues.has(pid)) {
var Subtitle_TSPESQueue = this.Subtitle_TSPESQueues.get(pid);
Subtitle_TSPESQueue.push(packet);
while (!Subtitle_TSPESQueue.isEmpty()) {
var SubtitlePES = Subtitle_TSPESQueue.pop();
var pts = 0;
pts *= (1 << 3);
pts += ((SubtitlePES[arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + 3 + 0] & 0x0E) >> 1);
pts *= (1 << 8);
pts += ((SubtitlePES[arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + 3 + 1] & 0xFF) >> 0);
pts *= (1 << 7);
pts += ((SubtitlePES[arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + 3 + 2] & 0xFE) >> 1);
pts *= (1 << 8);
pts += ((SubtitlePES[arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + 3 + 3] & 0xFF) >> 0);
pts *= (1 << 7);
pts += ((SubtitlePES[arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + 3 + 4] & 0xFE) >> 1);
var PES_header_data_length = SubtitlePES[arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + 2];
var PES_data_packet_header_length = (SubtitlePES[(arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + 3) + PES_header_data_length + 2] & 0x0F);
var data_group = arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + (3 + PES_header_data_length) + (3 + PES_data_packet_header_length);
var data_group_id = (SubtitlePES[data_group + 0] & 0xFC) >> 2;
if ((data_group_id & 0x0F) != 1) { // FIXME!
continue; // FIXME!
} // FIXME!
for (var _i = 0, _f = Array.from((_e = this.Subtitle_PMTPids.get(pid)) !== null && _e !== void 0 ? _e : []); _i < _f.length; _i++) {
var PMT_PID = _f[_i];
if (!this.PMT_ID3Pids.has(PMT_PID)) {
continue;
}
var timedMetadataPID = this.PMT_ID3Pids.get(PMT_PID);
var subtitleData = SubtitlePES.slice(arib_mpeg2ts_parser_3.TSPES.PES_HEADER_SIZE + (3 + PES_header_data_length));
var id3 = id3_1.default.ID3v2PRIV('aribb24.js', subtitleData);
var timedMetadataPES = id3_1.default.timedmetadata(pts, id3);
var begin = 0;
while (begin < timedMetadataPES.length) {
var header = Buffer.from([
packet[0],
((packet[1] & 0xA0) | ((begin === 0 ? 1 : 0) << 6) | ((timedMetadataPID & 0x1F00) >> 8)),
(timedMetadataPID & 0x00FF),
((packet[3] & 0xC0) | (1 << 4) /* payload */ | (this.Metadata_ContinuityCounters.get(timedMetadataPID) & 0x0F)),
]);
this.Metadata_ContinuityCounters.set(timedMetadataPID, (this.Metadata_ContinuityCounters.get(timedMetadataPID) + 1) & 0x0F);
var next = begin + (arib_mpeg2ts_parser_1.TSPacket.PACKET_SIZE - arib_mpeg2ts_parser_1.TSPacket.HEADER_SIZE);
this.push(Buffer.concat([
header,
timedMetadataPES.slice(begin, next)
]));
begin = next;
}
}
}
this.push(packet);
}
else {
this.push(packet);
}
}
callback();
};
MetadataTransform.prototype._flush = function (callback) {
callback();
};
return MetadataTransform;
}(stream_1.Transform));
exports.default = MetadataTransform;