feat(streaming): 添加自编码串流模式切换功能

This commit is contained in:
2026-07-23 12:01:08 +08:00
parent a1c29246d7
commit e56723a010
20 changed files with 1684 additions and 16 deletions

View File

@@ -8,6 +8,7 @@ import 'config/ice_servers.dart';
import 'controller/remote_controller.dart';
import 'utils/control_commands.dart';
import 'utils/device_utils.dart';
import 'webrtc/self_codec_decoder.dart';
import 'widgets/remote_touch_view.dart';
void main() {
@@ -55,6 +56,12 @@ class _ControllerHomeState extends State<ControllerHome> {
String _stats = '';
double _videoAspect = 16 / 9;
/// 当前串流模式0=WebRTC 全托管1=自编码(自建 MediaCodec 解码)。
int _streamMode = SelfCodecDecoder.streamModeWebRtc;
int? _selfCodecTextureId;
bool _selfCodecReady = false;
bool _selfCodecSupported = true;
/// 分辨率预设width 为长边像素0 表示被控端原生分辨率;
/// height 传 0由被控端按屏幕宽高比计算fps 传 0沿用当前帧率
int _selectedResolution = 0;
@@ -217,6 +224,28 @@ class _ControllerHomeState extends State<ControllerHome> {
renderer.addListener(_onRendererUpdate);
};
_controller!.onStats = (stats) => setState(() => _stats = stats);
_controller!.onSelfCodecReady = (textureId) {
if (mounted) {
setState(() {
_selfCodecTextureId = textureId;
_selfCodecReady = true;
});
}
};
_controller!.onStreamModeReport = (mode) {
if (mounted) setState(() => _streamMode = mode);
};
_controller!.onResolutionReported = (w, h) {
if (w > 0 && h > 0 && mounted) {
final aspect = w / h;
setState(() => _videoAspect = aspect);
_resizeWindowToAspect(aspect);
}
};
_controller!.onSelfCodecNotSupported = () {
if (mounted) setState(() => _selfCodecSupported = false);
_showAlert('当前平台不支持自编码硬解,已回退到 WebRTC 媒体流。');
};
_controller!.connect(authType: authType, authValue: authValue);
}
@@ -300,6 +329,19 @@ class _ControllerHomeState extends State<ControllerHome> {
);
}
/// 切换串流模式WebRTC 全托管 <-> 自编码(自建 MediaCodec 解码)。
void _toggleStreamMode() {
if (!_selfCodecSupported) {
_showAlert('当前平台不支持自编码硬解。');
return;
}
final next = _streamMode == SelfCodecDecoder.streamModeSelfCodec
? SelfCodecDecoder.streamModeWebRtc
: SelfCodecDecoder.streamModeSelfCodec;
setState(() => _streamMode = next);
_controller?.sendStreamMode(next);
}
Future<void> _disconnect() async {
await _controller?.disconnect();
_controller = null;
@@ -310,6 +352,10 @@ class _ControllerHomeState extends State<ControllerHome> {
_renderer = null;
_status = '状态: 已停止';
_stats = '';
_streamMode = SelfCodecDecoder.streamModeWebRtc;
_selfCodecTextureId = null;
_selfCodecReady = false;
_selfCodecSupported = true;
});
}
@@ -412,6 +458,33 @@ class _ControllerHomeState extends State<ControllerHome> {
],
),
),
// 自编码串流开关:仅 Android 等支持原生硬解的平台可用。
CupertinoButton(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
onPressed: _selfCodecSupported ? _toggleStreamMode : null,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'自编码',
style: TextStyle(
color: _selfCodecSupported
? CupertinoColors.white
: CupertinoColors.white.withValues(alpha: 0.4),
fontSize: 14,
),
),
const SizedBox(width: 6),
CupertinoSwitch(
value: _streamMode == SelfCodecDecoder.streamModeSelfCodec,
onChanged: _selfCodecSupported
? (_) => _toggleStreamMode()
: null,
activeTrackColor: CupertinoColors.activeBlue,
),
],
),
),
// 分隔线
Container(
width: 1,
@@ -444,7 +517,31 @@ class _ControllerHomeState extends State<ControllerHome> {
child: Stack(
children: [
Container(color: Colors.black),
if (_renderer != null)
if (_streamMode == SelfCodecDecoder.streamModeSelfCodec &&
_selfCodecReady &&
_selfCodecTextureId != null)
Center(
child: AspectRatio(
aspectRatio: _videoAspect,
child: Stack(
fit: StackFit.expand,
children: [
Texture(textureId: _selfCodecTextureId!),
RemoteTouchView(
onTouch: (x, y) {},
onSwipe: (x1, y1, x2, y2, d) {},
onLongPress: (x, y) {},
onKey: (k, a) =>
_controller?.sendControlCommand(ControlCommands.key(k, a)),
onMotionEvent: (a, x, y) => _controller?.sendControlCommand(
ControlCommands.motionEvent(a, x, y),
),
),
],
),
),
)
else if (_renderer != null)
Center(
child: AspectRatio(
aspectRatio: _videoAspect,