@torrent-tv/proxy 2.98.2 → 2.98.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/services/encode/MatroskaInput.js +87 -30
package/package.json
CHANGED
|
@@ -54,20 +54,56 @@ export async function* matroskaInput({ tracks, readPacket, originSeconds = 0, in
|
|
|
54
54
|
slices = avcPacketSlices(slices);
|
|
55
55
|
payloadBytes = slices.reduce((sum, slice) => sum + slice.length, 0);
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
// EVERY PACKET'S CLUSTER IS WRITTEN INTO ONE BUFFER, its sizes worked out
|
|
58
|
+
// first: an element at a time, each id parsed from hex, each number split
|
|
59
|
+
// into bytes through BigInt and every part joined again, this writer was
|
|
60
|
+
// 6 % of the main thread over a two-hour AVI on Home Assistant (r30,
|
|
61
|
+
// torrent-tv/meta#178). The bytes are the same.
|
|
58
62
|
const duration = Math.round(packet.duration * 1e6);
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
const padding = packet.discardPaddingSeconds ? Math.round(packet.discardPaddingSeconds * 1e9) : null;
|
|
64
|
+
if (duration > 0 && !Number.isSafeInteger(duration)) throw new TypeError("EBML unsigned integer is invalid.");
|
|
65
|
+
if (padding !== null && !Number.isSafeInteger(padding)) throw new TypeError("EBML signed integer is outside its exact range.");
|
|
66
|
+
const blockHeaderBytes = vintWidth(selected + 1) + 3;
|
|
67
|
+
const durationWidth = duration > 0 ? uintWidth(duration) : 0;
|
|
68
|
+
const afterBytes = (duration > 0 ? 1 + vintWidth(durationWidth) + durationWidth : 0) +
|
|
69
|
+
(padding !== null ? 2 + 1 + 8 : 0) + (packet.keyframe ? 0 : 3);
|
|
70
|
+
const blockSize = blockHeaderBytes + payloadBytes;
|
|
71
|
+
const blockPrefixBytes = 1 + vintWidth(blockSize);
|
|
72
|
+
const groupSize = blockPrefixBytes + blockSize + afterBytes;
|
|
73
|
+
const groupPrefixBytes = 1 + vintWidth(groupSize);
|
|
74
|
+
const stampWidth = uintWidth(stamp);
|
|
75
|
+
const timestampBytes = 1 + vintWidth(stampWidth) + stampWidth;
|
|
76
|
+
const clusterSize = timestampBytes + groupPrefixBytes + groupSize;
|
|
77
|
+
const head = Buffer.allocUnsafe(4 + vintWidth(clusterSize) + timestampBytes + groupPrefixBytes + blockPrefixBytes + blockHeaderBytes);
|
|
78
|
+
let at = head.writeUInt32BE(0x1f43b675, 0);
|
|
79
|
+
at = writeVint(head, at, clusterSize);
|
|
80
|
+
head[at++] = 0xe7;
|
|
81
|
+
at = writeVint(head, at, stampWidth);
|
|
82
|
+
at = writeUint(head, at, stamp, stampWidth);
|
|
83
|
+
head[at++] = 0xa0;
|
|
84
|
+
at = writeVint(head, at, groupSize);
|
|
85
|
+
head[at++] = 0xa1;
|
|
86
|
+
at = writeVint(head, at, blockSize);
|
|
87
|
+
at = writeVint(head, at, selected + 1);
|
|
88
|
+
head[at++] = 0; head[at++] = 0; head[at++] = 0;
|
|
89
|
+
yield head;
|
|
69
90
|
for (const slice of slices) yield slice;
|
|
70
|
-
if (
|
|
91
|
+
if (afterBytes > 0) {
|
|
92
|
+
const after = Buffer.allocUnsafe(afterBytes);
|
|
93
|
+
let offset = 0;
|
|
94
|
+
if (duration > 0) {
|
|
95
|
+
after[offset++] = 0x9b;
|
|
96
|
+
offset = writeVint(after, offset, durationWidth);
|
|
97
|
+
offset = writeUint(after, offset, duration, durationWidth);
|
|
98
|
+
}
|
|
99
|
+
if (padding !== null) {
|
|
100
|
+
offset = after.writeUInt16BE(0x75a2, offset);
|
|
101
|
+
offset = writeVint(after, offset, 8);
|
|
102
|
+
offset = after.writeBigInt64BE(BigInt(padding), offset);
|
|
103
|
+
}
|
|
104
|
+
if (!packet.keyframe) { after[offset++] = 0xfb; after[offset++] = 0x81; after[offset++] = 0; }
|
|
105
|
+
yield after;
|
|
106
|
+
}
|
|
71
107
|
}
|
|
72
108
|
}
|
|
73
109
|
|
|
@@ -128,31 +164,52 @@ function matroskaCodec(codec) {
|
|
|
128
164
|
return declared;
|
|
129
165
|
}
|
|
130
166
|
|
|
131
|
-
|
|
167
|
+
/** How many bytes an EBML size of this value takes: the narrowest whose all-ones value it is below. */
|
|
168
|
+
function vintWidth(value) {
|
|
132
169
|
if (!Number.isSafeInteger(value) || value < 0) throw new TypeError("EBML value is outside its integer range.");
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
170
|
+
// 2 ** 56 - 1 is above every safe integer, so eight bytes always hold one.
|
|
171
|
+
for (let width = 1; width < 8; width++) if (value < 2 ** (7 * width) - 1) return width;
|
|
172
|
+
return 8;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** The value as an EBML size at `at`, its width's marker bit set; the next offset. */
|
|
176
|
+
function writeVint(target, at, value) {
|
|
177
|
+
const width = vintWidth(value);
|
|
178
|
+
writeUint(target, at, value, width);
|
|
179
|
+
target[at] |= 1 << (8 - width);
|
|
180
|
+
return at + width;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** How many bytes an unsigned integer takes, one at least. */
|
|
184
|
+
function uintWidth(value) {
|
|
185
|
+
let width = 1;
|
|
186
|
+
for (let rest = Math.floor(value / 256); rest > 0; rest = Math.floor(rest / 256)) width += 1;
|
|
187
|
+
return width;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The value big-endian in `width` bytes at `at`; the next offset. */
|
|
191
|
+
function writeUint(target, at, value, width) {
|
|
192
|
+
let rest = value;
|
|
193
|
+
for (let index = width - 1; index >= 0; index--) {
|
|
194
|
+
target[at + index] = rest % 256;
|
|
195
|
+
rest = Math.floor(rest / 256);
|
|
139
196
|
}
|
|
140
|
-
|
|
197
|
+
return at + width;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function vint(value) {
|
|
201
|
+
const encoded = Buffer.alloc(vintWidth(value));
|
|
202
|
+
writeVint(encoded, 0, value);
|
|
203
|
+
return encoded;
|
|
141
204
|
}
|
|
142
205
|
|
|
143
206
|
function prefix(id, size) { return Buffer.concat([Buffer.from(id, "hex"), vint(size)]); }
|
|
144
207
|
function element(id, payload) { return Buffer.concat([prefix(id, payload.length), payload]); }
|
|
145
208
|
function textElement(id, text) { return element(id, Buffer.from(text, "utf8")); }
|
|
146
|
-
function signedElement(id, value) {
|
|
147
|
-
if (!Number.isSafeInteger(value)) throw new TypeError("EBML signed integer is outside its exact range.");
|
|
148
|
-
const bytes = Buffer.alloc(8);
|
|
149
|
-
bytes.writeBigInt64BE(BigInt(value));
|
|
150
|
-
return element(id, bytes);
|
|
151
|
-
}
|
|
152
209
|
function uintElement(id, value) {
|
|
153
210
|
if (!Number.isSafeInteger(value) || value < 0) throw new TypeError("EBML unsigned integer is invalid.");
|
|
154
|
-
|
|
155
|
-
const bytes =
|
|
156
|
-
|
|
157
|
-
return element(id,
|
|
211
|
+
const width = uintWidth(value);
|
|
212
|
+
const bytes = Buffer.alloc(width);
|
|
213
|
+
writeUint(bytes, 0, value, width);
|
|
214
|
+
return element(id, bytes);
|
|
158
215
|
}
|