跳到主要内容

配准媒体 API

配准图像、视频与动态帧(16.1)

共同脚本采用 MapLibre 风格的 image/video/canvas 图源、raster 图层和 setCoordinates/play/pause。图层面板和播放按钮由使用方编写。当前子阶段接受宿主已解码的 RGBA 帧;视频 URL 已接通下文16.4;Canvas 输入已接通下文;地形贴附已按terrain-quad接通,自定义渲染扩展仍在实施,不能把本子阶段称为完整媒体兼容。

// @gis-api 0.5-session
// @permissions ["project.read", "map.write"]
import { map } from 'sqsmap';
map.setProjection({ type: 'mercator' });
map.addSource('camera', {
  type: 'video',
  coordinates: [[-4, 4], [4, 4], [4, -4], [-4, -4]],
  attribution: 'Your media source'
});
map.addLayer({ id: 'camera-layer', type: 'raster', source: 'camera' });
await map.sqs.flush();
const camera = await map.getSource('camera');
await camera.sqs.submitFrame({ sequence: 1, width: 1, height: 1, data: [255, 0, 0, 255] });
await camera.pause();
await camera.play();
await map.sqs.flush({ render: true });
export default await camera.sqs.getState();

四角顺序为左上、右上、右下、左下,WGS84 经纬度,必须构成有限、凸、无交叉的 Mercator 范围;不能跨日期变更线。显示支持平面、倾斜 Mercator 和球面,当前不支持共同媒体地形贴附。image 与 video 都可提交帧,只有视频接受播放控制。raster-opacity 支持常量和已有缩放表达式,不支持要素属性、状态或过滤。透明度、缩放范围、可见性和图层排序使用共同图层方法;原始四角真实绘制,不退化为边界框。媒体没有可查询要素。

帧序号为正安全整数,必须严格增长;迟到/重复帧返回 CONFLICT。暂停丢弃输入帧,返回 applied:false,保留序号、画面和修订;恢复后接受后续新序号。输入复制后才替换唯一最新帧,失败保留旧帧。删除或重建同名图源使旧句柄和迟到解码输入返回 STALE_HANDLE,销毁释放地图资源;删除图源前移除引用图层。

边长1~4096,RGBA长度必须等于宽×高×4,单帧32MiB、每图媒体64MiB、最多32媒体源。脚本 JSON 数组还受脚本消息大小限制,大帧请由宿主使用二进制入口:独立网页 SDK 的 source.sqs.submitFrame 接收 Uint8Array,WASM 的 mediaFrame 和 C 的 sqsm_map_media_frame 使用相同身份/序号/预算。C 输入仅在调用期间借用,结果独立分配并用 sqsm_map_bytes_free 释放,失败输出分配不提交帧。动态库包含下文所述共享纯Rust MP4/H.264解码器,不接管浏览器GL上下文或HTTP。宿主已解码帧仍可使用相同二进制入口。

getSourceInfo 提供 mediaState 和加载状态,首帧前未加载;sourcedataloading/sourcedata 使用已有源事件。命令确认表示提交,render:true 等当前画面完成。桌面、独立原生 QuickJS 和浏览器主线程/严格Worker已使用同一验收脚本验证;本机软件GPU证据不能替代其他设备或正式发行验收。

在线图像源与 updateImage(16.2)

图像源可传 url(无内嵌凭据的 HTTP(S) 地址),宿主使用统一资源策略下载,共享核心解码PNG/JPEG/WebP;压缩输入最多4MiB,边长最多4096、解码RGBA最多32MiB。不使用浏览器专属图像对象,不改变已有图标512像素限制。

map.addSource('photo', {type:'image',url:'https://your.example/orthophoto.png',coordinates:[[-4,4],[4,4],[4,-4],[-4,-4]]});
map.addLayer({id:'photo-layer',type:'raster',source:'photo'});
await map.sqs.flush();
const photo=await map.getSource('photo');
await photo.updateImage({url:'https://your.example/new.png',coordinates:[[-5,5],[5,5],[5,-5],[-5,-5]]});

updateImage的确认仅表示新请求已登记,使用sourcedata/isSourceLoaded判断下载和解码成功。新像素与可选四角一起提交;失败保留旧帧和旧配准,error结束loading但hasData保留。请求代次拒绝迟到响应,后续更新/删除取消旧下载。更新捕获四角期间setCoordinates返回CONFLICT;不带四角的更新允许独立setCoordinates。显式submitFrame取消未完成图像请求并清除URL快照归属,旧响应不能覆盖新帧。

共同能力查询提供mediaImageURLSources/mediaImageUpdates/mediaFrames/mediaRasterPlanar/mediaRasterPitched;mediaVideoURLSources在16.4接通;Canvas命名帧已接通;地形和自定义绘制仍返回false。移动脚本宿主不因这些共享标记自动宣称已验收。

完整网页示例包含样式、所有按钮事件、图像加载通知、署名和销毁清理。

球面媒体显示(16.3)

已注册的 image/video RGBA媒体与URL图像源可使用 map.setProjection({type:'globe'}) 显示,mediaRasterGlobe 为true。相同句柄、帧序号、暂停、配准、透明度、可见性和图层顺序保持一致;切换Mercator/球面保留媒体。球面媒体按真实四角生成球面网格,复用共同深度/光照与缓存;不以平面截图替代。当前四角仍需满足公开Mercator配准范围,不支持跨日期变更线。

球面照明可能改变读回颜色,验收检查色彩通道及真实图层遮盖而不要求与平面字节完全相同。媒体不产生要素查询结果,其他矢量的球面查询保持原语义。取消/销毁释放媒体与缓存,当前画面确认同时核对相机、密度、业务修订和媒体帧签名,旧帧不能通过render屏障。

URL 视频与共享播放时钟(16.4)

import { map } from 'sqsmap';
map.addSource('film', {
  type: 'video',
  urls: ['https://your.example/clip.mp4'],
  coordinates: [[-4,4],[4,4],[4,-4],[-4,-4]],
  attribution: '视频作者及许可'
});
map.addLayer({ id:'film-layer', type:'raster', source:'film' });
await map.sqs.flush();
const film=await map.getSource('film');
await film.pause();
await film.play();
export default await film.sqs.getState();

urls 包含1~8个无内嵌凭据的HTTP(S)地址,按顺序下载/解码回退,保持同一源身份;全部失败才发出终结error。RESOURCE_LIMIT/CANCELLED不自动重试其它地址。核心不执行HTTP,由浏览器、桌面或动态库调用者沿统一资源策略下载。首帧接纳后sourcedata.isSourceLoaded才为true,注册确认不能替代加载完成。通过map.on监听该事件;提前暂停仍能加载首帧。

所有端使用同一纯Rust普通MP4/H.264解码器:8位、逐行、YUV420,不支持分片MP4、WebM、HEVC、音频播放或浏览器专属getVideo。文件与地图压缩数据各最多64MiB,每地图最多2个在线视频、1小时/216000样本;编码边长最多2048、总像素不超过1920×1088,显示帧保留桌面规则缩小至960×540,使用有限范围BT.601转换。最多16帧重排,每地图推进每个视频一次最多32帧;不预解码全片。格式不支持会明确失败。RGBA总预算仍64MiB。

地图持有单调播放时钟:自动开始,pause冻结当前像素与时间,play续播,末尾循环。状态额外包含duration/currentTime(秒),currentTime是已接纳帧的展示时间。视频使用sourcedata报告帧变化;显示失败暂停并发出error,保留上次已显示帧。删除/重建与销毁释放下载、压缩数据及解码器,迟到回传不能复活源。显式sqs.submitFrame接管媒体,终止URL解码归属;暂停仍丢弃该外部帧。

C资源回传的总上限为64MiB,并在复制前校验请求较小预算;GeoJSON8MiB和图片4MiB不变,ABI1的符号/布局/输出所有权不变。媒体栅格仍支持平面、倾斜及球面,地形贴附继续待实现。共同能力mediaVideoURLSources=true仅代表匹配共享实现,移动应用宿主/设备仍须验收。同一视频脚本与完整网页例子包含加载事件、播放暂停、版权和清理。

Canvas 动态画面

type:'canvas'、canvas、coordinates、animate 参考 MapLibre CanvasSource,实现使用 SqsMap 自研核心。animate 默认 true;false 接纳初始帧后保持暂停。play() 续传,pause() 冻结最新画面。getStyle() 保存命名标识和最初的 animate 设置,播放状态用 sqs.getState() 查询。

跨端脚本只传 canvas:'drawing' 这样的字符串,由宿主生成 RGBA 并调用 source.sqs.submitFrame({sequence,width,height,data})。脚本 data 是字节数组,浏览器 SDK 是 Uint8Array;序号为递增正安全整数。没有第一帧时源仍未就绪,成功提交才发 sourcedata;source.sqs.fail({code:'IO_ERROR',message:'无法读取画面'}) 结束加载并发 error,保留已显示像素。失败后调用 play 再提交可恢复。旧源句柄不能修改同名重建的源。

浏览器 SDK 的 canvas 可传 HTMLCanvasElement 或现有元素 ID;自动读取可访问的 2D 画布,约30帧/秒且每源最多一帧在途,严格 Worker 渲染仍由主线程供给像素。await map.getSource(id) 后的 source.getCanvas() 返回浏览器元素;此 DOM 方法不进入共同脚本或原生声明。不存在对应 DOM 的字符串作为命名手动供给源。被跨域内容污染、空尺寸或非2D画布自动供给失败;WebGL/OffscreenCanvas 应自行提交 RGBA。显式提交帧会接管该源并停止自动捕获。限制保持边长4096、单帧32MiB、地图最新帧合计64MiB。

移除或销毁停止供给,迟到任务按源实例拒绝。配准画面沿用 raster 的平面、倾斜和球面显示;地形贴附、自定义GL回调仍未实现。canvasFrameSources/mediaCanvasSources 表示共有帧接口,canvasDOM 只由浏览器SDK报告。移动宿主仍待接入。完整的 HTML/CSS/JS 示例 展示绘图、播放按钮和清理;跨端脚本 展示命名帧供给。

13.6c已接通GeoJSON、TileJSON和配准图片/视频源的自定义URI及URL更新,保留原解码/取消/身份规则,见图源协议。Style/glyph/loadImage/实时协议入口继续各自范围。

共同二维组合的能力边界

当匹配SDK的commonPlanarLayerComposition为true时,墨卡托零pitch/roll、无terrain/extrusion的共同二维画面允许影像、背景、图文、热力及既有静态线面效果按完整图层顺序组合。本文旧阶段关于“媒体组合拒绝”的限制在此共同二维范围内由该能力取代;自定义线动画、倾斜/球面/地形及其它未实现材料组合仍保持各自限制。重排和兼容diff保留身份/缓存/在途请求/淡入时钟;所有素材、联合几何和纹理预算均先验证再发布。参见二维图层合成。

浏览器静态三维模型(SqsMap 扩展)

匹配浏览器 SDK 的 staticModels=true 时,MapView.setModel(bytes, placement) 可加载一个自包含的 glTF 2.0 GLB,使用与桌面端相同的 Rust 解码器和三维渲染器。网络请求由宿主 fetch 完成,传入 Uint8Array;这不是共同 Style 的 model 图层或桌面 GIS 脚本的模型文件接口。

map.setProjection('mercator');
map.jumpTo({ center: [102.671647, 24.970096], zoom: 18.5, pitch: 55 });
const response = await fetch(modelUrl);
if (!response.ok) throw new Error('HTTP ' + response.status);
const placement = { lngLat: [102.671647, 24.970096], elevationM: 0,
  verticalReference: 'local-zero', headingDeg: 45, scale: 40, visible: true };
await map.setModel(new Uint8Array(await response.arrayBuffer()), placement);
await map.flush({ render: true });
const state = await map.getModelState();
if (!state?.rendered) throw new Error('模型尚未完成绘制');
await map.setModelPlacement({ ...placement, headingDeg: 90 });
// await map.clearModel();

每张地图最多保留一个此类模型,新上传只替换前一个模型,不改样式图层和数据源。setModelPlacement 完整替换位置、方向、尺度与显隐,复用已解码的几何和纹理;clearModel 释放模型,getModelState 返回不可变元数据(局部包围盒、部件数、三角面数、源字节数和最近完成的倾斜场景绘制状态),清理后返回 null。上传和位置修改确认的是命令应用,不能代替绘制确认;使用 flush({render:true}) 后核对 rendered。

经纬度为 WGS84;elevationM 和模型坐标单位为米。必须明确给出 verticalReference;这里 local-zero 仅代表示例的局部零面,不代表测量高程或自动贴地。方向为顺时针角度,尺度为正倍数。写入要求墨卡托投影,展示要求倾斜视图;不在球面或平面模式绘制,不进行地形采样。

沿用模型解码限制:源数据和解码数据各不超过 32 MiB,单张纹理边长不超过 2048,模型距锚点不超过 1 千米。仅静态模型,不支持骨骼、动画、透明和高级材质贴图;基础色纹理内嵌在 GLB 中。输入无效时保留上一份模型。模型的著作权、来源与地理摆放说明由调用方展示。桥梁完整示例 使用 Kenney Hexagon Kit 的 CC0 素材,并明确标注演示位置。