@torrent-tv/proxy 2.89.7 → 2.89.8
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/.claude/commands/opsx/apply.md +155 -155
- package/.claude/commands/opsx/archive.md +160 -160
- package/.claude/commands/opsx/explore.md +174 -174
- package/.claude/commands/opsx/propose.md +109 -109
- package/.claude/commands/opsx/sync.md +143 -143
- package/.claude/skills/openspec-apply-change/SKILL.md +159 -159
- package/.claude/skills/openspec-archive-change/SKILL.md +117 -117
- package/.claude/skills/openspec-explore/SKILL.md +289 -289
- package/.claude/skills/openspec-propose/SKILL.md +113 -113
- package/.claude/skills/openspec-sync-specs/SKILL.md +147 -147
- package/.dockerignore +5 -5
- package/AGENTS.md +358 -338
- package/CHANGELOG.md +2340 -2335
- package/Dockerfile +30 -30
- package/LICENSE +16 -16
- package/README.md +369 -369
- package/assets/calibration/NOTICE.md +100 -100
- package/assets/calibration/audio/NOTICE.md +19 -19
- package/assets/calibration/audio/manifest.json +98 -98
- package/assets/diagnostics/sctpstate.gdb +31 -31
- package/bin/cli.js +684 -684
- package/bin/thread-pool.js +30 -30
- package/biome.json +412 -412
- package/docs/browser-proxy-contract.md +155 -155
- package/docs/container-architecture.md +273 -273
- package/docs/download-architecture.md +261 -261
- package/docs/encode-architecture.md +765 -765
- package/docs/encode-run-state.md +96 -96
- package/docs/logs.md +97 -97
- package/docs/playback-start-forecast.md +113 -113
- package/docs/socks5-egress-research.md +114 -114
- package/docs/storage-architecture.md +273 -273
- package/knip.json +14 -14
- package/openspec/changes/adaptive-bitrate/design.md +92 -92
- package/openspec/changes/adaptive-bitrate/proposal.md +56 -56
- package/openspec/changes/adaptive-bitrate/specs/adaptive-bitrate/spec.md +51 -51
- package/openspec/changes/adaptive-bitrate/tasks.md +40 -40
- package/openspec/changes/binary-distribution/.openspec.yaml +2 -2
- package/openspec/changes/binary-distribution/proposal.md +53 -53
- package/openspec/changes/chunked-request-bodies/design.md +81 -81
- package/openspec/changes/chunked-request-bodies/proposal.md +53 -53
- package/openspec/changes/chunked-request-bodies/specs/chunked-request-bodies/spec.md +30 -30
- package/openspec/changes/chunked-request-bodies/tasks.md +40 -40
- package/openspec/changes/cold-start/design.md +98 -98
- package/openspec/changes/cold-start/proposal.md +62 -62
- package/openspec/changes/cold-start/specs/cold-start/spec.md +47 -47
- package/openspec/changes/cold-start/tasks.md +48 -48
- package/openspec/changes/disk-cap/.openspec.yaml +2 -2
- package/openspec/changes/disk-cap/proposal.md +37 -37
- package/openspec/changes/disk-cap/specs/disk-cap/spec.md +25 -25
- package/openspec/changes/disk-cap/tasks.md +19 -19
- package/openspec/changes/proxy-observability/.openspec.yaml +2 -2
- package/openspec/changes/proxy-observability/design.md +38 -38
- package/openspec/changes/proxy-observability/proposal.md +49 -49
- package/openspec/changes/proxy-observability/specs/observability/spec.md +33 -33
- package/openspec/changes/proxy-observability/tasks.md +21 -21
- package/openspec/changes/seek-debounce/design.md +118 -118
- package/openspec/changes/seek-debounce/proposal.md +59 -59
- package/openspec/changes/seek-debounce/specs/seek-debounce/spec.md +41 -41
- package/openspec/changes/seek-debounce/tasks.md +33 -33
- package/openspec/changes/subtitle-language/.openspec.yaml +2 -2
- package/openspec/changes/subtitle-language/proposal.md +50 -50
- package/openspec/changes/subtitle-language/specs/subtitle-language/spec.md +34 -34
- package/openspec/changes/subtitle-language/tasks.md +26 -26
- package/openspec/changes/track-selection/.openspec.yaml +2 -2
- package/openspec/changes/track-selection/design.md +47 -47
- package/openspec/changes/track-selection/proposal.md +45 -45
- package/openspec/changes/track-selection/specs/track-selection/spec.md +41 -41
- package/openspec/changes/track-selection/tasks.md +20 -20
- package/openspec/changes/transcode-quality/.openspec.yaml +2 -2
- package/openspec/changes/transcode-quality/proposal.md +51 -51
- package/openspec/changes/transcode-quality/specs/transcode-quality/spec.md +139 -139
- package/openspec/changes/transcode-quality/tasks.md +63 -63
- package/openspec/config.yaml +38 -38
- package/package.json +51 -50
- package/public/.well-known/appspecific/com.chrome.devtools.json +1 -1
- package/research/delivery-wedge-stand-ladder-2026-09-13.md +329 -329
- package/research/double-spawn-2026-09-10.md +171 -171
- package/research/handover-2026-09-13.md +209 -209
- package/research/handover-reader-claims-removal-2026-09-12.md +166 -166
- package/research/piece-withdrawn-but-still-claimed-2026-09-12.md +175 -175
- package/research/preset-benchmark-size-scaling-2026-08-22.md +55 -55
- package/research/priority-map-is-the-truth-2026-09-12.md +225 -225
- package/routes/api/client-logs/post.js +86 -86
- package/routes/api/delivery-sink/get.js +72 -72
- package/routes/api/link-probe/get.js +51 -51
- package/routes/api/playback-plan/audio-tracks/post.js +29 -29
- package/routes/api/playback-plan/post.js +53 -53
- package/routes/api/sources/files/get.js +106 -106
- package/routes/api/sources/post.js +36 -36
- package/routes/api/sources/stats/get.js +132 -132
- package/routes/api/sources/warm/post.js +217 -217
- package/routes/api/subtitles/get.js +230 -230
- package/routes/api/transcode-sessions/fragment-far/post.js +60 -60
- package/routes/api/transcode-sessions/net-report/post.js +138 -138
- package/routes/api/transcode-sessions/post.js +178 -178
- package/routes/api/transcode-sessions/progress/get.js +27 -27
- package/routes/api/transcode-sessions/release/post.js +41 -41
- package/routes/api/transcode-sessions/seek/post.js +63 -63
- package/routes/health/get.js +13 -13
- package/routes/healthz/get.js +13 -13
- package/routes/stream/get.js +416 -416
- package/routes/transcode/audio-file/get.js +64 -64
- package/routes/transcode/audio-warm/get.js +95 -95
- package/routes/transcode/session-file/get.js +52 -52
- package/routes/transcode/variant-file/get.js +95 -95
- package/routes/transcode/variant-warm/get.js +84 -84
- package/scripts/build-audio-samples.mjs +31 -31
- package/scripts/render-run-graph.js +173 -173
- package/server.js +748 -748
- package/services/encode/CoverageMap.js +428 -428
- package/services/encode/CushionReport.js +345 -345
- package/services/encode/EncodeAdmission.js +376 -376
- package/services/encode/EncodeOrchestrator.js +1192 -1192
- package/services/encode/EncodePlan.js +1368 -1368
- package/services/encode/EncodeRun.js +36 -12
- package/services/encode/Encoder.js +142 -142
- package/services/encode/EncoderSelection.js +38 -38
- package/services/encode/LocalObservations.js +359 -359
- package/services/encode/NvencEncoder.js +50 -50
- package/services/encode/OutputOpening.js +784 -784
- package/services/encode/OutputTimes.js +579 -579
- package/services/encode/QsvEncoder.js +58 -58
- package/services/encode/Renditions.js +2283 -2283
- package/services/encode/RunClock.js +87 -87
- package/services/encode/RunProgress.js +79 -79
- package/services/encode/SegmentDemand.js +95 -95
- package/services/encode/SoftwareEncoder.js +121 -121
- package/services/encode/V4l2m2mEncoder.js +53 -53
- package/services/encode/VaapiEncoder.js +66 -66
- package/services/encode/args.js +418 -418
- package/services/encode/audio-calibration.js +67 -67
- package/services/encode/audio-work-rate.js +15 -15
- package/services/encode/available-share.js +89 -89
- package/services/encode/calibration.js +361 -361
- package/services/encode/contention.js +128 -128
- package/services/encode/decode-cost-fit.js +363 -363
- package/services/encode/encode-exit.js +116 -116
- package/services/encode/encode-run-state.js +551 -551
- package/services/encode/encoder-readings.js +43 -43
- package/services/encode/fingerprint.js +322 -322
- package/services/encode/host-load.js +174 -174
- package/services/encode/hwaccel.js +1894 -1894
- package/services/encode/index.js +9 -9
- package/services/encode/learned-median.js +90 -90
- package/services/encode/output/EncodedOutput.js +57 -57
- package/services/encode/output/Output.js +131 -131
- package/services/encode/output/OutputCatalog.js +414 -414
- package/services/encode/output/OutputSpec.js +390 -390
- package/services/encode/output/Timeline.js +308 -308
- package/services/encode/output/cut-grid.js +107 -107
- package/services/encode/output/index.js +24 -24
- package/services/encode/output/ladder.js +32 -32
- package/services/encode/output/playlists.js +284 -284
- package/services/encode/output/rates.js +125 -125
- package/services/encode/output-key-format.js +21 -21
- package/services/encode/quality/EncodeCost.js +1043 -1043
- package/services/encode/quality/HostLoad.js +525 -525
- package/services/encode/quality/HostTimings.js +249 -249
- package/services/encode/quality/OutputQualityState.js +24 -24
- package/services/encode/quality/QualityController.js +758 -758
- package/services/encode/quality/QualityOffer.js +416 -416
- package/services/encode/quality/drain-threat.js +47 -47
- package/services/encode/quality/link-budget.js +337 -337
- package/services/encode/quality/output-format.js +319 -319
- package/services/encode/quality/serving-output.js +216 -216
- package/services/encode/quality/visible-rung.js +57 -57
- package/services/encode/run-budget.js +97 -97
- package/services/encode/run-command.js +757 -757
- package/services/encode/run-costs.js +155 -155
- package/services/encode/run-inputs.js +53 -53
- package/services/encode/segment-formats/fmp4.js +476 -476
- package/services/encode/segment-formats/init-compat.js +324 -324
- package/services/encode/segment-formats/mpegts.js +134 -134
- package/services/encode/start-stop-cost.js +178 -178
- package/services/encode/throughput.js +97 -97
- package/services/encode/torrent-cost.js +88 -88
- package/services/identity/installation-id.js +38 -38
- package/services/media/ContainerOrchestrator.js +202 -202
- package/services/media/KeyframeTables.js +356 -356
- package/services/media/SourceFile.js +298 -298
- package/services/media/SubtitleCues.js +592 -592
- package/services/media/SubtitleOrchestrator.js +167 -167
- package/services/media/audio-inventory.js +299 -299
- package/services/media/container/AviContainer.js +268 -268
- package/services/media/container/Container.js +632 -632
- package/services/media/container/ContainerFactory.js +38 -38
- package/services/media/container/KeyframeTable.js +272 -272
- package/services/media/container/MatroskaContainer.js +1031 -1031
- package/services/media/container/Mp4Container.js +1354 -1354
- package/services/media/container/SubtitleFileContainer.js +339 -339
- package/services/media/container/ebml-reader.js +159 -159
- package/services/media/container/ebml-stream.js +174 -174
- package/services/media/container/matroska-clusters.js +1165 -1165
- package/services/media/container/unavailable.js +77 -77
- package/services/media/ffmpeg-banner.js +260 -260
- package/services/media/keyframe-probe.js +157 -157
- package/services/media/media-info-probe.js +93 -93
- package/services/media/playback-planner.js +931 -931
- package/services/media/tracks/AudioTrack.js +143 -143
- package/services/media/tracks/ContainerTrack.js +84 -84
- package/services/media/tracks/ImageSubtitleTrack.js +19 -19
- package/services/media/tracks/SubtitleTrack.js +38 -38
- package/services/media/tracks/TextSubtitleTrack.js +295 -295
- package/services/media/tracks/VideoTrack.js +33 -33
- package/services/media/tracks/audio-bound.js +233 -233
- package/services/media/tracks/index.js +15 -15
- package/services/media/tracks/language-detect.js +174 -174
- package/services/server/OutputLifecycle.js +418 -418
- package/services/server/SegmentServing.js +1152 -1152
- package/services/server/ViewerRequests.js +785 -785
- package/services/server/WaitLedger.js +142 -142
- package/services/server/controllers/PlaybackController.js +40 -40
- package/services/server/controllers/SubtitleController.js +109 -109
- package/services/server/http-responses.js +60 -60
- package/services/server/transcode-session-files.js +325 -325
- package/services/server/wire-outputs.js +1029 -1029
- package/services/storage/Diagnostics.js +202 -202
- package/services/storage/MachineBudget.js +235 -235
- package/services/storage/allowance.js +107 -107
- package/services/storage/core-dumps.js +106 -106
- package/services/storage/files/CompletedFiles.js +391 -391
- package/services/storage/files/piece-from-whole-file.js +118 -118
- package/services/storage/free.js +71 -71
- package/services/storage/keep.js +48 -48
- package/services/storage/machine-memory.js +56 -56
- package/services/storage/memory-report.js +575 -575
- package/services/storage/piece-store/piece-disk-store.js +539 -539
- package/services/storage/piece-store/piece-lru.js +495 -495
- package/services/storage/piece-store/shared-piece-store.js +1937 -1937
- package/services/storage/returns.js +103 -103
- package/services/storage/segment-store/SegmentStore.js +1294 -1294
- package/services/storage/wire.js +175 -175
- package/services/torrent/Contents.js +382 -382
- package/services/torrent/demand/DemandRegister.js +202 -202
- package/services/torrent/demand/Urgency.js +137 -137
- package/services/torrent/demand/Window.js +118 -118
- package/services/torrent/demand/index.js +8 -8
- package/services/torrent/demand/pieces.js +140 -140
- package/services/torrent/download/SwarmSelection.js +386 -386
- package/services/torrent/download/registry.js +102 -102
- package/services/torrent/download/withdraw-claim.js +80 -80
- package/services/torrent/episode-naming.js +182 -182
- package/services/torrent/files.js +455 -455
- package/services/torrent/naming.js +619 -619
- package/services/torrent/piece-store-of.js +29 -29
- package/services/torrent/supply-margin.js +264 -264
- package/services/torrent/torrent-pool.js +2688 -2688
- package/services/torrent/worker/background-fill.js +213 -213
- package/services/torrent/worker/channel.js +271 -271
- package/services/torrent/worker/client.js +836 -836
- package/services/torrent/worker/fastest-wires.js +342 -342
- package/services/torrent/worker/handle-state.js +23 -23
- package/services/torrent/worker/held-bytes.js +231 -231
- package/services/torrent/worker/install-webrtc-shim.js +32 -32
- package/services/torrent/worker/piece-reader.js +1078 -1078
- package/services/torrent/worker/pool-adapter.js +371 -371
- package/services/torrent/worker/protocol.js +184 -184
- package/services/torrent/worker/resume-warm.js +107 -107
- package/services/torrent/worker/webrtc-shim.js +219 -219
- package/services/torrent/worker/worker.js +1137 -1137
- package/services/transport/data-channel-handler.js +1373 -1373
- package/services/transport/delivery-probe.js +842 -842
- package/services/transport/health-collector.js +53 -53
- package/services/transport/nat-classifier.js +231 -231
- package/services/transport/packet-witness.js +808 -808
- package/services/transport/port-mapper.js +235 -235
- package/services/transport/registry-api.js +81 -81
- package/services/transport/tunnel-client.js +447 -447
- package/services/transport/usrsctp-state.js +175 -175
- package/services/transport/webrtc-manager.js +484 -484
- package/services/viewer/Assignments.js +340 -340
- package/services/viewer/PriorityMap.js +421 -421
- package/services/viewer/PriorityOrchestrator.js +325 -325
- package/services/viewer/Viewer.js +691 -691
- package/services/viewer/Viewers.js +368 -368
- package/services/viewer/active-output.js +37 -37
- package/services/viewer/audio-start.js +46 -46
- package/services/viewer/buffer-trend.js +81 -81
- package/services/viewer/choices.js +647 -647
- package/services/viewer/media-time.js +355 -355
- package/services/viewer/playback-readiness.js +635 -635
- package/services/viewer/positions.js +126 -126
- package/services/viewer/report-intake.js +46 -46
- package/store/source-registry.js +71 -71
- package/test/asset-paths.test.js +28 -28
- package/test/audio-buffer-continuity.test.js +77 -77
- package/test/audio-calibration.test.js +23 -23
- package/test/audio-inventory.test.js +212 -212
- package/test/audio-track-bitrate.test.js +40 -40
- package/test/auto-quality-step.test.js +762 -762
- package/test/available-share.test.js +76 -76
- package/test/background-fill.test.js +190 -190
- package/test/client-log-file.test.js +110 -110
- package/test/coalesce.test.js +39 -39
- package/test/completed-files.test.js +115 -115
- package/test/concurrent-cost.test.js +148 -148
- package/test/container-media-info.test.js +228 -228
- package/test/contention.test.js +76 -76
- package/test/core-dumps.test.js +57 -57
- package/test/coverage-follows-the-disk.test.js +233 -228
- package/test/coverage-map.test.js +195 -195
- package/test/cue-push-carries-what-the-walk-found.test.js +58 -58
- package/test/cut-times-timeline.test.js +65 -65
- package/test/cuts-follow-published-grid.test.js +109 -109
- package/test/data-channel-frame.test.js +63 -63
- package/test/data-channel-viewer-lifecycle.test.js +92 -92
- package/test/dead-torrent-handle.test.js +52 -52
- package/test/declared-rates.test.js +116 -116
- package/test/declared-tracks.test.js +43 -43
- package/test/decode-cost-fit.test.js +202 -202
- package/test/decode-cost.test.js +475 -475
- package/test/delivery-probe.test.js +393 -393
- package/test/demand-register.test.js +206 -206
- package/test/dht-bootstrap.test.js +72 -72
- package/test/drain-threat.test.js +65 -65
- package/test/duplicate-add.test.js +48 -48
- package/test/encode-admission.test.js +146 -146
- package/test/encode-cost.test.js +275 -275
- package/test/encode-exit.test.js +111 -111
- package/test/encode-orchestrator.test.js +426 -426
- package/test/encode-plan-viewers.test.js +725 -725
- package/test/encode-plan.test.js +545 -545
- package/test/encode-run-state.test.js +314 -314
- package/test/encode-run.test.js +20 -0
- package/test/encode-slope.test.js +46 -46
- package/test/encoded-output.test.js +39 -39
- package/test/encoder-kinds.test.js +122 -122
- package/test/encoder-readings.test.js +68 -68
- package/test/episode-naming.test.js +131 -131
- package/test/every-claimant-is-told-its-share.test.js +152 -152
- package/test/failed-encoder-still-serves-what-exists.test.js +354 -354
- package/test/failed-start-breaker.test.js +202 -202
- package/test/fastest-wires.test.js +143 -143
- package/test/ffmpeg-stream-counts.test.js +78 -78
- package/test/file-edges.test.js +191 -191
- package/test/fixtures/audio-frame-boundary.json +1 -1
- package/test/fmp4-self-contained.test.js +80 -80
- package/test/fmp4-timestamps.test.js +140 -140
- package/test/fmp4-track-completeness.test.js +41 -41
- package/test/format-keyed-outputs.test.js +78 -78
- package/test/health-metrics.test.js +36 -38
- package/test/held-read-ownership.test.js +77 -77
- package/test/held-request-width.test.js +157 -157
- package/test/helpers/encode-run.js +248 -240
- package/test/helpers/held-file.js +77 -77
- package/test/helpers/manager.js +62 -62
- package/test/helpers/matroska-file.js +296 -296
- package/test/helpers/output-spec.js +63 -63
- package/test/host-load.test.js +68 -68
- package/test/index-accuracy-is-about-the-file.test.js +128 -128
- package/test/init-compat.test.js +219 -219
- package/test/input-lost-quiets-the-plan.test.js +261 -261
- package/test/input-unavailable.test.js +48 -48
- package/test/installation-id.test.js +39 -39
- package/test/keeping-period.test.js +83 -83
- package/test/keyframe-index-accuracy.test.js +188 -188
- package/test/keyframe-table-budget.test.js +123 -123
- package/test/keyframes-belong-to-the-file.test.js +249 -249
- package/test/learned-median.test.js +37 -37
- package/test/letting-go-asks-who-is-watching.test.js +191 -191
- package/test/limit-row-by-area.test.js +60 -60
- package/test/link-budget.test.js +111 -111
- package/test/link-probe.test.js +56 -56
- package/test/local-encoding-data.test.js +273 -273
- package/test/logger-repeats.test.js +134 -134
- package/test/look-ahead-coverage.test.js +56 -56
- package/test/manager-surface.test.js +291 -291
- package/test/matroska-cluster-discovery.test.js +323 -323
- package/test/matroska-cues-track.test.js +192 -192
- package/test/media-time.test.js +62 -62
- package/test/memory-budget.test.js +390 -390
- package/test/move-cost.test.js +216 -216
- package/test/mp4-subtitles.test.js +173 -173
- package/test/one-authority.test.js +285 -285
- package/test/one-budget.test.js +149 -149
- package/test/one-output-one-session.test.js +273 -273
- package/test/one-resource-divided.test.js +185 -185
- package/test/one-serving-output-per-height.test.js +458 -458
- package/test/orchestrator-wired.test.js +207 -207
- package/test/output-catalog.test.js +39 -39
- package/test/output-shape.test.js +21 -21
- package/test/output-spec.test.js +251 -251
- package/test/output-speed.test.js +92 -87
- package/test/outputs-being-prepared.test.js +40 -40
- package/test/packet-witness-ring.test.js +236 -236
- package/test/packet-witness.test.js +148 -148
- package/test/piece-disk-store.test.js +401 -401
- package/test/piece-from-whole-file.test.js +129 -129
- package/test/piece-lru.test.js +319 -319
- package/test/piece-reader.test.js +162 -162
- package/test/piece-selection-offset.test.js +85 -85
- package/test/piece-store-eviction.test.js +595 -595
- package/test/piece-store-never-refuses.test.js +153 -153
- package/test/piece-store-reservations.test.js +403 -403
- package/test/piece-store-slow-disk.test.js +159 -159
- package/test/piece-tail.test.js +97 -97
- package/test/plan-host-timings.test.js +68 -68
- package/test/plan-is-steady.test.js +225 -225
- package/test/playback-readiness.test.js +518 -518
- package/test/playback-start-regressions.test.js +101 -101
- package/test/priority-map-download.test.js +174 -174
- package/test/priority-map-emptied.test.js +204 -204
- package/test/priority-map-per-output.test.js +215 -215
- package/test/priority-map.test.js +163 -163
- package/test/probe-wedge-certainty.test.js +60 -60
- package/test/produced-copy-choice.test.js +213 -213
- package/test/published-timeline.test.js +83 -83
- package/test/quality-offer.test.js +160 -160
- package/test/quality-variants.test.js +1274 -1270
- package/test/rate-control-in-the-output.test.js +181 -180
- package/test/read-survives-withdrawal.test.js +164 -164
- package/test/read-window.test.js +365 -365
- package/test/reads-not-yet-arrived.test.js +218 -218
- package/test/resume-warm.test.js +39 -39
- package/test/run-graph-drift.test.js +37 -37
- package/test/run-inputs.test.js +80 -80
- package/test/run-intervals.test.js +100 -100
- package/test/run-position-follows-published-grid.test.js +89 -89
- package/test/run-progress.test.js +64 -64
- package/test/same-height-switch.test.js +663 -663
- package/test/seek-frees-the-viewers-requests.test.js +217 -217
- package/test/seek-landing.test.js +109 -109
- package/test/seek-target-not-superseded.test.js +195 -195
- package/test/segment-closed-on-both-branches.test.js +114 -114
- package/test/segment-cut-times.test.js +63 -63
- package/test/segment-demand.test.js +80 -80
- package/test/segment-hold-supersede.test.js +91 -91
- package/test/segment-judged-by-its-own-header.test.js +222 -222
- package/test/segment-serve-wiring.test.js +481 -481
- package/test/segment-store-eviction.test.js +247 -247
- package/test/segment-store.test.js +352 -352
- package/test/segment-true-start.test.js +86 -86
- package/test/segments-are-shared.test.js +176 -176
- package/test/send-chunk-bytes.test.js +86 -86
- package/test/serving-existing-output.test.js +111 -111
- package/test/serving-output.test.js +102 -102
- package/test/shared-piece-store.test.js +310 -310
- package/test/sidecar-naming.test.js +142 -142
- package/test/soundtrack-rate-bound.test.js +289 -289
- package/test/source-file.test.js +133 -133
- package/test/source-files-route.test.js +113 -113
- package/test/source-registry.test.js +18 -18
- package/test/split-a-stretch.test.js +139 -139
- package/test/stale-request-after-seek.test.js +158 -158
- package/test/startup-readings.test.js +124 -124
- package/test/stream-route.test.js +237 -237
- package/test/subtitle-cue-framing.test.js +200 -200
- package/test/subtitle-cue-source.test.js +102 -102
- package/test/subtitle-cue-walk.test.js +385 -385
- package/test/subtitle-cursor.test.js +63 -63
- package/test/subtitle-defaults.test.js +118 -118
- package/test/subtitle-language.test.js +252 -252
- package/test/subtitle-metadata.test.js +15 -15
- package/test/subtitle-plan-waits.test.js +125 -125
- package/test/subtitle-track-numbering.test.js +391 -391
- package/test/supply-margin.test.js +190 -190
- package/test/swarm-follows-readers.test.js +174 -174
- package/test/swarm-reach.test.js +130 -130
- package/test/swarm-selection.test.js +220 -220
- package/test/tail-duplication.test.js +167 -167
- package/test/the-channel-has-both-ends.test.js +91 -91
- package/test/the-torrent-thread-serves-bytes.test.js +107 -107
- package/test/thread-pool.test.js +53 -53
- package/test/timeline.test.js +84 -84
- package/test/torrent-contents.test.js +235 -235
- package/test/torrent-cost.test.js +71 -71
- package/test/torrent-files.test.js +221 -221
- package/test/torrent-naming.test.js +255 -255
- package/test/tracks-begin-together.test.js +209 -209
- package/test/tunnel-renewal.test.js +167 -167
- package/test/two-viewers-one-picture.test.js +508 -508
- package/test/upload-hurry.test.js +186 -186
- package/test/usrsctp-state.test.js +131 -131
- package/test/video-facts.test.js +102 -102
- package/test/viewer-assignments.test.js +143 -143
- package/test/viewer-outputs.test.js +285 -285
- package/test/viewer-presence.test.js +116 -116
- package/test/viewer-requests-admission.test.js +92 -92
- package/test/viewer-starts-on-map.test.js +27 -27
- package/test/viewer-states.test.js +192 -189
- package/test/viewer-subtitle-subscription.test.js +96 -96
- package/test/viewer.test.js +139 -139
- package/test/viewing-generations.test.js +390 -390
- package/test/visible-rung.test.js +37 -37
- package/test/wait-ledger.test.js +100 -100
- package/test/webrtc-shim.test.js +149 -149
- package/test/wedge-certainty.test.js +131 -131
- package/test/whole-file-held-read.test.js +30 -30
- package/test/withdraw-piece-claim.test.js +212 -212
- package/test/worker-channel.test.js +158 -158
- package/utils/client-log-file.js +151 -151
- package/utils/coalesce.js +41 -41
- package/utils/logger.js +312 -312
- package/utils/parse-range.js +25 -25
- package/utils/perf.js +59 -59
- package/utils/torrent-source-key.js +38 -38
package/test/init-compat.test.js
CHANGED
|
@@ -1,219 +1,219 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file The rule that decides whether one output's pieces may be played under
|
|
3
|
-
* another's header — and it is written BEFORE the experiment that will use it.
|
|
4
|
-
*
|
|
5
|
-
* The order matters and was a review finding: a criterion derived from the
|
|
6
|
-
* differences an experiment happened to produce proves only that those
|
|
7
|
-
* differences were handled. This one compares the whole header, names every
|
|
8
|
-
* difference by where it sits, and refuses anything no listed exception covers.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import test from "node:test";
|
|
12
|
-
import assert from "node:assert/strict";
|
|
13
|
-
import { INIT_DIFFERENCE_EXCEPTIONS, compareInits, initLeaves } from "../services/encode/segment-formats/init-compat.js";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* One ISO base media box.
|
|
17
|
-
*
|
|
18
|
-
* @param {string} type
|
|
19
|
-
* @param {...(Buffer | number[])} parts
|
|
20
|
-
* @returns {Buffer}
|
|
21
|
-
*/
|
|
22
|
-
function box(type, ...parts) {
|
|
23
|
-
const body = Buffer.concat(parts.map((part) => (Buffer.isBuffer(part) ? part : Buffer.from(part))));
|
|
24
|
-
const header = Buffer.alloc(8);
|
|
25
|
-
header.writeUInt32BE(body.length + 8, 0);
|
|
26
|
-
header.write(type, 4, "latin1");
|
|
27
|
-
return Buffer.concat([header, body]);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* A version-0 `mdhd`: version+flags, creation, modification, timescale,
|
|
32
|
-
* duration, language, quality.
|
|
33
|
-
*
|
|
34
|
-
* @param {number} timescale
|
|
35
|
-
* @returns {Buffer}
|
|
36
|
-
*/
|
|
37
|
-
function mdhd(timescale) {
|
|
38
|
-
const body = Buffer.alloc(24);
|
|
39
|
-
body.writeUInt32BE(timescale, 12);
|
|
40
|
-
return box("mdhd", body);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* A `btrt`: decoding buffer size, maximum rate, average rate.
|
|
45
|
-
*
|
|
46
|
-
* @param {number} maxBitrate
|
|
47
|
-
* @returns {Buffer}
|
|
48
|
-
*/
|
|
49
|
-
function btrt(maxBitrate) {
|
|
50
|
-
const body = Buffer.alloc(12);
|
|
51
|
-
body.writeUInt32BE(1875072, 0);
|
|
52
|
-
body.writeUInt32BE(maxBitrate, 4);
|
|
53
|
-
body.writeUInt32BE(maxBitrate, 8);
|
|
54
|
-
return box("btrt", body);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* A `stsd` carrying one visual sample entry: its 78-byte preamble, then the
|
|
59
|
-
* codec configuration, then optionally a bit rate declaration.
|
|
60
|
-
*
|
|
61
|
-
* @param {{ entryType?: string, config?: number[], maxBitrate?: number | null, preamble?: number }} [how]
|
|
62
|
-
* @returns {Buffer}
|
|
63
|
-
*/
|
|
64
|
-
function stsd({ entryType = "avc1", config = [1, 100, 0, 31], maxBitrate = null, preamble = 78 } = {}) {
|
|
65
|
-
const versionAndCount = Buffer.alloc(8);
|
|
66
|
-
versionAndCount.writeUInt32BE(1, 4);
|
|
67
|
-
const children = [box("avcC", config)];
|
|
68
|
-
if (maxBitrate !== null) {
|
|
69
|
-
children.push(btrt(maxBitrate));
|
|
70
|
-
}
|
|
71
|
-
const entry = box(entryType, Buffer.alloc(preamble), ...children);
|
|
72
|
-
return box("stsd", versionAndCount, entry);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* A whole init segment, shaped as ffmpeg writes one.
|
|
77
|
-
*
|
|
78
|
-
* @param {{ timescale?: number, tracks?: number } & Parameters<typeof stsd>[0]} [how]
|
|
79
|
-
* @returns {Buffer}
|
|
80
|
-
*/
|
|
81
|
-
function init({ timescale = 90000, tracks = 1, ...entry } = {}) {
|
|
82
|
-
const trak = (index) =>
|
|
83
|
-
box(
|
|
84
|
-
"trak",
|
|
85
|
-
box("tkhd", Buffer.alloc(84, index)),
|
|
86
|
-
box("mdia", mdhd(timescale), box("hdlr", Buffer.alloc(32)), box("minf", box("stbl", stsd(entry))))
|
|
87
|
-
);
|
|
88
|
-
const traks = [];
|
|
89
|
-
for (let index = 0; index < tracks; index += 1) {
|
|
90
|
-
traks.push(trak(index));
|
|
91
|
-
}
|
|
92
|
-
return Buffer.concat([
|
|
93
|
-
box("ftyp", Buffer.from("isom")),
|
|
94
|
-
box("moov", box("mvhd", Buffer.alloc(100)), ...traks, box("mvex", box("trex", Buffer.alloc(24))))
|
|
95
|
-
]);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const ENTRY = "moov[0]/trak[0]/mdia[0]/minf[0]/stbl[0]/stsd[0]/avc1[0]";
|
|
99
|
-
|
|
100
|
-
test("every exception carries the reason it is one", () => {
|
|
101
|
-
for (const exception of INIT_DIFFERENCE_EXCEPTIONS) {
|
|
102
|
-
assert.ok(exception.why && exception.why.length > 40, `no reason given for ${JSON.stringify(exception)}`);
|
|
103
|
-
assert.ok(
|
|
104
|
-
exception.path !== undefined || exception.sampleEntryBox !== undefined,
|
|
105
|
-
"an exception says WHAT it covers"
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("every leaf of the header is named by whose child it is, inside a sample entry too", () => {
|
|
111
|
-
const paths = [...initLeaves(init({ tracks: 2, maxBitrate: 3_000_000 })).keys()];
|
|
112
|
-
|
|
113
|
-
assert.ok(paths.includes("moov[0]/trak[0]/mdia[0]/mdhd[0]"), paths.join(" "));
|
|
114
|
-
assert.ok(paths.includes("moov[0]/trak[1]/mdia[0]/mdhd[0]"), "the second track is its own path");
|
|
115
|
-
assert.ok(paths.includes("moov[0]/mvex[0]/trex[0]"));
|
|
116
|
-
assert.ok(
|
|
117
|
-
paths.includes(`${ENTRY}/avcC[0]`),
|
|
118
|
-
"the codec configuration is a leaf of its own, so it can refuse on its own"
|
|
119
|
-
);
|
|
120
|
-
assert.ok(paths.includes(`${ENTRY}/btrt[0]`), "and so is the bit rate declaration");
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test("one header serves its own pieces", () => {
|
|
124
|
-
const answer = compareInits(init(), init());
|
|
125
|
-
|
|
126
|
-
assert.equal(answer.compatible, true);
|
|
127
|
-
assert.deepEqual(answer.differences, []);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test("a bit rate declaration is the one difference that does not refuse", () => {
|
|
131
|
-
const answer = compareInits(init({ maxBitrate: 3_000_000 }), init({ maxBitrate: 1_200_000 }));
|
|
132
|
-
|
|
133
|
-
assert.equal(answer.compatible, true, answer.differences.join(" | "));
|
|
134
|
-
assert.deepEqual(answer.refusedPaths, []);
|
|
135
|
-
assert.ok(
|
|
136
|
-
answer.differences.some((line) => line.includes("max 3000000") && line.includes("max 1200000")),
|
|
137
|
-
`the difference is still reported, with its numbers: ${answer.differences.join(" | ")}`
|
|
138
|
-
);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
test("allowing the bit rate does not allow the parameter sets beside it", () => {
|
|
142
|
-
const answer = compareInits(
|
|
143
|
-
init({ maxBitrate: 3_000_000, config: [1, 100, 0, 31] }),
|
|
144
|
-
init({ maxBitrate: 1_200_000, config: [1, 100, 0, 30] })
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
assert.equal(answer.compatible, false);
|
|
148
|
-
assert.deepEqual(answer.refusedPaths, [`${ENTRY}/avcC[0]`]);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test("the bit rate exception is scoped to a sample entry", () => {
|
|
152
|
-
const strayLeft = box("moov", box("trak", box("mdia", box("minf", box("stbl", btrt(3_000_000))))));
|
|
153
|
-
const strayRight = box("moov", box("trak", box("mdia", box("minf", box("stbl", btrt(1_200_000))))));
|
|
154
|
-
|
|
155
|
-
const answer = compareInits(strayLeft, strayRight);
|
|
156
|
-
|
|
157
|
-
assert.equal(answer.compatible, false, "a btrt that is nobody's sample entry is not the box the reason is about");
|
|
158
|
-
assert.deepEqual(answer.refusedPaths, ["moov[0]/trak[0]/mdia[0]/minf[0]/stbl[0]/btrt[0]"]);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
test("a sample entry whose children do not tile is compared whole", () => {
|
|
162
|
-
const answer = compareInits(init({ preamble: 8, config: [1, 100, 0, 31] }), init({ preamble: 8, config: [1, 100, 0, 30] }));
|
|
163
|
-
|
|
164
|
-
assert.equal(answer.compatible, false);
|
|
165
|
-
assert.deepEqual(
|
|
166
|
-
answer.refusedPaths,
|
|
167
|
-
[ENTRY],
|
|
168
|
-
"the descent is checked, and where it does not hold the whole entry refuses"
|
|
169
|
-
);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test("a different media timescale is refused, and said in those words", () => {
|
|
173
|
-
const answer = compareInits(init({ timescale: 90000 }), init({ timescale: 48000 }));
|
|
174
|
-
|
|
175
|
-
assert.equal(answer.compatible, false);
|
|
176
|
-
assert.ok(
|
|
177
|
-
answer.differences.some((line) => line.includes("timescale 90000 against 48000")),
|
|
178
|
-
answer.differences.join(" | ")
|
|
179
|
-
);
|
|
180
|
-
assert.deepEqual(answer.refusedPaths, ["moov[0]/trak[0]/mdia[0]/mdhd[0]"]);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
test("a track present in one header and not the other is refused", () => {
|
|
184
|
-
const answer = compareInits(init({ tracks: 1 }), init({ tracks: 2 }));
|
|
185
|
-
|
|
186
|
-
assert.equal(answer.compatible, false);
|
|
187
|
-
assert.ok(
|
|
188
|
-
answer.differences.some((line) => line.includes("trak[1]") && line.includes("absent from the first")),
|
|
189
|
-
answer.differences.join(" | ")
|
|
190
|
-
);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
test("an exact-path exception decides by path", () => {
|
|
194
|
-
const served = init({ timescale: 90000 });
|
|
195
|
-
const made = init({ timescale: 48000 });
|
|
196
|
-
|
|
197
|
-
const refused = compareInits(served, made);
|
|
198
|
-
const permitted = compareInits(served, made, {
|
|
199
|
-
exceptions: [{ path: "moov[0]/trak[0]/mdia[0]/mdhd[0]", why: "for this check only" }]
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
assert.equal(refused.compatible, false);
|
|
203
|
-
assert.equal(permitted.compatible, true, "the exception list is what decides, and it is asked by path");
|
|
204
|
-
assert.equal(permitted.differences.length, 1, "a permitted difference is still reported");
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test("allowing one path does not allow the same box of another track", () => {
|
|
208
|
-
const answer = compareInits(init({ tracks: 2, timescale: 90000 }), init({ tracks: 2, timescale: 48000 }), {
|
|
209
|
-
exceptions: [{ path: "moov[0]/trak[0]/mdia[0]/mdhd[0]", why: "for this check only" }]
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
assert.equal(answer.compatible, false);
|
|
213
|
-
assert.deepEqual(answer.refusedPaths, ["moov[0]/trak[1]/mdia[0]/mdhd[0]"]);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
test("a missing header is never compatible", () => {
|
|
217
|
-
assert.equal(compareInits(init(), Buffer.alloc(0)).compatible, false);
|
|
218
|
-
assert.equal(compareInits(Buffer.alloc(0), init()).compatible, false);
|
|
219
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* @file The rule that decides whether one output's pieces may be played under
|
|
3
|
+
* another's header — and it is written BEFORE the experiment that will use it.
|
|
4
|
+
*
|
|
5
|
+
* The order matters and was a review finding: a criterion derived from the
|
|
6
|
+
* differences an experiment happened to produce proves only that those
|
|
7
|
+
* differences were handled. This one compares the whole header, names every
|
|
8
|
+
* difference by where it sits, and refuses anything no listed exception covers.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import test from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
import { INIT_DIFFERENCE_EXCEPTIONS, compareInits, initLeaves } from "../services/encode/segment-formats/init-compat.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* One ISO base media box.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} type
|
|
19
|
+
* @param {...(Buffer | number[])} parts
|
|
20
|
+
* @returns {Buffer}
|
|
21
|
+
*/
|
|
22
|
+
function box(type, ...parts) {
|
|
23
|
+
const body = Buffer.concat(parts.map((part) => (Buffer.isBuffer(part) ? part : Buffer.from(part))));
|
|
24
|
+
const header = Buffer.alloc(8);
|
|
25
|
+
header.writeUInt32BE(body.length + 8, 0);
|
|
26
|
+
header.write(type, 4, "latin1");
|
|
27
|
+
return Buffer.concat([header, body]);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A version-0 `mdhd`: version+flags, creation, modification, timescale,
|
|
32
|
+
* duration, language, quality.
|
|
33
|
+
*
|
|
34
|
+
* @param {number} timescale
|
|
35
|
+
* @returns {Buffer}
|
|
36
|
+
*/
|
|
37
|
+
function mdhd(timescale) {
|
|
38
|
+
const body = Buffer.alloc(24);
|
|
39
|
+
body.writeUInt32BE(timescale, 12);
|
|
40
|
+
return box("mdhd", body);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A `btrt`: decoding buffer size, maximum rate, average rate.
|
|
45
|
+
*
|
|
46
|
+
* @param {number} maxBitrate
|
|
47
|
+
* @returns {Buffer}
|
|
48
|
+
*/
|
|
49
|
+
function btrt(maxBitrate) {
|
|
50
|
+
const body = Buffer.alloc(12);
|
|
51
|
+
body.writeUInt32BE(1875072, 0);
|
|
52
|
+
body.writeUInt32BE(maxBitrate, 4);
|
|
53
|
+
body.writeUInt32BE(maxBitrate, 8);
|
|
54
|
+
return box("btrt", body);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A `stsd` carrying one visual sample entry: its 78-byte preamble, then the
|
|
59
|
+
* codec configuration, then optionally a bit rate declaration.
|
|
60
|
+
*
|
|
61
|
+
* @param {{ entryType?: string, config?: number[], maxBitrate?: number | null, preamble?: number }} [how]
|
|
62
|
+
* @returns {Buffer}
|
|
63
|
+
*/
|
|
64
|
+
function stsd({ entryType = "avc1", config = [1, 100, 0, 31], maxBitrate = null, preamble = 78 } = {}) {
|
|
65
|
+
const versionAndCount = Buffer.alloc(8);
|
|
66
|
+
versionAndCount.writeUInt32BE(1, 4);
|
|
67
|
+
const children = [box("avcC", config)];
|
|
68
|
+
if (maxBitrate !== null) {
|
|
69
|
+
children.push(btrt(maxBitrate));
|
|
70
|
+
}
|
|
71
|
+
const entry = box(entryType, Buffer.alloc(preamble), ...children);
|
|
72
|
+
return box("stsd", versionAndCount, entry);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A whole init segment, shaped as ffmpeg writes one.
|
|
77
|
+
*
|
|
78
|
+
* @param {{ timescale?: number, tracks?: number } & Parameters<typeof stsd>[0]} [how]
|
|
79
|
+
* @returns {Buffer}
|
|
80
|
+
*/
|
|
81
|
+
function init({ timescale = 90000, tracks = 1, ...entry } = {}) {
|
|
82
|
+
const trak = (index) =>
|
|
83
|
+
box(
|
|
84
|
+
"trak",
|
|
85
|
+
box("tkhd", Buffer.alloc(84, index)),
|
|
86
|
+
box("mdia", mdhd(timescale), box("hdlr", Buffer.alloc(32)), box("minf", box("stbl", stsd(entry))))
|
|
87
|
+
);
|
|
88
|
+
const traks = [];
|
|
89
|
+
for (let index = 0; index < tracks; index += 1) {
|
|
90
|
+
traks.push(trak(index));
|
|
91
|
+
}
|
|
92
|
+
return Buffer.concat([
|
|
93
|
+
box("ftyp", Buffer.from("isom")),
|
|
94
|
+
box("moov", box("mvhd", Buffer.alloc(100)), ...traks, box("mvex", box("trex", Buffer.alloc(24))))
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const ENTRY = "moov[0]/trak[0]/mdia[0]/minf[0]/stbl[0]/stsd[0]/avc1[0]";
|
|
99
|
+
|
|
100
|
+
test("every exception carries the reason it is one", () => {
|
|
101
|
+
for (const exception of INIT_DIFFERENCE_EXCEPTIONS) {
|
|
102
|
+
assert.ok(exception.why && exception.why.length > 40, `no reason given for ${JSON.stringify(exception)}`);
|
|
103
|
+
assert.ok(
|
|
104
|
+
exception.path !== undefined || exception.sampleEntryBox !== undefined,
|
|
105
|
+
"an exception says WHAT it covers"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("every leaf of the header is named by whose child it is, inside a sample entry too", () => {
|
|
111
|
+
const paths = [...initLeaves(init({ tracks: 2, maxBitrate: 3_000_000 })).keys()];
|
|
112
|
+
|
|
113
|
+
assert.ok(paths.includes("moov[0]/trak[0]/mdia[0]/mdhd[0]"), paths.join(" "));
|
|
114
|
+
assert.ok(paths.includes("moov[0]/trak[1]/mdia[0]/mdhd[0]"), "the second track is its own path");
|
|
115
|
+
assert.ok(paths.includes("moov[0]/mvex[0]/trex[0]"));
|
|
116
|
+
assert.ok(
|
|
117
|
+
paths.includes(`${ENTRY}/avcC[0]`),
|
|
118
|
+
"the codec configuration is a leaf of its own, so it can refuse on its own"
|
|
119
|
+
);
|
|
120
|
+
assert.ok(paths.includes(`${ENTRY}/btrt[0]`), "and so is the bit rate declaration");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("one header serves its own pieces", () => {
|
|
124
|
+
const answer = compareInits(init(), init());
|
|
125
|
+
|
|
126
|
+
assert.equal(answer.compatible, true);
|
|
127
|
+
assert.deepEqual(answer.differences, []);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("a bit rate declaration is the one difference that does not refuse", () => {
|
|
131
|
+
const answer = compareInits(init({ maxBitrate: 3_000_000 }), init({ maxBitrate: 1_200_000 }));
|
|
132
|
+
|
|
133
|
+
assert.equal(answer.compatible, true, answer.differences.join(" | "));
|
|
134
|
+
assert.deepEqual(answer.refusedPaths, []);
|
|
135
|
+
assert.ok(
|
|
136
|
+
answer.differences.some((line) => line.includes("max 3000000") && line.includes("max 1200000")),
|
|
137
|
+
`the difference is still reported, with its numbers: ${answer.differences.join(" | ")}`
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("allowing the bit rate does not allow the parameter sets beside it", () => {
|
|
142
|
+
const answer = compareInits(
|
|
143
|
+
init({ maxBitrate: 3_000_000, config: [1, 100, 0, 31] }),
|
|
144
|
+
init({ maxBitrate: 1_200_000, config: [1, 100, 0, 30] })
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
assert.equal(answer.compatible, false);
|
|
148
|
+
assert.deepEqual(answer.refusedPaths, [`${ENTRY}/avcC[0]`]);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("the bit rate exception is scoped to a sample entry", () => {
|
|
152
|
+
const strayLeft = box("moov", box("trak", box("mdia", box("minf", box("stbl", btrt(3_000_000))))));
|
|
153
|
+
const strayRight = box("moov", box("trak", box("mdia", box("minf", box("stbl", btrt(1_200_000))))));
|
|
154
|
+
|
|
155
|
+
const answer = compareInits(strayLeft, strayRight);
|
|
156
|
+
|
|
157
|
+
assert.equal(answer.compatible, false, "a btrt that is nobody's sample entry is not the box the reason is about");
|
|
158
|
+
assert.deepEqual(answer.refusedPaths, ["moov[0]/trak[0]/mdia[0]/minf[0]/stbl[0]/btrt[0]"]);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("a sample entry whose children do not tile is compared whole", () => {
|
|
162
|
+
const answer = compareInits(init({ preamble: 8, config: [1, 100, 0, 31] }), init({ preamble: 8, config: [1, 100, 0, 30] }));
|
|
163
|
+
|
|
164
|
+
assert.equal(answer.compatible, false);
|
|
165
|
+
assert.deepEqual(
|
|
166
|
+
answer.refusedPaths,
|
|
167
|
+
[ENTRY],
|
|
168
|
+
"the descent is checked, and where it does not hold the whole entry refuses"
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("a different media timescale is refused, and said in those words", () => {
|
|
173
|
+
const answer = compareInits(init({ timescale: 90000 }), init({ timescale: 48000 }));
|
|
174
|
+
|
|
175
|
+
assert.equal(answer.compatible, false);
|
|
176
|
+
assert.ok(
|
|
177
|
+
answer.differences.some((line) => line.includes("timescale 90000 against 48000")),
|
|
178
|
+
answer.differences.join(" | ")
|
|
179
|
+
);
|
|
180
|
+
assert.deepEqual(answer.refusedPaths, ["moov[0]/trak[0]/mdia[0]/mdhd[0]"]);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("a track present in one header and not the other is refused", () => {
|
|
184
|
+
const answer = compareInits(init({ tracks: 1 }), init({ tracks: 2 }));
|
|
185
|
+
|
|
186
|
+
assert.equal(answer.compatible, false);
|
|
187
|
+
assert.ok(
|
|
188
|
+
answer.differences.some((line) => line.includes("trak[1]") && line.includes("absent from the first")),
|
|
189
|
+
answer.differences.join(" | ")
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("an exact-path exception decides by path", () => {
|
|
194
|
+
const served = init({ timescale: 90000 });
|
|
195
|
+
const made = init({ timescale: 48000 });
|
|
196
|
+
|
|
197
|
+
const refused = compareInits(served, made);
|
|
198
|
+
const permitted = compareInits(served, made, {
|
|
199
|
+
exceptions: [{ path: "moov[0]/trak[0]/mdia[0]/mdhd[0]", why: "for this check only" }]
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
assert.equal(refused.compatible, false);
|
|
203
|
+
assert.equal(permitted.compatible, true, "the exception list is what decides, and it is asked by path");
|
|
204
|
+
assert.equal(permitted.differences.length, 1, "a permitted difference is still reported");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("allowing one path does not allow the same box of another track", () => {
|
|
208
|
+
const answer = compareInits(init({ tracks: 2, timescale: 90000 }), init({ tracks: 2, timescale: 48000 }), {
|
|
209
|
+
exceptions: [{ path: "moov[0]/trak[0]/mdia[0]/mdhd[0]", why: "for this check only" }]
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
assert.equal(answer.compatible, false);
|
|
213
|
+
assert.deepEqual(answer.refusedPaths, ["moov[0]/trak[1]/mdia[0]/mdhd[0]"]);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("a missing header is never compatible", () => {
|
|
217
|
+
assert.equal(compareInits(init(), Buffer.alloc(0)).compatible, false);
|
|
218
|
+
assert.equal(compareInits(Buffer.alloc(0), init()).compatible, false);
|
|
219
|
+
});
|