Add Force Software Encoder Feature

This commit is contained in:
copecone committed 2026-06-23 09:22:55 +09:00
1 parent 5f463273c7
commit 33ddd6a3d3
5 files changed
+33 -10

No files matched your search

+2
View File
@@ -466,6 +466,8 @@ namespace ADOFAIRenderer.Core
TargetBitrate = Configuration.EncodingConfig.Bitrate, TargetBitrate = Configuration.EncodingConfig.Bitrate,
MaxBitrate = Configuration.EncodingConfig.MaxBitrate, MaxBitrate = Configuration.EncodingConfig.MaxBitrate,
GopSize = Configuration.EncodingConfig.KeyframeInterval GopSize = Configuration.EncodingConfig.KeyframeInterval
GopSize = Configuration.EncodingConfig.KeyframeInterval,
ForceSoftware = Configuration.EncodingConfig.ForceSoftwareEncoder
}; };
videoFFmpeg = new FFmpegNativeEncoder(settings); videoFFmpeg = new FFmpegNativeEncoder(settings);
+1
View File
@@ -29,5 +29,6 @@ namespace ADOFAIRenderer.Data
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
public int QP; public int QP;
public double KeyframeInterval; public double KeyframeInterval;
public bool ForceSoftwareEncoder;
} }
} }
+17 -7
View File
@@ -1,4 +1,3 @@
using System.Text;
using ADOFAIRenderer.Core; using ADOFAIRenderer.Core;
using ADOFAIRenderer.Data; using ADOFAIRenderer.Data;
using ADOFAIRenderer.Util.FFmpeg; using ADOFAIRenderer.Util.FFmpeg;
@@ -103,7 +102,8 @@ namespace ADOFAIRenderer.UI
Bitrate = config.EncodingConfig.Bitrate, Bitrate = config.EncodingConfig.Bitrate,
MaxBitrate = config.EncodingConfig.MaxBitrate, MaxBitrate = config.EncodingConfig.MaxBitrate,
QP = config.EncodingConfig.QP, QP = config.EncodingConfig.QP,
KeyframeInterval = config.EncodingConfig.KeyframeInterval KeyframeInterval = config.EncodingConfig.KeyframeInterval,
ForceSoftwareEncoder = config.EncodingConfig.ForceSoftwareEncoder
}; };
if (_root.Contains(_encodingConfigContainer)) if (_root.Contains(_encodingConfigContainer))
@@ -203,6 +203,14 @@ namespace ADOFAIRenderer.UI
keyframeRow.Add(keyframeField); keyframeRow.Add(keyframeField);
_encodingConfigContainer.Add(keyframeRow); _encodingConfigContainer.Add(keyframeRow);
// 6.75. 강제 소프트웨어 인코더 로우 (라벨 + 토글)
var forceSoftwareRow = CreateRow();
var forceSoftwareLabel = CreateFormLabel("소프트웨어 인코더");
var forceSoftwareToggle = new Toggle { name = "ForceSoftwareEncoder", label = "", value = tempConfig.ForceSoftwareEncoder };
forceSoftwareRow.Add(forceSoftwareLabel);
forceSoftwareRow.Add(forceSoftwareToggle);
_encodingConfigContainer.Add(forceSoftwareRow);
// 7. QP = 0 (무손실) 경고 라벨 로우 생성 (ui-row 클래스를 상속받아 NanumSquareNeo 폰트가 적용되도록 처리) // 7. QP = 0 (무손실) 경고 라벨 로우 생성 (ui-row 클래스를 상속받아 NanumSquareNeo 폰트가 적용되도록 처리)
var warningRow = CreateRow(); var warningRow = CreateRow();
warningRow.style.height = StyleKeyword.Auto; warningRow.style.height = StyleKeyword.Auto;
@@ -240,10 +248,10 @@ namespace ADOFAIRenderer.UI
{ {
if (System.Enum.TryParse<RateControlMode>(selectedModeStr, out var mode)) if (System.Enum.TryParse<RateControlMode>(selectedModeStr, out var mode))
{ {
bitrateRow.style.display = (mode == RateControlMode.CBR || mode == RateControlMode.VBR) ? DisplayStyle.Flex : DisplayStyle.None; bitrateRow.style.display = mode is RateControlMode.CBR or RateControlMode.VBR ? DisplayStyle.Flex : DisplayStyle.None;
maxBitrateRow.style.display = (mode == RateControlMode.VBR) ? DisplayStyle.Flex : DisplayStyle.None; maxBitrateRow.style.display = mode == RateControlMode.VBR ? DisplayStyle.Flex : DisplayStyle.None;
qpRow.style.display = (mode == RateControlMode.CQP) ? DisplayStyle.Flex : DisplayStyle.None; qpRow.style.display = mode == RateControlMode.CQP ? DisplayStyle.Flex : DisplayStyle.None;
warningRow.style.display = (mode == RateControlMode.CQP && qpField.value == 0) ? DisplayStyle.Flex : DisplayStyle.None; warningRow.style.display = mode == RateControlMode.CQP && qpField.value == 0 ? DisplayStyle.Flex : DisplayStyle.None;
} }
} }
@@ -292,6 +300,7 @@ namespace ADOFAIRenderer.UI
tempConfig.MaxBitrate = maxBitrateField.value; tempConfig.MaxBitrate = maxBitrateField.value;
tempConfig.QP = qpField.value; tempConfig.QP = qpField.value;
tempConfig.KeyframeInterval = keyframeField.value; tempConfig.KeyframeInterval = keyframeField.value;
tempConfig.ForceSoftwareEncoder = forceSoftwareToggle.value;
if (tempConfig.RateControlMode == RateControlMode.VBR && tempConfig.MaxBitrate < tempConfig.Bitrate) if (tempConfig.RateControlMode == RateControlMode.VBR && tempConfig.MaxBitrate < tempConfig.Bitrate)
{ {
@@ -362,7 +371,8 @@ namespace ADOFAIRenderer.UI
{ {
RateControlMode = RateControlMode.CBR, RateControlMode = RateControlMode.CBR,
Bitrate = 30000, MaxBitrate = 50000, Bitrate = 30000, MaxBitrate = 50000,
QP = 18, KeyframeInterval = 2.0 QP = 18, KeyframeInterval = 2.0,
ForceSoftwareEncoder = false
}; };
} }
} }
+4 -1
View File
@@ -68,6 +68,9 @@ namespace ADOFAIRenderer.Util.FFmpeg
/// <summary>GOP(Group of Pictures) 크기 (초). 키프레임 간격을 의미합니다.</summary> /// <summary>GOP(Group of Pictures) 크기 (초). 키프레임 간격을 의미합니다.</summary>
public double GopSize; public double GopSize;
/// <summary>소프트웨어 CPU 인코더를 강제 사용할지 여부.</summary>
public bool ForceSoftware;
} }
// ────────────────────────────────────────────────────────────── // ──────────────────────────────────────────────────────────────
@@ -214,7 +217,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
/// </summary> /// </summary>
private string[] GetEncoderCandidates() private string[] GetEncoderCandidates()
{ {
return GPUUtil.GetPrioritizedEncoderCandidates(_settings.Codec).ToArray(); return GPUUtil.GetPrioritizedEncoderCandidates(_settings.Codec, _settings.ForceSoftware).ToArray();
} }
/// <summary> /// <summary>
+9 -2
View File
@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ADOFAIRenderer.Util.FFmpeg; using ADOFAIRenderer.Util.FFmpeg;
using MelonLoader; using MelonLoader;
@@ -130,12 +131,18 @@ namespace ADOFAIRenderer.Util
return null; return null;
} }
public static List<string> GetPrioritizedEncoderCandidates(Codec codec) public static List<string> GetPrioritizedEncoderCandidates(Codec codec, bool forceSoftware = false)
{ {
if (!CodecMap.TryGetValue(codec, out var list)) return new List<string>(); if (!CodecMap.TryGetValue(codec, out var list)) return new List<string>();
var vendor = GetActiveGPUVendor();
var prioritized = new List<string>(); var prioritized = new List<string>();
if (forceSoftware)
{
prioritized.AddRange(from item in list where item.Item1 == GPUVendor.Unknown select item.Item2);
return prioritized;
}
var vendor = GetActiveGPUVendor();
var others = new List<string>(); var others = new List<string>();
foreach (var item in list) foreach (var item in list)