feat: Android Codec Preference

This commit is contained in:
csf 2022-09-16 20:31:01 +08:00
parent c6e1e84c72
commit 6f92edca5c
3 changed files with 76 additions and 41 deletions

View File

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -1011,17 +1012,22 @@ class QualityMonitor extends StatelessWidget {
void showOptions(String id, OverlayDialogManager dialogManager) async { void showOptions(String id, OverlayDialogManager dialogManager) async {
String quality = await bind.sessionGetImageQuality(id: id) ?? 'balanced'; String quality = await bind.sessionGetImageQuality(id: id) ?? 'balanced';
if (quality == '') quality = 'balanced'; if (quality == '') quality = 'balanced';
String codec =
await bind.sessionGetOption(id: id, arg: 'codec-preference') ?? 'auto';
if (codec == '') codec = 'auto';
String viewStyle = String viewStyle =
await bind.sessionGetOption(id: id, arg: 'view-style') ?? ''; await bind.sessionGetOption(id: id, arg: 'view-style') ?? '';
var displays = <Widget>[]; var displays = <Widget>[];
final pi = gFFI.ffiModel.pi; final pi = gFFI.ffiModel.pi;
final image = gFFI.ffiModel.getConnectionImage(); final image = gFFI.ffiModel.getConnectionImage();
if (image != null) if (image != null) {
displays.add(Padding(padding: const EdgeInsets.only(top: 8), child: image)); displays.add(Padding(padding: const EdgeInsets.only(top: 8), child: image));
}
if (pi.displays.length > 1) { if (pi.displays.length > 1) {
final cur = pi.currentDisplay; final cur = pi.currentDisplay;
final children = <Widget>[]; final children = <Widget>[];
for (var i = 0; i < pi.displays.length; ++i) for (var i = 0; i < pi.displays.length; ++i) {
children.add(InkWell( children.add(InkWell(
onTap: () { onTap: () {
if (i == cur) return; if (i == cur) return;
@ -1038,6 +1044,7 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
child: Text((i + 1).toString(), child: Text((i + 1).toString(),
style: TextStyle( style: TextStyle(
color: i == cur ? Colors.white : Colors.black87)))))); color: i == cur ? Colors.white : Colors.black87))))));
}
displays.add(Padding( displays.add(Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Wrap( child: Wrap(
@ -1047,9 +1054,21 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
))); )));
} }
if (displays.isNotEmpty) { if (displays.isNotEmpty) {
displays.add(Divider(color: MyTheme.border)); displays.add(const Divider(color: MyTheme.border));
} }
final perms = gFFI.ffiModel.permissions; final perms = gFFI.ffiModel.permissions;
final hasHwcodec = bind.mainHasHwcodec();
final List<bool> codecs = [];
if (hasHwcodec) {
try {
final Map codecsJson =
jsonDecode(await bind.sessionSupportedHwcodec(id: id));
final h264 = codecsJson['h264'] ?? false;
final h265 = codecsJson['h265'] ?? false;
codecs.add(h264);
codecs.add(h265);
} finally {}
}
dialogManager.show((setState, close) { dialogManager.show((setState, close) {
final more = <Widget>[]; final more = <Widget>[];
@ -1057,50 +1076,77 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
more.add(getToggle(id, setState, 'disable-audio', 'Mute')); more.add(getToggle(id, setState, 'disable-audio', 'Mute'));
} }
if (perms['keyboard'] != false) { if (perms['keyboard'] != false) {
if (perms['clipboard'] != false) if (perms['clipboard'] != false) {
more.add( more.add(
getToggle(id, setState, 'disable-clipboard', 'Disable clipboard')); getToggle(id, setState, 'disable-clipboard', 'Disable clipboard'));
}
more.add(getToggle( more.add(getToggle(
id, setState, 'lock-after-session-end', 'Lock after session end')); id, setState, 'lock-after-session-end', 'Lock after session end'));
if (pi.platform == 'Windows') { if (pi.platform == 'Windows') {
more.add(getToggle(id, setState, 'privacy-mode', 'Privacy mode')); more.add(getToggle(id, setState, 'privacy-mode', 'Privacy mode'));
} }
} }
var setQuality = (String? value) { setQuality(String? value) {
if (value == null) return; if (value == null) return;
setState(() { setState(() {
quality = value; quality = value;
bind.sessionSetImageQuality(id: id, value: value); bind.sessionSetImageQuality(id: id, value: value);
}); });
}; }
var setViewStyle = (String? value) {
setViewStyle(String? value) {
if (value == null) return; if (value == null) return;
setState(() { setState(() {
viewStyle = value; viewStyle = value;
bind.sessionPeerOption(id: id, name: "view-style", value: value); bind
gFFI.canvasModel.updateViewStyle(); .sessionPeerOption(id: id, name: "view-style", value: value)
.then((_) => gFFI.canvasModel.updateViewStyle());
}); });
}; }
return CustomAlertDialog(
title: SizedBox.shrink(), setCodec(String? value) {
content: Column( if (value == null) return;
mainAxisSize: MainAxisSize.min, setState(() {
children: displays + codec = value;
<Widget>[ bind
getRadio('Scale Original', 'original', viewStyle, setViewStyle), .sessionPeerOption(id: id, name: "codec-preference", value: value)
.then((_) => bind.sessionChangePreferCodec(id: id));
});
}
final radios = [
getRadio('Scale original', 'original', viewStyle, setViewStyle),
getRadio('Scale adaptive', 'adaptive', viewStyle, setViewStyle), getRadio('Scale adaptive', 'adaptive', viewStyle, setViewStyle),
Divider(color: MyTheme.border), const Divider(color: MyTheme.border),
getRadio('Good image quality', 'best', quality, setQuality), getRadio('Good image quality', 'best', quality, setQuality),
getRadio('Balanced', 'balanced', quality, setQuality), getRadio('Balanced', 'balanced', quality, setQuality),
getRadio('Optimize reaction time', 'low', quality, setQuality), getRadio('Optimize reaction time', 'low', quality, setQuality),
Divider(color: MyTheme.border), const Divider(color: MyTheme.border)
getToggle( ];
id, setState, 'show-remote-cursor', 'Show remote cursor'),
getToggle(id, setState, 'show-quality-monitor', if (hasHwcodec && codecs.length == 2 && (codecs[0] || codecs[1])) {
'Show quality monitor'), radios.addAll([
] + getRadio(translate('Auto'), 'auto', codec, setCodec),
more), getRadio('VP9', 'vp9', codec, setCodec),
actions: [], ]);
if (codecs[0]) {
radios.add(getRadio('H264', 'h264', codec, setCodec));
}
if (codecs[1]) {
radios.add(getRadio('H265', 'h265', codec, setCodec));
}
radios.add(const Divider(color: MyTheme.border));
}
final toggles = [
getToggle(id, setState, 'show-remote-cursor', 'Show remote cursor'),
getToggle(id, setState, 'show-quality-monitor', 'Show quality monitor'),
];
return CustomAlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: displays + radios + toggles + more),
contentPadding: 0, contentPadding: 0,
); );
}, clickMaskDismiss: true, backDismiss: true); }, clickMaskDismiss: true, backDismiss: true);

View File

@ -744,9 +744,9 @@ pub fn get_api_server() -> String {
#[inline] #[inline]
pub fn has_hwcodec() -> bool { pub fn has_hwcodec() -> bool {
#[cfg(not(feature = "hwcodec"))] #[cfg(not(any(feature = "hwcodec", feature = "mediacodec")))]
return false; return false;
#[cfg(feature = "hwcodec")] #[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
return true; return true;
} }

View File

@ -136,15 +136,8 @@ impl<T: InvokeUiSession> Session<T> {
true true
} }
pub fn has_hwcodec(&self) -> bool {
#[cfg(not(feature = "hwcodec"))]
return false;
#[cfg(feature = "hwcodec")]
return true;
}
pub fn supported_hwcodec(&self) -> (bool, bool) { pub fn supported_hwcodec(&self) -> (bool, bool) {
#[cfg(feature = "hwcodec")] #[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
{ {
let decoder = scrap::codec::Decoder::video_codec_state(&self.id); let decoder = scrap::codec::Decoder::video_codec_state(&self.id);
let mut h264 = decoder.score_h264 > 0; let mut h264 = decoder.score_h264 > 0;
@ -155,10 +148,6 @@ impl<T: InvokeUiSession> Session<T> {
} }
return (h264, h265); return (h264, h265);
} }
#[cfg(feature = "mediacodec")]
{
todo!();
}
(false, false) (false, false)
} }