@torrent-tv/proxy 2.52.0 → 2.54.0
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/CHANGELOG.md +20 -0
- package/package.json +2 -2
- package/services/hls-session-manager.js +697 -169
- package/services/hwaccel.js +49 -6
- package/services/segment-formats/fmp4.js +320 -300
- package/services/segment-formats/mp4-boxes.js +59 -0
- package/test/auto-quality-step.test.js +442 -0
- package/test/quality-variants.test.js +6 -5
package/services/hwaccel.js
CHANGED
|
@@ -118,16 +118,59 @@ export function nominalKbpsForHeight(height) {
|
|
|
118
118
|
return best[1];
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* The peak this encode may reach, in kbit/s, for a nominal rate.
|
|
123
|
+
*
|
|
124
|
+
* Exported because the same figure answers a second question: whether a rung
|
|
125
|
+
* fits the viewer's measured link. The budget compares the link against what
|
|
126
|
+
* the encode is ALLOWED to peak at rather than against what it happened to
|
|
127
|
+
* produce in the last few segments, so a rung is judged by the bound we impose
|
|
128
|
+
* on it and not by a quiet stretch of the film.
|
|
129
|
+
*
|
|
130
|
+
* @param {number} nominalKbps
|
|
131
|
+
* @returns {number}
|
|
132
|
+
*/
|
|
133
|
+
export function maxrateKbpsFor(nominalKbps) {
|
|
134
|
+
return Math.round(nominalKbps * CAP_MAXRATE_FACTOR);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The nominal rate whose cap is a given peak — the inverse of
|
|
139
|
+
* {@link maxrateKbpsFor}.
|
|
140
|
+
*
|
|
141
|
+
* Used to turn a MEASURED limit into the figure the cap arithmetic takes. The
|
|
142
|
+
* viewer's usable link is a peak the stream must not exceed, and the encoder is
|
|
143
|
+
* configured from a nominal rate, so the two are converted through the one
|
|
144
|
+
* factor rather than through a second constant invented for the purpose.
|
|
145
|
+
*
|
|
146
|
+
* @param {number} maxrateKbps
|
|
147
|
+
* @returns {number}
|
|
148
|
+
*/
|
|
149
|
+
export function nominalKbpsForMaxrate(maxrateKbps) {
|
|
150
|
+
return Math.round(maxrateKbps / CAP_MAXRATE_FACTOR);
|
|
151
|
+
}
|
|
152
|
+
|
|
121
153
|
/**
|
|
122
154
|
* `-maxrate`/`-bufsize` args for an encode height (constrained CRF).
|
|
123
155
|
*
|
|
156
|
+
* `nominalKbps` overrides the height's own nominal rate. It is how a measured
|
|
157
|
+
* limit — the viewer's link, the only figure that bounds an encode from
|
|
158
|
+
* outside this host — reaches the encoder without touching the picture's SIZE.
|
|
159
|
+
* That distinction is the whole point: `-maxrate`, `-bufsize` and CRF do not
|
|
160
|
+
* appear in the SPS (x264 writes no HRD parameters by default), so they can be
|
|
161
|
+
* moved in the middle of a session while one init segment goes on describing
|
|
162
|
+
* every fragment. The size cannot.
|
|
163
|
+
*
|
|
124
164
|
* @param {number} height
|
|
165
|
+
* @param {number | null} [nominalKbps=null]
|
|
125
166
|
* @returns {string[]}
|
|
126
167
|
*/
|
|
127
|
-
function bitrateCapArgs(height) {
|
|
128
|
-
const nominal =
|
|
168
|
+
function bitrateCapArgs(height, nominalKbps = null) {
|
|
169
|
+
const nominal = Number.isFinite(nominalKbps) && nominalKbps > 0
|
|
170
|
+
? nominalKbps
|
|
171
|
+
: nominalKbpsForHeight(height);
|
|
129
172
|
return [
|
|
130
|
-
"-maxrate", `${
|
|
173
|
+
"-maxrate", `${maxrateKbpsFor(nominal)}k`,
|
|
131
174
|
"-bufsize", `${Math.round(nominal * CAP_BUFSIZE_FACTOR)}k`
|
|
132
175
|
];
|
|
133
176
|
}
|
|
@@ -221,7 +264,7 @@ export function softwareDescriptor() {
|
|
|
221
264
|
kind: "software",
|
|
222
265
|
device: null,
|
|
223
266
|
inputArgs: [],
|
|
224
|
-
buildVideoArgs({ targetWidth, targetHeight, segmentDurationSec, preset, fps, tonemap, forcedKeyframeTimes }) {
|
|
267
|
+
buildVideoArgs({ targetWidth, targetHeight, segmentDurationSec, preset, fps, tonemap, forcedKeyframeTimes, nominalKbps = null }) {
|
|
225
268
|
const { w, h } = safeDimensions(targetWidth, targetHeight);
|
|
226
269
|
const chosenPreset = typeof preset === "string" && preset.length > 0 ? preset : SOFTWARE_PRESET;
|
|
227
270
|
// Output frame rate: inherited from the source (rounded/capped) by the
|
|
@@ -249,7 +292,7 @@ export function softwareDescriptor() {
|
|
|
249
292
|
// cannot produce segments a thin viewer link (cellular) can't
|
|
250
293
|
// download in time. Sized by the TARGET box height (the rung the
|
|
251
294
|
// budget/manual selection chose).
|
|
252
|
-
...bitrateCapArgs(h),
|
|
295
|
+
...bitrateCapArgs(h, nominalKbps),
|
|
253
296
|
"-threads", String(CPU_THREADS),
|
|
254
297
|
"-pix_fmt", "yuv420p",
|
|
255
298
|
// Fixed GOP: a keyframe exactly every (segmentDurationSec × fps) frames,
|
|
@@ -396,7 +439,7 @@ function v4l2m2mDescriptor() {
|
|
|
396
439
|
* @property {"software"|"vaapi"|"qsv"|"nvenc"|"v4l2m2m"} kind
|
|
397
440
|
* @property {string|null} device
|
|
398
441
|
* @property {string[]} inputArgs
|
|
399
|
-
* @property {(opts: { targetWidth: number, targetHeight: number, segmentDurationSec: number, preset?: string, fps?: number, tonemap?: boolean, forcedKeyframeTimes?: number[] | null }) => string[]} buildVideoArgs
|
|
442
|
+
* @property {(opts: { targetWidth: number, targetHeight: number, segmentDurationSec: number, preset?: string, fps?: number, tonemap?: boolean, forcedKeyframeTimes?: number[] | null, nominalKbps?: number | null }) => string[]} buildVideoArgs
|
|
400
443
|
*/
|
|
401
444
|
|
|
402
445
|
/**
|