해상도 올리기 메모리 설정 (176 보충)
- 환경 설정 > AI: 해상도 올리기 메모리 적게 (20%) · 보통 (30%, 처음 값) · 많이 (45%) - Android CPU 타일 크기 - 수준마다 이 기기에서의 타일 · 예상 메모리, 예시 시간 (16GB 폰) - 빠르기 기록 열쇠에 메모리 설정을 넣어 다른 설정의 시간으로 어림하지 않음 - 모르는 설정 값은 보통 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>fix_mkv
parent
d6f3de130c
commit
36de96dd0b
|
|
@ -799,6 +799,8 @@
|
|||
"만화 · 그림용": "Comics · art",
|
||||
"만화 · 그림용은 가볍고 빠르며, 사진용은 사진의 질감을 더 잘 살리지만 그래픽카드가 없으면 느립니다.": "Comics · art is light and fast. Photos keeps photo texture better but is slow without a graphics card.",
|
||||
"만화 보기": "Read as comic",
|
||||
"많이 (빠름)": "High (faster)",
|
||||
"많이 (빠름): {0} - 다른 앱이 많이 켜져 있으면 Android 가 이 앱을 끌 수 있습니다": "High (faster): {0} - if many other apps are open, Android may close this app",
|
||||
"말레이어": "Malay",
|
||||
"맞추기 (검은 여백)": "Fit (black bars)",
|
||||
"맞추기 (비율이 다를 때)": "Conform (when the aspect differs)",
|
||||
|
|
@ -952,6 +954,8 @@
|
|||
"보안": "Security",
|
||||
"보일 버튼을 고르고, 끌어서 순서를 바꿉니다.": "Choose the buttons to show and drag to reorder.",
|
||||
"보정은 다시 인코딩해야 해서 코덱을 \"원본 유지\" 에서 H.264 로 바꿨습니다.": "Adjustments require re-encoding, so the codec was changed from \"Keep original\" to H.264.",
|
||||
"보통": "Normal",
|
||||
"보통: {0}": "Normal: {0}",
|
||||
"복사": "Copy",
|
||||
"복사 (붙여넣기로)": "Copy (to paste)",
|
||||
"복사 · rsync": "Copy · rsync",
|
||||
|
|
@ -1402,6 +1406,7 @@
|
|||
"이 그림을 바탕으로 (그림 → 그림)": "Use this as the base (image → image)",
|
||||
"이 기기 (SD1.5 + LCM)": "This device (SD1.5 + LCM)",
|
||||
"이 기기 ({0})": "This device ({0})",
|
||||
"이 기기 메모리 {0}GB 기준:": "For this device's {0}GB of memory:",
|
||||
"이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "Only an irreversible hash is stored on this device, not the password itself.",
|
||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "About {0} per image on this device (based on last time)",
|
||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "About {0} per image, {1} in total on this device (based on last time)",
|
||||
|
|
@ -1628,6 +1633,8 @@
|
|||
"저장했습니다": "Saved",
|
||||
"저장했습니다: {0}": "Saved: {0}",
|
||||
"저장했습니다: {0} (MKV 에 반영됨)": "Saved: {0} (applied to MKV)",
|
||||
"적게 (느림)": "Low (slower)",
|
||||
"적게 (느림): {0}": "Low (slower): {0}",
|
||||
"적용": "Apply",
|
||||
"전체 {0}개 중 {1}번째": "Item {1} of {0}",
|
||||
"전체 만들기": "Make all",
|
||||
|
|
@ -1842,6 +1849,8 @@
|
|||
"키 있음": "Key saved",
|
||||
"타갈로그어": "Tagalog",
|
||||
"타밀어": "Tamil",
|
||||
"타일 {0} · 약 {1}GB": "tile {0} · about {1}GB",
|
||||
"타일이 작을수록 느립니다 (예: 16GB 폰에서 1024×768 을 2배로 - 512 약 4분 · 320 약 9분 30초).": "Smaller tiles are slower (e.g. doubling 1024×768 on a 16GB phone: 512 about 4 min · 320 about 9 min 30 s).",
|
||||
"탐색기": "Explorer",
|
||||
"탐색기 오른쪽 클릭 메뉴": "Explorer right-click menu",
|
||||
"탐색기에서 동영상을 열 때": "When opening a video from Explorer",
|
||||
|
|
@ -1971,6 +1980,7 @@
|
|||
"할 일": "Task",
|
||||
"항목 {0}/{1}": "Items {0}/{1}",
|
||||
"항목마다 따로 (기본)": "Each item separately (default)",
|
||||
"해상도 올리기 메모리": "Upscaling memory",
|
||||
"해상도 올리기 모델": "Upscaling model",
|
||||
"해상도 올리기 모델을 받아 주세요 (환경 설정 > AI 그림)": "Download an upscaling model (Settings > AI images)",
|
||||
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "An upscaling model is needed. Which one should be downloaded?",
|
||||
|
|
|
|||
|
|
@ -799,6 +799,8 @@
|
|||
"만화 · 그림용": "漫画・イラスト用",
|
||||
"만화 · 그림용은 가볍고 빠르며, 사진용은 사진의 질감을 더 잘 살리지만 그래픽카드가 없으면 느립니다.": "漫画・イラスト用は軽くて速く、写真用は写真の質感をよく保ちますが、グラフィックカードがないと遅くなります。",
|
||||
"만화 보기": "マンガ表示",
|
||||
"많이 (빠름)": "多め (速い)",
|
||||
"많이 (빠름): {0} - 다른 앱이 많이 켜져 있으면 Android 가 이 앱을 끌 수 있습니다": "多め (速い): {0} - 他のアプリが多く開いていると Android がこのアプリを終了することがあります",
|
||||
"말레이어": "マレー語",
|
||||
"맞추기 (검은 여백)": "フィット(黒い余白)",
|
||||
"맞추기 (비율이 다를 때)": "合わせ方(比率が違うとき)",
|
||||
|
|
@ -952,6 +954,8 @@
|
|||
"보안": "セキュリティ",
|
||||
"보일 버튼을 고르고, 끌어서 순서를 바꿉니다.": "表示するボタンを選び、ドラッグで順序を変えます。",
|
||||
"보정은 다시 인코딩해야 해서 코덱을 \"원본 유지\" 에서 H.264 로 바꿨습니다.": "補正には再エンコードが必要なため、コーデックを「元のまま」から H.264 に変更しました。",
|
||||
"보통": "普通",
|
||||
"보통: {0}": "普通: {0}",
|
||||
"복사": "コピー",
|
||||
"복사 (붙여넣기로)": "コピー (貼り付け用)",
|
||||
"복사 · rsync": "コピー · rsync",
|
||||
|
|
@ -1402,6 +1406,7 @@
|
|||
"이 그림을 바탕으로 (그림 → 그림)": "この画像を元に (画像 → 画像)",
|
||||
"이 기기 (SD1.5 + LCM)": "この端末 (SD1.5 + LCM)",
|
||||
"이 기기 ({0})": "この端末 ({0})",
|
||||
"이 기기 메모리 {0}GB 기준:": "この端末のメモリ {0}GB の場合:",
|
||||
"이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "この端末にはパスワード自体ではなく、元に戻せないハッシュだけが残ります。",
|
||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0} (前回の所要時間から)",
|
||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0}・全部で約 {1} (前回の所要時間から)",
|
||||
|
|
@ -1628,6 +1633,8 @@
|
|||
"저장했습니다": "保存しました",
|
||||
"저장했습니다: {0}": "保存しました: {0}",
|
||||
"저장했습니다: {0} (MKV 에 반영됨)": "保存しました: {0}(MKV に反映済み)",
|
||||
"적게 (느림)": "少なめ (遅い)",
|
||||
"적게 (느림): {0}": "少なめ (遅い): {0}",
|
||||
"적용": "適用",
|
||||
"전체 {0}개 중 {1}번째": "全 {0} 件中 {1} 件目",
|
||||
"전체 만들기": "すべて作成",
|
||||
|
|
@ -1842,6 +1849,8 @@
|
|||
"키 있음": "キーあり",
|
||||
"타갈로그어": "タガログ語",
|
||||
"타밀어": "タミル語",
|
||||
"타일 {0} · 약 {1}GB": "タイル {0} · 約 {1}GB",
|
||||
"타일이 작을수록 느립니다 (예: 16GB 폰에서 1024×768 을 2배로 - 512 약 4분 · 320 약 9분 30초).": "タイルが小さいほど遅くなります (例: 16GB のスマホで 1024×768 を 2 倍に - 512 で約 4 分 · 320 で約 9 分 30 秒)。",
|
||||
"탐색기": "エクスプローラー",
|
||||
"탐색기 오른쪽 클릭 메뉴": "エクスプローラーの右クリックメニュー",
|
||||
"탐색기에서 동영상을 열 때": "エクスプローラーで動画を開いたとき",
|
||||
|
|
@ -1971,6 +1980,7 @@
|
|||
"할 일": "内容",
|
||||
"항목 {0}/{1}": "項目 {0}/{1}",
|
||||
"항목마다 따로 (기본)": "項目ごとに (既定)",
|
||||
"해상도 올리기 메모리": "高解像度化のメモリ",
|
||||
"해상도 올리기 모델": "高解像度化モデル",
|
||||
"해상도 올리기 모델을 받아 주세요 (환경 설정 > AI 그림)": "高解像度化モデルをダウンロードしてください (環境設定 > AI 画像)",
|
||||
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "解像度アップのモデルが必要です。どれをダウンロードしますか?",
|
||||
|
|
|
|||
|
|
@ -799,6 +799,8 @@
|
|||
"만화 · 그림용": "漫画 · 插画",
|
||||
"만화 · 그림용은 가볍고 빠르며, 사진용은 사진의 질감을 더 잘 살리지만 그래픽카드가 없으면 느립니다.": "漫画 · 插画模型轻巧快速;照片模型更能保留照片质感,但没有显卡时较慢。",
|
||||
"만화 보기": "漫画阅读",
|
||||
"많이 (빠름)": "多(较快)",
|
||||
"많이 (빠름): {0} - 다른 앱이 많이 켜져 있으면 Android 가 이 앱을 끌 수 있습니다": "多(较快):{0} - 若打开了很多其他应用,Android 可能会关闭本应用",
|
||||
"말레이어": "马来语",
|
||||
"맞추기 (검은 여백)": "适应(黑边)",
|
||||
"맞추기 (비율이 다를 때)": "适配方式(比例不同时)",
|
||||
|
|
@ -952,6 +954,8 @@
|
|||
"보안": "安全",
|
||||
"보일 버튼을 고르고, 끌어서 순서를 바꿉니다.": "选择要显示的按钮,拖动以调整顺序。",
|
||||
"보정은 다시 인코딩해야 해서 코덱을 \"원본 유지\" 에서 H.264 로 바꿨습니다.": "调整需要重新编码,因此编解码器已从“保持原样”改为 H.264。",
|
||||
"보통": "普通",
|
||||
"보통: {0}": "普通:{0}",
|
||||
"복사": "复制",
|
||||
"복사 (붙여넣기로)": "复制 (用于粘贴)",
|
||||
"복사 · rsync": "复制 · rsync",
|
||||
|
|
@ -1402,6 +1406,7 @@
|
|||
"이 그림을 바탕으로 (그림 → 그림)": "以此图片为基础 (图片 → 图片)",
|
||||
"이 기기 (SD1.5 + LCM)": "本设备 (SD1.5 + LCM)",
|
||||
"이 기기 ({0})": "本设备 ({0})",
|
||||
"이 기기 메모리 {0}GB 기준:": "按本设备内存 {0}GB:",
|
||||
"이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "本设备只保存无法还原的哈希值,而不是密码本身。",
|
||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "本设备每张约 {0} (按上次耗时)",
|
||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "本设备每张约 {0} · 共约 {1} (按上次耗时)",
|
||||
|
|
@ -1628,6 +1633,8 @@
|
|||
"저장했습니다": "已保存",
|
||||
"저장했습니다: {0}": "已保存: {0}",
|
||||
"저장했습니다: {0} (MKV 에 반영됨)": "已保存: {0}(已应用到 MKV)",
|
||||
"적게 (느림)": "少(较慢)",
|
||||
"적게 (느림): {0}": "少(较慢):{0}",
|
||||
"적용": "应用",
|
||||
"전체 {0}개 중 {1}번째": "共 {0} 个中的第 {1} 个",
|
||||
"전체 만들기": "全部制作",
|
||||
|
|
@ -1842,6 +1849,8 @@
|
|||
"키 있음": "已有密钥",
|
||||
"타갈로그어": "他加禄语",
|
||||
"타밀어": "泰米尔语",
|
||||
"타일 {0} · 약 {1}GB": "分块 {0} · 约 {1}GB",
|
||||
"타일이 작을수록 느립니다 (예: 16GB 폰에서 1024×768 을 2배로 - 512 약 4분 · 320 약 9분 30초).": "图块越小越慢(例如:在 16GB 手机上将 1024×768 放大 2 倍 - 512 约 4 分钟 · 320 约 9 分 30 秒)。",
|
||||
"탐색기": "文件管理",
|
||||
"탐색기 오른쪽 클릭 메뉴": "资源管理器右键菜单",
|
||||
"탐색기에서 동영상을 열 때": "从资源管理器打开视频时",
|
||||
|
|
@ -1971,6 +1980,7 @@
|
|||
"할 일": "任务",
|
||||
"항목 {0}/{1}": "项目 {0}/{1}",
|
||||
"항목마다 따로 (기본)": "逐个项目 (默认)",
|
||||
"해상도 올리기 메모리": "提升分辨率内存",
|
||||
"해상도 올리기 모델": "提高分辨率模型",
|
||||
"해상도 올리기 모델을 받아 주세요 (환경 설정 > AI 그림)": "请下载提高分辨率模型 (设置 > AI 图片)",
|
||||
"해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "需要放大模型。要下载哪一个?",
|
||||
|
|
|
|||
|
|
@ -71,20 +71,30 @@ Uint8List _finish((Uint8List, int, int, int, String, int) a) {
|
|||
/// 그 밖 (Windows · GPU) 은 엔진 기본값
|
||||
bool _androidCpu(SdDevice d) => Platform.isAndroid && d.backend == 'cpu';
|
||||
int upscaleThreads(SdDevice d) => _androidCpu(d) ? Platform.numberOfProcessors : 0;
|
||||
int upscaleTileSize(SdDevice d, {int? memTotalMb, int? longSide}) =>
|
||||
_androidCpu(d) ? androidUpscaleTile(memTotalMb: memTotalMb, longSide: longSide) : 0;
|
||||
int upscaleTileSize(SdDevice d, {int? memTotalMb, int? longSide, double share = 0.30}) =>
|
||||
_androidCpu(d) ? androidUpscaleTile(memTotalMb: memTotalMb, longSide: longSide, share: share) : 0;
|
||||
|
||||
/// 176: 환경 설정의 해상도 올리기 메모리 → 기기 메모리 중 쓸 몫
|
||||
double upscaleMemoryShare(String setting) => switch (setting) {
|
||||
'low' => 0.20,
|
||||
'high' => 0.45,
|
||||
_ => 0.30,
|
||||
};
|
||||
|
||||
/// 176: Android CPU 타일 크기 - 메모리는 타일 넓이에 비례한다 (S10 실측: 타일 512 에서 엔진 6.6GB, 기기의 45%).
|
||||
/// 기기 전체 메모리의 20% 안에 드는 가장 큰 타일 (512 · 384 · 320 · 256 · 192). 메모리를 모르면 큰 그림 (긴 변 1000 이상) 은 256.
|
||||
int androidUpscaleTile({int? memTotalMb, int? longSide}) {
|
||||
const at512Mb = 6600;
|
||||
/// 기기 전체 메모리의 [share] 안에 드는 가장 큰 타일 (512 · 384 · 320 · 256 · 192). 메모리를 모르면 큰 그림 (긴 변 1000 이상) 은 256.
|
||||
/// 타일이 작을수록 느리다 (S10 1024×768 2배: 512 약 4분, 320 약 9분 30초)
|
||||
int androidUpscaleTile({int? memTotalMb, int? longSide, double share = 0.30}) {
|
||||
if (memTotalMb == null || memTotalMb <= 0) return (longSide ?? 0) >= 1000 ? 256 : 512;
|
||||
for (final t in const [512, 384, 320, 256]) {
|
||||
if (at512Mb * (t / 512) * (t / 512) <= memTotalMb * 0.20) return t;
|
||||
if (upscaleTileMemoryMb(t) <= memTotalMb * share) return t;
|
||||
}
|
||||
return 192;
|
||||
}
|
||||
|
||||
/// 타일 크기 → 엔진이 쓸 메모리 어림 (MB, S10 실측 512 → 6.6GB 에서 넓이 비례)
|
||||
int upscaleTileMemoryMb(int tile) => (6600 * (tile / 512) * (tile / 512)).round();
|
||||
|
||||
/// 기기 전체 메모리 (MB, /proc/meminfo - Android · Linux). 모르면 null
|
||||
int? deviceMemTotalMb() {
|
||||
try {
|
||||
|
|
@ -96,7 +106,8 @@ int? deviceMemTotalMb() {
|
|||
}
|
||||
|
||||
/// 156-2: 걸린 시간을 기억할 열쇠 (처리 장치 · 모델이 같아야 비교가 된다)
|
||||
String upscaleSpeedKey(AiUpscaler up) => '${up.device.backend}|${up.modelId}';
|
||||
/// 176: Android CPU 는 메모리 설정 (타일 크기) 에 따라 빠르기가 달라 그것도 열쇠에 (다른 설정의 시간으로 어림하지 않게)
|
||||
String upscaleSpeedKey(AiUpscaler up) => '${up.device.backend}|${up.modelId}${_androidCpu(up.device) ? '|${up.memory}' : ''}';
|
||||
|
||||
/// 그림의 화소 수 (백만 단위, 머리만 읽음 - 모르면 null)
|
||||
double? megapixels(Uint8List bytes) {
|
||||
|
|
@ -135,7 +146,10 @@ bool isFourTimes(Uint8List input, Uint8List result) {
|
|||
/// 그림 한 장 올리기. [input] 은 이 기기의 파일 (ZIP · WebDAV 의 그림은 부르는 쪽이 임시 파일로).
|
||||
/// 결과를 [save] 가 true 면 저장하고 그 경로를, 아니면 임시 파일 경로를 돌려준다 (비교해 보고 저장할 때).
|
||||
class AiUpscaler {
|
||||
AiUpscaler({required this.device, required this.modelPath, this.modelId = '', this.runner = runSdCli});
|
||||
AiUpscaler({required this.device, required this.modelPath, this.modelId = '', this.runner = runSdCli, this.memory = 'normal'});
|
||||
|
||||
/// 176: 환경 설정의 해상도 올리기 메모리 ('low' · 'normal' · 'high') - Android CPU 타일 크기
|
||||
final String memory;
|
||||
final SdDevice device;
|
||||
final String modelPath;
|
||||
|
||||
|
|
@ -165,7 +179,8 @@ class AiUpscaler {
|
|||
final info = img.findDecoderForData(Uint8List.fromList(bytes))?.startDecode(Uint8List.fromList(bytes));
|
||||
if (info != null) longSide = info.width > info.height ? info.width : info.height;
|
||||
} catch (_) {}
|
||||
final tile = upscaleTileSize(device, memTotalMb: Platform.isAndroid ? deviceMemTotalMb() : null, longSide: longSide);
|
||||
final tile = upscaleTileSize(device,
|
||||
memTotalMb: Platform.isAndroid ? deviceMemTotalMb() : null, longSide: longSide, share: upscaleMemoryShare(memory));
|
||||
await runner(device.exe, sdUpscaleArgs(model: modelPath, input: input, out: out, backend: device.backend, threads: upscaleThreads(device), tileSize: tile),
|
||||
onProgress: (prog) {
|
||||
final (v, left) = upscaleProgressOf(prog);
|
||||
|
|
@ -240,10 +255,11 @@ Future<SdDevice?> pickUpscaleDevice(AiStore store, {String device = 'auto'}) asy
|
|||
}
|
||||
|
||||
/// 해상도 올리기에 쓸 장치 · 모델 (없으면 null - 받을 것을 묻는다)
|
||||
Future<AiUpscaler?> prepareUpscaler(AiStore store, {required String modelSetting, String device = 'auto', String autoDevice = ''}) async {
|
||||
Future<AiUpscaler?> prepareUpscaler(AiStore store,
|
||||
{required String modelSetting, String device = 'auto', String autoDevice = '', String memory = 'normal'}) async {
|
||||
final dev = await pickUpscaleDevice(store, device: device);
|
||||
if (dev == null) return null;
|
||||
final id = installedUpscaleModel(store.isInstalled, modelSetting, gpu: dev.backend != 'cpu');
|
||||
if (id == null) return null;
|
||||
return AiUpscaler(device: dev, modelPath: store.pathOf(aiFile(id)), modelId: id);
|
||||
return AiUpscaler(device: dev, modelPath: store.pathOf(aiFile(id)), modelId: id, memory: memory);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -516,6 +516,9 @@ class AppSettings {
|
|||
/// 모델 'auto' (GPU 면 사진용, CPU 뿐이면 가볍고 빠른 만화용) · 'photo' · 'anime'
|
||||
String aiUpModel = 'auto';
|
||||
|
||||
/// 176: 해상도 올리기 메모리 (Android CPU 타일 크기) - 'low' 20% · 'normal' 30% (처음 값) · 'high' 45% (기기 메모리 중)
|
||||
String aiUpMemory = 'normal';
|
||||
|
||||
/// 156-2: 해상도 올리기에 걸린 시간 (처리 장치|모델 → 원본 100만 화소당 초) - "한 장 약 n초" 를 미리 알리려고
|
||||
Map<String, double> aiUpSecPerMp = {};
|
||||
|
||||
|
|
@ -712,6 +715,7 @@ class AppSettings {
|
|||
'aiSaveDir': aiSaveDir,
|
||||
'aiAgreed': aiAgreed,
|
||||
'aiUpModel': aiUpModel,
|
||||
'aiUpMemory': aiUpMemory,
|
||||
'aiUpSecPerMp': aiUpSecPerMp,
|
||||
'aiUpScale': aiUpScale,
|
||||
'aiUpFormat': aiUpFormat,
|
||||
|
|
@ -905,6 +909,7 @@ class AppSettings {
|
|||
..aiSaveDir = j['aiSaveDir'] as String? ?? ''
|
||||
..aiAgreed = [for (final x in (j['aiAgreed'] as List?) ?? const []) '$x']
|
||||
..aiUpModel = const ['photo', 'anime'].contains(j['aiUpModel']) ? j['aiUpModel'] as String : 'auto'
|
||||
..aiUpMemory = const ['low', 'high'].contains(j['aiUpMemory']) ? j['aiUpMemory'] as String : 'normal'
|
||||
..aiUpSecPerMp = {
|
||||
if (j['aiUpSecPerMp'] case final Map m)
|
||||
for (final e in m.entries)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import 'folder_picker.dart';
|
|||
import 'license_texts.dart' show showLicenseDocument;
|
||||
import 'setting_tile.dart';
|
||||
import 'theme.dart';
|
||||
import '../app/ai_upscale.dart' show androidUpscaleTile, upscaleMemoryShare, upscaleTileMemoryMb, deviceMemTotalMb;
|
||||
|
||||
/// 기기 안에서 그리는 데 아직 받지 않은 파일 (Windows 는 실행 파일까지, TAESD 포함) - AI 그림 화면 · 받기 화면이 같은 값을 보인다 (139)
|
||||
List<AiFile> aiMissingFiles(AiStore store) => [
|
||||
|
|
@ -71,6 +72,37 @@ class _AiSettingsState extends State<AiSettings> {
|
|||
|
||||
String get _platform => Platform.isAndroid ? 'android' : 'windows';
|
||||
|
||||
/// 176: 해상도 올리기 메모리 (적게 · 보통 · 많이) - 이 기기에서의 타일 · 예상 메모리
|
||||
Widget _upMemoryTile() {
|
||||
final mem = deviceMemTotalMb();
|
||||
String level(String id) {
|
||||
final t = androidUpscaleTile(memTotalMb: mem, share: upscaleMemoryShare(id));
|
||||
return trf('타일 {0} · 약 {1}GB', [t, (upscaleTileMemoryMb(t) / 1024).toStringAsFixed(1)]);
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
leading: const Icon(Icons.memory),
|
||||
title: Text(tr('해상도 올리기 메모리')),
|
||||
subtitle: Text([
|
||||
if (mem != null) trf('이 기기 메모리 {0}GB 기준:', [(mem / 1024).toStringAsFixed(0)]),
|
||||
trf('적게 (느림): {0}', [level('low')]),
|
||||
trf('보통: {0}', [level('normal')]),
|
||||
trf('많이 (빠름): {0} - 다른 앱이 많이 켜져 있으면 Android 가 이 앱을 끌 수 있습니다', [level('high')]),
|
||||
tr('타일이 작을수록 느립니다 (예: 16GB 폰에서 1024×768 을 2배로 - 512 약 4분 · 320 약 9분 30초).'),
|
||||
].join('\n')),
|
||||
isThreeLine: true,
|
||||
trailing: DropdownButton<String>(
|
||||
value: c.settings.aiUpMemory,
|
||||
items: [
|
||||
DropdownMenuItem(value: 'low', child: Text(tr('적게 (느림)'))),
|
||||
DropdownMenuItem(value: 'normal', child: Text(tr('보통'))),
|
||||
DropdownMenuItem(value: 'high', child: Text(tr('많이 (빠름)'))),
|
||||
],
|
||||
onChanged: (v) => c.updateSettings((x) => x.aiUpMemory = v ?? 'normal'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<AiFile> get _files => [
|
||||
for (final f in aiCatalog)
|
||||
if ((f.platforms.isEmpty || f.platforms.contains(_platform)) && (f.needs != 'nvidia' || _nvidia)) f,
|
||||
|
|
@ -229,6 +261,8 @@ class _AiSettingsState extends State<AiSettings> {
|
|||
onChanged: (v) => c.updateSettings((x) => x.aiUpModel = v ?? 'auto'),
|
||||
),
|
||||
),
|
||||
// 176: Android CPU - 메모리를 많이 쓸수록 빠르다 (그래픽카드 · Windows 는 엔진이 정함)
|
||||
if (Platform.isAndroid) _upMemoryTile(),
|
||||
SettingTile(
|
||||
leading: const Icon(Icons.zoom_out_map),
|
||||
title: Text(tr('배율')),
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ Future<AiUpscaler?> _prepare(BuildContext context, AppController c) async {
|
|||
if (debugUpscalerForTest case final f?) return f();
|
||||
final store = AiStore.instance ??= AiStore(Directory.systemTemp.path);
|
||||
Future<AiUpscaler?> ready() =>
|
||||
prepareUpscaler(store, modelSetting: c.settings.aiUpModel, device: c.settings.aiDevice, autoDevice: c.settings.aiAutoDevice);
|
||||
prepareUpscaler(store,
|
||||
modelSetting: c.settings.aiUpModel, device: c.settings.aiDevice, autoDevice: c.settings.aiAutoDevice, memory: c.settings.aiUpMemory);
|
||||
final up = await ready();
|
||||
if (up != null || !context.mounted) return up;
|
||||
// 엔진 (Windows 는 받아야 함) · 모델 중 없는 것
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:image/image.dart' as img;
|
|||
import 'package:jj_mkvmaker/app/ai_local.dart';
|
||||
import 'package:jj_mkvmaker/app/ai_upscale.dart';
|
||||
import 'package:jj_mkvmaker/app/app_controller.dart';
|
||||
import 'package:jj_mkvmaker/app/settings.dart';
|
||||
import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
|
||||
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
|
||||
import 'package:jj_mkvmaker/services/platform_services.dart';
|
||||
|
|
@ -40,10 +41,22 @@ void main() {
|
|||
tmp.deleteSync(recursive: true);
|
||||
});
|
||||
|
||||
test('176: 해상도 올리기 메모리 설정 - 적게 20% · 보통 30% (처음 값) · 많이 45%, 저장', () {
|
||||
expect(AppSettings().aiUpMemory, 'normal');
|
||||
expect(AppSettings.fromJson((AppSettings()..aiUpMemory = 'high').toJson()).aiUpMemory, 'high');
|
||||
expect(AppSettings.fromJson({'aiUpMemory': 'x'}).aiUpMemory, 'normal');
|
||||
// S10 (약 15GB): 적게 320 · 보통 384 · 많이 512
|
||||
expect([for (final m in ['low', 'normal', 'high']) androidUpscaleTile(memTotalMb: 15000, share: upscaleMemoryShare(m))], [320, 384, 512]);
|
||||
expect(upscaleTileMemoryMb(512), 6600);
|
||||
// 빠르기 기록은 메모리 설정마다 따로 (Android CPU 만)
|
||||
final a = AiUpscaler(device: const SdDevice('x', 'cpu', 'CPU'), modelPath: 'm', modelId: 'esrgan-x4plus', memory: 'low');
|
||||
expect(upscaleSpeedKey(a), Platform.isAndroid ? 'cpu|esrgan-x4plus|low' : 'cpu|esrgan-x4plus');
|
||||
});
|
||||
|
||||
test('타일 크기: 기기 메모리의 20% 안 (S10 16GB → 320), 메모리를 모르면 큰 그림만 256', () {
|
||||
expect(androidUpscaleTile(memTotalMb: 15000), 320);
|
||||
expect(androidUpscaleTile(memTotalMb: 40000), 512);
|
||||
expect(androidUpscaleTile(memTotalMb: 6000), 192);
|
||||
expect(androidUpscaleTile(memTotalMb: 15000, share: 0.20), 320);
|
||||
expect(androidUpscaleTile(memTotalMb: 40000, share: 0.20), 512);
|
||||
expect(androidUpscaleTile(memTotalMb: 6000, share: 0.20), 192);
|
||||
expect(androidUpscaleTile(longSide: 1024), 256);
|
||||
expect(androidUpscaleTile(longSide: 800), 512);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue