fix: 修复自编码模式黑屏及并发问题

- 修复 MediaCodec 回调需在 configure 前设置导致的异常
- 修复解码器线程安全问题及包乱序/重复处理
- 增加关键帧前重发 SPS/PPS 以防首帧丢失导致黑屏
- 支持分辨率切换时重置解码器
- 修复 Flutter 控制端连接类型选项 UI 显示拥挤问题
This commit is contained in:
2026-07-24 09:31:58 +08:00
parent f8048e1331
commit 778c37b8db
9 changed files with 374 additions and 107 deletions

View File

@@ -126,6 +126,69 @@ class _ControllerHomeState extends State<ControllerHome> {
String selectedType = 'NONE';
final valueController = TextEditingController();
// 纵向选项列表,避免分段控件在窄弹窗中把中文选项挤压成两行。
Widget buildOption(
String value,
String title,
String desc,
void Function(void Function()) setDialogState,
) {
final selected = selectedType == value;
return GestureDetector(
onTap: () => setDialogState(() => selectedType = value),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
margin: const EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
border: Border.all(
color: selected
? CupertinoColors.activeBlue
: CupertinoColors.systemGrey4,
),
borderRadius: BorderRadius.circular(10),
color: selected
? CupertinoColors.activeBlue.withValues(alpha: 0.06)
: null,
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 2),
Text(
desc,
style: const TextStyle(
fontSize: 12,
color: CupertinoColors.systemGrey,
),
),
],
),
),
const SizedBox(width: 8),
Icon(
selected
? CupertinoIcons.check_mark_circled_solid
: CupertinoIcons.circle,
color: selected
? CupertinoColors.activeBlue
: CupertinoColors.systemGrey,
),
],
),
),
);
}
await showCupertinoDialog<void>(
context: context,
builder: (ctx) => StatefulBuilder(
@@ -134,37 +197,37 @@ class _ControllerHomeState extends State<ControllerHome> {
content: Column(
children: [
const SizedBox(height: 12),
CupertinoSegmentedControl<String>(
children: const {
'NONE': Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text('免密连接'),
),
'CODE': Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text('动态验证码'),
),
'PASSWORD': Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text('固定密码'),
),
},
groupValue: selectedType,
onValueChanged: (v) => setDialogState(() => selectedType = v),
buildOption(
'NONE',
'免密连接',
'被控端弹出手动确认框,无需验证码或密码',
setDialogState,
),
buildOption(
'CODE',
'动态验证码',
'使用一次性动态验证码鉴权',
setDialogState,
),
buildOption(
'PASSWORD',
'固定密码',
'使用固定连接密码鉴权',
setDialogState,
),
const SizedBox(height: 4),
CupertinoTextField(
controller: valueController,
enabled: selectedType != 'NONE',
placeholder: selectedType == 'NONE'
? '免密连接,无需填写'
: selectedType == 'PASSWORD'
? '请输入固定密码'
: '请输入动态验证码',
obscureText: true,
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
),
const SizedBox(height: 12),
if (selectedType == 'NONE')
const Text(
'免密连接:被控端将弹出手动确认对话框,无需输入验证码或密码。',
style: TextStyle(fontSize: 13, color: CupertinoColors.systemGrey),
)
else
CupertinoTextField(
controller: valueController,
placeholder: selectedType == 'PASSWORD' ? '请输入固定密码' : '请输入动态验证码',
obscureText: true,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
),
],
),
actions: [
@@ -245,6 +308,14 @@ class _ControllerHomeState extends State<ControllerHome> {
});
}
};
_controller!.onSelfCodecLost = () {
if (mounted) {
setState(() {
_selfCodecReady = false;
_selfCodecTextureId = null;
});
}
};
_controller!.onStreamModeReport = (mode) {
if (mounted) setState(() => _streamMode = mode);
};