@bubo-squared/gyroview 0.3.0 → 0.4.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 (59) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +20 -11
  3. package/dist/index.d.ts +56 -2
  4. package/dist/index.js +2 -2
  5. package/dist/packages/adapters/mediabunny/src/MediabunnyAudioPackager.js +49 -15
  6. package/dist/packages/adapters/mediabunny/src/MediabunnyCodecReader.js +3 -1
  7. package/dist/packages/adapters/mediabunny/src/decoderConfigurations.js +2 -2
  8. package/dist/packages/adapters/mediabunny/src/trackColour.js +21 -0
  9. package/dist/packages/adapters/mse-audio/src/SourceBufferFeeder.js +12 -1
  10. package/dist/packages/adapters/three/src/ThreeFrameRenderer.js +3 -0
  11. package/dist/packages/adapters/three/src/conversionUniforms.js +61 -0
  12. package/dist/packages/adapters/three/src/glslLiterals.js +10 -0
  13. package/dist/packages/adapters/three/src/matrixCorrections.js +35 -0
  14. package/dist/packages/adapters/three/src/rendererUniforms.js +33 -12
  15. package/dist/packages/adapters/three/src/shaderPrograms.js +4 -2
  16. package/dist/packages/adapters/three/src/shaders/analysis.frag.js +1 -1
  17. package/dist/packages/adapters/three/src/shaders/displayConversion.js +4 -0
  18. package/dist/packages/adapters/three/src/shaders/lensModels.js +1 -1
  19. package/dist/packages/adapters/three/src/shaders/lensSampling.js +1 -1
  20. package/dist/packages/adapters/three/src/shaders/rawLenses.frag.js +1 -1
  21. package/dist/packages/adapters/three/src/shaders/stitch.frag.js +1 -1
  22. package/dist/packages/adapters/three/src/threeMatrix.js +10 -0
  23. package/dist/packages/adapters/webcodecs/src/WebCodecsVideoDecoderPort.js +16 -5
  24. package/dist/packages/adapters/webcodecs/src/colorSpaceOf.js +32 -0
  25. package/dist/packages/core/src/application/playback/probeDecoding.js +2 -2
  26. package/dist/packages/core/src/application/recording/frameTimesOf.js +0 -1
  27. package/dist/packages/core/src/domain/colour/DisplayConversion.js +137 -0
  28. package/dist/packages/core/src/domain/colour/TrackColour.js +38 -0
  29. package/dist/packages/core/src/domain/colour/matrixCorrection.js +76 -0
  30. package/dist/packages/core/src/domain/format/calibration/CalibrationVersion.js +7 -4
  31. package/dist/packages/core/src/domain/format/calibration/layouts/CalibrationStringLayout.js +1 -1
  32. package/dist/packages/core/src/domain/format/calibration/layouts/LegacyCalibrationLayout.js +1 -0
  33. package/dist/packages/core/src/domain/format/calibration/layouts/MeiCalibrationLayout.js +109 -35
  34. package/dist/packages/core/src/domain/format/calibration/layouts/PolynomialCalibrationLayout.js +1 -0
  35. package/dist/packages/core/src/domain/format/calibration/offsetTokens.js +33 -4
  36. package/dist/packages/core/src/domain/format/calibration/parseOffsetString.js +22 -17
  37. package/dist/packages/core/src/domain/format/calibration/selectCalibration.js +28 -15
  38. package/dist/packages/core/src/domain/format/calibration/v6TermReading.js +20 -0
  39. package/dist/packages/core/src/domain/format/info/calibrationSources.js +27 -0
  40. package/dist/packages/core/src/domain/format/info/infoFields.js +8 -2
  41. package/dist/packages/core/src/domain/format/info/parseInfoRecord.js +11 -6
  42. package/dist/packages/core/src/domain/motion/imu/ImuFrame.js +17 -8
  43. package/dist/packages/core/src/domain/motion/timing/FrameTimes.js +1 -3
  44. package/dist/packages/core/src/domain/motion/timing/frameTimeSources.js +0 -3
  45. package/dist/packages/core/src/domain/optics/MeiDistortion.js +43 -0
  46. package/dist/packages/core/src/domain/optics/MeiModel.js +6 -14
  47. package/dist/packages/core/src/domain/optics/scaledProjection.js +30 -0
  48. package/dist/packages/core/src/domain/stitching/StitchingSetup.js +13 -4
  49. package/dist/packages/core/src/index.js +7 -3
  50. package/dist/packages/core/src/shared/errors/GyroViewError.js +55 -3
  51. package/dist/packages/core/src/shared/index.js +11 -0
  52. package/dist/packages/core/src/shared/mapRecord.js +11 -0
  53. package/dist/packages/core/src/shared/protobuf/ProtobufMessage.js +12 -26
  54. package/dist/packages/core/src/shared/protobuf/wireFormat.js +16 -0
  55. package/dist/packages/player/src/composition/buildPipeline.js +2 -1
  56. package/dist/packages/player/src/composition/openInputs.js +4 -1
  57. package/dist/packages/player/src/controls/messages.js +2 -1
  58. package/dist/standalone.js +211 -100
  59. package/package.json +4 -4
@@ -1,9 +1,10 @@
1
1
  import { HALF_FIELD_OF_VIEW } from "./opticsConstants.js";
2
+ import { distortMei, ensureWithinTermCapacity } from "./MeiDistortion.js";
2
3
  //#region ../../packages/core/src/domain/optics/MeiModel.ts
3
4
  /**
4
- * Unified (Mei) omnidirectional camera model with radial-tangential distortion, as stored in
5
- * `offset_v3`. A direction is projected onto the unit sphere, then from a point `xi` behind the
6
- * sphere centre onto the normalised image plane, then distorted and scaled.
5
+ * Unified (Mei) omnidirectional camera model with radial, tangential and thin-prism distortion,
6
+ * as stored in `offset_v3` and `offset_v6`. A direction is projected onto the unit sphere, then from a point
7
+ * `xi` behind the sphere centre onto the normalised image plane, then distorted and scaled.
7
8
  */
8
9
  var MeiModel = class {
9
10
  parameters;
@@ -12,6 +13,7 @@ var MeiModel = class {
12
13
  principalPoint;
13
14
  constructor(parameters) {
14
15
  this.parameters = parameters;
16
+ ensureWithinTermCapacity(parameters.distortion);
15
17
  this.principalPoint = parameters.principalPoint;
16
18
  }
17
19
  get projection() {
@@ -24,22 +26,12 @@ var MeiModel = class {
24
26
  const [x, y, z] = direction;
25
27
  const depth = z + this.parameters.xi;
26
28
  if (depth <= 0 || Math.atan2(Math.hypot(x, y), z) > this.halfFieldOfView) return void 0;
27
- const normalised = [x / depth, y / depth];
28
- const [distortedX, distortedY] = this.distort(normalised);
29
+ const [distortedX, distortedY] = distortMei(this.parameters.distortion, [x / depth, y / depth]);
29
30
  return {
30
31
  x: this.parameters.focal[0] * distortedX + this.principalPoint.x,
31
32
  y: this.parameters.focal[1] * distortedY + this.principalPoint.y
32
33
  };
33
34
  }
34
- distort([mx, my]) {
35
- const [k1, k2, k3] = this.parameters.radial;
36
- const [p1, p2] = this.parameters.tangential;
37
- const r2 = mx * mx + my * my;
38
- const radial = 1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2;
39
- const tangentialX = 2 * p1 * mx * my + p2 * (r2 + 2 * mx * mx);
40
- const tangentialY = p1 * (r2 + 2 * my * my) + 2 * p2 * mx * my;
41
- return [radial * mx + tangentialX, radial * my + tangentialY];
42
- }
43
35
  };
44
36
  //#endregion
45
37
  export { MeiModel };
@@ -0,0 +1,30 @@
1
+ //#region ../../packages/core/src/domain/optics/scaledProjection.ts
2
+ /**
3
+ * The projection with every image radius multiplied by `scale` about the principal point: the
4
+ * Mei model's focal lengths, or the radial polynomial's coefficients. Exact at a scale of 1.
5
+ */
6
+ function scaledProjection(projection, scale) {
7
+ switch (projection.kind) {
8
+ case "mei": {
9
+ const [fx, fy] = projection.focal;
10
+ return {
11
+ ...projection,
12
+ focal: [fx * scale, fy * scale]
13
+ };
14
+ }
15
+ case "radial-polynomial": {
16
+ const [c1, c2, c3, c4] = projection.coefficients;
17
+ return {
18
+ ...projection,
19
+ coefficients: [
20
+ c1 * scale,
21
+ c2 * scale,
22
+ c3 * scale,
23
+ c4 * scale
24
+ ]
25
+ };
26
+ }
27
+ }
28
+ }
29
+ //#endregion
30
+ export { scaledProjection };
@@ -1,7 +1,8 @@
1
1
  import { degrees, degreesToRadians } from "../../shared/units/angle.js";
2
- import { GyroViewError } from "../../shared/errors/GyroViewError.js";
2
+ import { GyroViewError, ensureInvariant } from "../../shared/errors/GyroViewError.js";
3
3
  import { lensRotation } from "../optics/lensPose.js";
4
4
  import { SEAM_RING_ANGLE } from "./seamRing.js";
5
+ import { scaledProjection } from "../optics/scaledProjection.js";
5
6
  //#region ../../packages/core/src/domain/stitching/StitchingSetup.ts
6
7
  /**
7
8
  * Two 200-degree lenses overlap between 80 and 100 degrees from their axes; the blend spans 5
@@ -33,23 +34,31 @@ function buildStitchingSetup(inputs) {
33
34
  const { calibration, layout } = inputs;
34
35
  if (calibration.lenses.length !== layout.sources.length) throw new GyroViewError("unsupported-layout", `the calibration describes ${calibration.lenses.length} lenses but the layout has ${layout.sources.length}`);
35
36
  const frames = lensFrameOrder(layout);
37
+ ensureInvariant(inputs.displayConversions.length === frames.length, `${inputs.displayConversions.length} display conversions for ${frames.length} frame sources`);
36
38
  return {
37
39
  lenses: layout.sources.map((source) => {
38
40
  const lens = lensOf(calibration, source.lensIndex);
41
+ const frameSlot = frames.findIndex((key) => isSameSource(key, source));
39
42
  return {
40
43
  lensIndex: source.lensIndex,
41
- frameSlot: frames.findIndex((key) => isSameSource(key, source)),
44
+ frameSlot,
42
45
  region: source.region,
43
46
  window: canvasWindowOf(calibration, lens),
44
47
  rotation: lensRotation(lens),
45
- projection: lens.model.projection,
46
- halfFieldOfView: lens.model.halfFieldOfView
48
+ projection: scaledProjection(lens.model.projection, calibration.radialScale),
49
+ halfFieldOfView: lens.model.halfFieldOfView,
50
+ displayConversion: conversionAt(inputs.displayConversions, frameSlot)
47
51
  };
48
52
  }),
49
53
  frameSlotCount: frames.length,
50
54
  feather: DEFAULT_FEATHER
51
55
  };
52
56
  }
57
+ function conversionAt(conversions, frameSlot) {
58
+ const conversion = conversions[frameSlot];
59
+ ensureInvariant(conversion !== void 0, `no display conversion for frame slot ${frameSlot}`);
60
+ return conversion;
61
+ }
53
62
  function isSameSource(key, source) {
54
63
  return key.inputIndex === source.inputIndex && key.trackIndex === source.trackIndex;
55
64
  }
@@ -1,7 +1,7 @@
1
1
  import { degrees } from "./shared/units/angle.js";
2
- import "./domain/optics/EquidistantModel.js";
3
2
  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";
3
+ import { GYRO_VIEW_ERROR_CATEGORIES, GYRO_VIEW_ERROR_CODES, GyroViewError, asGyroViewError, ensureIndexInRange, ensureInvariant, hasErrorCode, isAbortError, isGyroViewErrorCode, messageOf } from "./shared/errors/GyroViewError.js";
4
+ import { MEI_TERM_CAPACITY } from "./domain/optics/MeiDistortion.js";
5
5
  import { lazy } from "./shared/lazy.js";
6
6
  import { microseconds, microsecondsToSeconds, milliseconds, seconds, secondsToMicroseconds } from "./shared/units/time.js";
7
7
  import "./domain/motion/exposure/ExposureRecord.js";
@@ -48,8 +48,12 @@ import "./domain/stitching/seamMismatch.js";
48
48
  import "./domain/stitching/seamDisparity.js";
49
49
  import "./domain/stitching/seamDisparityField.js";
50
50
  import "./domain/stitching/seamJoin.js";
51
+ import { COLOUR_PRIMARIES, MATRIX_COEFFICIENTS, TRANSFER_CHARACTERISTICS, namedOrUnspecified } from "./domain/colour/TrackColour.js";
52
+ import { BT709_LUMINANCE, HLG_OETF, displayConversionsOf } from "./domain/colour/DisplayConversion.js";
53
+ import { matrixCorrectionOf } from "./domain/colour/matrixCorrection.js";
51
54
  import { keysOf } from "./shared/keysOf.js";
52
55
  import { Outbox } from "./shared/events/Outbox.js";
56
+ import "./shared/index.js";
53
57
  import { Ending, ITERATION_END } from "./shared/async/iteration.js";
54
58
  import { SourceByteStream } from "./application/download/SourceByteStream.js";
55
59
  import { startFileDownload } from "./application/download/startFileDownload.js";
@@ -64,4 +68,4 @@ import { WallClock } from "./application/playback/WallClock.js";
64
68
  import { isFlowing } from "./domain/playback/PlayerState.js";
65
69
  import { TypedEmitter } from "./shared/events/TypedEmitter.js";
66
70
  import { PlaybackSession } from "./application/playback/PlaybackSession.js";
67
- export { ByteRange, DEFAULT_FRAMING, DEFAULT_PICTURE_QUALITY, DEFAULT_STABILIZATION_MODE, DEFAULT_VIEW_MODE, Deferred, Ending, GYRO_VIEW_ERROR_CODES, GainMatchingFrameSink, GyroViewError, IDENTITY_MATRIX3, ITERATION_END, Outbox, PICTURE_QUALITIES, PlaybackSession, RecordingBuffer, RunStop, SCREEN_CENTRE, STABILIZATION_MODES, STOPPED, SourceByteStream, StabilizingFrameSink, TypedEmitter, VIEW_MODES, WallClock, asGyroViewError, aspectOf, aspectOfArea, buildStitchingSetup, clamp, clampView, degrees, detectLensLayout, downloadPolicyFor, ensureIndexInRange, ensureInvariant, fileNameOfUrl, hasErrorCode, inspectRecording, isAbortError, isFlowing, isGyroViewErrorCode, isSameFraming, isSameView, keysOf, lazy, lensFrameOrder, locateOtherLensFile, lookAt, messageOf, microseconds, microsecondsToSeconds, milliseconds, pixelRatioCapOf, planeHalfExtentOf, probeDecoding, readRecording, readSampleTable, seconds, secondsToMicroseconds, stabilizerFor, startFileDownload, timeRecording, viewModeRulesFor, zoomStepsForPinch };
71
+ export { BT709_LUMINANCE, ByteRange, COLOUR_PRIMARIES, DEFAULT_FRAMING, DEFAULT_PICTURE_QUALITY, DEFAULT_STABILIZATION_MODE, DEFAULT_VIEW_MODE, Deferred, Ending, GYRO_VIEW_ERROR_CATEGORIES, GYRO_VIEW_ERROR_CODES, GainMatchingFrameSink, GyroViewError, HLG_OETF, IDENTITY_MATRIX3, ITERATION_END, MATRIX_COEFFICIENTS, MEI_TERM_CAPACITY, Outbox, PICTURE_QUALITIES, PlaybackSession, RecordingBuffer, RunStop, SCREEN_CENTRE, STABILIZATION_MODES, STOPPED, SourceByteStream, StabilizingFrameSink, TRANSFER_CHARACTERISTICS, TypedEmitter, VIEW_MODES, WallClock, asGyroViewError, aspectOf, aspectOfArea, buildStitchingSetup, clamp, clampView, degrees, detectLensLayout, displayConversionsOf, downloadPolicyFor, ensureIndexInRange, ensureInvariant, fileNameOfUrl, hasErrorCode, inspectRecording, isAbortError, isFlowing, isGyroViewErrorCode, isSameFraming, isSameView, keysOf, lazy, lensFrameOrder, locateOtherLensFile, lookAt, matrixCorrectionOf, messageOf, microseconds, microsecondsToSeconds, milliseconds, namedOrUnspecified, pixelRatioCapOf, planeHalfExtentOf, probeDecoding, readRecording, readSampleTable, seconds, secondsToMicroseconds, stabilizerFor, startFileDownload, timeRecording, viewModeRulesFor, zoomStepsForPinch };
@@ -1,6 +1,6 @@
1
1
  //#region ../../packages/core/src/shared/errors/GyroViewError.ts
2
2
  /**
3
- * Stable machine-readable failure categories. Embedders switch on these; messages are for humans.
3
+ * Stable machine-readable failure codes. Embedders switch on these; messages are for humans.
4
4
  */
5
5
  var GYRO_VIEW_ERROR_CODES = [
6
6
  "binary-out-of-bounds",
@@ -30,17 +30,69 @@ var GYRO_VIEW_ERROR_CODES = [
30
30
  "unsupported-container",
31
31
  "unsupported-gyro-record",
32
32
  "unsupported-info-format",
33
- "unsupported-layout"
33
+ "unsupported-layout",
34
+ "webcodecs-unavailable"
34
35
  ];
36
+ /**
37
+ * Whose side a failure is on, for embedders that handle failures by kind: the browser cannot
38
+ * decode or draw the recording, the file is not one the player can play, its bytes could not be
39
+ * read, the page misused the API, or the player failed in a way it did not expect.
40
+ */
41
+ var GYRO_VIEW_ERROR_CATEGORIES = [
42
+ "browser",
43
+ "recording",
44
+ "source",
45
+ "usage",
46
+ "internal"
47
+ ];
48
+ /**
49
+ * A record, so a new code cannot be added without its category.
50
+ */
51
+ var CATEGORY_OF_CODE = {
52
+ "binary-out-of-bounds": "recording",
53
+ "binary-unsafe-integer": "recording",
54
+ "codec-unsupported": "browser",
55
+ cors: "source",
56
+ decode: "browser",
57
+ "embed-destroyed": "usage",
58
+ "index-out-of-range": "internal",
59
+ "invalid-argument": "usage",
60
+ "invalid-byte-range": "recording",
61
+ "invalid-calibration": "recording",
62
+ "invalid-protobuf": "recording",
63
+ "invalid-trailer": "recording",
64
+ "invariant-violation": "internal",
65
+ "missing-second-file": "recording",
66
+ "no-calibration": "recording",
67
+ "no-info-record": "recording",
68
+ "no-key-frame": "recording",
69
+ "playback-blocked": "browser",
70
+ "range-unsupported": "source",
71
+ "render-unavailable": "browser",
72
+ "source-changed": "source",
73
+ "source-truncated": "source",
74
+ "source-unreadable": "source",
75
+ "unsupported-calibration": "recording",
76
+ "unsupported-container": "recording",
77
+ "unsupported-gyro-record": "recording",
78
+ "unsupported-info-format": "recording",
79
+ "unsupported-layout": "recording",
80
+ "webcodecs-unavailable": "browser"
81
+ };
35
82
  function isGyroViewErrorCode(value) {
36
83
  return typeof value === "string" && GYRO_VIEW_ERROR_CODES.includes(value);
37
84
  }
38
85
  var GyroViewError = class extends Error {
39
86
  code;
87
+ /**
88
+ * Its own property rather than a getter, so a serialized or logged copy of the error keeps it.
89
+ */
90
+ category;
40
91
  constructor(code, message, options) {
41
92
  super(message, options);
42
93
  this.code = code;
43
94
  this.name = "GyroViewError";
95
+ this.category = CATEGORY_OF_CODE[code];
44
96
  }
45
97
  };
46
98
  /**
@@ -79,4 +131,4 @@ function ensureIndexInRange(index, length, subject) {
79
131
  if (!Number.isSafeInteger(index) || index < 0 || index >= length) throw new GyroViewError("index-out-of-range", `${subject} index ${index} is outside 0..${length - 1}`);
80
132
  }
81
133
  //#endregion
82
- export { GYRO_VIEW_ERROR_CODES, GyroViewError, asGyroViewError, ensureIndexInRange, ensureInvariant, hasErrorCode, isAbortError, isGyroViewErrorCode, messageOf };
134
+ export { GYRO_VIEW_ERROR_CATEGORIES, GYRO_VIEW_ERROR_CODES, GyroViewError, asGyroViewError, ensureIndexInRange, ensureInvariant, hasErrorCode, isAbortError, isGyroViewErrorCode, messageOf };
@@ -0,0 +1,11 @@
1
+ import { degrees } from "./units/angle.js";
2
+ import { GYRO_VIEW_ERROR_CATEGORIES, GYRO_VIEW_ERROR_CODES, GyroViewError, asGyroViewError, ensureIndexInRange, ensureInvariant, hasErrorCode, isAbortError, isGyroViewErrorCode, messageOf } from "./errors/GyroViewError.js";
3
+ import { lazy } from "./lazy.js";
4
+ import { microseconds, microsecondsToSeconds, milliseconds, seconds, secondsToMicroseconds } from "./units/time.js";
5
+ import "./math/Vector3.js";
6
+ import { clamp } from "./math/clamp.js";
7
+ import { IDENTITY_MATRIX3 } from "./math/Matrix3.js";
8
+ import "./math/Quaternion.js";
9
+ import { keysOf } from "./keysOf.js";
10
+ import { Outbox } from "./events/Outbox.js";
11
+ export { GYRO_VIEW_ERROR_CATEGORIES, GYRO_VIEW_ERROR_CODES, GyroViewError, IDENTITY_MATRIX3, Outbox, asGyroViewError, clamp, degrees, ensureIndexInRange, ensureInvariant, hasErrorCode, isAbortError, isGyroViewErrorCode, keysOf, lazy, messageOf, microseconds, microsecondsToSeconds, milliseconds, seconds, secondsToMicroseconds };
@@ -0,0 +1,11 @@
1
+ //#region ../../packages/core/src/shared/mapRecord.ts
2
+ /**
3
+ * A record with each value of `every` turned by `map`, under the same keys: a table declared once
4
+ * becomes a record of what it describes, and the record's type keeps every key of the table.
5
+ */
6
+ function mapRecord(every, map) {
7
+ const entries = Object.entries(every).map(([key, value]) => [key, map(value, key)]);
8
+ return Object.fromEntries(entries);
9
+ }
10
+ //#endregion
11
+ export { mapRecord };
@@ -1,24 +1,10 @@
1
1
  import { GyroViewError } from "../errors/GyroViewError.js";
2
2
  import { ByteReader } from "../binary/ByteReader.js";
3
3
  import { decodeUtf8 } from "../text/utf8.js";
4
+ import { WireType } from "./wireFormat.js";
4
5
  //#region ../../packages/core/src/shared/protobuf/ProtobufMessage.ts
5
- /**
6
- * Protocol Buffers wire types this decoder understands. Groups (3, 4) are obsolete and rejected.
7
- */
8
- var WireType = {
9
- Varint: 0,
10
- Fixed64: 1,
11
- LengthDelimited: 2,
12
- Fixed32: 5
13
- };
14
- var FIELD_NUMBER_SHIFT = 3;
15
- var WIRE_TYPE_MASK = 7;
16
- var VARINT_PAYLOAD_BITS = 7n;
17
- var VARINT_PAYLOAD_MASK = 127n;
18
- var VARINT_CONTINUATION_BIT = 128;
19
- var FIXED64_SIZE = 8;
20
- var FIXED32_SIZE = 4;
21
- var MAX_VARINT_BYTES = 10;
6
+ var VARINT_SHIFT = BigInt(7);
7
+ var VARINT_MASK = BigInt(127);
22
8
  var MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
23
9
  /**
24
10
  * A schema-less view of one encoded protobuf message: fields are looked up by number and unknown
@@ -93,8 +79,8 @@ var Cursor = class {
93
79
  }
94
80
  readField() {
95
81
  const key = this.readVarint();
96
- const number = Number(key >> BigInt(FIELD_NUMBER_SHIFT));
97
- const wireType = Number(key & BigInt(WIRE_TYPE_MASK));
82
+ const number = Number(key >> BigInt(3));
83
+ const wireType = Number(key & BigInt(7));
98
84
  return {
99
85
  number,
100
86
  value: this.readValue(wireType, number)
@@ -108,11 +94,11 @@ var Cursor = class {
108
94
  };
109
95
  case WireType.Fixed64: return {
110
96
  kind: "fixed64",
111
- bytes: this.readBytes(FIXED64_SIZE)
97
+ bytes: this.readBytes(8)
112
98
  };
113
99
  case WireType.Fixed32: return {
114
100
  kind: "fixed32",
115
- bytes: this.readBytes(FIXED32_SIZE)
101
+ bytes: this.readBytes(4)
116
102
  };
117
103
  case WireType.LengthDelimited: return {
118
104
  kind: "bytes",
@@ -124,13 +110,13 @@ var Cursor = class {
124
110
  readVarint() {
125
111
  let result = 0n;
126
112
  let shift = 0n;
127
- for (let consumed = 0; consumed < MAX_VARINT_BYTES; consumed += 1) {
113
+ for (let consumed = 0; consumed < 10; consumed += 1) {
128
114
  const byte = this.readByte();
129
- result |= (BigInt(byte) & VARINT_PAYLOAD_MASK) << shift;
130
- if ((byte & VARINT_CONTINUATION_BIT) === 0) return result;
131
- shift += VARINT_PAYLOAD_BITS;
115
+ result |= (BigInt(byte) & VARINT_MASK) << shift;
116
+ if ((byte & 128) === 0) return result;
117
+ shift += VARINT_SHIFT;
132
118
  }
133
- throw new GyroViewError("invalid-protobuf", `varint longer than ${MAX_VARINT_BYTES} bytes at byte ${this.position}`);
119
+ throw new GyroViewError("invalid-protobuf", `varint longer than 10 bytes at byte ${this.position}`);
134
120
  }
135
121
  readLength() {
136
122
  const length = this.readVarint();
@@ -0,0 +1,16 @@
1
+ //#region ../../packages/core/src/shared/protobuf/wireFormat.ts
2
+ /**
3
+ * The Protocol Buffers wire format (protobuf encoding spec, "Message Structure"): the wire types
4
+ * a field key names and how keys and varints are laid out. The decoder and the fixtures' encoder
5
+ * share it, so that the two cannot disagree on a byte.
6
+ *
7
+ * The wire types the info record uses; groups (3, 4) are obsolete, and the decoder rejects them.
8
+ */
9
+ var WireType = {
10
+ Varint: 0,
11
+ Fixed64: 1,
12
+ LengthDelimited: 2,
13
+ Fixed32: 5
14
+ };
15
+ //#endregion
16
+ export { WireType };
@@ -122,7 +122,8 @@ function wallClock(warning) {
122
122
  function stitchingSetupOf(opened) {
123
123
  return buildStitchingSetup({
124
124
  calibration: opened.calibration,
125
- layout: opened.layout
125
+ layout: opened.layout,
126
+ displayConversions: opened.displayConversions
126
127
  });
127
128
  }
128
129
  function sinkOver(renderer, opened) {
@@ -3,6 +3,7 @@ import { seconds } from "../../../core/src/shared/units/time.js";
3
3
  import { timeRecording } from "../../../core/src/application/recording/timeRecording.js";
4
4
  import { detectLensLayout } from "../../../core/src/domain/format/layout/detectLensLayout.js";
5
5
  import { lensFrameOrder } from "../../../core/src/domain/stitching/StitchingSetup.js";
6
+ import { displayConversionsOf } from "../../../core/src/domain/colour/DisplayConversion.js";
6
7
  import { startFileDownload } from "../../../core/src/application/download/startFileDownload.js";
7
8
  import { downloadPolicyFor } from "../../../core/src/domain/download/DownloadPolicy.js";
8
9
  import { RecordingBuffer } from "../../../core/src/application/download/RecordingBuffer.js";
@@ -77,18 +78,20 @@ function calibrationOf(recording) {
77
78
  function assemble(parts, packager, disposables) {
78
79
  const { read, files, layout, frameSources, calibration, timing } = parts;
79
80
  const duration = seconds(Math.min(...files.map((file) => file.duration)));
81
+ const display = displayConversionsOf(frameSources.map((source) => source.description.colour));
80
82
  const [sound] = files.flatMap((file) => file.audioTracks);
81
83
  return {
82
84
  recording: read.recording,
83
85
  layout,
84
86
  frameSources,
85
87
  calibration,
88
+ displayConversions: display.conversions,
86
89
  duration,
87
90
  frameTimes: timing.frameTimes,
88
91
  motion: timing.motion,
89
92
  soundSegments: sound && (() => packager.segmentsOf(sound.samples, sound.configuration)),
90
93
  metadata: metadataOf(parts, duration, sound !== void 0),
91
- warnings: timing.warnings,
94
+ warnings: [...timing.warnings, ...display.warnings],
92
95
  readAhead: () => {
93
96
  for (const file of files) file.download.startReadingAhead();
94
97
  },
@@ -78,7 +78,8 @@ var DEFAULT_MESSAGES = {
78
78
  "unsupported-container": UNREADABLE,
79
79
  "unsupported-gyro-record": UNREADABLE,
80
80
  "unsupported-info-format": UNREADABLE,
81
- "unsupported-layout": UNREADABLE
81
+ "unsupported-layout": UNREADABLE,
82
+ "webcodecs-unavailable": UNSUPPORTED_BROWSER
82
83
  }
83
84
  };
84
85
  /**