feat: 支持手动切换采集帧率

在 Android、Web 及 Flutter 控制端新增帧率选择 UI,被控端按屏幕刷新率生成支持的帧率档位并上报,允许在保持分辨率不变的情况下仅切换帧率。

另附带更新信号服务器的数据库配置。
This commit is contained in:
TongTongStudio
2026-07-31 03:26:40 +08:00
parent c3602493dd
commit 362b9f238a
23 changed files with 483 additions and 13 deletions

View File

@@ -48,4 +48,9 @@ message ControlMessage {
int32 width = 12;
int32 height = 13;
int32 fps = 14;
// 15 预留给 Android 端的 stream_modeWeb 端暂未使用,编号保持对齐)。
// 被控端支持的帧率档位列表REPORT_RESOLUTION 上报,按屏幕刷新率筛选,升序)。
repeated int32 supported_fps = 16;
}

View File

@@ -25,6 +25,10 @@ const resolutionPresets = [
// 因此这里也必须用数字(不能用字符串 '0'),否则默认选中项与比较逻辑会类型不一致。
const selectedResolution = ref(0);
// 帧率档位:默认常用档位,收到被控端上报的 supported_fps 后以上报列表为准。
const fpsOptions = ref([15, 24, 30, 60]);
const selectedFps = ref(0); // 0 表示尚未同步到被控端当前帧率
function press(code) {
if (!store.dataChannelOpen) return;
sendKey(code);
@@ -39,12 +43,29 @@ function onResolutionChange() {
}
}
// 被控端上报当前实际采集分辨率时,把下拉框同步到对应预设(避免 UI 与实际不一致)。
function onFpsChange() {
if (!store.dataChannelOpen) return;
const fps = Number(selectedFps.value);
if (fps <= 0) return;
// 仅切换帧率分辨率沿用被控端最近上报的实际采集尺寸0 表示原生)。
const res = store.currentResolution;
sendResolutionChange(res ? res.width : 0, res ? res.height : 0, fps);
}
// 被控端上报当前实际采集分辨率/帧率时,同步下拉框(避免 UI 与实际不一致)。
watch(() => store.currentResolution, (res) => {
if (!res) return;
const longEdge = Math.max(res.width, res.height);
const preset = resolutionPresets.find((p) => p.width === longEdge);
if (preset) selectedResolution.value = preset.width;
// 帧率档位以被控端上报为准(按屏幕刷新率筛选)
if (Array.isArray(res.supportedFps) && res.supportedFps.length > 0) {
fpsOptions.value = res.supportedFps;
}
if (res.fps > 0 && fpsOptions.value.includes(res.fps)) {
selectedFps.value = res.fps;
}
});
</script>
@@ -62,8 +83,19 @@ watch(() => store.currentResolution, (res) => {
{{ p.label }}
</option>
</select>
<label class="resolution-label">帧率:</label>
<select
class="resolution-select"
v-model="selectedFps"
:disabled="!store.dataChannelOpen"
@change="onFpsChange"
>
<option v-if="selectedFps === 0" :value="0" disabled>--</option>
<option v-for="f in fpsOptions" :key="f" :value="f">{{ f }}fps</option>
</select>
<span class="resolution-current" v-if="store.currentResolution">
当前: {{ store.currentResolution.width }}×{{ store.currentResolution.height }}
当前: {{ store.currentResolution.width }}×{{ store.currentResolution.height }}@{{ store.currentResolution.fps }}fps
</span>
<span class="record-sep"></span>

View File

@@ -167,6 +167,8 @@ export class WebRtcController {
width: msg.width | 0,
height: msg.height | 0,
fps: msg.fps | 0,
// 被控端按屏幕刷新率筛选出的帧率档位(供帧率下拉框使用)
supportedFps: Array.isArray(msg.supportedFps) ? msg.supportedFps.map((f) => f | 0) : [],
});
}
} catch (err) {