SHA256
Add Encoding Config UI
This commit is contained in:
2 files changed
+204
-2
No files matched your search
+203
-1
@@ -20,6 +20,7 @@ namespace ADOFAIRenderer.UI
|
|||||||
|
|
||||||
private Button _goRenderButton = null!;
|
private Button _goRenderButton = null!;
|
||||||
private Button _encodingConfigButton = null!;
|
private Button _encodingConfigButton = null!;
|
||||||
|
private VisualElement _encodingConfigContainer = null!;
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
@@ -92,7 +93,208 @@ namespace ADOFAIRenderer.UI
|
|||||||
private void OpenEncodingConfig()
|
private void OpenEncodingConfig()
|
||||||
{
|
{
|
||||||
Melon<RenderMod>.Logger.Msg("[UI] OpenEncodingConfig 호출됨");
|
Melon<RenderMod>.Logger.Msg("[UI] OpenEncodingConfig 호출됨");
|
||||||
RenderManager.Instance.Configuration.EncodingConfig ??= GenerateEncodingConfig(_codecBinder.Value);
|
|
||||||
|
var config = RenderManager.Instance.Configuration;
|
||||||
|
config.EncodingConfig ??= GenerateEncodingConfig(_codecBinder.Value);
|
||||||
|
|
||||||
|
var tempConfig = new EncodingConfig
|
||||||
|
{
|
||||||
|
RateControlMode = config.EncodingConfig.RateControlMode,
|
||||||
|
Bitrate = config.EncodingConfig.Bitrate,
|
||||||
|
MaxBitrate = config.EncodingConfig.MaxBitrate,
|
||||||
|
QP = config.EncodingConfig.QP
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_root.Contains(_encodingConfigContainer))
|
||||||
|
{
|
||||||
|
_root.Remove(_encodingConfigContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 전체 화면 컨테이너 생성 및 배경 적용
|
||||||
|
_encodingConfigContainer = new VisualElement { name = "EncodingSettingsContainer" };
|
||||||
|
_encodingConfigContainer.style.position = Position.Absolute;
|
||||||
|
_encodingConfigContainer.style.width = Length.Percent(100);
|
||||||
|
_encodingConfigContainer.style.height = Length.Percent(100);
|
||||||
|
_encodingConfigContainer.style.left = 0;
|
||||||
|
_encodingConfigContainer.style.top = 0;
|
||||||
|
_encodingConfigContainer.style.backgroundColor = new StyleColor(new Color(0.15f, 0.15f, 0.15f, 1.0f));
|
||||||
|
_encodingConfigContainer.style.justifyContent = Justify.Center;
|
||||||
|
_encodingConfigContainer.style.alignItems = Align.Center;
|
||||||
|
|
||||||
|
// 로우 생성 헬퍼 (UXML의 ui-row 속성 복제)
|
||||||
|
VisualElement CreateRow()
|
||||||
|
{
|
||||||
|
var row = new VisualElement();
|
||||||
|
row.AddToClassList("ui-row");
|
||||||
|
row.style.flexDirection = FlexDirection.Row;
|
||||||
|
row.style.height = 130;
|
||||||
|
row.style.maxHeight = 130;
|
||||||
|
row.style.minHeight = 80;
|
||||||
|
row.style.justifyContent = Justify.Center;
|
||||||
|
row.style.alignItems = Align.Center;
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 라벨 생성 헬퍼 (우측 정렬 적용하여 인풋과의 인접성 향상)
|
||||||
|
Label CreateFormLabel(string text)
|
||||||
|
{
|
||||||
|
var label = new Label(text);
|
||||||
|
label.style.unityTextAlign = TextAnchor.MiddleRight;
|
||||||
|
label.style.color = new StyleColor(Color.white);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 타이틀 로우
|
||||||
|
var titleRow = CreateRow();
|
||||||
|
var title = new Label("인코딩 설정");
|
||||||
|
title.style.fontSize = 36;
|
||||||
|
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||||
|
title.style.color = new StyleColor(Color.white);
|
||||||
|
title.style.unityTextAlign = TextAnchor.MiddleCenter;
|
||||||
|
title.style.width = 770; // 360 * 2 + 50 (여백)에 맞춤
|
||||||
|
title.style.height = StyleKeyword.Auto;
|
||||||
|
titleRow.Add(title);
|
||||||
|
_encodingConfigContainer.Add(titleRow);
|
||||||
|
|
||||||
|
// 3. 전송률 모드 로우 (라벨 + 드롭다운)
|
||||||
|
var modeRow = CreateRow();
|
||||||
|
var modeLabel = CreateFormLabel("전송률 제어 모드");
|
||||||
|
var modeDropdown = new DropdownField { label = "" };
|
||||||
|
foreach (RateControlMode modeVal in System.Enum.GetValues(typeof(RateControlMode)))
|
||||||
|
{
|
||||||
|
modeDropdown.choices.Add(modeVal.ToString());
|
||||||
|
}
|
||||||
|
modeDropdown.value = tempConfig.RateControlMode.ToString();
|
||||||
|
|
||||||
|
modeRow.Add(modeLabel);
|
||||||
|
modeRow.Add(modeDropdown);
|
||||||
|
_encodingConfigContainer.Add(modeRow);
|
||||||
|
|
||||||
|
// 4. Bitrate 로우 (라벨 + 입력)
|
||||||
|
var bitrateRow = CreateRow();
|
||||||
|
var bitrateLabel = CreateFormLabel("대상 비트레이트 (kbps)");
|
||||||
|
var bitrateField = new IntegerField { name = "EncodingBitrate", label = "", value = tempConfig.Bitrate };
|
||||||
|
bitrateRow.Add(bitrateLabel);
|
||||||
|
bitrateRow.Add(bitrateField);
|
||||||
|
_encodingConfigContainer.Add(bitrateRow);
|
||||||
|
|
||||||
|
// 5. Max Bitrate 로우 (라벨 + 입력)
|
||||||
|
var maxBitrateRow = CreateRow();
|
||||||
|
var maxBitrateLabel = CreateFormLabel("최대 비트레이트 (kbps)");
|
||||||
|
var maxBitrateField = new IntegerField { name = "EncodingMaxBitrate", label = "", value = tempConfig.MaxBitrate };
|
||||||
|
maxBitrateRow.Add(maxBitrateLabel);
|
||||||
|
maxBitrateRow.Add(maxBitrateField);
|
||||||
|
_encodingConfigContainer.Add(maxBitrateRow);
|
||||||
|
|
||||||
|
// 6. QP 로우 (라벨 + 입력)
|
||||||
|
var qpRow = CreateRow();
|
||||||
|
var qpLabel = CreateFormLabel("QP 품질 값 (0 ~ 51)");
|
||||||
|
var qpField = new IntegerField { name = "EncodingQP", label = "", value = tempConfig.QP };
|
||||||
|
qpRow.Add(qpLabel);
|
||||||
|
qpRow.Add(qpField);
|
||||||
|
_encodingConfigContainer.Add(qpRow);
|
||||||
|
|
||||||
|
// 7. QP = 0 (무손실) 경고 라벨 로우 생성 (ui-row 클래스를 상속받아 NanumSquareNeo 폰트가 적용되도록 처리)
|
||||||
|
var warningRow = CreateRow();
|
||||||
|
warningRow.style.height = StyleKeyword.Auto;
|
||||||
|
warningRow.style.maxHeight = StyleKeyword.Null;
|
||||||
|
warningRow.style.minHeight = StyleKeyword.Null;
|
||||||
|
|
||||||
|
var warningLabel = new Label("※ QP 0 (무손실)은 일부 하드웨어/코덱에서 지원되지 않을 수 있으며, 인코딩 실패 시 CPU 모드로 폴백됩니다.");
|
||||||
|
warningLabel.style.fontSize = 20; // 30px에서 20px로 오버라이드
|
||||||
|
warningLabel.style.color = new StyleColor(new Color(0.9f, 0.6f, 0.2f));
|
||||||
|
warningLabel.style.whiteSpace = WhiteSpace.Normal;
|
||||||
|
warningLabel.style.width = 720; // 360px에서 720px로 오버라이드
|
||||||
|
warningLabel.style.height = StyleKeyword.Auto;
|
||||||
|
warningLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
|
||||||
|
warningLabel.style.marginTop = 10;
|
||||||
|
warningLabel.style.marginBottom = 10;
|
||||||
|
|
||||||
|
warningRow.Add(warningLabel);
|
||||||
|
_encodingConfigContainer.Add(warningRow);
|
||||||
|
|
||||||
|
// 7.5. 유효성 검사기 설정 (기존에 작성된 validator 재사용 및 이전 값 복원)
|
||||||
|
var encodingValidator = new IntegerInputValidator(_encodingConfigContainer);
|
||||||
|
encodingValidator
|
||||||
|
.AddLimits("EncodingBitrate", new RangeIntegerLimit(100, 1000000))
|
||||||
|
.AddLimits("EncodingMaxBitrate", new RangeIntegerLimit(100, 1000000))
|
||||||
|
.AddLimits("EncodingQP", new RangeIntegerLimit(0, 51));
|
||||||
|
encodingValidator.SetupValidation();
|
||||||
|
|
||||||
|
// 가시성 필터링 업데이트 (행 단위로 보임/숨김 제어)
|
||||||
|
void UpdateVisibility(string selectedModeStr)
|
||||||
|
{
|
||||||
|
if (System.Enum.TryParse<RateControlMode>(selectedModeStr, out var mode))
|
||||||
|
{
|
||||||
|
bitrateRow.style.display = (mode == RateControlMode.CBR || 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;
|
||||||
|
warningRow.style.display = (mode == RateControlMode.CQP && qpField.value == 0) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modeDropdown.RegisterValueChangedCallback(evt => UpdateVisibility(evt.newValue));
|
||||||
|
qpField.RegisterValueChangedCallback(evt =>
|
||||||
|
{
|
||||||
|
warningRow.style.display = (modeDropdown.value == "CQP" && evt.newValue == 0) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
});
|
||||||
|
|
||||||
|
UpdateVisibility(modeDropdown.value);
|
||||||
|
|
||||||
|
// 화면 전환 제어
|
||||||
|
void ToggleScreens(bool showEncoding)
|
||||||
|
{
|
||||||
|
foreach (var child in _root.Children())
|
||||||
|
{
|
||||||
|
if (child == _encodingConfigContainer) continue;
|
||||||
|
child.style.display = showEncoding ? DisplayStyle.None : DisplayStyle.Flex;
|
||||||
|
}
|
||||||
|
_encodingConfigContainer.style.display = showEncoding ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. 제어 버튼 로우 (취소 / 저장)
|
||||||
|
var buttonRow = CreateRow();
|
||||||
|
var cancelBtn = new Button { text = "취소" };
|
||||||
|
var saveBtn = new Button { text = "저장" };
|
||||||
|
|
||||||
|
buttonRow.Add(cancelBtn);
|
||||||
|
buttonRow.Add(saveBtn);
|
||||||
|
_encodingConfigContainer.Add(buttonRow);
|
||||||
|
|
||||||
|
cancelBtn.RegisterCallback<ClickEvent>(evt =>
|
||||||
|
{
|
||||||
|
ToggleScreens(false);
|
||||||
|
_root.Remove(_encodingConfigContainer);
|
||||||
|
_encodingConfigContainer = null!;
|
||||||
|
});
|
||||||
|
|
||||||
|
saveBtn.RegisterCallback<ClickEvent>(evt =>
|
||||||
|
{
|
||||||
|
if (System.Enum.TryParse<RateControlMode>(modeDropdown.value, out var mode))
|
||||||
|
{
|
||||||
|
tempConfig.RateControlMode = mode;
|
||||||
|
}
|
||||||
|
tempConfig.Bitrate = bitrateField.value;
|
||||||
|
tempConfig.MaxBitrate = maxBitrateField.value;
|
||||||
|
tempConfig.QP = qpField.value;
|
||||||
|
|
||||||
|
if (tempConfig.RateControlMode == RateControlMode.VBR && tempConfig.MaxBitrate < tempConfig.Bitrate)
|
||||||
|
{
|
||||||
|
tempConfig.MaxBitrate = tempConfig.Bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.EncodingConfig = tempConfig;
|
||||||
|
|
||||||
|
ToggleScreens(false);
|
||||||
|
_root.Remove(_encodingConfigContainer);
|
||||||
|
_encodingConfigContainer = null!;
|
||||||
|
Melon<RenderMod>.Logger.Msg($"[UI] EncodingConfig 저장 완료");
|
||||||
|
});
|
||||||
|
|
||||||
|
_root.Add(_encodingConfigContainer);
|
||||||
|
|
||||||
|
// 화면 전환 활성화
|
||||||
|
ToggleScreens(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TryGoRender()
|
private void TryGoRender()
|
||||||
|
|||||||
@@ -772,7 +772,7 @@ namespace ADOFAIRenderer.Util.FFmpeg
|
|||||||
case RateControlMode.CQP:
|
case RateControlMode.CQP:
|
||||||
// 기본값 18: H.264에서 "시각적으로 거의 무손실"에 가까운 품질.
|
// 기본값 18: H.264에서 "시각적으로 거의 무손실"에 가까운 품질.
|
||||||
// 다른 코덱에서도 비슷한 수준의 품질을 제공합니다.
|
// 다른 코덱에서도 비슷한 수준의 품질을 제공합니다.
|
||||||
var qpValue = _settings.QualityValue > 0 ? _settings.QualityValue : 18;
|
var qpValue = (_settings.QualityValue >= 0 && _settings.QualityValue <= 51) ? _settings.QualityValue : 18;
|
||||||
|
|
||||||
if (encoderName.Contains("nvenc"))
|
if (encoderName.Contains("nvenc"))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user