@bubo-squared/gyroview 0.1.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.
Files changed (228) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +21 -0
  3. package/README.md +216 -0
  4. package/dist/define.d.ts +3 -0
  5. package/dist/define.js +4 -0
  6. package/dist/index.d.ts +959 -0
  7. package/dist/index.js +13 -0
  8. package/dist/packages/adapters/blob/src/BlobRandomAccessSource.js +37 -0
  9. package/dist/packages/adapters/blob/src/index.js +2 -0
  10. package/dist/packages/adapters/fetch/src/HttpRangeSource.js +194 -0
  11. package/dist/packages/adapters/fetch/src/HttpResourceLocator.js +35 -0
  12. package/dist/packages/adapters/fetch/src/httpRequest.js +126 -0
  13. package/dist/packages/adapters/fetch/src/index.js +3 -0
  14. package/dist/packages/adapters/mediabunny/src/MediabunnyAudioSegments.js +133 -0
  15. package/dist/packages/adapters/mediabunny/src/MediabunnyDemuxer.js +63 -0
  16. package/dist/packages/adapters/mediabunny/src/MediabunnyVideoTrackReader.js +84 -0
  17. package/dist/packages/adapters/mediabunny/src/SegmentChannel.js +84 -0
  18. package/dist/packages/adapters/mediabunny/src/bufferSources.js +12 -0
  19. package/dist/packages/adapters/mediabunny/src/index.js +2 -0
  20. package/dist/packages/adapters/mse-audio/src/MediaSourceAudioClock.js +139 -0
  21. package/dist/packages/adapters/mse-audio/src/SourceBufferFeeder.js +174 -0
  22. package/dist/packages/adapters/mse-audio/src/events.js +26 -0
  23. package/dist/packages/adapters/mse-audio/src/index.js +2 -0
  24. package/dist/packages/adapters/mse-audio/src/mediaSourceSupport.js +82 -0
  25. package/dist/packages/adapters/three/src/ThreeFrameRenderer.js +274 -0
  26. package/dist/packages/adapters/three/src/compileAndProve.js +14 -0
  27. package/dist/packages/adapters/three/src/fullscreenPass.js +52 -0
  28. package/dist/packages/adapters/three/src/index.js +2 -0
  29. package/dist/packages/adapters/three/src/lensTextures.js +25 -0
  30. package/dist/packages/adapters/three/src/pictureMaterials.js +44 -0
  31. package/dist/packages/adapters/three/src/renderInto.js +15 -0
  32. package/dist/packages/adapters/three/src/rendererUniforms.js +157 -0
  33. package/dist/packages/adapters/three/src/samplingStrategies.js +26 -0
  34. package/dist/packages/adapters/three/src/seamMeter/SeamMeterPass.js +79 -0
  35. package/dist/packages/adapters/three/src/seamMeter/rowMeans.js +38 -0
  36. package/dist/packages/adapters/three/src/shaderPrograms.js +66 -0
  37. package/dist/packages/adapters/three/src/shaders/analysis.frag.js +4 -0
  38. package/dist/packages/adapters/three/src/shaders/equirectangularRays.js +4 -0
  39. package/dist/packages/adapters/three/src/shaders/fixedJoin.js +4 -0
  40. package/dist/packages/adapters/three/src/shaders/fullscreen.vert.js +4 -0
  41. package/dist/packages/adapters/three/src/shaders/header.js +4 -0
  42. package/dist/packages/adapters/three/src/shaders/lensModels.js +4 -0
  43. package/dist/packages/adapters/three/src/shaders/lensSampling.js +4 -0
  44. package/dist/packages/adapters/three/src/shaders/lensTextures.js +4 -0
  45. package/dist/packages/adapters/three/src/shaders/rawLenses.frag.js +4 -0
  46. package/dist/packages/adapters/three/src/shaders/rectilinearRays.js +4 -0
  47. package/dist/packages/adapters/three/src/shaders/screenAreas.js +4 -0
  48. package/dist/packages/adapters/three/src/shaders/stitch.frag.js +4 -0
  49. package/dist/packages/adapters/three/src/webglRenderer.js +37 -0
  50. package/dist/packages/adapters/webcodecs/src/WebCodecsVideoDecoderPort.js +135 -0
  51. package/dist/packages/adapters/webcodecs/src/index.js +2 -0
  52. package/dist/packages/core/src/application/gainMatching/GainMatching.js +66 -0
  53. package/dist/packages/core/src/application/gainMatching/GainMatchingFrameSink.js +62 -0
  54. package/dist/packages/core/src/application/playback/ClockWatch.js +76 -0
  55. package/dist/packages/core/src/application/playback/DecodePipeline.js +188 -0
  56. package/dist/packages/core/src/application/playback/DecodeRun.js +93 -0
  57. package/dist/packages/core/src/application/playback/FramePairQueue.js +93 -0
  58. package/dist/packages/core/src/application/playback/FramePairer.js +60 -0
  59. package/dist/packages/core/src/application/playback/PlaybackSession.js +417 -0
  60. package/dist/packages/core/src/application/playback/SeekOrder.js +36 -0
  61. package/dist/packages/core/src/application/playback/SessionLifecycle.js +42 -0
  62. package/dist/packages/core/src/application/playback/StartGate.js +55 -0
  63. package/dist/packages/core/src/application/playback/TimeUpdates.js +31 -0
  64. package/dist/packages/core/src/application/playback/WallClock.js +46 -0
  65. package/dist/packages/core/src/application/playback/keyframeTimeAt.js +15 -0
  66. package/dist/packages/core/src/application/playback/probeDecoding.js +168 -0
  67. package/dist/packages/core/src/application/recording/frameTimesOf.js +22 -0
  68. package/dist/packages/core/src/application/recording/inspectLayout.js +21 -0
  69. package/dist/packages/core/src/application/recording/inspectRecording.js +124 -0
  70. package/dist/packages/core/src/application/recording/locateOtherLensFile.js +18 -0
  71. package/dist/packages/core/src/application/recording/motionOf.js +39 -0
  72. package/dist/packages/core/src/application/recording/readRecording.js +31 -0
  73. package/dist/packages/core/src/application/recording/timeRecording.js +57 -0
  74. package/dist/packages/core/src/application/stabilization/StabilizingFrameSink.js +31 -0
  75. package/dist/packages/core/src/domain/format/boxes/BoxLayout.js +7 -0
  76. package/dist/packages/core/src/domain/format/boxes/boxConstants.js +16 -0
  77. package/dist/packages/core/src/domain/format/boxes/scanBoxes.js +59 -0
  78. package/dist/packages/core/src/domain/format/calibration/CalibrationVersion.js +13 -0
  79. package/dist/packages/core/src/domain/format/calibration/layouts/CalibrationStringLayout.js +34 -0
  80. package/dist/packages/core/src/domain/format/calibration/layouts/LegacyCalibrationLayout.js +44 -0
  81. package/dist/packages/core/src/domain/format/calibration/layouts/MeiCalibrationLayout.js +45 -0
  82. package/dist/packages/core/src/domain/format/calibration/layouts/PolynomialCalibrationLayout.js +44 -0
  83. package/dist/packages/core/src/domain/format/calibration/offsetTokens.js +65 -0
  84. package/dist/packages/core/src/domain/format/calibration/parseOffsetString.js +52 -0
  85. package/dist/packages/core/src/domain/format/calibration/selectCalibration.js +46 -0
  86. package/dist/packages/core/src/domain/format/captureOrigin.js +20 -0
  87. package/dist/packages/core/src/domain/format/constants.js +33 -0
  88. package/dist/packages/core/src/domain/format/info/infoFields.js +110 -0
  89. package/dist/packages/core/src/domain/format/info/parseInfoRecord.js +90 -0
  90. package/dist/packages/core/src/domain/format/info/readInfoRecord.js +14 -0
  91. package/dist/packages/core/src/domain/format/layout/detectLensLayout.js +122 -0
  92. package/dist/packages/core/src/domain/format/naming/RecordingFileName.js +67 -0
  93. package/dist/packages/core/src/domain/format/records/TrailerRecords.js +83 -0
  94. package/dist/packages/core/src/domain/format/records/exposure/parseExposureRecord.js +48 -0
  95. package/dist/packages/core/src/domain/format/records/gyro/FloatGyroSampleLayout.js +39 -0
  96. package/dist/packages/core/src/domain/format/records/gyro/RawGyroSampleLayout.js +55 -0
  97. package/dist/packages/core/src/domain/format/records/gyro/SampleColumns.js +82 -0
  98. package/dist/packages/core/src/domain/format/records/gyro/gyroLayouts.js +12 -0
  99. package/dist/packages/core/src/domain/format/records/gyro/parseGyroRecord.js +129 -0
  100. package/dist/packages/core/src/domain/format/trailer/RecordHeader.js +23 -0
  101. package/dist/packages/core/src/domain/format/trailer/Trailer.js +23 -0
  102. package/dist/packages/core/src/domain/format/trailer/TrailerFooter.js +27 -0
  103. package/dist/packages/core/src/domain/format/trailer/locateRecords.js +80 -0
  104. package/dist/packages/core/src/domain/format/trailer/parseRecordIndex.js +28 -0
  105. package/dist/packages/core/src/domain/format/trailer/readTrailer.js +32 -0
  106. package/dist/packages/core/src/domain/motion/exposure/ExposureRecord.js +53 -0
  107. package/dist/packages/core/src/domain/motion/gyro/GyroTrack.js +60 -0
  108. package/dist/packages/core/src/domain/motion/gyro/medianStep.js +11 -0
  109. package/dist/packages/core/src/domain/motion/gyro/repairedTimeline.js +101 -0
  110. package/dist/packages/core/src/domain/motion/imu/ImuFrame.js +112 -0
  111. package/dist/packages/core/src/domain/motion/orientation/OrientationTrack.js +146 -0
  112. package/dist/packages/core/src/domain/motion/orientation/estimateGyroBias.js +64 -0
  113. package/dist/packages/core/src/domain/motion/orientation/gravity.js +97 -0
  114. package/dist/packages/core/src/domain/motion/stabilization/Stabilizer.js +13 -0
  115. package/dist/packages/core/src/domain/motion/stabilization/stabilizers.js +86 -0
  116. package/dist/packages/core/src/domain/motion/timing/CaptureClock.js +41 -0
  117. package/dist/packages/core/src/domain/motion/timing/FrameTimes.js +92 -0
  118. package/dist/packages/core/src/domain/motion/timing/frameTimeSources.js +61 -0
  119. package/dist/packages/core/src/domain/motion/timing/resolveFrameTimes.js +68 -0
  120. package/dist/packages/core/src/domain/optics/EquidistantModel.js +39 -0
  121. package/dist/packages/core/src/domain/optics/MeiModel.js +45 -0
  122. package/dist/packages/core/src/domain/optics/PolynomialModel.js +44 -0
  123. package/dist/packages/core/src/domain/optics/gainMatch.js +62 -0
  124. package/dist/packages/core/src/domain/optics/lensGeometry.js +18 -0
  125. package/dist/packages/core/src/domain/optics/lensPose.js +35 -0
  126. package/dist/packages/core/src/domain/optics/opticsConstants.js +5 -0
  127. package/dist/packages/core/src/domain/playback/PlayerState.js +83 -0
  128. package/dist/packages/core/src/domain/stitching/LensLayout.js +21 -0
  129. package/dist/packages/core/src/domain/stitching/StitchingSetup.js +78 -0
  130. package/dist/packages/core/src/domain/stitching/seamDisparity.js +4 -0
  131. package/dist/packages/core/src/domain/stitching/seamDisparityField.js +5 -0
  132. package/dist/packages/core/src/domain/stitching/seamJoin.js +16 -0
  133. package/dist/packages/core/src/domain/stitching/seamMismatch.js +1 -0
  134. package/dist/packages/core/src/domain/stitching/seamRing.js +4 -0
  135. package/dist/packages/core/src/domain/stitching/seamStrip.js +26 -0
  136. package/dist/packages/core/src/domain/view/Framing.js +31 -0
  137. package/dist/packages/core/src/domain/view/PictureQuality.js +26 -0
  138. package/dist/packages/core/src/domain/view/ViewMode.js +9 -0
  139. package/dist/packages/core/src/domain/view/ViewState.js +48 -0
  140. package/dist/packages/core/src/domain/view/lensTilesView.js +63 -0
  141. package/dist/packages/core/src/domain/view/magnification.js +103 -0
  142. package/dist/packages/core/src/domain/view/normalView.js +29 -0
  143. package/dist/packages/core/src/domain/view/panoramaView.js +99 -0
  144. package/dist/packages/core/src/domain/view/rectilinear.js +40 -0
  145. package/dist/packages/core/src/domain/view/screenLayout.js +113 -0
  146. package/dist/packages/core/src/domain/view/viewGestures.js +98 -0
  147. package/dist/packages/core/src/domain/view/viewModes.js +14 -0
  148. package/dist/packages/core/src/index.js +59 -0
  149. package/dist/packages/core/src/ports/FramePair.js +6 -0
  150. package/dist/packages/core/src/shared/async/Deferred.js +42 -0
  151. package/dist/packages/core/src/shared/async/RunStop.js +40 -0
  152. package/dist/packages/core/src/shared/binary/ByteRange.js +38 -0
  153. package/dist/packages/core/src/shared/binary/ByteReader.js +77 -0
  154. package/dist/packages/core/src/shared/errors/GyroViewError.js +81 -0
  155. package/dist/packages/core/src/shared/errors/reportLater.js +11 -0
  156. package/dist/packages/core/src/shared/events/Outbox.js +68 -0
  157. package/dist/packages/core/src/shared/events/TypedEmitter.js +55 -0
  158. package/dist/packages/core/src/shared/keysOf.js +10 -0
  159. package/dist/packages/core/src/shared/lazy.js +11 -0
  160. package/dist/packages/core/src/shared/math/Matrix3.js +93 -0
  161. package/dist/packages/core/src/shared/math/Quaternion.js +133 -0
  162. package/dist/packages/core/src/shared/math/Vector3.js +54 -0
  163. package/dist/packages/core/src/shared/math/clamp.js +9 -0
  164. package/dist/packages/core/src/shared/protobuf/ProtobufMessage.js +157 -0
  165. package/dist/packages/core/src/shared/text/urlPath.js +31 -0
  166. package/dist/packages/core/src/shared/text/utf8.js +12 -0
  167. package/dist/packages/core/src/shared/units/angle.js +22 -0
  168. package/dist/packages/core/src/shared/units/time.js +13 -0
  169. package/dist/packages/player/src/PlayerSource.js +15 -0
  170. package/dist/packages/player/src/browserPlayer.js +18 -0
  171. package/dist/packages/player/src/choices.js +25 -0
  172. package/dist/packages/player/src/composition/Disposables.js +31 -0
  173. package/dist/packages/player/src/composition/browserPorts.js +46 -0
  174. package/dist/packages/player/src/composition/buildPipeline.js +153 -0
  175. package/dist/packages/player/src/composition/ensureDecodable.js +63 -0
  176. package/dist/packages/player/src/composition/openInputs.js +179 -0
  177. package/dist/packages/player/src/composition/openRecording.js +42 -0
  178. package/dist/packages/player/src/controls/ChoiceMenu.js +113 -0
  179. package/dist/packages/player/src/controls/PictureMenus.js +47 -0
  180. package/dist/packages/player/src/controls/SeekBar.js +125 -0
  181. package/dist/packages/player/src/controls/SoundControls.js +41 -0
  182. package/dist/packages/player/src/controls/TransportButtons.js +31 -0
  183. package/dist/packages/player/src/controls/ViewGestures.js +136 -0
  184. package/dist/packages/player/src/controls/Wording.js +78 -0
  185. package/dist/packages/player/src/controls/controlParts.js +36 -0
  186. package/dist/packages/player/src/controls/controls.js +4 -0
  187. package/dist/packages/player/src/controls/controlsBar.js +23 -0
  188. package/dist/packages/player/src/controls/controlsMarkup.js +85 -0
  189. package/dist/packages/player/src/controls/customControls.js +59 -0
  190. package/dist/packages/player/src/controls/formatTime.js +19 -0
  191. package/dist/packages/player/src/controls/icons.js +40 -0
  192. package/dist/packages/player/src/controls/keyboard.js +118 -0
  193. package/dist/packages/player/src/controls/messages.js +94 -0
  194. package/dist/packages/player/src/controls/parseMarkup.js +31 -0
  195. package/dist/packages/player/src/controls/viewButtons.js +14 -0
  196. package/dist/packages/player/src/element/ElementLoads.js +119 -0
  197. package/dist/packages/player/src/element/FullscreenToggle.js +39 -0
  198. package/dist/packages/player/src/element/GyroViewElement.js +313 -0
  199. package/dist/packages/player/src/element/IdleWatcher.js +71 -0
  200. package/dist/packages/player/src/element/TypedEventElement.js +22 -0
  201. package/dist/packages/player/src/element/accessibleRegion.js +19 -0
  202. package/dist/packages/player/src/element/attributeNames.js +51 -0
  203. package/dist/packages/player/src/element/attributes.js +101 -0
  204. package/dist/packages/player/src/element/defineGyroView.js +21 -0
  205. package/dist/packages/player/src/element/earlyProperties.js +36 -0
  206. package/dist/packages/player/src/element/elementSource.js +23 -0
  207. package/dist/packages/player/src/element/liveSettings.js +138 -0
  208. package/dist/packages/player/src/element/playbackAttributes.js +53 -0
  209. package/dist/packages/player/src/element/playerEventMirror.js +33 -0
  210. package/dist/packages/player/src/element/reflectedProperties.js +78 -0
  211. package/dist/packages/player/src/element/styles.js +4 -0
  212. package/dist/packages/player/src/element/template.js +47 -0
  213. package/dist/packages/player/src/index.js +10 -0
  214. package/dist/packages/player/src/inspectRecording.js +22 -0
  215. package/dist/packages/player/src/player/DrawingBufferFit.js +77 -0
  216. package/dist/packages/player/src/player/FrameLoop.js +40 -0
  217. package/dist/packages/player/src/player/PictureSettings.js +60 -0
  218. package/dist/packages/player/src/player/Player.js +377 -0
  219. package/dist/packages/player/src/player/PlayerEvents.js +28 -0
  220. package/dist/packages/player/src/player/PlayerPhase.js +21 -0
  221. package/dist/packages/player/src/player/PlayerSound.js +61 -0
  222. package/dist/packages/player/src/player/PlayerView.js +113 -0
  223. package/dist/packages/player/src/player/SessionRelay.js +66 -0
  224. package/dist/packages/player/src/player/ensureFinite.js +26 -0
  225. package/dist/packages/player/src/player/loadRecording.js +65 -0
  226. package/dist/packages/player/src/player/transportEvents.js +29 -0
  227. package/dist/standalone.js +4919 -0
  228. package/package.json +73 -0
@@ -0,0 +1,29 @@
1
+ import { degrees } from "../../shared/units/angle.js";
2
+ import { DEFAULT_VIEW, viewRotation } from "./ViewState.js";
3
+ import { WHOLE_SCREEN, aspectOf } from "./screenLayout.js";
4
+ import { lookAt, panView, zoomViewAt } from "./viewGestures.js";
5
+ import { withView } from "./Framing.js";
6
+ //#region ../../packages/core/src/domain/view/normalView.ts
7
+ /**
8
+ * A rectilinear window into the stitched sphere over the whole viewport, turned by drags and
9
+ * arrows and zoomed by its field of view toward the pointer.
10
+ */
11
+ var NORMAL_VIEW = {
12
+ isStabilized: true,
13
+ canPan: () => true,
14
+ pan: (framing, delta, { viewport }) => withView(framing, panView(framing.view, delta, viewport.width)),
15
+ turn: (framing, turn) => {
16
+ const { view } = framing;
17
+ return withView(framing, lookAt(view, degrees(view.yaw + turn.yaw), degrees(view.pitch + turn.pitch)));
18
+ },
19
+ zoom: (framing, zoom, { viewport }) => withView(framing, zoomViewAt(framing.view, zoom, aspectOf(viewport))),
20
+ reset: (framing) => withView(framing, DEFAULT_VIEW),
21
+ picture: ({ view }) => ({
22
+ kind: "rectilinear",
23
+ rotation: viewRotation(view),
24
+ fieldOfView: view.fieldOfView,
25
+ area: WHOLE_SCREEN
26
+ })
27
+ };
28
+ //#endregion
29
+ export { NORMAL_VIEW };
@@ -0,0 +1,99 @@
1
+ import { FULL_TURN, HALF_TURN, degrees, degreesToRadians } from "../../shared/units/angle.js";
2
+ import { rotationAboutY } from "../../shared/math/Matrix3.js";
3
+ import { HALF, aspectOf, fittedRectangle, pictureAt, shiftOf } from "./screenLayout.js";
4
+ import { lookAt } from "./viewGestures.js";
5
+ import { FITTED, clampMagnification, magnifiedArea, magnifyAt, panMagnification, pictureShiftOf } from "./magnification.js";
6
+ import { withView } from "./Framing.js";
7
+ //#region ../../packages/core/src/domain/view/panoramaView.ts
8
+ /**
9
+ * An equirectangular picture spans a full turn across for a half turn from top to bottom.
10
+ */
11
+ var EQUIRECTANGULAR_ASPECT = 2;
12
+ function levelled(fitted, magnification) {
13
+ const clamped = clampMagnification(fitted, magnification);
14
+ return {
15
+ ...clamped,
16
+ centre: {
17
+ x: HALF,
18
+ y: clamped.centre.y
19
+ }
20
+ };
21
+ }
22
+ function shownPanorama(framing, { viewport }) {
23
+ const fitted = fittedRectangle(EQUIRECTANGULAR_ASPECT, aspectOf(viewport));
24
+ return {
25
+ fitted,
26
+ panorama: levelled(fitted, framing.panorama)
27
+ };
28
+ }
29
+ function withPanorama(framing, panorama, yawDelta) {
30
+ const { view } = framing;
31
+ return {
32
+ ...withView(framing, lookAt(view, degrees(view.yaw + yawDelta), view.pitch)),
33
+ panorama
34
+ };
35
+ }
36
+ /**
37
+ * A drag turns the panorama a whole turn per width of the picture as shown, and moves it up and
38
+ * down once it is taller than the viewport.
39
+ */
40
+ function panPanorama(framing, delta, context) {
41
+ const { fitted, panorama } = shownPanorama(framing, context);
42
+ const shift = shiftOf(delta, context.viewport);
43
+ const moved = panMagnification(fitted, panorama, {
44
+ across: 0,
45
+ down: shift.down
46
+ });
47
+ const turned = pictureShiftOf(fitted, panorama, shift).across * FULL_TURN;
48
+ return withPanorama(framing, moved, degrees(-turned));
49
+ }
50
+ /**
51
+ * Sideways the arrows turn it; up and down they move a panorama taller than the viewport by the
52
+ * angle they name, the picture spanning a half turn from top to bottom.
53
+ */
54
+ function turnPanorama(framing, turn, context) {
55
+ const { fitted, panorama } = shownPanorama(framing, context);
56
+ return withPanorama(framing, levelled(fitted, {
57
+ ...panorama,
58
+ centre: {
59
+ x: HALF,
60
+ y: panorama.centre.y - turn.pitch / HALF_TURN
61
+ }
62
+ }), turn.yaw);
63
+ }
64
+ /**
65
+ * Keeps the point under the pointer where it is: up and down by the magnification's own rule,
66
+ * sideways by turning the panorama as far as the pointer's longitude moved.
67
+ */
68
+ function zoomPanorama(framing, zoom, context) {
69
+ const { fitted, panorama } = shownPanorama(framing, context);
70
+ const zoomed = levelled(fitted, magnifyAt(fitted, panorama, zoom));
71
+ const before = pictureAt(magnifiedArea(fitted, panorama), zoom.focus);
72
+ const after = pictureAt(magnifiedArea(fitted, zoomed), zoom.focus);
73
+ return withPanorama(framing, zoomed, degrees((before.x - after.x) * FULL_TURN));
74
+ }
75
+ /**
76
+ * Level, as an exported equirectangular video: the yaw picks the direction at the centre, and the
77
+ * panorama magnifies up to four times and moves up and down within itself.
78
+ */
79
+ var PANORAMA_VIEW = {
80
+ isStabilized: true,
81
+ canPan: () => true,
82
+ pan: panPanorama,
83
+ turn: turnPanorama,
84
+ zoom: zoomPanorama,
85
+ reset: (framing) => ({
86
+ ...withView(framing, lookAt(framing.view, degrees(0), framing.view.pitch)),
87
+ panorama: FITTED
88
+ }),
89
+ picture: (framing, context) => {
90
+ const { fitted, panorama } = shownPanorama(framing, context);
91
+ return {
92
+ kind: "equirectangular",
93
+ rotation: rotationAboutY(degreesToRadians(framing.view.yaw)),
94
+ area: magnifiedArea(fitted, panorama)
95
+ };
96
+ }
97
+ };
98
+ //#endregion
99
+ export { PANORAMA_VIEW };
@@ -0,0 +1,40 @@
1
+ import { degrees, degreesToRadians } from "../../shared/units/angle.js";
2
+ import { magnitudeOf, scaleVector } from "../../shared/math/Vector3.js";
3
+ import { transformVector } from "../../shared/math/Matrix3.js";
4
+ import { viewRotation } from "./ViewState.js";
5
+ //#region ../../packages/core/src/domain/view/rectilinear.ts
6
+ /**
7
+ * Half the width of the image plane at unit distance, so that a rectilinear picture spans the
8
+ * given horizontal field of view across its width. The renderer's shader takes it as it is.
9
+ */
10
+ function planeHalfExtentOf(fieldOfView) {
11
+ return Math.tan(degreesToRadians(degrees(fieldOfView / 2)));
12
+ }
13
+ /**
14
+ * Width over height of an area of a viewport with the given aspect.
15
+ */
16
+ function aspectOfArea(area, viewportAspect) {
17
+ return viewportAspect * area.width / area.height;
18
+ }
19
+ /**
20
+ * The view-space direction (x right, y down, z forward) through a point of a rectilinear picture,
21
+ * given as fractions of the picture; `rectilinearRays.glsl` computes the same for every pixel.
22
+ */
23
+ function rayThroughPicture(fieldOfView, point, pictureAspect) {
24
+ const halfExtent = planeHalfExtentOf(fieldOfView);
25
+ const plane = [
26
+ (point.x * 2 - 1) * halfExtent,
27
+ (point.y * 2 - 1) * halfExtent / pictureAspect,
28
+ 1
29
+ ];
30
+ return scaleVector(plane, 1 / magnitudeOf(plane));
31
+ }
32
+ /**
33
+ * The camera body direction seen through a point of the normal view's picture, which fills the
34
+ * viewport, so its points are the viewport's.
35
+ */
36
+ function directionAt(view, point, viewportAspect) {
37
+ return transformVector(viewRotation(view), rayThroughPicture(view.fieldOfView, point, viewportAspect));
38
+ }
39
+ //#endregion
40
+ export { aspectOfArea, directionAt, planeHalfExtentOf, rayThroughPicture };
@@ -0,0 +1,113 @@
1
+ import { ensureInvariant } from "../../shared/errors/GyroViewError.js";
2
+ //#region ../../packages/core/src/domain/view/screenLayout.ts
3
+ /**
4
+ * Half of a length along one axis, as a fraction of it: the middle of the viewport or of a
5
+ * picture.
6
+ */
7
+ var HALF = .5;
8
+ var WHOLE_SCREEN = {
9
+ x: 0,
10
+ y: 0,
11
+ width: 1,
12
+ height: 1
13
+ };
14
+ var SCREEN_CENTRE = {
15
+ x: HALF,
16
+ y: HALF
17
+ };
18
+ /**
19
+ * An empty viewport counts as one unit wide and high, so no measure of it divides by zero.
20
+ */
21
+ function measured(length) {
22
+ return Math.max(length, 1);
23
+ }
24
+ /**
25
+ * Width over height.
26
+ */
27
+ function aspectOf(viewport) {
28
+ return viewport.width / measured(viewport.height);
29
+ }
30
+ /**
31
+ * A drag as fractions of the viewport it happened on.
32
+ */
33
+ function shiftOf(delta, viewport) {
34
+ return {
35
+ across: delta.x / measured(viewport.width),
36
+ down: delta.y / measured(viewport.height)
37
+ };
38
+ }
39
+ /**
40
+ * The point of a picture shown at a point of the viewport, as fractions of the picture.
41
+ */
42
+ function pictureAt(area, point) {
43
+ return {
44
+ x: (point.x - area.x) / area.width,
45
+ y: (point.y - area.y) / area.height
46
+ };
47
+ }
48
+ /**
49
+ * One square tile per lens, in a row or in a column, whichever gives the larger tiles on this
50
+ * viewport, centred with bars around. Square because every lens layout the player accepts has
51
+ * square lens images: square tracks, or the halves of a 2:1 packed frame.
52
+ */
53
+ function lensTiles(lensCount, viewportAspect) {
54
+ const row = fittedRectangle(lensCount, viewportAspect);
55
+ const column = fittedRectangle(1 / lensCount, viewportAspect);
56
+ return row.height >= column.height / lensCount ? tilesAcross(row, lensCount) : tilesDown(column, lensCount);
57
+ }
58
+ function tilesAcross(area, count) {
59
+ const width = area.width / count;
60
+ return Array.from({ length: count }, (_unused, index) => ({
61
+ ...area,
62
+ x: area.x + index * width,
63
+ width
64
+ }));
65
+ }
66
+ function tilesDown(area, count) {
67
+ const height = area.height / count;
68
+ return Array.from({ length: count }, (_unused, index) => ({
69
+ ...area,
70
+ y: area.y + index * height,
71
+ height
72
+ }));
73
+ }
74
+ /**
75
+ * The smallest rectangle holding every one of the given rectangles.
76
+ */
77
+ function boundsOf(rectangles) {
78
+ ensureInvariant(rectangles.length > 0, "bounds need at least one rectangle");
79
+ const left = Math.min(...rectangles.map((rectangle) => rectangle.x));
80
+ const top = Math.min(...rectangles.map((rectangle) => rectangle.y));
81
+ const right = Math.max(...rectangles.map((rectangle) => rectangle.x + rectangle.width));
82
+ const bottom = Math.max(...rectangles.map((rectangle) => rectangle.y + rectangle.height));
83
+ return {
84
+ x: left,
85
+ y: top,
86
+ width: right - left,
87
+ height: bottom - top
88
+ };
89
+ }
90
+ /**
91
+ * The largest centred rectangle of the content's shape inside the viewport. Both aspects are
92
+ * width over height; the bars it leaves go above and below wider content, beside narrower.
93
+ */
94
+ function fittedRectangle(contentAspect, viewportAspect) {
95
+ if (contentAspect >= viewportAspect) {
96
+ const height = viewportAspect / contentAspect;
97
+ return {
98
+ x: 0,
99
+ y: (1 - height) * HALF,
100
+ width: 1,
101
+ height
102
+ };
103
+ }
104
+ const width = contentAspect / viewportAspect;
105
+ return {
106
+ x: (1 - width) * HALF,
107
+ y: 0,
108
+ width,
109
+ height: 1
110
+ };
111
+ }
112
+ //#endregion
113
+ export { HALF, SCREEN_CENTRE, WHOLE_SCREEN, aspectOf, boundsOf, fittedRectangle, lensTiles, pictureAt, shiftOf };
@@ -0,0 +1,98 @@
1
+ import { degrees, degreesToRadians, radians, radiansToDegrees, wrapHalfTurn } from "../../shared/units/angle.js";
2
+ import { rotationAboutX, transformVector } from "../../shared/math/Matrix3.js";
3
+ import { clampView } from "./ViewState.js";
4
+ import { SCREEN_CENTRE } from "./screenLayout.js";
5
+ import { directionAt, rayThroughPicture } from "./rectilinear.js";
6
+ //#region ../../packages/core/src/domain/view/viewGestures.ts
7
+ /**
8
+ * How much each wheel notch or pinch step magnifies, in every view mode.
9
+ */
10
+ var ZOOM_STEP = 1.1;
11
+ /**
12
+ * The magnification `steps` zoom steps make: above 1 zooms in, below 1 out.
13
+ */
14
+ function zoomFactor(steps) {
15
+ return ZOOM_STEP ** steps;
16
+ }
17
+ /**
18
+ * Angle covered by one pixel across the viewport: the field of view spread over its width.
19
+ */
20
+ function degreesPerPixel(view, viewportWidth) {
21
+ return degrees(view.fieldOfView / Math.max(viewportWidth, 1));
22
+ }
23
+ /**
24
+ * Turns the view by a drag: dragging the picture to the right turns the viewer to the left, as
25
+ * grabbing a globe does, by as many degrees as the drag covers at the current field of view.
26
+ */
27
+ function panView(view, delta, viewportWidth) {
28
+ const perPixel = degreesPerPixel(view, viewportWidth);
29
+ return clampView({
30
+ ...view,
31
+ yaw: degrees(view.yaw - delta.x * perPixel),
32
+ pitch: degrees(view.pitch + delta.y * perPixel)
33
+ });
34
+ }
35
+ /**
36
+ * Narrows the field of view by `steps` zoom steps (negative widens), within its bounds.
37
+ */
38
+ function zoomView(view, steps) {
39
+ return clampView({
40
+ ...view,
41
+ fieldOfView: degrees(view.fieldOfView / zoomFactor(steps))
42
+ });
43
+ }
44
+ /**
45
+ * Zooms the normal view toward a point of the viewport: the field of view narrows or widens by
46
+ * the zoom's steps within its bounds, and the view turns so that the direction under the point
47
+ * stays under it. When the poles leave no such turn, it zooms about the centre.
48
+ */
49
+ function zoomViewAt(view, zoom, viewportAspect) {
50
+ const zoomed = zoomView(view, zoom.steps);
51
+ if (zoom.focus.x === SCREEN_CENTRE.x && zoom.focus.y === SCREEN_CENTRE.y || zoomed.fieldOfView === view.fieldOfView) return zoomed;
52
+ const direction = directionAt(view, zoom.focus, viewportAspect);
53
+ const ray = rayThroughPicture(zoomed.fieldOfView, zoom.focus, viewportAspect);
54
+ const pitch = pitchRaising(ray, direction[1], view.pitch);
55
+ if (pitch === void 0) return zoomed;
56
+ const tilted = transformVector(rotationAboutX(degreesToRadians(pitch)), ray);
57
+ const yaw = radiansToDegrees(radians(Math.atan2(direction[0], direction[2]) - Math.atan2(tilted[0], tilted[2])));
58
+ return clampView({
59
+ ...zoomed,
60
+ yaw,
61
+ pitch
62
+ });
63
+ }
64
+ /**
65
+ * The pitch that brings `ray` to the height `height` of the target direction, which the yaw
66
+ * applied after it leaves alone: `y cos θ - z sin θ` is `reach cos(θ + phase)`. Of the two
67
+ * solutions the one nearer `current`; none when no pitch reaches that height.
68
+ */
69
+ function pitchRaising(ray, height, current) {
70
+ const [, y, z] = ray;
71
+ const cosine = height / Math.hypot(y, z);
72
+ if (Math.abs(cosine) > 1) return void 0;
73
+ const phase = radiansToDegrees(radians(Math.atan2(z, y)));
74
+ const spread = radiansToDegrees(radians(Math.acos(cosine)));
75
+ const rising = wrapHalfTurn(degrees(spread - phase));
76
+ const falling = wrapHalfTurn(degrees(-spread - phase));
77
+ return Math.abs(rising - current) <= Math.abs(falling - current) ? rising : falling;
78
+ }
79
+ /**
80
+ * How many zoom steps a pinch from `previousDistance` to `distance` is worth, in the same steps
81
+ * as a wheel notch: positive when the fingers spread (zoom in), zero when either distance is
82
+ * degenerate.
83
+ */
84
+ function zoomStepsForPinch(previousDistance, distance) {
85
+ return previousDistance <= 0 || distance <= 0 ? 0 : Math.log(distance / previousDistance) / Math.log(ZOOM_STEP);
86
+ }
87
+ /**
88
+ * Points the view at a direction, clamped like every other change.
89
+ */
90
+ function lookAt(view, yaw, pitch) {
91
+ return clampView({
92
+ ...view,
93
+ yaw,
94
+ pitch
95
+ });
96
+ }
97
+ //#endregion
98
+ export { lookAt, panView, zoomFactor, zoomStepsForPinch, zoomViewAt };
@@ -0,0 +1,14 @@
1
+ import { LENS_TILES_VIEW } from "./lensTilesView.js";
2
+ import { NORMAL_VIEW } from "./normalView.js";
3
+ import { PANORAMA_VIEW } from "./panoramaView.js";
4
+ //#region ../../packages/core/src/domain/view/viewModes.ts
5
+ var RULES = {
6
+ normal: NORMAL_VIEW,
7
+ equirectangular: PANORAMA_VIEW,
8
+ "raw-lenses": LENS_TILES_VIEW
9
+ };
10
+ function viewModeRulesFor(mode) {
11
+ return RULES[mode];
12
+ }
13
+ //#endregion
14
+ export { viewModeRulesFor };
@@ -0,0 +1,59 @@
1
+ import { degrees } from "./shared/units/angle.js";
2
+ import "./domain/optics/EquidistantModel.js";
3
+ import "./domain/format/calibration/CalibrationVersion.js";
4
+ import { GYRO_VIEW_ERROR_CODES, GyroViewError, asGyroViewError, ensureIndexInRange, ensureInvariant, hasErrorCode, isAbortError, isGyroViewErrorCode, messageOf } from "./shared/errors/GyroViewError.js";
5
+ import { lazy } from "./shared/lazy.js";
6
+ import { microseconds, microsecondsToSeconds, milliseconds, seconds, secondsToMicroseconds } from "./shared/units/time.js";
7
+ import "./domain/motion/exposure/ExposureRecord.js";
8
+ import "./shared/math/Vector3.js";
9
+ import { ByteRange } from "./shared/binary/ByteRange.js";
10
+ import "./domain/motion/timing/CaptureClock.js";
11
+ import { readRecording } from "./application/recording/readRecording.js";
12
+ import "./application/recording/inspectLayout.js";
13
+ import { inspectRecording } from "./application/recording/inspectRecording.js";
14
+ import { clamp } from "./shared/math/clamp.js";
15
+ import "./domain/motion/timing/FrameTimes.js";
16
+ import { IDENTITY_MATRIX3 } from "./shared/math/Matrix3.js";
17
+ import "./domain/motion/imu/ImuFrame.js";
18
+ import "./shared/math/Quaternion.js";
19
+ import "./domain/motion/orientation/OrientationTrack.js";
20
+ import { timeRecording } from "./application/recording/timeRecording.js";
21
+ import "./domain/format/naming/RecordingFileName.js";
22
+ import { fileNameOfUrl } from "./shared/text/urlPath.js";
23
+ import { locateOtherLensFile } from "./application/recording/locateOtherLensFile.js";
24
+ import "./domain/stitching/LensLayout.js";
25
+ import { detectLensLayout } from "./domain/format/layout/detectLensLayout.js";
26
+ import { DEFAULT_STABILIZATION_MODE, STABILIZATION_MODES } from "./domain/motion/stabilization/Stabilizer.js";
27
+ import { stabilizerFor } from "./domain/motion/stabilization/stabilizers.js";
28
+ import "./domain/optics/lensPose.js";
29
+ import "./domain/optics/gainMatch.js";
30
+ import { clampView, isSameView } from "./domain/view/ViewState.js";
31
+ import { DEFAULT_PICTURE_QUALITY, PICTURE_QUALITIES, pixelRatioCapOf } from "./domain/view/PictureQuality.js";
32
+ import { DEFAULT_VIEW_MODE, VIEW_MODES } from "./domain/view/ViewMode.js";
33
+ import { SCREEN_CENTRE, aspectOf } from "./domain/view/screenLayout.js";
34
+ import { aspectOfArea, planeHalfExtentOf } from "./domain/view/rectilinear.js";
35
+ import { lookAt, zoomStepsForPinch } from "./domain/view/viewGestures.js";
36
+ import "./domain/view/magnification.js";
37
+ import { DEFAULT_FRAMING, isSameFraming } from "./domain/view/Framing.js";
38
+ import { viewModeRulesFor } from "./domain/view/viewModes.js";
39
+ import "./domain/stitching/seamRing.js";
40
+ import { buildStitchingSetup, lensFrameOrder } from "./domain/stitching/StitchingSetup.js";
41
+ import { StabilizingFrameSink } from "./application/stabilization/StabilizingFrameSink.js";
42
+ import { GainMatchingFrameSink } from "./application/gainMatching/GainMatchingFrameSink.js";
43
+ import "./domain/stitching/seamStrip.js";
44
+ import "./domain/stitching/seamMismatch.js";
45
+ import "./domain/stitching/seamDisparity.js";
46
+ import "./domain/stitching/seamDisparityField.js";
47
+ import "./domain/stitching/seamJoin.js";
48
+ import { keysOf } from "./shared/keysOf.js";
49
+ import { Outbox } from "./shared/events/Outbox.js";
50
+ import "./application/playback/FramePairQueue.js";
51
+ import { Deferred } from "./shared/async/Deferred.js";
52
+ import { RunStop, STOPPED } from "./shared/async/RunStop.js";
53
+ import "./application/playback/DecodePipeline.js";
54
+ import { probeDecoding } from "./application/playback/probeDecoding.js";
55
+ import { WallClock } from "./application/playback/WallClock.js";
56
+ import { isFlowing } from "./domain/playback/PlayerState.js";
57
+ import { TypedEmitter } from "./shared/events/TypedEmitter.js";
58
+ import { PlaybackSession } from "./application/playback/PlaybackSession.js";
59
+ export { ByteRange, DEFAULT_FRAMING, DEFAULT_PICTURE_QUALITY, DEFAULT_STABILIZATION_MODE, DEFAULT_VIEW_MODE, Deferred, GYRO_VIEW_ERROR_CODES, GainMatchingFrameSink, GyroViewError, IDENTITY_MATRIX3, Outbox, PICTURE_QUALITIES, PlaybackSession, RunStop, SCREEN_CENTRE, STABILIZATION_MODES, STOPPED, StabilizingFrameSink, TypedEmitter, VIEW_MODES, WallClock, asGyroViewError, aspectOf, aspectOfArea, buildStitchingSetup, clamp, clampView, degrees, detectLensLayout, ensureIndexInRange, ensureInvariant, fileNameOfUrl, hasErrorCode, inspectRecording, isAbortError, isFlowing, isGyroViewErrorCode, isSameFraming, isSameView, keysOf, lazy, lensFrameOrder, locateOtherLensFile, lookAt, messageOf, microseconds, microsecondsToSeconds, milliseconds, pixelRatioCapOf, planeHalfExtentOf, probeDecoding, readRecording, seconds, secondsToMicroseconds, stabilizerFor, timeRecording, viewModeRulesFor, zoomStepsForPinch };
@@ -0,0 +1,6 @@
1
+ //#region ../../packages/core/src/ports/FramePair.ts
2
+ function closeFramePair(pair) {
3
+ for (const frame of pair.frames) frame.close();
4
+ }
5
+ //#endregion
6
+ export { closeFramePair };
@@ -0,0 +1,42 @@
1
+ //#region ../../packages/core/src/shared/async/Deferred.ts
2
+ /**
3
+ * A promise settled from outside, once: later settlements are ignored. Lets a producer report
4
+ * an outcome to whoever is waiting without knowing them.
5
+ */
6
+ var Deferred = class {
7
+ promise;
8
+ isSettledNow = false;
9
+ resolvePromise;
10
+ rejectPromise;
11
+ constructor() {
12
+ this.promise = new Promise((resolve, reject) => {
13
+ this.resolvePromise = resolve;
14
+ this.rejectPromise = reject;
15
+ });
16
+ }
17
+ get isSettled() {
18
+ return this.isSettledNow;
19
+ }
20
+ resolve(value) {
21
+ if (this.isSettledNow) return;
22
+ this.isSettledNow = true;
23
+ this.resolvePromise?.(value);
24
+ }
25
+ reject(reason) {
26
+ if (this.isSettledNow) return;
27
+ this.isSettledNow = true;
28
+ this.rejectPromise?.(reason);
29
+ }
30
+ /**
31
+ * Settles as `outcome` does, once it has: hands work begun elsewhere to whoever waits here.
32
+ */
33
+ async follow(outcome) {
34
+ try {
35
+ this.resolve(await outcome);
36
+ } catch (error) {
37
+ this.reject(error);
38
+ }
39
+ }
40
+ };
41
+ //#endregion
42
+ export { Deferred };
@@ -0,0 +1,40 @@
1
+ import { ensureInvariant } from "../errors/GyroViewError.js";
2
+ //#region ../../packages/core/src/shared/async/RunStop.ts
3
+ var STOPPED = Symbol("stopped");
4
+ /**
5
+ * Stops a run that waits for one thing at a time. `race` settles with `STOPPED` as soon as `stop`
6
+ * is called; only the wait in progress is remembered, so an hour-long run of short waits keeps
7
+ * nothing of the ones that finished. Once stopped it starts no work at all: work started and left
8
+ * unwatched could fail later with nobody to hear it.
9
+ */
10
+ var RunStop = class {
11
+ isStopped = false;
12
+ wakeWaiter;
13
+ get wasStopped() {
14
+ return this.isStopped;
15
+ }
16
+ stop() {
17
+ this.isStopped = true;
18
+ this.wakeWaiter?.();
19
+ }
20
+ /**
21
+ * The waiter is in place before `start` runs, so a stop that `start` itself causes (a decoder
22
+ * failing at once) ends the wait too.
23
+ */
24
+ async race(start) {
25
+ if (this.isStopped) return STOPPED;
26
+ ensureInvariant(this.wakeWaiter === void 0, "a run stop races one wait at a time");
27
+ const stopped = new Promise((resolve) => {
28
+ this.wakeWaiter = () => {
29
+ resolve(STOPPED);
30
+ };
31
+ });
32
+ try {
33
+ return await Promise.race([start(), stopped]);
34
+ } finally {
35
+ this.wakeWaiter = void 0;
36
+ }
37
+ }
38
+ };
39
+ //#endregion
40
+ export { RunStop, STOPPED };
@@ -0,0 +1,38 @@
1
+ import { GyroViewError } from "../errors/GyroViewError.js";
2
+ //#region ../../packages/core/src/shared/binary/ByteRange.ts
3
+ /**
4
+ * A contiguous span of bytes in a source: `offset` is inclusive, `end` is exclusive.
5
+ */
6
+ var ByteRange = class ByteRange {
7
+ offset;
8
+ length;
9
+ constructor(offset, length) {
10
+ this.offset = offset;
11
+ this.length = length;
12
+ }
13
+ static of(offset, length) {
14
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new GyroViewError("invalid-byte-range", `offset must be a non-negative integer, got ${offset}`);
15
+ if (!Number.isSafeInteger(length) || length < 0) throw new GyroViewError("invalid-byte-range", `length must be a non-negative integer, got ${length}`);
16
+ return new ByteRange(offset, length);
17
+ }
18
+ /**
19
+ * The last `length` bytes of a source of `totalSize` bytes.
20
+ */
21
+ static lastOf(totalSize, length) {
22
+ if (length > totalSize) throw new GyroViewError("invalid-byte-range", `cannot take ${length} bytes from a ${totalSize}-byte source`);
23
+ return this.of(totalSize - length, length);
24
+ }
25
+ get end() {
26
+ return this.offset + this.length;
27
+ }
28
+ /**
29
+ * Refuses a range that runs past the end of a `totalSize`-byte source with the error the
30
+ * `RandomAccessSource` contract asks for; `source` names the source in the message.
31
+ */
32
+ ensureWithin(totalSize, source) {
33
+ if (this.end <= totalSize) return;
34
+ throw new GyroViewError("invalid-byte-range", `range ${this.offset}+${this.length} exceeds the ${totalSize}-byte ${source}`);
35
+ }
36
+ };
37
+ //#endregion
38
+ export { ByteRange };
@@ -0,0 +1,77 @@
1
+ import { GyroViewError } from "../errors/GyroViewError.js";
2
+ //#region ../../packages/core/src/shared/binary/ByteReader.ts
3
+ var UINT8_SIZE = 1;
4
+ var UINT16_SIZE = 2;
5
+ var UINT32_SIZE = 4;
6
+ var UINT64_SIZE = 8;
7
+ var FLOAT64_SIZE = 8;
8
+ var IS_LITTLE_ENDIAN = true;
9
+ var IS_BIG_ENDIAN = false;
10
+ /**
11
+ * Bounds-checked, little-endian reads over a byte array. Every read is positional, so callers
12
+ * express the record layouts they parse as named offsets rather than as a moving cursor.
13
+ */
14
+ var ByteReader = class {
15
+ bytes;
16
+ view;
17
+ constructor(bytes) {
18
+ this.bytes = bytes;
19
+ this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
20
+ }
21
+ get length() {
22
+ return this.bytes.byteLength;
23
+ }
24
+ uint8At(offset) {
25
+ this.ensureAvailable(offset, UINT8_SIZE);
26
+ return this.view.getUint8(offset);
27
+ }
28
+ uint16LeAt(offset) {
29
+ this.ensureAvailable(offset, UINT16_SIZE);
30
+ return this.view.getUint16(offset, IS_LITTLE_ENDIAN);
31
+ }
32
+ uint32LeAt(offset) {
33
+ this.ensureAvailable(offset, UINT32_SIZE);
34
+ return this.view.getUint32(offset, IS_LITTLE_ENDIAN);
35
+ }
36
+ uint32BeAt(offset) {
37
+ this.ensureAvailable(offset, UINT32_SIZE);
38
+ return this.view.getUint32(offset, IS_BIG_ENDIAN);
39
+ }
40
+ /**
41
+ * Reads an unsigned 64-bit integer as a JavaScript number; rejects values beyond 2^53 - 1.
42
+ */
43
+ uint64LeAt(offset) {
44
+ this.ensureAvailable(offset, UINT64_SIZE);
45
+ return this.toSafeNumber(this.view.getBigUint64(offset, IS_LITTLE_ENDIAN), offset);
46
+ }
47
+ /**
48
+ * Reads a big-endian unsigned 64-bit integer (ISOBMFF box sizes) as a safe JavaScript number.
49
+ */
50
+ uint64BeAt(offset) {
51
+ this.ensureAvailable(offset, UINT64_SIZE);
52
+ return this.toSafeNumber(this.view.getBigUint64(offset, IS_BIG_ENDIAN), offset);
53
+ }
54
+ float64LeAt(offset) {
55
+ this.ensureAvailable(offset, FLOAT64_SIZE);
56
+ return this.view.getFloat64(offset, IS_LITTLE_ENDIAN);
57
+ }
58
+ /**
59
+ * Returns a view (not a copy) of `length` bytes starting at `offset`.
60
+ */
61
+ bytesAt(offset, length) {
62
+ this.ensureAvailable(offset, length);
63
+ return this.bytes.subarray(offset, offset + length);
64
+ }
65
+ asciiAt(offset, length) {
66
+ return Array.from(this.bytesAt(offset, length), (byte) => String.fromCodePoint(byte)).join("");
67
+ }
68
+ toSafeNumber(value, offset) {
69
+ if (value > BigInt(Number.MAX_SAFE_INTEGER)) throw new GyroViewError("binary-unsafe-integer", `uint64 at offset ${offset} (${value.toString()}) exceeds the safe integer range`);
70
+ return Number(value);
71
+ }
72
+ ensureAvailable(offset, length) {
73
+ if (offset < 0 || length < 0 || offset + length > this.bytes.byteLength) throw new GyroViewError("binary-out-of-bounds", `read of ${length} byte(s) at offset ${offset} exceeds ${this.bytes.byteLength} available`);
74
+ }
75
+ };
76
+ //#endregion
77
+ export { ByteReader };