feat: 支持手动切换采集帧率
在 Android、Web 及 Flutter 控制端新增帧率选择 UI,被控端按屏幕刷新率生成支持的帧率档位并上报,允许在保持分辨率不变的情况下仅切换帧率。 另附带更新信号服务器的数据库配置。
This commit is contained in:
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user