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());
}); });
}; }
setCodec(String? value) {
if (value == null) return;
setState(() {
codec = value;
bind
.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),
const Divider(color: MyTheme.border),
getRadio('Good image quality', 'best', quality, setQuality),
getRadio('Balanced', 'balanced', quality, setQuality),
getRadio('Optimize reaction time', 'low', quality, setQuality),
const Divider(color: MyTheme.border)
];
if (hasHwcodec && codecs.length == 2 && (codecs[0] || codecs[1])) {
radios.addAll([
getRadio(translate('Auto'), 'auto', codec, setCodec),
getRadio('VP9', 'vp9', codec, setCodec),
]);
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( return CustomAlertDialog(
title: SizedBox.shrink(),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: displays + children: displays + radios + toggles + more),
<Widget>[
getRadio('Scale Original', 'original', viewStyle, setViewStyle),
getRadio('Scale adaptive', 'adaptive', viewStyle, setViewStyle),
Divider(color: MyTheme.border),
getRadio('Good image quality', 'best', quality, setQuality),
getRadio('Balanced', 'balanced', quality, setQuality),
getRadio('Optimize reaction time', 'low', quality, setQuality),
Divider(color: MyTheme.border),
getToggle(
id, setState, 'show-remote-cursor', 'Show remote cursor'),
getToggle(id, setState, 'show-quality-monitor',
'Show quality monitor'),
] +
more),
actions: [],
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)
} }