@xmaxai/web-sdk 1.0.7 → 1.0.9
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/README.md +117 -18
- package/dist/RecordingProcessor-4TP5NICO.cjs +211 -0
- package/dist/RecordingProcessor-4TP5NICO.cjs.map +1 -0
- package/dist/RecordingProcessor-ZSBJFF4J.js +211 -0
- package/dist/RecordingProcessor-ZSBJFF4J.js.map +1 -0
- package/dist/{VideoRenderStatistics-C7zqzfuS.d.cts → TrajectoryEffectRendering-C7E2KJbV.d.cts} +48 -1
- package/dist/{VideoRenderStatistics-C7zqzfuS.d.ts → TrajectoryEffectRendering-C7E2KJbV.d.ts} +48 -1
- package/dist/chunk-4DE2IREA.cjs +8 -0
- package/dist/chunk-4DE2IREA.cjs.map +1 -0
- package/dist/{chunk-4O5BSMUX.js → chunk-ILZL4W2G.js} +2438 -425
- package/dist/chunk-ILZL4W2G.js.map +1 -0
- package/dist/{chunk-EKOYOFES.cjs → chunk-KROY2O4A.cjs} +2999 -986
- package/dist/chunk-KROY2O4A.cjs.map +1 -0
- package/dist/chunk-V6TY7KAL.js +8 -0
- package/dist/chunk-V6TY7KAL.js.map +1 -0
- package/dist/index.cjs +7 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +197 -43
- package/dist/index.d.ts +197 -43
- package/dist/index.js +6 -1
- package/dist/react/index.cjs +25 -4
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +17 -1
- package/dist/react/index.d.ts +17 -1
- package/dist/react/index.js +22 -1
- package/dist/react/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/chunk-4O5BSMUX.js.map +0 -1
- package/dist/chunk-EKOYOFES.cjs.map +0 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__publicField
|
|
3
|
+
} from "./chunk-V6TY7KAL.js";
|
|
4
|
+
|
|
5
|
+
// src/Media/Recording/RecordingProcessor.ts
|
|
6
|
+
import {
|
|
7
|
+
BlobSource,
|
|
8
|
+
BufferTarget,
|
|
9
|
+
EncodedAudioPacketSource,
|
|
10
|
+
EncodedPacketSink,
|
|
11
|
+
EncodedVideoPacketSource,
|
|
12
|
+
Input,
|
|
13
|
+
MP4,
|
|
14
|
+
WEBM,
|
|
15
|
+
Mp4OutputFormat,
|
|
16
|
+
Output,
|
|
17
|
+
WebMOutputFormat
|
|
18
|
+
} from "mediabunny";
|
|
19
|
+
|
|
20
|
+
// src/Media/Recording/RecordingTimeline.ts
|
|
21
|
+
var _RecordingTimeline = class _RecordingTimeline {
|
|
22
|
+
/**
|
|
23
|
+
* 从显示时间戳估计正常帧间隔,只裁掉显著超长的等待部分。
|
|
24
|
+
*/
|
|
25
|
+
constructor(timestamps, duration, audioPackets) {
|
|
26
|
+
__publicField(this, "duration", duration);
|
|
27
|
+
/**
|
|
28
|
+
* 原始时长、正常帧时长与待删除区间
|
|
29
|
+
*/
|
|
30
|
+
__publicField(this, "frameDuration");
|
|
31
|
+
__publicField(this, "cuts");
|
|
32
|
+
if (!Number.isFinite(duration) || duration <= 0 || timestamps.length === 0 || timestamps.some((value) => !Number.isFinite(value) || value < 0 || value > duration)) {
|
|
33
|
+
throw new Error("Invalid recording timeline");
|
|
34
|
+
}
|
|
35
|
+
const sorted = [...timestamps].sort((a, b) => a - b);
|
|
36
|
+
const intervals = sorted.slice(1).map((time, index) => time - sorted[index]).filter((value) => value > 0).sort((a, b) => a - b);
|
|
37
|
+
this.frameDuration = intervals[Math.floor(intervals.length / 2)] ?? _RecordingTimeline.fallbackFrameDuration;
|
|
38
|
+
const threshold = Math.max(_RecordingTimeline.minimumGap, this.frameDuration * _RecordingTimeline.gapMultiplier);
|
|
39
|
+
const cuts = sorted.flatMap((start, index) => {
|
|
40
|
+
const end = sorted[index + 1] ?? duration;
|
|
41
|
+
return end - start > threshold + 1e-6 ? [{ start: start + this.frameDuration, end }] : [];
|
|
42
|
+
});
|
|
43
|
+
this.cuts = audioPackets ? cuts.flatMap((cut) => {
|
|
44
|
+
const contained = audioPackets.filter((packet) => packet.end > packet.start && packet.start >= cut.start && packet.end <= cut.end);
|
|
45
|
+
if (contained.length === 0) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return [{
|
|
49
|
+
start: Math.min(...contained.map((packet) => packet.start)),
|
|
50
|
+
end: Math.max(...contained.map((packet) => packet.end))
|
|
51
|
+
}];
|
|
52
|
+
}) : cuts;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 将原始时间映射到裁剪后的时间;删除区间内的时刻映射到同一接缝。
|
|
56
|
+
*/
|
|
57
|
+
map(time) {
|
|
58
|
+
let removed = 0;
|
|
59
|
+
for (const cut of this.cuts) {
|
|
60
|
+
if (time <= cut.start) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
removed += Math.min(time, cut.end) - cut.start;
|
|
64
|
+
}
|
|
65
|
+
return time - removed;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 判断一个音频包是否位于删除区间;区间已对齐包边界,不会切断压缩数据。
|
|
69
|
+
*/
|
|
70
|
+
removes(start, end) {
|
|
71
|
+
return this.cuts.some((cut) => start >= cut.start && end <= cut.end);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* 长间隔判定与默认帧时长
|
|
76
|
+
*/
|
|
77
|
+
__publicField(_RecordingTimeline, "minimumGap", 0.12);
|
|
78
|
+
__publicField(_RecordingTimeline, "gapMultiplier", 3);
|
|
79
|
+
__publicField(_RecordingTimeline, "fallbackFrameDuration", 1 / 30);
|
|
80
|
+
var RecordingTimeline = _RecordingTimeline;
|
|
81
|
+
|
|
82
|
+
// src/Media/Recording/RecordingProcessor.ts
|
|
83
|
+
var _RecordingProcessor = class _RecordingProcessor {
|
|
84
|
+
/**
|
|
85
|
+
* 裁剪成功返回新文件,无需裁剪时返回原文件;失败交由调用方保留原始录像。
|
|
86
|
+
*/
|
|
87
|
+
async process(blob) {
|
|
88
|
+
if (blob.size > _RecordingProcessor.maximumBytes) {
|
|
89
|
+
throw new Error("Recording is too large to process");
|
|
90
|
+
}
|
|
91
|
+
const input = new Input({ source: new BlobSource(blob), formats: [MP4, WEBM] });
|
|
92
|
+
const controller = new AbortController();
|
|
93
|
+
let output;
|
|
94
|
+
let timer;
|
|
95
|
+
const timeout = new Promise((_, reject) => {
|
|
96
|
+
timer = setTimeout(() => {
|
|
97
|
+
controller.abort();
|
|
98
|
+
reject(new Error("Recording processing timed out"));
|
|
99
|
+
}, _RecordingProcessor.timeoutMs);
|
|
100
|
+
});
|
|
101
|
+
try {
|
|
102
|
+
return await Promise.race([
|
|
103
|
+
this.rewrite(input, blob, controller.signal, (value) => {
|
|
104
|
+
output = value;
|
|
105
|
+
}),
|
|
106
|
+
timeout
|
|
107
|
+
]);
|
|
108
|
+
} finally {
|
|
109
|
+
controller.abort();
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
input.dispose();
|
|
112
|
+
if (output && output.state !== "finalized" && output.state !== "canceled") {
|
|
113
|
+
void output.cancel().catch(() => {
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 读取有限数量的编码包,维持原始解码顺序。
|
|
120
|
+
*/
|
|
121
|
+
async readPackets(track, signal) {
|
|
122
|
+
const packets = [];
|
|
123
|
+
for await (const packet of new EncodedPacketSink(track).packets()) {
|
|
124
|
+
signal.throwIfAborted();
|
|
125
|
+
packets.push(packet);
|
|
126
|
+
if (packets.length > _RecordingProcessor.maximumPackets) {
|
|
127
|
+
throw new Error("Recording has too many media packets");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return packets;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 保留所有视频帧,删除等待区间内的完整音频包,并重新封装两条时间线。
|
|
134
|
+
*/
|
|
135
|
+
async rewrite(input, original, signal, registerOutput) {
|
|
136
|
+
const video = await input.getPrimaryVideoTrack();
|
|
137
|
+
if (!video) {
|
|
138
|
+
throw new Error("Recording has no video track");
|
|
139
|
+
}
|
|
140
|
+
const videoPackets = await this.readPackets(video, signal);
|
|
141
|
+
const audio = await input.getPrimaryAudioTrack();
|
|
142
|
+
const audioPackets = audio ? await this.readPackets(audio, signal) : [];
|
|
143
|
+
const duration = await input.computeDuration();
|
|
144
|
+
const audioRanges = audioPackets.map((packet, index) => ({
|
|
145
|
+
start: packet.timestamp,
|
|
146
|
+
end: packet.duration > 0 ? packet.timestamp + packet.duration : audioPackets[index + 1]?.timestamp ?? duration
|
|
147
|
+
}));
|
|
148
|
+
const timeline = new RecordingTimeline(videoPackets.map((packet) => packet.timestamp), duration, audio ? audioRanges : void 0);
|
|
149
|
+
if (timeline.cuts.length === 0) {
|
|
150
|
+
return original;
|
|
151
|
+
}
|
|
152
|
+
const videoCodec = await video.getCodec();
|
|
153
|
+
const videoConfig = await video.getDecoderConfig();
|
|
154
|
+
const audioCodec = await audio?.getCodec();
|
|
155
|
+
const audioConfig = await audio?.getDecoderConfig();
|
|
156
|
+
if (!videoCodec || !videoConfig || audio && (!audioCodec || !audioConfig)) {
|
|
157
|
+
throw new Error("Unsupported recording codec");
|
|
158
|
+
}
|
|
159
|
+
const isWebM = (await input.getFormat()).name === WEBM.name;
|
|
160
|
+
const rotation = await video.getRotation();
|
|
161
|
+
const flip = await video.getFlip();
|
|
162
|
+
signal.throwIfAborted();
|
|
163
|
+
const output = new Output({
|
|
164
|
+
format: isWebM ? new WebMOutputFormat() : new Mp4OutputFormat(),
|
|
165
|
+
target: new BufferTarget()
|
|
166
|
+
});
|
|
167
|
+
registerOutput(output);
|
|
168
|
+
const videoSource = new EncodedVideoPacketSource(videoCodec);
|
|
169
|
+
output.addVideoTrack(videoSource, { rotation, flip });
|
|
170
|
+
const audioSource = audioCodec ? new EncodedAudioPacketSource(audioCodec) : void 0;
|
|
171
|
+
if (audioSource) {
|
|
172
|
+
output.addAudioTrack(audioSource);
|
|
173
|
+
}
|
|
174
|
+
await output.start();
|
|
175
|
+
for (const packet of videoPackets) {
|
|
176
|
+
signal.throwIfAborted();
|
|
177
|
+
const timestamp = timeline.map(packet.timestamp);
|
|
178
|
+
const duration2 = timeline.map(packet.timestamp + packet.duration) - timestamp;
|
|
179
|
+
await videoSource.add(packet.clone({ timestamp, duration: duration2 }), { decoderConfig: videoConfig });
|
|
180
|
+
}
|
|
181
|
+
videoSource.close();
|
|
182
|
+
if (audioSource && audioConfig) {
|
|
183
|
+
for (const [index, packet] of audioPackets.entries()) {
|
|
184
|
+
signal.throwIfAborted();
|
|
185
|
+
const range = audioRanges[index];
|
|
186
|
+
if (timeline.removes(range.start, range.end)) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
await audioSource.add(packet.clone({ timestamp: timeline.map(packet.timestamp) }), { decoderConfig: audioConfig });
|
|
190
|
+
}
|
|
191
|
+
audioSource.close();
|
|
192
|
+
}
|
|
193
|
+
signal.throwIfAborted();
|
|
194
|
+
await output.finalize();
|
|
195
|
+
if (!output.target.buffer || output.target.buffer.byteLength > _RecordingProcessor.maximumBytes) {
|
|
196
|
+
throw new Error("Processed recording exceeds the memory limit");
|
|
197
|
+
}
|
|
198
|
+
return new Blob([output.target.buffer], { type: output.format.mimeType });
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* 后处理资源上限,与实时连接的清理超时分离
|
|
203
|
+
*/
|
|
204
|
+
__publicField(_RecordingProcessor, "timeoutMs", 1e4);
|
|
205
|
+
__publicField(_RecordingProcessor, "maximumBytes", 64 * 1024 * 1024);
|
|
206
|
+
__publicField(_RecordingProcessor, "maximumPackets", 1e4);
|
|
207
|
+
var RecordingProcessor = _RecordingProcessor;
|
|
208
|
+
export {
|
|
209
|
+
RecordingProcessor
|
|
210
|
+
};
|
|
211
|
+
//# sourceMappingURL=RecordingProcessor-ZSBJFF4J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Media/Recording/RecordingProcessor.ts","../src/Media/Recording/RecordingTimeline.ts"],"sourcesContent":["import {\n BlobSource, BufferTarget, EncodedAudioPacketSource, EncodedPacketSink,\n EncodedVideoPacketSource, Input, MP4, WEBM, Mp4OutputFormat, Output, WebMOutputFormat,\n type EncodedPacket, type InputTrack,\n} from \"mediabunny\";\nimport { RecordingTimeline } from \"./RecordingTimeline\";\n\n/**\n * 录制完成后裁掉长帧等待;音视频共用按音频包边界对齐的时间映射,不重新编码。\n */\nexport class RecordingProcessor {\n /**\n * 后处理资源上限,与实时连接的清理超时分离\n */\n private static readonly timeoutMs = 10_000;\n private static readonly maximumBytes = 64 * 1024 * 1024;\n private static readonly maximumPackets = 10_000;\n\n /**\n * 裁剪成功返回新文件,无需裁剪时返回原文件;失败交由调用方保留原始录像。\n */\n async process(blob: Blob): Promise<Blob> {\n if (blob.size > RecordingProcessor.maximumBytes) {\n throw new Error(\"Recording is too large to process\");\n }\n\n const input = new Input({ source: new BlobSource(blob), formats: [MP4, WEBM] });\n const controller = new AbortController();\n let output: Output | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new Error(\"Recording processing timed out\"));\n }, RecordingProcessor.timeoutMs);\n });\n\n try {\n return await Promise.race([\n this.rewrite(input, blob, controller.signal, value => { output = value; }),\n timeout,\n ]);\n } finally {\n controller.abort();\n clearTimeout(timer);\n input.dispose();\n if (output && output.state !== \"finalized\" && output.state !== \"canceled\") {\n void output.cancel().catch(() => {});\n }\n }\n }\n\n /**\n * 读取有限数量的编码包,维持原始解码顺序。\n */\n private async readPackets(track: InputTrack, signal: AbortSignal): Promise<EncodedPacket[]> {\n const packets: EncodedPacket[] = [];\n for await (const packet of new EncodedPacketSink(track).packets()) {\n signal.throwIfAborted();\n packets.push(packet);\n if (packets.length > RecordingProcessor.maximumPackets) {\n throw new Error(\"Recording has too many media packets\");\n }\n }\n return packets;\n }\n\n /**\n * 保留所有视频帧,删除等待区间内的完整音频包,并重新封装两条时间线。\n */\n private async rewrite(\n input: Input,\n original: Blob,\n signal: AbortSignal,\n registerOutput: (output: Output) => void,\n ): Promise<Blob> {\n const video = await input.getPrimaryVideoTrack();\n if (!video) {\n throw new Error(\"Recording has no video track\");\n }\n const videoPackets = await this.readPackets(video, signal);\n const audio = await input.getPrimaryAudioTrack();\n const audioPackets = audio ? await this.readPackets(audio, signal) : [];\n const duration = await input.computeDuration();\n const audioRanges = audioPackets.map((packet, index) => ({\n start: packet.timestamp,\n end: packet.duration > 0 ? packet.timestamp + packet.duration : audioPackets[index + 1]?.timestamp ?? duration,\n }));\n const timeline = new RecordingTimeline(videoPackets.map(packet => packet.timestamp), duration, audio ? audioRanges : undefined);\n if (timeline.cuts.length === 0) {\n return original;\n }\n\n const videoCodec = await video.getCodec();\n const videoConfig = await video.getDecoderConfig();\n const audioCodec = await audio?.getCodec();\n const audioConfig = await audio?.getDecoderConfig();\n if (!videoCodec || !videoConfig || (audio && (!audioCodec || !audioConfig))) {\n throw new Error(\"Unsupported recording codec\");\n }\n const isWebM = (await input.getFormat()).name === WEBM.name;\n const rotation = await video.getRotation();\n const flip = await video.getFlip();\n signal.throwIfAborted();\n\n const output = new Output({\n format: isWebM ? new WebMOutputFormat() : new Mp4OutputFormat(),\n target: new BufferTarget(),\n });\n registerOutput(output);\n const videoSource = new EncodedVideoPacketSource(videoCodec);\n output.addVideoTrack(videoSource, { rotation, flip });\n const audioSource = audioCodec ? new EncodedAudioPacketSource(audioCodec) : undefined;\n if (audioSource) {\n output.addAudioTrack(audioSource);\n }\n await output.start();\n\n // 不指定固定帧率,避免容器把原本不同的显示时间戳量化到同一帧。\n for (const packet of videoPackets) {\n signal.throwIfAborted();\n const timestamp = timeline.map(packet.timestamp);\n const duration = timeline.map(packet.timestamp + packet.duration) - timestamp;\n await videoSource.add(packet.clone({ timestamp, duration }), { decoderConfig: videoConfig });\n }\n videoSource.close();\n\n if (audioSource && audioConfig) {\n for (const [index, packet] of audioPackets.entries()) {\n signal.throwIfAborted();\n const range = audioRanges[index]!;\n if (timeline.removes(range.start, range.end)) {\n continue;\n }\n await audioSource.add(packet.clone({ timestamp: timeline.map(packet.timestamp) }), { decoderConfig: audioConfig });\n }\n audioSource.close();\n }\n signal.throwIfAborted();\n await output.finalize();\n if (!output.target.buffer || output.target.buffer.byteLength > RecordingProcessor.maximumBytes) {\n throw new Error(\"Processed recording exceeds the memory limit\");\n }\n return new Blob([output.target.buffer], { type: output.format.mimeType });\n }\n}\n","/**\n * 原始录制时间线上的区间,单位为秒。\n */\nexport interface RecordingTimeRange {\n start: number;\n end: number;\n}\n\n/**\n * 视频长帧裁剪计划。音视频共用同一映射,避免分别累计时间造成漂移。\n */\nexport class RecordingTimeline {\n /**\n * 长间隔判定与默认帧时长\n */\n private static readonly minimumGap = 0.12;\n private static readonly gapMultiplier = 3;\n private static readonly fallbackFrameDuration = 1 / 30;\n\n /**\n * 原始时长、正常帧时长与待删除区间\n */\n readonly frameDuration: number;\n readonly cuts: readonly RecordingTimeRange[];\n\n /**\n * 从显示时间戳估计正常帧间隔,只裁掉显著超长的等待部分。\n */\n constructor(timestamps: readonly number[], readonly duration: number, audioPackets?: readonly RecordingTimeRange[]) {\n if (!Number.isFinite(duration) || duration <= 0 || timestamps.length === 0 ||\n timestamps.some(value => !Number.isFinite(value) || value < 0 || value > duration)) {\n throw new Error(\"Invalid recording timeline\");\n }\n\n const sorted = [...timestamps].sort((a, b) => a - b);\n const intervals = sorted.slice(1).map((time, index) => time - sorted[index]!)\n .filter(value => value > 0).sort((a, b) => a - b);\n this.frameDuration = intervals[Math.floor(intervals.length / 2)] ?? RecordingTimeline.fallbackFrameDuration;\n const threshold = Math.max(RecordingTimeline.minimumGap, this.frameDuration * RecordingTimeline.gapMultiplier);\n\n const cuts = sorted.flatMap((start, index) => {\n const end = sorted[index + 1] ?? duration;\n return end - start > threshold + 1e-6 ? [{ start: start + this.frameDuration, end }] : [];\n });\n\n // 只删除完全落在等待区间内的音频包;同一裁剪边界同时用于视频,避免重编码延迟。\n this.cuts = audioPackets ? cuts.flatMap(cut => {\n const contained = audioPackets.filter(packet => packet.end > packet.start &&\n packet.start >= cut.start && packet.end <= cut.end);\n if (contained.length === 0) {\n return [];\n }\n return [{\n start: Math.min(...contained.map(packet => packet.start)),\n end: Math.max(...contained.map(packet => packet.end)),\n }];\n }) : cuts;\n }\n\n /**\n * 将原始时间映射到裁剪后的时间;删除区间内的时刻映射到同一接缝。\n */\n map(time: number): number {\n let removed = 0;\n for (const cut of this.cuts) {\n if (time <= cut.start) {\n break;\n }\n removed += Math.min(time, cut.end) - cut.start;\n }\n return time - removed;\n }\n\n /**\n * 判断一个音频包是否位于删除区间;区间已对齐包边界,不会切断压缩数据。\n */\n removes(start: number, end: number): boolean {\n return this.cuts.some(cut => start >= cut.start && end <= cut.end);\n }\n}\n"],"mappings":"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","names":["duration"]}
|
package/dist/{VideoRenderStatistics-C7zqzfuS.d.cts → TrajectoryEffectRendering-C7E2KJbV.d.cts}
RENAMED
|
@@ -212,4 +212,51 @@ interface VideoRenderStatistics {
|
|
|
212
212
|
readonly interpolatedFrameRate: number;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
|
|
215
|
+
/**
|
|
216
|
+
* 单次按下到释放期间稳定的轨迹标识,不依赖浏览器复用的 pointerId。
|
|
217
|
+
*/
|
|
218
|
+
type TrajectoryID = number;
|
|
219
|
+
/**
|
|
220
|
+
* 供视觉效果使用的触点;location 为视口 CSS 像素,timestamp 为毫秒。
|
|
221
|
+
*/
|
|
222
|
+
interface TrajectoryPoint {
|
|
223
|
+
readonly id: TrajectoryID;
|
|
224
|
+
readonly location: Readonly<{
|
|
225
|
+
x: number;
|
|
226
|
+
y: number;
|
|
227
|
+
}>;
|
|
228
|
+
readonly normalizedLocation: Readonly<{
|
|
229
|
+
x: number;
|
|
230
|
+
y: number;
|
|
231
|
+
}>;
|
|
232
|
+
readonly timestamp: number;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 可替换的轨迹视觉效果;不参与触点采样、坐标转换或网络发送。
|
|
237
|
+
* 一个实例仅供一个视图使用,reset 必须释放动画和清空轨迹。
|
|
238
|
+
*/
|
|
239
|
+
interface TrajectoryEffectRendering {
|
|
240
|
+
/**
|
|
241
|
+
* 安装在交互层中的元素;SDK 禁用该元素的指针事件。
|
|
242
|
+
*/
|
|
243
|
+
readonly element: HTMLElement;
|
|
244
|
+
/**
|
|
245
|
+
* 绘制新轨迹。
|
|
246
|
+
*/
|
|
247
|
+
renderBegan(points: readonly TrajectoryPoint[]): void;
|
|
248
|
+
/**
|
|
249
|
+
* 更新已有轨迹。
|
|
250
|
+
*/
|
|
251
|
+
renderMoved(points: readonly TrajectoryPoint[]): void;
|
|
252
|
+
/**
|
|
253
|
+
* 结束轨迹,可继续播放淡出效果。
|
|
254
|
+
*/
|
|
255
|
+
renderEnded(identifiers: readonly TrajectoryID[]): void;
|
|
256
|
+
/**
|
|
257
|
+
* 清除全部轨迹并取消动画;实例仍可再次使用。
|
|
258
|
+
*/
|
|
259
|
+
reset(): void;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export { CameraPosition as C, RealtimeVideoFormat as R, type TrajectoryEffectRendering as T, VideoContentMode as V, RealtimeVideoTrack as a, type VideoRenderStatistics as b, RealtimeVideoEncoderPreference as c, type RealtimeVideoFormatInit as d, type TrajectoryID as e, type TrajectoryPoint as f };
|
package/dist/{VideoRenderStatistics-C7zqzfuS.d.ts → TrajectoryEffectRendering-C7E2KJbV.d.ts}
RENAMED
|
@@ -212,4 +212,51 @@ interface VideoRenderStatistics {
|
|
|
212
212
|
readonly interpolatedFrameRate: number;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
|
|
215
|
+
/**
|
|
216
|
+
* 单次按下到释放期间稳定的轨迹标识,不依赖浏览器复用的 pointerId。
|
|
217
|
+
*/
|
|
218
|
+
type TrajectoryID = number;
|
|
219
|
+
/**
|
|
220
|
+
* 供视觉效果使用的触点;location 为视口 CSS 像素,timestamp 为毫秒。
|
|
221
|
+
*/
|
|
222
|
+
interface TrajectoryPoint {
|
|
223
|
+
readonly id: TrajectoryID;
|
|
224
|
+
readonly location: Readonly<{
|
|
225
|
+
x: number;
|
|
226
|
+
y: number;
|
|
227
|
+
}>;
|
|
228
|
+
readonly normalizedLocation: Readonly<{
|
|
229
|
+
x: number;
|
|
230
|
+
y: number;
|
|
231
|
+
}>;
|
|
232
|
+
readonly timestamp: number;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 可替换的轨迹视觉效果;不参与触点采样、坐标转换或网络发送。
|
|
237
|
+
* 一个实例仅供一个视图使用,reset 必须释放动画和清空轨迹。
|
|
238
|
+
*/
|
|
239
|
+
interface TrajectoryEffectRendering {
|
|
240
|
+
/**
|
|
241
|
+
* 安装在交互层中的元素;SDK 禁用该元素的指针事件。
|
|
242
|
+
*/
|
|
243
|
+
readonly element: HTMLElement;
|
|
244
|
+
/**
|
|
245
|
+
* 绘制新轨迹。
|
|
246
|
+
*/
|
|
247
|
+
renderBegan(points: readonly TrajectoryPoint[]): void;
|
|
248
|
+
/**
|
|
249
|
+
* 更新已有轨迹。
|
|
250
|
+
*/
|
|
251
|
+
renderMoved(points: readonly TrajectoryPoint[]): void;
|
|
252
|
+
/**
|
|
253
|
+
* 结束轨迹,可继续播放淡出效果。
|
|
254
|
+
*/
|
|
255
|
+
renderEnded(identifiers: readonly TrajectoryID[]): void;
|
|
256
|
+
/**
|
|
257
|
+
* 清除全部轨迹并取消动画;实例仍可再次使用。
|
|
258
|
+
*/
|
|
259
|
+
reset(): void;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export { CameraPosition as C, RealtimeVideoFormat as R, type TrajectoryEffectRendering as T, VideoContentMode as V, RealtimeVideoTrack as a, type VideoRenderStatistics as b, RealtimeVideoEncoderPreference as c, type RealtimeVideoFormatInit as d, type TrajectoryID as e, type TrajectoryPoint as f };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
exports.__publicField = __publicField;
|
|
8
|
+
//# sourceMappingURL=chunk-4DE2IREA.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/private/var/folders/5j/p3g3j18x2w3byrl5wtnk94tc0000gn/T/xmax-web-release-Zggzaq/source/packages/xmax-sdk/dist/chunk-4DE2IREA.cjs"],"names":[],"mappings":"AAAA,6EAAI,UAAU,EAAE,MAAM,CAAC,cAAc;AACrC,IAAI,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK;AAC/J,IAAI,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,IAAI,IAAI,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC;AAC9G;AACA;AACE;AACF,sCAAC","file":"/private/var/folders/5j/p3g3j18x2w3byrl5wtnk94tc0000gn/T/xmax-web-release-Zggzaq/source/packages/xmax-sdk/dist/chunk-4DE2IREA.cjs"}
|