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

@@ -82,6 +82,16 @@ class _ControllerHomeState extends State<ControllerHome> {
{'label': '480P', 'width': 854, 'height': 0, 'fps': 0},
];
/// 帧率档位:默认常用档位,收到被控端上报的 supported_fps 后以上报列表为准。
List<int> _fpsOptions = const [15, 24, 30, 60];
/// 被控端当前采集帧率0 表示尚未收到上报)。
int _currentFps = 0;
/// 被控端最近上报的实际采集尺寸仅切帧率时保持分辨率不变0 表示原生)。
int _lastReportedWidth = 0;
int _lastReportedHeight = 0;
@override
void initState() {
super.initState();
@@ -354,6 +364,16 @@ class _ControllerHomeState extends State<ControllerHome> {
_resizeWindowToAspect(aspect);
}
};
// 被控端上报当前帧率与支持的帧率档位 -> 同步帧率菜单
_controller!.onFpsReport = (w, h, fps, supportedFps) {
if (!mounted) return;
setState(() {
if (w > 0) _lastReportedWidth = w;
if (h > 0) _lastReportedHeight = h;
if (fps > 0) _currentFps = fps;
if (supportedFps.isNotEmpty) _fpsOptions = supportedFps;
});
};
_controller!.onSelfCodecNotSupported = () {
if (mounted) setState(() => _selfCodecSupported = false);
_showAlert('当前平台不支持自编码硬解,已回退到 WebRTC 媒体流。');
@@ -447,6 +467,47 @@ class _ControllerHomeState extends State<ControllerHome> {
);
}
/// 弹出帧率选择菜单iOS 风格 ActionSheet仅切帧率分辨率保持不变。
void _showFpsMenu() {
showCupertinoModalPopup<void>(
context: context,
builder: (ctx) => CupertinoActionSheet(
title: const Text('切换帧率'),
actions: [
for (final fps in _fpsOptions)
CupertinoActionSheetAction(
onPressed: () {
Navigator.of(ctx).pop();
if (fps <= 0 || fps == _currentFps) return;
// 分辨率沿用被控端最近上报的实际采集尺寸0 表示原生)
_controller?.sendResolutionChange(
_lastReportedWidth,
_lastReportedHeight,
fps,
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (fps == _currentFps) ...[
const Icon(CupertinoIcons.check_mark,
size: 18, color: CupertinoColors.activeBlue),
const SizedBox(width: 8),
],
Text('${fps}fps'),
],
),
),
],
cancelButton: CupertinoActionSheetAction(
isDefaultAction: true,
onPressed: () => Navigator.of(ctx).pop(),
child: const Text('取消'),
),
),
);
}
/// 切换串流模式WebRTC 全托管 <-> 自编码(自建 MediaCodec 解码)。
void _toggleStreamMode() {
if (!_selfCodecSupported) {
@@ -534,6 +595,10 @@ class _ControllerHomeState extends State<ControllerHome> {
_recording = false;
_recordStatus = '';
_pendingRecordStart = false;
_currentFps = 0;
_lastReportedWidth = 0;
_lastReportedHeight = 0;
_fpsOptions = const [15, 24, 30, 60];
});
}
@@ -636,6 +701,26 @@ class _ControllerHomeState extends State<ControllerHome> {
],
),
),
// 帧率菜单按钮:显示被控端当前采集帧率
CupertinoButton(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
onPressed: _showFpsMenu,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(CupertinoIcons.speedometer,
color: CupertinoColors.white, size: 20),
const SizedBox(width: 6),
Text(
_currentFps > 0 ? '${_currentFps}fps' : '帧率',
style: const TextStyle(
color: CupertinoColors.white,
fontSize: 14,
),
),
],
),
),
// 自编码串流开关:仅 Android 等支持原生硬解的平台可用。
CupertinoButton(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),