@bubo-squared/gyroview 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/README.md +3 -3
- package/dist/index.d.ts +36 -0
- package/dist/packages/adapters/mediabunny/src/MediabunnyAudioPackager.js +49 -15
- package/dist/packages/adapters/mediabunny/src/MediabunnyCodecReader.js +3 -1
- package/dist/packages/adapters/mediabunny/src/decoderConfigurations.js +2 -2
- package/dist/packages/adapters/mediabunny/src/trackColour.js +21 -0
- package/dist/packages/adapters/mse-audio/src/SourceBufferFeeder.js +12 -1
- package/dist/packages/adapters/three/src/ThreeFrameRenderer.js +3 -0
- package/dist/packages/adapters/three/src/conversionUniforms.js +61 -0
- package/dist/packages/adapters/three/src/glslLiterals.js +10 -0
- package/dist/packages/adapters/three/src/matrixCorrections.js +35 -0
- package/dist/packages/adapters/three/src/rendererUniforms.js +33 -12
- package/dist/packages/adapters/three/src/shaderPrograms.js +4 -2
- package/dist/packages/adapters/three/src/shaders/analysis.frag.js +1 -1
- package/dist/packages/adapters/three/src/shaders/displayConversion.js +4 -0
- package/dist/packages/adapters/three/src/shaders/lensModels.js +1 -1
- package/dist/packages/adapters/three/src/shaders/lensSampling.js +1 -1
- package/dist/packages/adapters/three/src/shaders/rawLenses.frag.js +1 -1
- package/dist/packages/adapters/three/src/shaders/stitch.frag.js +1 -1
- package/dist/packages/adapters/three/src/threeMatrix.js +10 -0
- package/dist/packages/adapters/webcodecs/src/WebCodecsVideoDecoderPort.js +4 -2
- package/dist/packages/adapters/webcodecs/src/colorSpaceOf.js +32 -0
- package/dist/packages/core/src/application/recording/frameTimesOf.js +0 -1
- package/dist/packages/core/src/domain/colour/DisplayConversion.js +137 -0
- package/dist/packages/core/src/domain/colour/TrackColour.js +38 -0
- package/dist/packages/core/src/domain/colour/matrixCorrection.js +76 -0
- package/dist/packages/core/src/domain/format/calibration/CalibrationVersion.js +7 -4
- package/dist/packages/core/src/domain/format/calibration/layouts/CalibrationStringLayout.js +1 -1
- package/dist/packages/core/src/domain/format/calibration/layouts/LegacyCalibrationLayout.js +1 -0
- package/dist/packages/core/src/domain/format/calibration/layouts/MeiCalibrationLayout.js +109 -35
- package/dist/packages/core/src/domain/format/calibration/layouts/PolynomialCalibrationLayout.js +1 -0
- package/dist/packages/core/src/domain/format/calibration/offsetTokens.js +33 -4
- package/dist/packages/core/src/domain/format/calibration/parseOffsetString.js +22 -17
- package/dist/packages/core/src/domain/format/calibration/selectCalibration.js +28 -15
- package/dist/packages/core/src/domain/format/calibration/v6TermReading.js +20 -0
- package/dist/packages/core/src/domain/format/info/calibrationSources.js +27 -0
- package/dist/packages/core/src/domain/format/info/infoFields.js +8 -2
- package/dist/packages/core/src/domain/format/info/parseInfoRecord.js +11 -6
- package/dist/packages/core/src/domain/motion/imu/ImuFrame.js +31 -9
- package/dist/packages/core/src/domain/motion/timing/FrameTimes.js +1 -3
- package/dist/packages/core/src/domain/motion/timing/frameTimeSources.js +0 -3
- package/dist/packages/core/src/domain/optics/MeiDistortion.js +43 -0
- package/dist/packages/core/src/domain/optics/MeiModel.js +6 -14
- package/dist/packages/core/src/domain/optics/scaledProjection.js +30 -0
- package/dist/packages/core/src/domain/stitching/StitchingSetup.js +13 -4
- package/dist/packages/core/src/index.js +6 -2
- package/dist/packages/core/src/shared/index.js +11 -0
- package/dist/packages/core/src/shared/mapRecord.js +11 -0
- package/dist/packages/core/src/shared/protobuf/ProtobufMessage.js +12 -26
- package/dist/packages/core/src/shared/protobuf/wireFormat.js +16 -0
- package/dist/packages/player/src/composition/buildPipeline.js +2 -1
- package/dist/packages/player/src/composition/openInputs.js +4 -1
- package/dist/standalone.js +211 -100
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region ../../packages/adapters/three/src/shaders/rawLenses.frag.glsl?raw
|
|
2
|
-
var rawLenses_frag_default = "// The decoded lens images on their own, unstitched: each lens's region of its frame
|
|
2
|
+
var rawLenses_frag_default = "// The decoded lens images on their own, unstitched: each lens's region of its frame as the\n// decoder delivered it, brought to the display (ADR 0033), in the lens's screen area, with no\n// pose, stabilization or gain. Black around the areas. Every pixel reads every tile, and the area\n// picks one without a branch: a read inside a branch that some pixels of a 2x2 quad skip took a\n// far too coarse footprint on Apple GPUs (Chrome through Metal), a grey line along a tile's edge\n// wherever the edge fell inside a quad.\nin vec2 vNdc;\nout vec4 outColor;\n\nvoid main() {\n vec3 color = vec3(0.0);\n for (int i = 0; i < MAX_LENSES; i++) {\n if (i >= uLensCount) break;\n vec2 point = pointInArea(vNdc, uScreenArea[i]);\n Footprint footprint = footprintOf(i, point);\n vec3 sampled = toDisplay(i, sampleLens(uLensTexture[i], footprint, uSampling).rgb);\n color = mix(color, sampled, float(isInArea(point)));\n }\n outColor = vec4(color, 1.0);\n}\n";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { rawLenses_frag_default as default };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region ../../packages/adapters/three/src/shaders/stitch.frag.glsl?raw
|
|
2
|
-
var stitch_frag_default = "// The stitched sphere through the picture's rays: each lens's texel for the ray, read and weighted\n// across the feather band as the seam join says, and matched in exposure. Every pixel samples
|
|
2
|
+
var stitch_frag_default = "// The stitched sphere through the picture's rays: each lens's texel for the ray, read and weighted\n// across the feather band as the seam join says, and matched in exposure. Every pixel samples,\n// even outside the picture's area, so the footprints' derivatives are defined; the area decides\n// what shows.\nuniform mat3 uViewRotation;\nuniform mat3 uStabilization;\nuniform vec3 uLensGain[MAX_LENSES];\n\nin vec2 vNdc;\nout vec4 outColor;\n\nvoid main() {\n vec2 point = pointInArea(vNdc, uScreenArea[0]);\n vec3 dirView = rayThroughPicture(point);\n vec3 dirBody = uStabilization * (uViewRotation * dirView);\n vec3 sum = vec3(0.0);\n float weightSum = 0.0;\n float disparity = disparityAt(dirBody);\n vec2 feather = seamFeather(disparity);\n for (int i = 0; i < MAX_LENSES; i++) {\n if (i >= uLensCount) break;\n // A lens silenced through its gain (ADR 0012) leaves the blend altogether, so the other\n // lens fills the feather band alone and a lens-only render shows that lens as it is.\n if (all(equal(uLensGain[i], vec3(0.0)))) continue;\n LensSample lens = sampleLensAt(i, seamReadDirection(i, dirBody, disparity));\n if (!lens.isImaged) continue;\n // Weighed by the angle from the lens's axis where it is read, which a seam join may move.\n float weight = 1.0 - smoothstep(feather.x, feather.y, lens.theta);\n // Matched in exposure where exposure is a factor, then brought to the display (ADR 0033).\n sum += weight * shownOf(i, uLensGain[i] * lens.signal);\n weightSum += weight;\n }\n bool isShown = isInArea(point) && weightSum > 0.0;\n outColor = isShown ? vec4(sum / weightSum, 1.0) : vec4(0.0, 0.0, 0.0, 1.0);\n}\n";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { stitch_frag_default as default };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Matrix3 } from "three";
|
|
2
|
+
//#region ../../packages/adapters/three/src/threeMatrix.ts
|
|
3
|
+
/**
|
|
4
|
+
* Row-major core matrix into a three matrix, whose `set` takes rows too.
|
|
5
|
+
*/
|
|
6
|
+
function toThreeMatrix(m) {
|
|
7
|
+
return new Matrix3().set(...m);
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { toThreeMatrix };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GyroViewError, asGyroViewError, messageOf } from "../../../core/src/shared/errors/GyroViewError.js";
|
|
2
2
|
import { microseconds, microsecondsToSeconds, secondsToMicroseconds } from "../../../core/src/shared/units/time.js";
|
|
3
3
|
import "../../../core/src/index.js";
|
|
4
|
+
import { colorSpaceOf } from "./colorSpaceOf.js";
|
|
4
5
|
//#region ../../packages/adapters/webcodecs/src/WebCodecsVideoDecoderPort.ts
|
|
5
6
|
/**
|
|
6
7
|
* A hard `prefer-hardware` refuses codecs the browser could decode in software (H.264 recordings
|
|
@@ -38,13 +39,14 @@ var WebCodecsVideoDecoderPort = class {
|
|
|
38
39
|
return new WebCodecsDecoderHandle(this.toWebCodecsConfig(configuration), callbacks);
|
|
39
40
|
}
|
|
40
41
|
toWebCodecsConfig(configuration) {
|
|
41
|
-
const { description
|
|
42
|
+
const { description } = configuration;
|
|
43
|
+
const colorSpace = colorSpaceOf(configuration.colour);
|
|
42
44
|
return {
|
|
43
45
|
codec: configuration.codec,
|
|
44
46
|
codedWidth: configuration.codedWidth,
|
|
45
47
|
codedHeight: configuration.codedHeight,
|
|
46
48
|
...description && { description },
|
|
47
|
-
...
|
|
49
|
+
...colorSpace && { colorSpace },
|
|
48
50
|
hardwareAcceleration: HARDWARE_ACCELERATION,
|
|
49
51
|
optimizeForLatency: false
|
|
50
52
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region ../../packages/adapters/webcodecs/src/colorSpaceOf.ts
|
|
2
|
+
/**
|
|
3
|
+
* A track's colour as a decoder configuration's colour space: every value the track names, none
|
|
4
|
+
* it leaves unspecified. WebCodecs gives the frames the configured colour space whole ("Output
|
|
5
|
+
* VideoFrames"), so it says all the bitstream says, and the frames carry the colour the display
|
|
6
|
+
* conversion was chosen for (ADR 0033). An engine whose WebCodecs does not know one of the values
|
|
7
|
+
* would refuse the whole configuration, so it is told the range alone, as before. Undefined for a
|
|
8
|
+
* track that names nothing.
|
|
9
|
+
*/
|
|
10
|
+
function colorSpaceOf(colour) {
|
|
11
|
+
const range = colour.range === "unspecified" ? void 0 : { fullRange: colour.range === "full" };
|
|
12
|
+
const named = {
|
|
13
|
+
...colour.primaries !== "unspecified" && { primaries: colour.primaries },
|
|
14
|
+
...colour.transfer !== "unspecified" && { transfer: colour.transfer },
|
|
15
|
+
...colour.matrix !== "unspecified" && { matrix: colour.matrix },
|
|
16
|
+
...range
|
|
17
|
+
};
|
|
18
|
+
return Object.keys(named).length === 0 ? void 0 : understoodHere(named) ?? range;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The colour space as this engine reads it, undefined where it names a value the engine does not
|
|
22
|
+
* know.
|
|
23
|
+
*/
|
|
24
|
+
function understoodHere(colorSpace) {
|
|
25
|
+
try {
|
|
26
|
+
return new VideoColorSpace(colorSpace).toJSON();
|
|
27
|
+
} catch {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { colorSpaceOf };
|
|
@@ -13,7 +13,6 @@ async function frameTimesOf(recording, frameSource, timeline) {
|
|
|
13
13
|
...timeline,
|
|
14
14
|
frameCount,
|
|
15
15
|
frameRate: info.frameRate,
|
|
16
|
-
readoutTime: info.readoutTime,
|
|
17
16
|
exposureRecord
|
|
18
17
|
}, info.preferredFrameTimeSource);
|
|
19
18
|
return plan.needsTrackTimestamps ? plan.resolveWith(await frameSource.sampleTimestamps()) : plan.resolved;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { IDENTITY_MATRIX3 } from "../../shared/math/Matrix3.js";
|
|
2
|
+
//#region ../../packages/core/src/domain/colour/DisplayConversion.ts
|
|
3
|
+
/**
|
|
4
|
+
* BT.2100 HLG's inverse OETF (ITU-R BT.2100-2, table 5): `E'² / 3` up to half signal, then
|
|
5
|
+
* `(exp((E' - c) / a) + b) / 12`, with a, b (1 - 4a) and c; the shader's defines come from here.
|
|
6
|
+
*/
|
|
7
|
+
var HLG_OETF = {
|
|
8
|
+
a: .17883277,
|
|
9
|
+
b: .28466892,
|
|
10
|
+
c: .55991073,
|
|
11
|
+
segmentJoin: .5,
|
|
12
|
+
squareSegmentDivisor: 3,
|
|
13
|
+
logSegmentDivisor: 12
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Linear BT.2020 to linear BT.709 RGB (ITU-R BT.2087-0, equation 5), to seven decimals as the two
|
|
17
|
+
* sets of primaries and their shared D65 white derive it, so each row sums to one and greys stay
|
|
18
|
+
* grey.
|
|
19
|
+
*/
|
|
20
|
+
var BT2020_TO_BT709 = [
|
|
21
|
+
1.660491,
|
|
22
|
+
-.5876411,
|
|
23
|
+
-.0728499,
|
|
24
|
+
-.1245505,
|
|
25
|
+
1.1328999,
|
|
26
|
+
-.0083494,
|
|
27
|
+
-.0181508,
|
|
28
|
+
-.1005789,
|
|
29
|
+
1.1187297
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* BT.709's luminance of linear red, green and blue (ITU-R BT.709-6, item 3.2): what the highlight
|
|
33
|
+
* roll-off acts on, so a colour keeps its hue as it rolls off.
|
|
34
|
+
*/
|
|
35
|
+
var BT709_LUMINANCE = [
|
|
36
|
+
.2126,
|
|
37
|
+
.7152,
|
|
38
|
+
.0722
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Insta360 Studio's own HLG-to-SDR curve, fitted pixel by pixel to the X6's HLG and Rec.709
|
|
42
|
+
* exports of the same stitch: scene light, no OOTF, brought up by two fifths, its luminance
|
|
43
|
+
* rolled off above 0.2 and encoded with a power of 1/2.2 (ADR 0033).
|
|
44
|
+
*/
|
|
45
|
+
var STUDIO_TONE = {
|
|
46
|
+
exposure: 1.4,
|
|
47
|
+
kneeStart: .2,
|
|
48
|
+
ceiling: 1.5,
|
|
49
|
+
exponent: 2.2
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The primaries SDR is shown as recorded with: BT.709's, and the SD primaries close to them; a
|
|
53
|
+
* track that names none is taken for BT.709.
|
|
54
|
+
*/
|
|
55
|
+
var BT709_LIKE_PRIMARIES = /* @__PURE__ */ new Set([
|
|
56
|
+
"bt709",
|
|
57
|
+
"bt470bg",
|
|
58
|
+
"smpte170m",
|
|
59
|
+
"unspecified"
|
|
60
|
+
]);
|
|
61
|
+
/**
|
|
62
|
+
* The matrix that brings HLG's linear light into BT.709, by the track's primaries: none for
|
|
63
|
+
* BT.709, BT.2087's for BT.2020, which BT.2100 means when a track names none. Undefined for
|
|
64
|
+
* primaries HLG is not recorded with, whose gamut is left as it is.
|
|
65
|
+
*/
|
|
66
|
+
var HLG_GAMUT_BY_PRIMARIES = {
|
|
67
|
+
bt709: IDENTITY_MATRIX3,
|
|
68
|
+
bt2020: BT2020_TO_BT709,
|
|
69
|
+
unspecified: BT2020_TO_BT709,
|
|
70
|
+
bt470bg: void 0,
|
|
71
|
+
smpte170m: void 0,
|
|
72
|
+
smpte432: void 0
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* A track's texels shown as recorded, its own matrix still corrected back to: what the player
|
|
76
|
+
* draws of SDR, and the measurements of a recording drawn in its own signal.
|
|
77
|
+
*/
|
|
78
|
+
function asRecordedOf({ matrix }) {
|
|
79
|
+
return {
|
|
80
|
+
kind: "as-recorded",
|
|
81
|
+
matrix
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function asRecordedFrom(colour) {
|
|
85
|
+
const conversion = asRecordedOf(colour);
|
|
86
|
+
return BT709_LIKE_PRIMARIES.has(colour.primaries) ? { conversion } : {
|
|
87
|
+
conversion,
|
|
88
|
+
problem: `${colour.primaries} primaries are shown as BT.709`
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function hlgFrom(colour) {
|
|
92
|
+
const gamut = HLG_GAMUT_BY_PRIMARIES[colour.primaries];
|
|
93
|
+
const conversion = {
|
|
94
|
+
kind: "hlg-to-sdr-bt709",
|
|
95
|
+
matrix: colour.matrix,
|
|
96
|
+
gamut: gamut ?? IDENTITY_MATRIX3,
|
|
97
|
+
tone: STUDIO_TONE
|
|
98
|
+
};
|
|
99
|
+
return gamut === void 0 ? {
|
|
100
|
+
conversion,
|
|
101
|
+
problem: `HLG of ${colour.primaries} primaries is shown without their gamut`
|
|
102
|
+
} : { conversion };
|
|
103
|
+
}
|
|
104
|
+
function notShown(transfer) {
|
|
105
|
+
return (colour) => ({
|
|
106
|
+
conversion: asRecordedOf(colour),
|
|
107
|
+
problem: `the ${transfer} transfer cannot be shown yet: drawn as recorded`
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The conversion of every transfer, from the track's colour: a transfer the player learns to
|
|
112
|
+
* name does not compile until it is given one.
|
|
113
|
+
*/
|
|
114
|
+
var CONVERSION_BY_TRANSFER = {
|
|
115
|
+
bt709: asRecordedFrom,
|
|
116
|
+
smpte170m: asRecordedFrom,
|
|
117
|
+
"iec61966-2-1": asRecordedFrom,
|
|
118
|
+
unspecified: asRecordedFrom,
|
|
119
|
+
hlg: hlgFrom,
|
|
120
|
+
pq: notShown("pq"),
|
|
121
|
+
linear: notShown("linear")
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Picks a conversion for each track's colour; a colour no conversion shows is drawn as recorded,
|
|
125
|
+
* with a warning, rather than refused: the picture is there, its colours wrong. Tracks that share
|
|
126
|
+
* a problem share its warning.
|
|
127
|
+
*/
|
|
128
|
+
function displayConversionsOf(colours) {
|
|
129
|
+
const choices = colours.map((colour) => CONVERSION_BY_TRANSFER[colour.transfer](colour));
|
|
130
|
+
const problems = choices.flatMap((choice) => choice.problem === void 0 ? [] : [choice.problem]);
|
|
131
|
+
return {
|
|
132
|
+
conversions: choices.map((choice) => choice.conversion),
|
|
133
|
+
warnings: [...new Set(problems)]
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
export { BT709_LUMINANCE, HLG_OETF, asRecordedOf, displayConversionsOf };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//#region ../../packages/core/src/domain/colour/TrackColour.ts
|
|
2
|
+
/**
|
|
3
|
+
* The values a video track's colour can name, as its bitstream says: the HEVC or AVC VUI, or the
|
|
4
|
+
* sample entry's `colr` box. Spelled as WebCodecs spells `VideoColorSpaceInit`, so an adapter
|
|
5
|
+
* passes values through; `unspecified` where the track says nothing, or something the player
|
|
6
|
+
* does not know.
|
|
7
|
+
*/
|
|
8
|
+
var COLOUR_PRIMARIES = [
|
|
9
|
+
"bt709",
|
|
10
|
+
"bt470bg",
|
|
11
|
+
"smpte170m",
|
|
12
|
+
"bt2020",
|
|
13
|
+
"smpte432"
|
|
14
|
+
];
|
|
15
|
+
var TRANSFER_CHARACTERISTICS = [
|
|
16
|
+
"bt709",
|
|
17
|
+
"smpte170m",
|
|
18
|
+
"iec61966-2-1",
|
|
19
|
+
"linear",
|
|
20
|
+
"pq",
|
|
21
|
+
"hlg"
|
|
22
|
+
];
|
|
23
|
+
var MATRIX_COEFFICIENTS = [
|
|
24
|
+
"rgb",
|
|
25
|
+
"bt709",
|
|
26
|
+
"bt470bg",
|
|
27
|
+
"smpte170m",
|
|
28
|
+
"bt2020-ncl"
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* A value as WebCodecs spells it, as the core names it: one of `names`, or unspecified for any
|
|
32
|
+
* other value or none.
|
|
33
|
+
*/
|
|
34
|
+
function namedOrUnspecified(names, value) {
|
|
35
|
+
return names.find((name) => name === value) ?? "unspecified";
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { COLOUR_PRIMARIES, MATRIX_COEFFICIENTS, TRANSFER_CHARACTERISTICS, namedOrUnspecified };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { IDENTITY_MATRIX3, multiplyMatrices } from "../../shared/math/Matrix3.js";
|
|
2
|
+
//#region ../../packages/core/src/domain/colour/matrixCorrection.ts
|
|
3
|
+
/**
|
|
4
|
+
* The weights of each matrix (ITU-R BT.709-6 item 3.2, BT.2020-2 table 4, BT.601-7 item 2.5.1,
|
|
5
|
+
* whose SD matrices BT.470BG and SMPTE 170M share); none for RGB or a matrix left unsaid.
|
|
6
|
+
*/
|
|
7
|
+
var LUMA_WEIGHTS = {
|
|
8
|
+
bt709: {
|
|
9
|
+
red: .2126,
|
|
10
|
+
blue: .0722
|
|
11
|
+
},
|
|
12
|
+
"bt2020-ncl": {
|
|
13
|
+
red: .2627,
|
|
14
|
+
blue: .0593
|
|
15
|
+
},
|
|
16
|
+
bt470bg: {
|
|
17
|
+
red: .299,
|
|
18
|
+
blue: .114
|
|
19
|
+
},
|
|
20
|
+
smpte170m: {
|
|
21
|
+
red: .299,
|
|
22
|
+
blue: .114
|
|
23
|
+
},
|
|
24
|
+
rgb: void 0,
|
|
25
|
+
unspecified: void 0
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The matrix that brings R′G′B′ a platform derived from Y′CbCr through `applied` to the R′G′B′
|
|
29
|
+
* `recorded` gives: WebKit's decoders convert with BT.709 whatever a stream says (ADR 0033). No
|
|
30
|
+
* correction when the two agree, or either is not known.
|
|
31
|
+
*/
|
|
32
|
+
function matrixCorrectionOf(recorded, applied) {
|
|
33
|
+
const to = LUMA_WEIGHTS[recorded];
|
|
34
|
+
const from = LUMA_WEIGHTS[applied];
|
|
35
|
+
return to === void 0 || from === void 0 || recorded === applied ? IDENTITY_MATRIX3 : multiplyMatrices(rgbFromYcbcr(to), ycbcrFromRgb(from));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* R′G′B′ of Y′, Pb and Pr.
|
|
39
|
+
*/
|
|
40
|
+
function rgbFromYcbcr({ red, blue }) {
|
|
41
|
+
const green = 1 - red - blue;
|
|
42
|
+
const redChroma = 2 * (1 - red);
|
|
43
|
+
const blueChroma = 2 * (1 - blue);
|
|
44
|
+
return [
|
|
45
|
+
1,
|
|
46
|
+
0,
|
|
47
|
+
redChroma,
|
|
48
|
+
1,
|
|
49
|
+
-blue * blueChroma / green,
|
|
50
|
+
-red * redChroma / green,
|
|
51
|
+
1,
|
|
52
|
+
blueChroma,
|
|
53
|
+
0
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Y′, Pb and Pr of R′G′B′.
|
|
58
|
+
*/
|
|
59
|
+
function ycbcrFromRgb({ red, blue }) {
|
|
60
|
+
const green = 1 - red - blue;
|
|
61
|
+
const blueChroma = 2 * (1 - blue);
|
|
62
|
+
const redChroma = 2 * (1 - red);
|
|
63
|
+
return [
|
|
64
|
+
red,
|
|
65
|
+
green,
|
|
66
|
+
blue,
|
|
67
|
+
-red / blueChroma,
|
|
68
|
+
-green / blueChroma,
|
|
69
|
+
(1 - blue) / blueChroma,
|
|
70
|
+
(1 - red) / redChroma,
|
|
71
|
+
-green / redChroma,
|
|
72
|
+
-blue / redChroma
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { matrixCorrectionOf };
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
//#region ../../packages/core/src/domain/format/calibration/CalibrationVersion.ts
|
|
2
2
|
/**
|
|
3
|
-
* Which calibration string a set was read from
|
|
4
|
-
* `
|
|
5
|
-
* their version word (the X5 recordings; insta360-rs docs); the legacy one declares
|
|
3
|
+
* Which calibration string a set was read from: `offset` (1), `offset_v2` (2), `offset_v3` (3)
|
|
4
|
+
* and `offset_v6` (6, the Mei model with more terms). The versioned strings declare theirs in the
|
|
5
|
+
* high bits of their version word (the X5 recordings; insta360-rs docs); the legacy one declares
|
|
6
|
+
* none. The number says nothing of which reading draws the lenses best: that is the calibration
|
|
7
|
+
* preference's (ADR 0023).
|
|
6
8
|
*/
|
|
7
9
|
var CalibrationVersion = {
|
|
8
10
|
Legacy: 1,
|
|
9
11
|
Polynomial: 2,
|
|
10
|
-
Mei: 3
|
|
12
|
+
Mei: 3,
|
|
13
|
+
ExtendedMei: 6
|
|
11
14
|
};
|
|
12
15
|
//#endregion
|
|
13
16
|
export { CalibrationVersion };
|
|
@@ -8,7 +8,7 @@ function eulerDegrees(yaw, pitch, roll) {
|
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* For the versioned strings (v2, v3): what is wrong with a version word that does not declare
|
|
11
|
+
* For the versioned strings (v2, v3, v6): what is wrong with a version word that does not declare
|
|
12
12
|
* `expected` in its high bits, if anything.
|
|
13
13
|
*/
|
|
14
14
|
function versionWordMismatch(versionWord, expected) {
|
|
@@ -1,45 +1,119 @@
|
|
|
1
|
-
import { V3Token } from "../offsetTokens.js";
|
|
1
|
+
import { MeiToken, V3Token, V6Token } from "../offsetTokens.js";
|
|
2
2
|
import { canvasOfFirstBlock, eulerDegrees, versionWordMismatch } from "./CalibrationStringLayout.js";
|
|
3
3
|
import { CalibrationVersion } from "../CalibrationVersion.js";
|
|
4
4
|
import { MeiModel } from "../../../optics/MeiModel.js";
|
|
5
|
+
import { RADIAL_AND_FIRST_PAIR } from "../v6TermReading.js";
|
|
5
6
|
//#region ../../packages/core/src/domain/format/calibration/layouts/MeiCalibrationLayout.ts
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
-
* lens, then a version word with 3 in its high 16 bits.
|
|
8
|
+
* The layout of a Mei string version, a version word after its lens blocks.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
function meiLayout(format) {
|
|
11
|
+
return {
|
|
12
|
+
version: format.version,
|
|
13
|
+
lensTokens: format.lensTokens,
|
|
14
|
+
trailingTokens: 1,
|
|
15
|
+
radialScale: format.radialScale,
|
|
16
|
+
versionWordProblem: (versionWord) => versionWordMismatch(versionWord, format.version),
|
|
17
|
+
parseLens: (block, lensIndex) => meiLensOf(block, lensIndex, format),
|
|
18
|
+
canvasOf: (_numbers, blocks) => canvasOfFirstBlock(blocks, format.canvasTokens.width, format.canvasTokens.height)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function meiLensOf(block, lensIndex, format) {
|
|
22
|
+
return {
|
|
23
|
+
lensIndex,
|
|
24
|
+
model: new MeiModel({
|
|
25
|
+
xi: block(MeiToken.Xi),
|
|
26
|
+
focal: [block(MeiToken.FocalX), block(MeiToken.FocalY)],
|
|
27
|
+
principalPoint: {
|
|
28
|
+
x: block(MeiToken.CenterX),
|
|
29
|
+
y: block(MeiToken.CenterY)
|
|
30
|
+
},
|
|
31
|
+
distortion: format.distortionOf(block)
|
|
32
|
+
}),
|
|
33
|
+
orientation: eulerDegrees(block(MeiToken.Yaw), block(MeiToken.Pitch), block(MeiToken.Roll)),
|
|
34
|
+
translation: [
|
|
35
|
+
block(MeiToken.TranslationX),
|
|
36
|
+
block(MeiToken.TranslationY),
|
|
37
|
+
block(MeiToken.TranslationZ)
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `offset_v3`: the Mei tokens, then `k1 k2 k3 p1 p2 width height type` per lens, and a version
|
|
43
|
+
* word with 3 in its high 16 bits. Drawn as read: the X5, the only camera seen to write it,
|
|
44
|
+
* stitches through its legacy string (ADR 0023).
|
|
45
|
+
*/
|
|
46
|
+
var MEI_CALIBRATION_LAYOUT = meiLayout({
|
|
11
47
|
version: CalibrationVersion.Mei,
|
|
12
48
|
lensTokens: 19,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
lensIndex,
|
|
18
|
-
model: new MeiModel({
|
|
19
|
-
xi: block(V3Token.Xi),
|
|
20
|
-
focal: [block(V3Token.FocalX), block(V3Token.FocalY)],
|
|
21
|
-
principalPoint: {
|
|
22
|
-
x: block(V3Token.CenterX),
|
|
23
|
-
y: block(V3Token.CenterY)
|
|
24
|
-
},
|
|
25
|
-
radial: [
|
|
26
|
-
block(V3Token.K1),
|
|
27
|
-
block(V3Token.K2),
|
|
28
|
-
block(V3Token.K3)
|
|
29
|
-
],
|
|
30
|
-
tangential: [block(V3Token.P1), block(V3Token.P2)]
|
|
31
|
-
}),
|
|
32
|
-
orientation: eulerDegrees(block(V3Token.Yaw), block(V3Token.Pitch), block(V3Token.Roll)),
|
|
33
|
-
translation: [
|
|
34
|
-
block(V3Token.TranslationX),
|
|
35
|
-
block(V3Token.TranslationY),
|
|
36
|
-
block(V3Token.TranslationZ)
|
|
37
|
-
]
|
|
38
|
-
};
|
|
49
|
+
canvasTokens: {
|
|
50
|
+
width: V3Token.CanvasWidth,
|
|
51
|
+
height: V3Token.CanvasHeight
|
|
39
52
|
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
distortionOf: (block) => ({
|
|
54
|
+
radial: [
|
|
55
|
+
block(V3Token.K1),
|
|
56
|
+
block(V3Token.K2),
|
|
57
|
+
block(V3Token.K3)
|
|
58
|
+
],
|
|
59
|
+
tangential: [{
|
|
60
|
+
p1: block(V3Token.P1),
|
|
61
|
+
p2: block(V3Token.P2)
|
|
62
|
+
}],
|
|
63
|
+
thinPrism: []
|
|
64
|
+
}),
|
|
65
|
+
radialScale: 1
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* The radial scale a v6 reading is drawn at, measured on the X6, the one camera seen to stitch
|
|
69
|
+
* through it: Insta360 Studio's far field and the seam's far bins agree on it to 0.3 percent
|
|
70
|
+
* (ADR 0023). Provisional, from one unit; the X5's own v6 strings would want 1.02 to 1.04, but
|
|
71
|
+
* the X5 stitches through its legacy string.
|
|
72
|
+
*/
|
|
73
|
+
var V6_RADIAL_SCALE = 1.008;
|
|
74
|
+
/**
|
|
75
|
+
* `offset_v6`: the Mei tokens, then `k1..k5 p1..p4 s1..s4 width height type` per lens, and a
|
|
76
|
+
* version word with 6 in its high 16 bits; its distortion tokens read by `reading` (ADR 0032).
|
|
77
|
+
*/
|
|
78
|
+
function extendedMeiLayout(reading) {
|
|
79
|
+
return meiLayout({
|
|
80
|
+
version: CalibrationVersion.ExtendedMei,
|
|
81
|
+
lensTokens: 27,
|
|
82
|
+
canvasTokens: {
|
|
83
|
+
width: V6Token.CanvasWidth,
|
|
84
|
+
height: V6Token.CanvasHeight
|
|
85
|
+
},
|
|
86
|
+
distortionOf: (block) => reading(v6DistortionTokensOf(block)),
|
|
87
|
+
radialScale: V6_RADIAL_SCALE
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* `offset_v6` as the player reads it: its radial terms and first tangential pair (ADR 0032,
|
|
92
|
+
* provisional).
|
|
93
|
+
*/
|
|
94
|
+
var EXTENDED_MEI_CALIBRATION_LAYOUT = extendedMeiLayout(RADIAL_AND_FIRST_PAIR);
|
|
95
|
+
function v6DistortionTokensOf(block) {
|
|
96
|
+
return {
|
|
97
|
+
radial: [
|
|
98
|
+
block(V6Token.K1),
|
|
99
|
+
block(V6Token.K2),
|
|
100
|
+
block(V6Token.K3),
|
|
101
|
+
block(V6Token.K4),
|
|
102
|
+
block(V6Token.K5)
|
|
103
|
+
],
|
|
104
|
+
tangential: [
|
|
105
|
+
block(V6Token.P1),
|
|
106
|
+
block(V6Token.P2),
|
|
107
|
+
block(V6Token.P3),
|
|
108
|
+
block(V6Token.P4)
|
|
109
|
+
],
|
|
110
|
+
thinPrism: [
|
|
111
|
+
block(V6Token.S1),
|
|
112
|
+
block(V6Token.S2),
|
|
113
|
+
block(V6Token.S3),
|
|
114
|
+
block(V6Token.S4)
|
|
115
|
+
]
|
|
116
|
+
};
|
|
117
|
+
}
|
|
44
118
|
//#endregion
|
|
45
|
-
export { MEI_CALIBRATION_LAYOUT };
|
|
119
|
+
export { EXTENDED_MEI_CALIBRATION_LAYOUT, MEI_CALIBRATION_LAYOUT, extendedMeiLayout, meiLayout };
|
package/dist/packages/core/src/domain/format/calibration/layouts/PolynomialCalibrationLayout.js
CHANGED
|
@@ -11,6 +11,7 @@ var POLYNOMIAL_CALIBRATION_LAYOUT = {
|
|
|
11
11
|
version: CalibrationVersion.Polynomial,
|
|
12
12
|
lensTokens: 16,
|
|
13
13
|
trailingTokens: 1,
|
|
14
|
+
radialScale: 1,
|
|
14
15
|
versionWordProblem: (versionWord) => versionWordMismatch(versionWord, CalibrationVersion.Polynomial),
|
|
15
16
|
parseLens(block, lensIndex) {
|
|
16
17
|
return {
|
|
@@ -31,7 +31,10 @@ var V2Token = {
|
|
|
31
31
|
CanvasHeight: 14,
|
|
32
32
|
LensType: 15
|
|
33
33
|
};
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* The tokens every Mei string (v3, v6) starts its lens block with; each version's own follow.
|
|
36
|
+
*/
|
|
37
|
+
var MeiToken = {
|
|
35
38
|
Xi: 0,
|
|
36
39
|
FocalX: 1,
|
|
37
40
|
FocalY: 2,
|
|
@@ -42,7 +45,9 @@ var V3Token = {
|
|
|
42
45
|
Roll: 7,
|
|
43
46
|
TranslationX: 8,
|
|
44
47
|
TranslationY: 9,
|
|
45
|
-
TranslationZ: 10
|
|
48
|
+
TranslationZ: 10
|
|
49
|
+
};
|
|
50
|
+
var V3Token = {
|
|
46
51
|
K1: 11,
|
|
47
52
|
K2: 12,
|
|
48
53
|
K3: 13,
|
|
@@ -53,8 +58,32 @@ var V3Token = {
|
|
|
53
58
|
LensType: 18
|
|
54
59
|
};
|
|
55
60
|
/**
|
|
61
|
+
* `offset_v6` after the Mei tokens: five radial terms, four tangential and four thin-prism
|
|
62
|
+
* tokens, then the canvas and the lens type. The order is insta360-rs's (`docs/INSV_FORMAT.md`),
|
|
63
|
+
* confirmed on the X5, whose v6 and v3 strings agree on the Mei tokens, the canvas and the lens
|
|
64
|
+
* type (ADR 0032).
|
|
65
|
+
*/
|
|
66
|
+
var V6Token = {
|
|
67
|
+
K1: 11,
|
|
68
|
+
K2: 12,
|
|
69
|
+
K3: 13,
|
|
70
|
+
K4: 14,
|
|
71
|
+
K5: 15,
|
|
72
|
+
P1: 16,
|
|
73
|
+
P2: 17,
|
|
74
|
+
P3: 18,
|
|
75
|
+
P4: 19,
|
|
76
|
+
S1: 20,
|
|
77
|
+
S2: 21,
|
|
78
|
+
S3: 22,
|
|
79
|
+
S4: 23,
|
|
80
|
+
CanvasWidth: 24,
|
|
81
|
+
CanvasHeight: 25,
|
|
82
|
+
LensType: 26
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
56
85
|
* Tokens after the lens blocks. v1 ends with canvas width, canvas height and a version word;
|
|
57
|
-
* v2 and
|
|
86
|
+
* v2, v3 and v6 end with the version word only.
|
|
58
87
|
*/
|
|
59
88
|
var V1Trailing = {
|
|
60
89
|
CanvasWidth: 0,
|
|
@@ -62,4 +91,4 @@ var V1Trailing = {
|
|
|
62
91
|
VersionWord: 2
|
|
63
92
|
};
|
|
64
93
|
//#endregion
|
|
65
|
-
export { V1Token, V1Trailing, V2Token, V3Token };
|
|
94
|
+
export { MeiToken, V1Token, V1Trailing, V2Token, V3Token, V6Token };
|