|
|
@@ -0,0 +1,1461 @@
|
|
|
+#include "recorder_settings_dialog.h"
|
|
|
+#include "../recorder.h"
|
|
|
+#include <QApplication>
|
|
|
+#include <QMessageBox>
|
|
|
+#include <QDir>
|
|
|
+#include <QJsonDocument>
|
|
|
+#include <QJsonObject>
|
|
|
+#include <QDateTime>
|
|
|
+#include <QDebug>
|
|
|
+#include <QHeaderView>
|
|
|
+#include <QSplitter>
|
|
|
+#include <QFormLayout>
|
|
|
+#include <QButtonGroup>
|
|
|
+#include <QRadioButton>
|
|
|
+#include <QScrollArea>
|
|
|
+#include <QCloseEvent>
|
|
|
+
|
|
|
+RecorderSettingsDialog::RecorderSettingsDialog(av::recorder::RecorderModule* recorderModule, QWidget* parent)
|
|
|
+ : QDialog(parent)
|
|
|
+ , m_recorderModule(recorderModule)
|
|
|
+ , m_tabWidget(nullptr)
|
|
|
+ , m_mainLayout(nullptr)
|
|
|
+ , m_buttonLayout(nullptr)
|
|
|
+ , m_okButton(nullptr)
|
|
|
+ , m_cancelButton(nullptr)
|
|
|
+ , m_applyButton(nullptr)
|
|
|
+ , m_resetButton(nullptr)
|
|
|
+ , m_settingsChanged(false)
|
|
|
+ , m_updating(false) {
|
|
|
+
|
|
|
+ setWindowTitle("录制器设置");
|
|
|
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
|
+ setModal(true);
|
|
|
+ resize(800, 600);
|
|
|
+
|
|
|
+ // 初始化定时器
|
|
|
+ m_previewUpdateTimer = new QTimer(this);
|
|
|
+ m_previewUpdateTimer->setSingleShot(true);
|
|
|
+ m_previewUpdateTimer->setInterval(500);
|
|
|
+ connect(m_previewUpdateTimer, &QTimer::timeout, this, &RecorderSettingsDialog::updatePreview);
|
|
|
+
|
|
|
+ m_deviceRefreshTimer = new QTimer(this);
|
|
|
+ m_deviceRefreshTimer->setInterval(5000); // 每5秒刷新一次设备列表
|
|
|
+ connect(m_deviceRefreshTimer, &QTimer::timeout, this, &RecorderSettingsDialog::refreshDevices);
|
|
|
+
|
|
|
+ initializeUI();
|
|
|
+ connectSignals();
|
|
|
+
|
|
|
+ // 加载默认设置
|
|
|
+ m_currentSettings = getDefaultSettings();
|
|
|
+ m_originalSettings = m_currentSettings;
|
|
|
+
|
|
|
+ loadSettings();
|
|
|
+ writeSettingsToUI();
|
|
|
+ updateUI();
|
|
|
+}
|
|
|
+
|
|
|
+RecorderSettingsDialog::~RecorderSettingsDialog() = default;
|
|
|
+
|
|
|
+void RecorderSettingsDialog::setSettings(const Settings& settings) {
|
|
|
+ m_currentSettings = settings;
|
|
|
+ writeSettingsToUI();
|
|
|
+ updateUI();
|
|
|
+}
|
|
|
+
|
|
|
+RecorderSettingsDialog::Settings RecorderSettingsDialog::getSettings() const {
|
|
|
+ return m_currentSettings;
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::showCategory(SettingsCategory category) {
|
|
|
+ if (m_tabWidget) {
|
|
|
+ m_tabWidget->setCurrentIndex(static_cast<int>(category));
|
|
|
+ }
|
|
|
+ show();
|
|
|
+ raise();
|
|
|
+ activateWindow();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::resetToDefaults() {
|
|
|
+ int ret = QMessageBox::question(this, "重置设置",
|
|
|
+ "确定要重置所有设置为默认值吗?",
|
|
|
+ QMessageBox::Yes | QMessageBox::No,
|
|
|
+ QMessageBox::No);
|
|
|
+
|
|
|
+ if (ret == QMessageBox::Yes) {
|
|
|
+ m_currentSettings = getDefaultSettings();
|
|
|
+ writeSettingsToUI();
|
|
|
+ updateUI();
|
|
|
+ m_settingsChanged = true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::loadSettings() {
|
|
|
+ QSettings settings("AV", "Recorder");
|
|
|
+
|
|
|
+ // 音频设置
|
|
|
+ settings.beginGroup("Audio");
|
|
|
+ m_currentSettings.audio.deviceName = settings.value("deviceName", "").toString();
|
|
|
+ m_currentSettings.audio.sampleRate = settings.value("sampleRate", 44100).toInt();
|
|
|
+ m_currentSettings.audio.channels = settings.value("channels", 2).toInt();
|
|
|
+ m_currentSettings.audio.bitDepth = settings.value("bitDepth", 16).toInt();
|
|
|
+ m_currentSettings.audio.codec = settings.value("codec", "aac").toString();
|
|
|
+ m_currentSettings.audio.bitrate = settings.value("bitrate", 128000).toInt();
|
|
|
+ m_currentSettings.audio.enableNoiseSuppression = settings.value("enableNoiseSuppression", false).toBool();
|
|
|
+ m_currentSettings.audio.enableEchoCancellation = settings.value("enableEchoCancellation", false).toBool();
|
|
|
+ m_currentSettings.audio.inputGain = settings.value("inputGain", 1.0).toDouble();
|
|
|
+ settings.endGroup();
|
|
|
+
|
|
|
+ // 视频设置
|
|
|
+ settings.beginGroup("Video");
|
|
|
+ m_currentSettings.video.deviceName = settings.value("deviceName", "").toString();
|
|
|
+ m_currentSettings.video.width = settings.value("width", 1920).toInt();
|
|
|
+ m_currentSettings.video.height = settings.value("height", 1080).toInt();
|
|
|
+ m_currentSettings.video.frameRate = settings.value("frameRate", 30.0).toDouble();
|
|
|
+ m_currentSettings.video.codec = settings.value("codec", "h264").toString();
|
|
|
+ m_currentSettings.video.bitrate = settings.value("bitrate", 5000000).toInt();
|
|
|
+ m_currentSettings.video.preset = settings.value("preset", "medium").toString();
|
|
|
+ m_currentSettings.video.profile = settings.value("profile", "high").toString();
|
|
|
+ m_currentSettings.video.keyFrameInterval = settings.value("keyFrameInterval", 60).toInt();
|
|
|
+ m_currentSettings.video.enableHardwareAcceleration = settings.value("enableHardwareAcceleration", true).toBool();
|
|
|
+ settings.endGroup();
|
|
|
+
|
|
|
+ // 输出设置
|
|
|
+ settings.beginGroup("Output");
|
|
|
+ m_currentSettings.output.outputDirectory = settings.value("outputDirectory",
|
|
|
+ QStandardPaths::writableLocation(QStandardPaths::MoviesLocation)).toString();
|
|
|
+ m_currentSettings.output.fileNameTemplate = settings.value("fileNameTemplate", "recording_%Y%m%d_%H%M%S").toString();
|
|
|
+ m_currentSettings.output.containerFormat = settings.value("containerFormat", "mp4").toString();
|
|
|
+ m_currentSettings.output.autoCreateDirectory = settings.value("autoCreateDirectory", true).toBool();
|
|
|
+ m_currentSettings.output.overwriteExisting = settings.value("overwriteExisting", false).toBool();
|
|
|
+ m_currentSettings.output.maxFileSize = settings.value("maxFileSize", 0).toInt();
|
|
|
+ m_currentSettings.output.maxDuration = settings.value("maxDuration", 0).toInt();
|
|
|
+ settings.endGroup();
|
|
|
+
|
|
|
+ // 高级设置
|
|
|
+ settings.beginGroup("Advanced");
|
|
|
+ m_currentSettings.advanced.bufferSize = settings.value("bufferSize", 4096).toInt();
|
|
|
+ m_currentSettings.advanced.threadCount = settings.value("threadCount", 0).toInt();
|
|
|
+ m_currentSettings.advanced.enableGPUAcceleration = settings.value("enableGPUAcceleration", true).toBool();
|
|
|
+ m_currentSettings.advanced.gpuDevice = settings.value("gpuDevice", "").toString();
|
|
|
+ m_currentSettings.advanced.enableLowLatency = settings.value("enableLowLatency", false).toBool();
|
|
|
+ m_currentSettings.advanced.enableRealTimeEncoding = settings.value("enableRealTimeEncoding", true).toBool();
|
|
|
+ m_currentSettings.advanced.encodingPriority = settings.value("encodingPriority", 0).toInt();
|
|
|
+ settings.endGroup();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::saveSettings() {
|
|
|
+ QSettings settings("AV", "Recorder");
|
|
|
+
|
|
|
+ // 音频设置
|
|
|
+ settings.beginGroup("Audio");
|
|
|
+ settings.setValue("deviceName", m_currentSettings.audio.deviceName);
|
|
|
+ settings.setValue("sampleRate", m_currentSettings.audio.sampleRate);
|
|
|
+ settings.setValue("channels", m_currentSettings.audio.channels);
|
|
|
+ settings.setValue("bitDepth", m_currentSettings.audio.bitDepth);
|
|
|
+ settings.setValue("codec", m_currentSettings.audio.codec);
|
|
|
+ settings.setValue("bitrate", m_currentSettings.audio.bitrate);
|
|
|
+ settings.setValue("enableNoiseSuppression", m_currentSettings.audio.enableNoiseSuppression);
|
|
|
+ settings.setValue("enableEchoCancellation", m_currentSettings.audio.enableEchoCancellation);
|
|
|
+ settings.setValue("inputGain", m_currentSettings.audio.inputGain);
|
|
|
+ settings.endGroup();
|
|
|
+
|
|
|
+ // 视频设置
|
|
|
+ settings.beginGroup("Video");
|
|
|
+ settings.setValue("deviceName", m_currentSettings.video.deviceName);
|
|
|
+ settings.setValue("width", m_currentSettings.video.width);
|
|
|
+ settings.setValue("height", m_currentSettings.video.height);
|
|
|
+ settings.setValue("frameRate", m_currentSettings.video.frameRate);
|
|
|
+ settings.setValue("codec", m_currentSettings.video.codec);
|
|
|
+ settings.setValue("bitrate", m_currentSettings.video.bitrate);
|
|
|
+ settings.setValue("preset", m_currentSettings.video.preset);
|
|
|
+ settings.setValue("profile", m_currentSettings.video.profile);
|
|
|
+ settings.setValue("keyFrameInterval", m_currentSettings.video.keyFrameInterval);
|
|
|
+ settings.setValue("enableHardwareAcceleration", m_currentSettings.video.enableHardwareAcceleration);
|
|
|
+ settings.endGroup();
|
|
|
+
|
|
|
+ // 输出设置
|
|
|
+ settings.beginGroup("Output");
|
|
|
+ settings.setValue("outputDirectory", m_currentSettings.output.outputDirectory);
|
|
|
+ settings.setValue("fileNameTemplate", m_currentSettings.output.fileNameTemplate);
|
|
|
+ settings.setValue("containerFormat", m_currentSettings.output.containerFormat);
|
|
|
+ settings.setValue("autoCreateDirectory", m_currentSettings.output.autoCreateDirectory);
|
|
|
+ settings.setValue("overwriteExisting", m_currentSettings.output.overwriteExisting);
|
|
|
+ settings.setValue("maxFileSize", m_currentSettings.output.maxFileSize);
|
|
|
+ settings.setValue("maxDuration", m_currentSettings.output.maxDuration);
|
|
|
+ settings.endGroup();
|
|
|
+
|
|
|
+ // 高级设置
|
|
|
+ settings.beginGroup("Advanced");
|
|
|
+ settings.setValue("bufferSize", m_currentSettings.advanced.bufferSize);
|
|
|
+ settings.setValue("threadCount", m_currentSettings.advanced.threadCount);
|
|
|
+ settings.setValue("enableGPUAcceleration", m_currentSettings.advanced.enableGPUAcceleration);
|
|
|
+ settings.setValue("gpuDevice", m_currentSettings.advanced.gpuDevice);
|
|
|
+ settings.setValue("enableLowLatency", m_currentSettings.advanced.enableLowLatency);
|
|
|
+ settings.setValue("enableRealTimeEncoding", m_currentSettings.advanced.enableRealTimeEncoding);
|
|
|
+ settings.setValue("encodingPriority", m_currentSettings.advanced.encodingPriority);
|
|
|
+ settings.endGroup();
|
|
|
+
|
|
|
+ settings.sync();
|
|
|
+}
|
|
|
+
|
|
|
+bool RecorderSettingsDialog::validateSettings(QString* errorMessage) const {
|
|
|
+ // 验证音频设置
|
|
|
+ if (m_currentSettings.audio.sampleRate <= 0) {
|
|
|
+ if (errorMessage) *errorMessage = "无效的音频采样率";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (m_currentSettings.audio.channels <= 0 || m_currentSettings.audio.channels > 8) {
|
|
|
+ if (errorMessage) *errorMessage = "无效的音频声道数";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (m_currentSettings.audio.bitrate <= 0) {
|
|
|
+ if (errorMessage) *errorMessage = "无效的音频比特率";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证视频设置
|
|
|
+ if (m_currentSettings.video.width <= 0 || m_currentSettings.video.height <= 0) {
|
|
|
+ if (errorMessage) *errorMessage = "无效的视频分辨率";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (m_currentSettings.video.frameRate <= 0) {
|
|
|
+ if (errorMessage) *errorMessage = "无效的视频帧率";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (m_currentSettings.video.bitrate <= 0) {
|
|
|
+ if (errorMessage) *errorMessage = "无效的视频比特率";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证输出设置
|
|
|
+ if (!validateOutputDirectory(m_currentSettings.output.outputDirectory)) {
|
|
|
+ if (errorMessage) *errorMessage = "输出目录无效或无法访问";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (m_currentSettings.output.fileNameTemplate.isEmpty()) {
|
|
|
+ if (errorMessage) *errorMessage = "文件名模板不能为空";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::showEvent(QShowEvent* event) {
|
|
|
+ QDialog::showEvent(event);
|
|
|
+
|
|
|
+ // 刷新设备列表
|
|
|
+ updateAudioDevices();
|
|
|
+ updateVideoDevices();
|
|
|
+ updateCodecLists();
|
|
|
+
|
|
|
+ // 启动设备刷新定时器
|
|
|
+ m_deviceRefreshTimer->start();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::closeEvent(QCloseEvent* event) {
|
|
|
+ // 停止定时器
|
|
|
+ m_deviceRefreshTimer->stop();
|
|
|
+
|
|
|
+ if (m_settingsChanged) {
|
|
|
+ int ret = QMessageBox::question(this, "保存设置",
|
|
|
+ "设置已修改,是否保存?",
|
|
|
+ QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
|
|
|
+ QMessageBox::Save);
|
|
|
+
|
|
|
+ if (ret == QMessageBox::Save) {
|
|
|
+ onApplySettings();
|
|
|
+ } else if (ret == QMessageBox::Cancel) {
|
|
|
+ event->ignore();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ QDialog::closeEvent(event);
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onTabChanged(int index) {
|
|
|
+ Q_UNUSED(index)
|
|
|
+ updateUI();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onAudioDeviceChanged(const QString& device) {
|
|
|
+ if (m_updating) return;
|
|
|
+
|
|
|
+ m_currentSettings.audio.deviceName = device;
|
|
|
+ m_settingsChanged = true;
|
|
|
+ updateUI();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onVideoDeviceChanged(const QString& device) {
|
|
|
+ if (m_updating) return;
|
|
|
+
|
|
|
+ m_currentSettings.video.deviceName = device;
|
|
|
+ m_settingsChanged = true;
|
|
|
+ updateUI();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onOutputDirectoryBrowse() {
|
|
|
+ QString dir = QFileDialog::getExistingDirectory(this, "选择输出目录",
|
|
|
+ m_currentSettings.output.outputDirectory);
|
|
|
+ if (!dir.isEmpty()) {
|
|
|
+ m_currentSettings.output.outputDirectory = dir;
|
|
|
+ if (m_outputDirectoryEdit) {
|
|
|
+ m_outputDirectoryEdit->setText(dir);
|
|
|
+ }
|
|
|
+ m_settingsChanged = true;
|
|
|
+ updateUI();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onFileNameTemplateChanged() {
|
|
|
+ if (m_updating || !m_fileNameTemplateEdit) return;
|
|
|
+
|
|
|
+ m_currentSettings.output.fileNameTemplate = m_fileNameTemplateEdit->text();
|
|
|
+ m_settingsChanged = true;
|
|
|
+
|
|
|
+ // 延迟更新预览
|
|
|
+ m_previewUpdateTimer->start();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onPresetSave() {
|
|
|
+ // TODO: 实现预设保存
|
|
|
+ QMessageBox::information(this, "预设管理", "预设保存功能待实现");
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onPresetLoad() {
|
|
|
+ // TODO: 实现预设加载
|
|
|
+ QMessageBox::information(this, "预设管理", "预设加载功能待实现");
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onPresetDelete() {
|
|
|
+ // TODO: 实现预设删除
|
|
|
+ QMessageBox::information(this, "预设管理", "预设删除功能待实现");
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onPresetExport() {
|
|
|
+ // TODO: 实现预设导出
|
|
|
+ QMessageBox::information(this, "预设管理", "预设导出功能待实现");
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onPresetImport() {
|
|
|
+ // TODO: 实现预设导入
|
|
|
+ QMessageBox::information(this, "预设管理", "预设导入功能待实现");
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onTestAudioDevice() {
|
|
|
+ // TODO: 实现音频设备测试
|
|
|
+ QMessageBox::information(this, "设备测试", "音频设备测试功能待实现");
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onTestVideoDevice() {
|
|
|
+ // TODO: 实现视频设备测试
|
|
|
+ QMessageBox::information(this, "设备测试", "视频设备测试功能待实现");
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onResetCategory() {
|
|
|
+ int currentTab = m_tabWidget ? m_tabWidget->currentIndex() : 0;
|
|
|
+
|
|
|
+ int ret = QMessageBox::question(this, "重置设置",
|
|
|
+ "确定要重置当前页面的设置为默认值吗?",
|
|
|
+ QMessageBox::Yes | QMessageBox::No,
|
|
|
+ QMessageBox::No);
|
|
|
+
|
|
|
+ if (ret == QMessageBox::Yes) {
|
|
|
+ Settings defaultSettings = getDefaultSettings();
|
|
|
+
|
|
|
+ switch (currentTab) {
|
|
|
+ case AudioCategory:
|
|
|
+ m_currentSettings.audio = defaultSettings.audio;
|
|
|
+ break;
|
|
|
+ case VideoCategory:
|
|
|
+ m_currentSettings.video = defaultSettings.video;
|
|
|
+ break;
|
|
|
+ case OutputCategory:
|
|
|
+ m_currentSettings.output = defaultSettings.output;
|
|
|
+ break;
|
|
|
+ case AdvancedCategory:
|
|
|
+ m_currentSettings.advanced = defaultSettings.advanced;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ writeSettingsToUI();
|
|
|
+ updateUI();
|
|
|
+ m_settingsChanged = true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onApplySettings() {
|
|
|
+ readSettingsFromUI();
|
|
|
+
|
|
|
+ QString errorMessage;
|
|
|
+ if (!validateSettings(&errorMessage)) {
|
|
|
+ QMessageBox::warning(this, "设置错误", errorMessage);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ saveSettings();
|
|
|
+ emit settingsApplied(m_currentSettings);
|
|
|
+
|
|
|
+ m_originalSettings = m_currentSettings;
|
|
|
+ m_settingsChanged = false;
|
|
|
+
|
|
|
+ if (m_applyButton) {
|
|
|
+ m_applyButton->setEnabled(false);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onOkClicked() {
|
|
|
+ onApplySettings();
|
|
|
+ accept();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::onCancelClicked() {
|
|
|
+ if (m_settingsChanged) {
|
|
|
+ int ret = QMessageBox::question(this, "取消设置",
|
|
|
+ "设置已修改,确定要取消吗?",
|
|
|
+ QMessageBox::Yes | QMessageBox::No,
|
|
|
+ QMessageBox::No);
|
|
|
+
|
|
|
+ if (ret == QMessageBox::No) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 恢复原始设置
|
|
|
+ m_currentSettings = m_originalSettings;
|
|
|
+ reject();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::updatePreview() {
|
|
|
+ if (m_fileNamePreviewLabel) {
|
|
|
+ m_fileNamePreviewLabel->setText(formatFileNamePreview());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::refreshDevices() {
|
|
|
+ updateAudioDevices();
|
|
|
+ updateVideoDevices();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::initializeUI() {
|
|
|
+ // 创建主布局
|
|
|
+ m_mainLayout = new QVBoxLayout(this);
|
|
|
+ m_mainLayout->setContentsMargins(8, 8, 8, 8);
|
|
|
+ m_mainLayout->setSpacing(8);
|
|
|
+
|
|
|
+ // 创建选项卡
|
|
|
+ m_tabWidget = new QTabWidget();
|
|
|
+ m_tabWidget->addTab(createAudioSettingsPage(), "音频");
|
|
|
+ m_tabWidget->addTab(createVideoSettingsPage(), "视频");
|
|
|
+ m_tabWidget->addTab(createOutputSettingsPage(), "输出");
|
|
|
+ m_tabWidget->addTab(createAdvancedSettingsPage(), "高级");
|
|
|
+ m_tabWidget->addTab(createPresetSettingsPage(), "预设");
|
|
|
+
|
|
|
+ // 创建按钮布局
|
|
|
+ m_buttonLayout = new QHBoxLayout();
|
|
|
+
|
|
|
+ m_resetButton = new QPushButton("重置");
|
|
|
+ m_resetButton->setToolTip("重置当前页面设置为默认值");
|
|
|
+
|
|
|
+ m_buttonLayout->addWidget(m_resetButton);
|
|
|
+ m_buttonLayout->addStretch();
|
|
|
+
|
|
|
+ m_okButton = new QPushButton("确定");
|
|
|
+ m_okButton->setDefault(true);
|
|
|
+
|
|
|
+ m_cancelButton = new QPushButton("取消");
|
|
|
+
|
|
|
+ m_applyButton = new QPushButton("应用");
|
|
|
+ m_applyButton->setEnabled(false);
|
|
|
+
|
|
|
+ m_buttonLayout->addWidget(m_okButton);
|
|
|
+ m_buttonLayout->addWidget(m_cancelButton);
|
|
|
+ m_buttonLayout->addWidget(m_applyButton);
|
|
|
+
|
|
|
+ // 添加到主布局
|
|
|
+ m_mainLayout->addWidget(m_tabWidget);
|
|
|
+ m_mainLayout->addLayout(m_buttonLayout);
|
|
|
+
|
|
|
+ // 设置样式
|
|
|
+ setStyleSheet(R"(
|
|
|
+ QDialog {
|
|
|
+ background-color: #2b2b2b;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ QTabWidget::pane {
|
|
|
+ border: 1px solid #555;
|
|
|
+ background-color: #333;
|
|
|
+ }
|
|
|
+ QTabBar::tab {
|
|
|
+ background-color: #444;
|
|
|
+ color: #fff;
|
|
|
+ padding: 8px 16px;
|
|
|
+ margin-right: 2px;
|
|
|
+ }
|
|
|
+ QTabBar::tab:selected {
|
|
|
+ background-color: #0a84ff;
|
|
|
+ }
|
|
|
+ QTabBar::tab:hover {
|
|
|
+ background-color: #555;
|
|
|
+ }
|
|
|
+ QGroupBox {
|
|
|
+ font-weight: bold;
|
|
|
+ border: 1px solid #555;
|
|
|
+ border-radius: 4px;
|
|
|
+ margin-top: 8px;
|
|
|
+ padding-top: 8px;
|
|
|
+ }
|
|
|
+ QGroupBox::title {
|
|
|
+ subcontrol-origin: margin;
|
|
|
+ left: 8px;
|
|
|
+ padding: 0 4px 0 4px;
|
|
|
+ }
|
|
|
+ QLabel {
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ QLineEdit, QComboBox, QSpinBox, QDoubleSpinBox {
|
|
|
+ background-color: #444;
|
|
|
+ border: 1px solid #666;
|
|
|
+ border-radius: 3px;
|
|
|
+ color: #fff;
|
|
|
+ padding: 4px;
|
|
|
+ }
|
|
|
+ QLineEdit:focus, QComboBox:focus, QSpinBox:focus, QDoubleSpinBox:focus {
|
|
|
+ border-color: #0a84ff;
|
|
|
+ }
|
|
|
+ QPushButton {
|
|
|
+ background-color: #444;
|
|
|
+ border: 1px solid #666;
|
|
|
+ border-radius: 3px;
|
|
|
+ color: #fff;
|
|
|
+ padding: 6px 12px;
|
|
|
+ }
|
|
|
+ QPushButton:hover {
|
|
|
+ background-color: #555;
|
|
|
+ }
|
|
|
+ QPushButton:pressed {
|
|
|
+ background-color: #333;
|
|
|
+ }
|
|
|
+ QPushButton:default {
|
|
|
+ background-color: #0a84ff;
|
|
|
+ }
|
|
|
+ QCheckBox {
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ QCheckBox::indicator {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ }
|
|
|
+ QCheckBox::indicator:unchecked {
|
|
|
+ background-color: #444;
|
|
|
+ border: 1px solid #666;
|
|
|
+ }
|
|
|
+ QCheckBox::indicator:checked {
|
|
|
+ background-color: #0a84ff;
|
|
|
+ border: 1px solid #0a84ff;
|
|
|
+ }
|
|
|
+ QSlider::groove:horizontal {
|
|
|
+ border: 1px solid #555;
|
|
|
+ height: 6px;
|
|
|
+ background: #333;
|
|
|
+ border-radius: 3px;
|
|
|
+ }
|
|
|
+ QSlider::handle:horizontal {
|
|
|
+ background: #0a84ff;
|
|
|
+ border: 1px solid #0a84ff;
|
|
|
+ width: 14px;
|
|
|
+ margin: -4px 0;
|
|
|
+ border-radius: 7px;
|
|
|
+ }
|
|
|
+ QSlider::sub-page:horizontal {
|
|
|
+ background: #0a84ff;
|
|
|
+ border-radius: 3px;
|
|
|
+ }
|
|
|
+ )");
|
|
|
+}
|
|
|
+
|
|
|
+QWidget* RecorderSettingsDialog::createAudioSettingsPage() {
|
|
|
+ QWidget* page = new QWidget();
|
|
|
+ QVBoxLayout* layout = new QVBoxLayout(page);
|
|
|
+ layout->setContentsMargins(16, 16, 16, 16);
|
|
|
+ layout->setSpacing(12);
|
|
|
+
|
|
|
+ // 音频设备组
|
|
|
+ QGroupBox* deviceGroup = new QGroupBox("音频设备");
|
|
|
+ QFormLayout* deviceLayout = new QFormLayout(deviceGroup);
|
|
|
+
|
|
|
+ m_audioDeviceCombo = new QComboBox();
|
|
|
+ m_testAudioButton = new QPushButton("测试");
|
|
|
+ m_testAudioButton->setMaximumWidth(60);
|
|
|
+
|
|
|
+ QHBoxLayout* deviceControlLayout = new QHBoxLayout();
|
|
|
+ deviceControlLayout->addWidget(m_audioDeviceCombo);
|
|
|
+ deviceControlLayout->addWidget(m_testAudioButton);
|
|
|
+
|
|
|
+ deviceLayout->addRow("设备:", deviceControlLayout);
|
|
|
+
|
|
|
+ // 音频格式组
|
|
|
+ QGroupBox* formatGroup = new QGroupBox("音频格式");
|
|
|
+ QFormLayout* formatLayout = new QFormLayout(formatGroup);
|
|
|
+
|
|
|
+ m_audioSampleRateCombo = new QComboBox();
|
|
|
+ m_audioSampleRateCombo->addItems({"8000", "16000", "22050", "44100", "48000", "96000"});
|
|
|
+ m_audioSampleRateCombo->setCurrentText("44100");
|
|
|
+
|
|
|
+ m_audioChannelsCombo = new QComboBox();
|
|
|
+ m_audioChannelsCombo->addItems({"1 (单声道)", "2 (立体声)", "6 (5.1)", "8 (7.1)"});
|
|
|
+ m_audioChannelsCombo->setCurrentIndex(1);
|
|
|
+
|
|
|
+ m_audioBitDepthCombo = new QComboBox();
|
|
|
+ m_audioBitDepthCombo->addItems({"16", "24", "32"});
|
|
|
+ m_audioBitDepthCombo->setCurrentText("16");
|
|
|
+
|
|
|
+ formatLayout->addRow("采样率:", m_audioSampleRateCombo);
|
|
|
+ formatLayout->addRow("声道:", m_audioChannelsCombo);
|
|
|
+ formatLayout->addRow("位深:", m_audioBitDepthCombo);
|
|
|
+
|
|
|
+ // 音频编码组
|
|
|
+ QGroupBox* codecGroup = new QGroupBox("音频编码");
|
|
|
+ QFormLayout* codecLayout = new QFormLayout(codecGroup);
|
|
|
+
|
|
|
+ m_audioCodecCombo = new QComboBox();
|
|
|
+ m_audioCodecCombo->addItems({"AAC", "MP3", "FLAC", "PCM"});
|
|
|
+ m_audioCodecCombo->setCurrentText("AAC");
|
|
|
+
|
|
|
+ m_audioBitrateSpinBox = new QSpinBox();
|
|
|
+ m_audioBitrateSpinBox->setRange(64, 320);
|
|
|
+ m_audioBitrateSpinBox->setValue(128);
|
|
|
+ m_audioBitrateSpinBox->setSuffix(" kbps");
|
|
|
+
|
|
|
+ codecLayout->addRow("编码器:", m_audioCodecCombo);
|
|
|
+ codecLayout->addRow("比特率:", m_audioBitrateSpinBox);
|
|
|
+
|
|
|
+ // 音频处理组
|
|
|
+ QGroupBox* processingGroup = new QGroupBox("音频处理");
|
|
|
+ QFormLayout* processingLayout = new QFormLayout(processingGroup);
|
|
|
+
|
|
|
+ m_audioNoiseSuppressionCheckBox = new QCheckBox("启用噪声抑制");
|
|
|
+ m_audioEchoCancellationCheckBox = new QCheckBox("启用回声消除");
|
|
|
+
|
|
|
+ m_audioInputGainSpinBox = new QDoubleSpinBox();
|
|
|
+ m_audioInputGainSpinBox->setRange(0.1, 10.0);
|
|
|
+ m_audioInputGainSpinBox->setValue(1.0);
|
|
|
+ m_audioInputGainSpinBox->setSingleStep(0.1);
|
|
|
+ m_audioInputGainSpinBox->setDecimals(1);
|
|
|
+
|
|
|
+ processingLayout->addRow(m_audioNoiseSuppressionCheckBox);
|
|
|
+ processingLayout->addRow(m_audioEchoCancellationCheckBox);
|
|
|
+ processingLayout->addRow("输入增益:", m_audioInputGainSpinBox);
|
|
|
+
|
|
|
+ // 添加到页面布局
|
|
|
+ layout->addWidget(deviceGroup);
|
|
|
+ layout->addWidget(formatGroup);
|
|
|
+ layout->addWidget(codecGroup);
|
|
|
+ layout->addWidget(processingGroup);
|
|
|
+ layout->addStretch();
|
|
|
+
|
|
|
+ return page;
|
|
|
+}
|
|
|
+
|
|
|
+QWidget* RecorderSettingsDialog::createVideoSettingsPage() {
|
|
|
+ QWidget* page = new QWidget();
|
|
|
+ QVBoxLayout* layout = new QVBoxLayout(page);
|
|
|
+ layout->setContentsMargins(16, 16, 16, 16);
|
|
|
+ layout->setSpacing(12);
|
|
|
+
|
|
|
+ // 视频设备组
|
|
|
+ QGroupBox* deviceGroup = new QGroupBox("视频设备");
|
|
|
+ QFormLayout* deviceLayout = new QFormLayout(deviceGroup);
|
|
|
+
|
|
|
+ m_videoDeviceCombo = new QComboBox();
|
|
|
+ m_testVideoButton = new QPushButton("测试");
|
|
|
+ m_testVideoButton->setMaximumWidth(60);
|
|
|
+
|
|
|
+ QHBoxLayout* deviceControlLayout = new QHBoxLayout();
|
|
|
+ deviceControlLayout->addWidget(m_videoDeviceCombo);
|
|
|
+ deviceControlLayout->addWidget(m_testVideoButton);
|
|
|
+
|
|
|
+ deviceLayout->addRow("设备:", deviceControlLayout);
|
|
|
+
|
|
|
+ // 视频格式组
|
|
|
+ QGroupBox* formatGroup = new QGroupBox("视频格式");
|
|
|
+ QFormLayout* formatLayout = new QFormLayout(formatGroup);
|
|
|
+
|
|
|
+ m_videoResolutionCombo = new QComboBox();
|
|
|
+ m_videoResolutionCombo->addItems({
|
|
|
+ "640x480", "800x600", "1024x768", "1280x720",
|
|
|
+ "1920x1080", "2560x1440", "3840x2160"
|
|
|
+ });
|
|
|
+ m_videoResolutionCombo->setCurrentText("1920x1080");
|
|
|
+
|
|
|
+ m_videoFrameRateSpinBox = new QDoubleSpinBox();
|
|
|
+ m_videoFrameRateSpinBox->setRange(1.0, 120.0);
|
|
|
+ m_videoFrameRateSpinBox->setValue(30.0);
|
|
|
+ m_videoFrameRateSpinBox->setSingleStep(1.0);
|
|
|
+ m_videoFrameRateSpinBox->setDecimals(1);
|
|
|
+ m_videoFrameRateSpinBox->setSuffix(" fps");
|
|
|
+
|
|
|
+ formatLayout->addRow("分辨率:", m_videoResolutionCombo);
|
|
|
+ formatLayout->addRow("帧率:", m_videoFrameRateSpinBox);
|
|
|
+
|
|
|
+ // 视频编码组
|
|
|
+ QGroupBox* codecGroup = new QGroupBox("视频编码");
|
|
|
+ QFormLayout* codecLayout = new QFormLayout(codecGroup);
|
|
|
+
|
|
|
+ m_videoCodecCombo = new QComboBox();
|
|
|
+ m_videoCodecCombo->addItems({"H.264", "H.265", "VP9", "AV1"});
|
|
|
+ m_videoCodecCombo->setCurrentText("H.264");
|
|
|
+
|
|
|
+ m_videoBitrateSpinBox = new QSpinBox();
|
|
|
+ m_videoBitrateSpinBox->setRange(500, 50000);
|
|
|
+ m_videoBitrateSpinBox->setValue(5000);
|
|
|
+ m_videoBitrateSpinBox->setSuffix(" kbps");
|
|
|
+
|
|
|
+ m_videoPresetCombo = new QComboBox();
|
|
|
+ m_videoPresetCombo->addItems({"ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow"});
|
|
|
+ m_videoPresetCombo->setCurrentText("medium");
|
|
|
+
|
|
|
+ m_videoProfileCombo = new QComboBox();
|
|
|
+ m_videoProfileCombo->addItems({"baseline", "main", "high"});
|
|
|
+ m_videoProfileCombo->setCurrentText("high");
|
|
|
+
|
|
|
+ m_videoKeyFrameSpinBox = new QSpinBox();
|
|
|
+ m_videoKeyFrameSpinBox->setRange(1, 300);
|
|
|
+ m_videoKeyFrameSpinBox->setValue(60);
|
|
|
+
|
|
|
+ codecLayout->addRow("编码器:", m_videoCodecCombo);
|
|
|
+ codecLayout->addRow("比特率:", m_videoBitrateSpinBox);
|
|
|
+ codecLayout->addRow("预设:", m_videoPresetCombo);
|
|
|
+ codecLayout->addRow("配置:", m_videoProfileCombo);
|
|
|
+ codecLayout->addRow("关键帧间隔:", m_videoKeyFrameSpinBox);
|
|
|
+
|
|
|
+ // 硬件加速组
|
|
|
+ QGroupBox* accelerationGroup = new QGroupBox("硬件加速");
|
|
|
+ QFormLayout* accelerationLayout = new QFormLayout(accelerationGroup);
|
|
|
+
|
|
|
+ m_videoHardwareAccelCheckBox = new QCheckBox("启用硬件加速");
|
|
|
+ m_videoHardwareAccelCheckBox->setChecked(true);
|
|
|
+
|
|
|
+ accelerationLayout->addRow(m_videoHardwareAccelCheckBox);
|
|
|
+
|
|
|
+ // 添加到页面布局
|
|
|
+ layout->addWidget(deviceGroup);
|
|
|
+ layout->addWidget(formatGroup);
|
|
|
+ layout->addWidget(codecGroup);
|
|
|
+ layout->addWidget(accelerationGroup);
|
|
|
+ layout->addStretch();
|
|
|
+
|
|
|
+ return page;
|
|
|
+}
|
|
|
+
|
|
|
+QWidget* RecorderSettingsDialog::createOutputSettingsPage() {
|
|
|
+ QWidget* page = new QWidget();
|
|
|
+ QVBoxLayout* layout = new QVBoxLayout(page);
|
|
|
+ layout->setContentsMargins(16, 16, 16, 16);
|
|
|
+ layout->setSpacing(12);
|
|
|
+
|
|
|
+ // 输出路径组
|
|
|
+ QGroupBox* pathGroup = new QGroupBox("输出路径");
|
|
|
+ QFormLayout* pathLayout = new QFormLayout(pathGroup);
|
|
|
+
|
|
|
+ m_outputDirectoryEdit = new QLineEdit();
|
|
|
+ m_outputDirectoryBrowseButton = new QPushButton("浏览");
|
|
|
+ m_outputDirectoryBrowseButton->setMaximumWidth(60);
|
|
|
+
|
|
|
+ QHBoxLayout* pathControlLayout = new QHBoxLayout();
|
|
|
+ pathControlLayout->addWidget(m_outputDirectoryEdit);
|
|
|
+ pathControlLayout->addWidget(m_outputDirectoryBrowseButton);
|
|
|
+
|
|
|
+ pathLayout->addRow("输出目录:", pathControlLayout);
|
|
|
+
|
|
|
+ // 文件命名组
|
|
|
+ QGroupBox* namingGroup = new QGroupBox("文件命名");
|
|
|
+ QFormLayout* namingLayout = new QFormLayout(namingGroup);
|
|
|
+
|
|
|
+ m_fileNameTemplateEdit = new QLineEdit();
|
|
|
+ m_fileNameTemplateEdit->setText("recording_%Y%m%d_%H%M%S");
|
|
|
+
|
|
|
+ m_fileNamePreviewLabel = new QLabel();
|
|
|
+ m_fileNamePreviewLabel->setStyleSheet("color: #888; font-style: italic;");
|
|
|
+
|
|
|
+ namingLayout->addRow("文件名模板:", m_fileNameTemplateEdit);
|
|
|
+ namingLayout->addRow("预览:", m_fileNamePreviewLabel);
|
|
|
+
|
|
|
+ // 格式设置组
|
|
|
+ QGroupBox* formatGroup = new QGroupBox("格式设置");
|
|
|
+ QFormLayout* formatLayout = new QFormLayout(formatGroup);
|
|
|
+
|
|
|
+ m_containerFormatCombo = new QComboBox();
|
|
|
+ m_containerFormatCombo->addItems({"MP4", "AVI", "MKV", "MOV", "FLV"});
|
|
|
+ m_containerFormatCombo->setCurrentText("MP4");
|
|
|
+
|
|
|
+ formatLayout->addRow("容器格式:", m_containerFormatCombo);
|
|
|
+
|
|
|
+ // 文件选项组
|
|
|
+ QGroupBox* optionsGroup = new QGroupBox("文件选项");
|
|
|
+ QFormLayout* optionsLayout = new QFormLayout(optionsGroup);
|
|
|
+
|
|
|
+ m_autoCreateDirectoryCheckBox = new QCheckBox("自动创建目录");
|
|
|
+ m_autoCreateDirectoryCheckBox->setChecked(true);
|
|
|
+
|
|
|
+ m_overwriteExistingCheckBox = new QCheckBox("覆盖已存在文件");
|
|
|
+
|
|
|
+ m_maxFileSizeSpinBox = new QSpinBox();
|
|
|
+ m_maxFileSizeSpinBox->setRange(0, 10000);
|
|
|
+ m_maxFileSizeSpinBox->setValue(0);
|
|
|
+ m_maxFileSizeSpinBox->setSuffix(" MB (0=无限制)");
|
|
|
+
|
|
|
+ m_maxDurationSpinBox = new QSpinBox();
|
|
|
+ m_maxDurationSpinBox->setRange(0, 10000);
|
|
|
+ m_maxDurationSpinBox->setValue(0);
|
|
|
+ m_maxDurationSpinBox->setSuffix(" 分钟 (0=无限制)");
|
|
|
+
|
|
|
+ optionsLayout->addRow(m_autoCreateDirectoryCheckBox);
|
|
|
+ optionsLayout->addRow(m_overwriteExistingCheckBox);
|
|
|
+ optionsLayout->addRow("最大文件大小:", m_maxFileSizeSpinBox);
|
|
|
+ optionsLayout->addRow("最大录制时长:", m_maxDurationSpinBox);
|
|
|
+
|
|
|
+ // 添加到页面布局
|
|
|
+ layout->addWidget(pathGroup);
|
|
|
+ layout->addWidget(namingGroup);
|
|
|
+ layout->addWidget(formatGroup);
|
|
|
+ layout->addWidget(optionsGroup);
|
|
|
+ layout->addStretch();
|
|
|
+
|
|
|
+ return page;
|
|
|
+}
|
|
|
+
|
|
|
+QWidget* RecorderSettingsDialog::createAdvancedSettingsPage() {
|
|
|
+ QWidget* page = new QWidget();
|
|
|
+ QVBoxLayout* layout = new QVBoxLayout(page);
|
|
|
+ layout->setContentsMargins(16, 16, 16, 16);
|
|
|
+ layout->setSpacing(12);
|
|
|
+
|
|
|
+ // 性能设置组
|
|
|
+ QGroupBox* performanceGroup = new QGroupBox("性能设置");
|
|
|
+ QFormLayout* performanceLayout = new QFormLayout(performanceGroup);
|
|
|
+
|
|
|
+ m_bufferSizeSpinBox = new QSpinBox();
|
|
|
+ m_bufferSizeSpinBox->setRange(1024, 65536);
|
|
|
+ m_bufferSizeSpinBox->setValue(4096);
|
|
|
+
|
|
|
+ m_threadCountSpinBox = new QSpinBox();
|
|
|
+ m_threadCountSpinBox->setRange(0, 16);
|
|
|
+ m_threadCountSpinBox->setValue(0);
|
|
|
+ m_threadCountSpinBox->setSuffix(" (0=自动)");
|
|
|
+
|
|
|
+ performanceLayout->addRow("缓冲区大小:", m_bufferSizeSpinBox);
|
|
|
+ performanceLayout->addRow("线程数:", m_threadCountSpinBox);
|
|
|
+
|
|
|
+ // GPU加速组
|
|
|
+ QGroupBox* gpuGroup = new QGroupBox("GPU加速");
|
|
|
+ QFormLayout* gpuLayout = new QFormLayout(gpuGroup);
|
|
|
+
|
|
|
+ m_gpuAccelerationCheckBox = new QCheckBox("启用GPU加速");
|
|
|
+ m_gpuAccelerationCheckBox->setChecked(true);
|
|
|
+
|
|
|
+ m_gpuDeviceCombo = new QComboBox();
|
|
|
+ m_gpuDeviceCombo->addItems({"自动选择", "NVIDIA CUDA", "Intel Quick Sync", "AMD VCE"});
|
|
|
+
|
|
|
+ gpuLayout->addRow(m_gpuAccelerationCheckBox);
|
|
|
+ gpuLayout->addRow("GPU设备:", m_gpuDeviceCombo);
|
|
|
+
|
|
|
+ // 编码设置组
|
|
|
+ QGroupBox* encodingGroup = new QGroupBox("编码设置");
|
|
|
+ QFormLayout* encodingLayout = new QFormLayout(encodingGroup);
|
|
|
+
|
|
|
+ m_lowLatencyCheckBox = new QCheckBox("启用低延迟模式");
|
|
|
+ m_realTimeEncodingCheckBox = new QCheckBox("启用实时编码");
|
|
|
+ m_realTimeEncodingCheckBox->setChecked(true);
|
|
|
+
|
|
|
+ m_encodingPrioritySlider = new QSlider(Qt::Horizontal);
|
|
|
+ m_encodingPrioritySlider->setRange(-2, 2);
|
|
|
+ m_encodingPrioritySlider->setValue(0);
|
|
|
+ m_encodingPrioritySlider->setTickPosition(QSlider::TicksBelow);
|
|
|
+ m_encodingPrioritySlider->setTickInterval(1);
|
|
|
+
|
|
|
+ m_encodingPriorityLabel = new QLabel("正常");
|
|
|
+
|
|
|
+ QHBoxLayout* priorityLayout = new QHBoxLayout();
|
|
|
+ priorityLayout->addWidget(m_encodingPrioritySlider);
|
|
|
+ priorityLayout->addWidget(m_encodingPriorityLabel);
|
|
|
+
|
|
|
+ encodingLayout->addRow(m_lowLatencyCheckBox);
|
|
|
+ encodingLayout->addRow(m_realTimeEncodingCheckBox);
|
|
|
+ encodingLayout->addRow("编码优先级:", priorityLayout);
|
|
|
+
|
|
|
+ // 添加到页面布局
|
|
|
+ layout->addWidget(performanceGroup);
|
|
|
+ layout->addWidget(gpuGroup);
|
|
|
+ layout->addWidget(encodingGroup);
|
|
|
+ layout->addStretch();
|
|
|
+
|
|
|
+ return page;
|
|
|
+}
|
|
|
+
|
|
|
+QWidget* RecorderSettingsDialog::createPresetSettingsPage() {
|
|
|
+ QWidget* page = new QWidget();
|
|
|
+ QVBoxLayout* layout = new QVBoxLayout(page);
|
|
|
+ layout->setContentsMargins(16, 16, 16, 16);
|
|
|
+ layout->setSpacing(12);
|
|
|
+
|
|
|
+ // 预设列表组
|
|
|
+ QGroupBox* listGroup = new QGroupBox("预设列表");
|
|
|
+ QVBoxLayout* listLayout = new QVBoxLayout(listGroup);
|
|
|
+
|
|
|
+ m_presetListWidget = new QListWidget();
|
|
|
+ m_presetListWidget->setMinimumHeight(200);
|
|
|
+
|
|
|
+ listLayout->addWidget(m_presetListWidget);
|
|
|
+
|
|
|
+ // 预设操作组
|
|
|
+ QGroupBox* operationsGroup = new QGroupBox("预设操作");
|
|
|
+ QHBoxLayout* operationsLayout = new QHBoxLayout(operationsGroup);
|
|
|
+
|
|
|
+ m_savePresetButton = new QPushButton("保存");
|
|
|
+ m_loadPresetButton = new QPushButton("加载");
|
|
|
+ m_deletePresetButton = new QPushButton("删除");
|
|
|
+ m_exportPresetButton = new QPushButton("导出");
|
|
|
+ m_importPresetButton = new QPushButton("导入");
|
|
|
+
|
|
|
+ operationsLayout->addWidget(m_savePresetButton);
|
|
|
+ operationsLayout->addWidget(m_loadPresetButton);
|
|
|
+ operationsLayout->addWidget(m_deletePresetButton);
|
|
|
+ operationsLayout->addStretch();
|
|
|
+ operationsLayout->addWidget(m_exportPresetButton);
|
|
|
+ operationsLayout->addWidget(m_importPresetButton);
|
|
|
+
|
|
|
+ // 预设描述组
|
|
|
+ QGroupBox* descriptionGroup = new QGroupBox("预设描述");
|
|
|
+ QVBoxLayout* descriptionLayout = new QVBoxLayout(descriptionGroup);
|
|
|
+
|
|
|
+ m_presetDescriptionEdit = new QTextEdit();
|
|
|
+ m_presetDescriptionEdit->setMaximumHeight(100);
|
|
|
+ m_presetDescriptionEdit->setPlaceholderText("输入预设描述...");
|
|
|
+
|
|
|
+ descriptionLayout->addWidget(m_presetDescriptionEdit);
|
|
|
+
|
|
|
+ // 添加到页面布局
|
|
|
+ layout->addWidget(listGroup);
|
|
|
+ layout->addWidget(operationsGroup);
|
|
|
+ layout->addWidget(descriptionGroup);
|
|
|
+
|
|
|
+ return page;
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::connectSignals() {
|
|
|
+ // 选项卡信号
|
|
|
+ connect(m_tabWidget, QOverload<int>::of(&QTabWidget::currentChanged),
|
|
|
+ this, &RecorderSettingsDialog::onTabChanged);
|
|
|
+
|
|
|
+ // 按钮信号
|
|
|
+ connect(m_okButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onOkClicked);
|
|
|
+ connect(m_cancelButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onCancelClicked);
|
|
|
+ connect(m_applyButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onApplySettings);
|
|
|
+ connect(m_resetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onResetCategory);
|
|
|
+
|
|
|
+ // 音频设置信号
|
|
|
+ if (m_audioDeviceCombo) {
|
|
|
+ connect(m_audioDeviceCombo, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
|
|
|
+ this, &RecorderSettingsDialog::onAudioDeviceChanged);
|
|
|
+ }
|
|
|
+ if (m_testAudioButton) {
|
|
|
+ connect(m_testAudioButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onTestAudioDevice);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 视频设置信号
|
|
|
+ if (m_videoDeviceCombo) {
|
|
|
+ connect(m_videoDeviceCombo, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
|
|
|
+ this, &RecorderSettingsDialog::onVideoDeviceChanged);
|
|
|
+ }
|
|
|
+ if (m_testVideoButton) {
|
|
|
+ connect(m_testVideoButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onTestVideoDevice);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 输出设置信号
|
|
|
+ if (m_outputDirectoryBrowseButton) {
|
|
|
+ connect(m_outputDirectoryBrowseButton, &QPushButton::clicked,
|
|
|
+ this, &RecorderSettingsDialog::onOutputDirectoryBrowse);
|
|
|
+ }
|
|
|
+ if (m_fileNameTemplateEdit) {
|
|
|
+ connect(m_fileNameTemplateEdit, &QLineEdit::textChanged,
|
|
|
+ this, &RecorderSettingsDialog::onFileNameTemplateChanged);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 预设管理信号
|
|
|
+ if (m_savePresetButton) {
|
|
|
+ connect(m_savePresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetSave);
|
|
|
+ }
|
|
|
+ if (m_loadPresetButton) {
|
|
|
+ connect(m_loadPresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetLoad);
|
|
|
+ }
|
|
|
+ if (m_deletePresetButton) {
|
|
|
+ connect(m_deletePresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetDelete);
|
|
|
+ }
|
|
|
+ if (m_exportPresetButton) {
|
|
|
+ connect(m_exportPresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetExport);
|
|
|
+ }
|
|
|
+ if (m_importPresetButton) {
|
|
|
+ connect(m_importPresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetImport);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 高级设置信号
|
|
|
+ if (m_encodingPrioritySlider) {
|
|
|
+ connect(m_encodingPrioritySlider, &QSlider::valueChanged, [this](int value) {
|
|
|
+ if (m_encodingPriorityLabel) {
|
|
|
+ QStringList labels = {"最低", "低", "正常", "高", "最高"};
|
|
|
+ m_encodingPriorityLabel->setText(labels[value + 2]);
|
|
|
+ }
|
|
|
+ m_settingsChanged = true;
|
|
|
+ if (m_applyButton) m_applyButton->setEnabled(true);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 通用设置改变信号
|
|
|
+ auto connectSettingsChanged = [this](QWidget* widget) {
|
|
|
+ if (auto* combo = qobject_cast<QComboBox*>(widget)) {
|
|
|
+ connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() {
|
|
|
+ if (!m_updating) {
|
|
|
+ m_settingsChanged = true;
|
|
|
+ if (m_applyButton) m_applyButton->setEnabled(true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else if (auto* spinBox = qobject_cast<QSpinBox*>(widget)) {
|
|
|
+ connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), [this]() {
|
|
|
+ if (!m_updating) {
|
|
|
+ m_settingsChanged = true;
|
|
|
+ if (m_applyButton) m_applyButton->setEnabled(true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else if (auto* doubleSpinBox = qobject_cast<QDoubleSpinBox*>(widget)) {
|
|
|
+ connect(doubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this]() {
|
|
|
+ if (!m_updating) {
|
|
|
+ m_settingsChanged = true;
|
|
|
+ if (m_applyButton) m_applyButton->setEnabled(true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else if (auto* checkBox = qobject_cast<QCheckBox*>(widget)) {
|
|
|
+ connect(checkBox, &QCheckBox::toggled, [this]() {
|
|
|
+ if (!m_updating) {
|
|
|
+ m_settingsChanged = true;
|
|
|
+ if (m_applyButton) m_applyButton->setEnabled(true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else if (auto* lineEdit = qobject_cast<QLineEdit*>(widget)) {
|
|
|
+ connect(lineEdit, &QLineEdit::textChanged, [this]() {
|
|
|
+ if (!m_updating) {
|
|
|
+ m_settingsChanged = true;
|
|
|
+ if (m_applyButton) m_applyButton->setEnabled(true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 连接所有设置控件
|
|
|
+ QList<QWidget*> settingsWidgets = {
|
|
|
+ m_audioSampleRateCombo, m_audioChannelsCombo, m_audioBitDepthCombo,
|
|
|
+ m_audioCodecCombo, m_audioBitrateSpinBox, m_audioNoiseSuppressionCheckBox,
|
|
|
+ m_audioEchoCancellationCheckBox, m_audioInputGainSpinBox,
|
|
|
+ m_videoResolutionCombo, m_videoFrameRateSpinBox, m_videoCodecCombo,
|
|
|
+ m_videoBitrateSpinBox, m_videoPresetCombo, m_videoProfileCombo,
|
|
|
+ m_videoKeyFrameSpinBox, m_videoHardwareAccelCheckBox,
|
|
|
+ m_outputDirectoryEdit, m_containerFormatCombo, m_autoCreateDirectoryCheckBox,
|
|
|
+ m_overwriteExistingCheckBox, m_maxFileSizeSpinBox, m_maxDurationSpinBox,
|
|
|
+ m_bufferSizeSpinBox, m_threadCountSpinBox, m_gpuAccelerationCheckBox,
|
|
|
+ m_gpuDeviceCombo, m_lowLatencyCheckBox, m_realTimeEncodingCheckBox
|
|
|
+ };
|
|
|
+
|
|
|
+ for (QWidget* widget : settingsWidgets) {
|
|
|
+ if (widget) {
|
|
|
+ connectSettingsChanged(widget);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::updateUI() {
|
|
|
+ // 更新按钮状态
|
|
|
+ if (m_applyButton) {
|
|
|
+ m_applyButton->setEnabled(m_settingsChanged);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新预览
|
|
|
+ updatePreview();
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::updateAudioDevices() {
|
|
|
+ if (!m_audioDeviceCombo || !m_recorderModule) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: 从录制器模块获取音频设备列表
|
|
|
+ QStringList devices = {"默认音频设备", "麦克风 (内置)", "麦克风 (USB)"};
|
|
|
+
|
|
|
+ QString currentDevice = m_audioDeviceCombo->currentText();
|
|
|
+ m_audioDeviceCombo->clear();
|
|
|
+ m_audioDeviceCombo->addItems(devices);
|
|
|
+
|
|
|
+ int index = m_audioDeviceCombo->findText(currentDevice);
|
|
|
+ if (index >= 0) {
|
|
|
+ m_audioDeviceCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::updateVideoDevices() {
|
|
|
+ if (!m_videoDeviceCombo || !m_recorderModule) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: 从录制器模块获取视频设备列表
|
|
|
+ QStringList devices = {"默认摄像头", "USB摄像头", "屏幕录制"};
|
|
|
+
|
|
|
+ QString currentDevice = m_videoDeviceCombo->currentText();
|
|
|
+ m_videoDeviceCombo->clear();
|
|
|
+ m_videoDeviceCombo->addItems(devices);
|
|
|
+
|
|
|
+ int index = m_videoDeviceCombo->findText(currentDevice);
|
|
|
+ if (index >= 0) {
|
|
|
+ m_videoDeviceCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::updateCodecLists() {
|
|
|
+ // TODO: 从录制器模块获取支持的编码器列表
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::updatePresetList() {
|
|
|
+ if (!m_presetListWidget) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: 加载预设列表
|
|
|
+ m_presetListWidget->clear();
|
|
|
+ m_presetListWidget->addItems({"默认设置", "高质量", "低延迟", "直播"});
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::readSettingsFromUI() {
|
|
|
+ m_updating = true;
|
|
|
+
|
|
|
+ // 读取音频设置
|
|
|
+ if (m_audioDeviceCombo) {
|
|
|
+ m_currentSettings.audio.deviceName = m_audioDeviceCombo->currentText();
|
|
|
+ }
|
|
|
+ if (m_audioSampleRateCombo) {
|
|
|
+ m_currentSettings.audio.sampleRate = m_audioSampleRateCombo->currentText().toInt();
|
|
|
+ }
|
|
|
+ if (m_audioChannelsCombo) {
|
|
|
+ m_currentSettings.audio.channels = m_audioChannelsCombo->currentIndex() == 0 ? 1 :
|
|
|
+ (m_audioChannelsCombo->currentIndex() == 1 ? 2 :
|
|
|
+ (m_audioChannelsCombo->currentIndex() == 2 ? 6 : 8));
|
|
|
+ }
|
|
|
+ if (m_audioBitDepthCombo) {
|
|
|
+ m_currentSettings.audio.bitDepth = m_audioBitDepthCombo->currentText().toInt();
|
|
|
+ }
|
|
|
+ if (m_audioCodecCombo) {
|
|
|
+ m_currentSettings.audio.codec = m_audioCodecCombo->currentText().toLower();
|
|
|
+ }
|
|
|
+ if (m_audioBitrateSpinBox) {
|
|
|
+ m_currentSettings.audio.bitrate = m_audioBitrateSpinBox->value() * 1000;
|
|
|
+ }
|
|
|
+ if (m_audioNoiseSuppressionCheckBox) {
|
|
|
+ m_currentSettings.audio.enableNoiseSuppression = m_audioNoiseSuppressionCheckBox->isChecked();
|
|
|
+ }
|
|
|
+ if (m_audioEchoCancellationCheckBox) {
|
|
|
+ m_currentSettings.audio.enableEchoCancellation = m_audioEchoCancellationCheckBox->isChecked();
|
|
|
+ }
|
|
|
+ if (m_audioInputGainSpinBox) {
|
|
|
+ m_currentSettings.audio.inputGain = m_audioInputGainSpinBox->value();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取视频设置
|
|
|
+ if (m_videoDeviceCombo) {
|
|
|
+ m_currentSettings.video.deviceName = m_videoDeviceCombo->currentText();
|
|
|
+ }
|
|
|
+ if (m_videoResolutionCombo) {
|
|
|
+ QStringList parts = m_videoResolutionCombo->currentText().split('x');
|
|
|
+ if (parts.size() == 2) {
|
|
|
+ m_currentSettings.video.width = parts[0].toInt();
|
|
|
+ m_currentSettings.video.height = parts[1].toInt();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (m_videoFrameRateSpinBox) {
|
|
|
+ m_currentSettings.video.frameRate = m_videoFrameRateSpinBox->value();
|
|
|
+ }
|
|
|
+ if (m_videoCodecCombo) {
|
|
|
+ QString codec = m_videoCodecCombo->currentText().toLower();
|
|
|
+ if (codec == "h.264") codec = "h264";
|
|
|
+ else if (codec == "h.265") codec = "h265";
|
|
|
+ m_currentSettings.video.codec = codec;
|
|
|
+ }
|
|
|
+ if (m_videoBitrateSpinBox) {
|
|
|
+ m_currentSettings.video.bitrate = m_videoBitrateSpinBox->value() * 1000;
|
|
|
+ }
|
|
|
+ if (m_videoPresetCombo) {
|
|
|
+ m_currentSettings.video.preset = m_videoPresetCombo->currentText();
|
|
|
+ }
|
|
|
+ if (m_videoProfileCombo) {
|
|
|
+ m_currentSettings.video.profile = m_videoProfileCombo->currentText();
|
|
|
+ }
|
|
|
+ if (m_videoKeyFrameSpinBox) {
|
|
|
+ m_currentSettings.video.keyFrameInterval = m_videoKeyFrameSpinBox->value();
|
|
|
+ }
|
|
|
+ if (m_videoHardwareAccelCheckBox) {
|
|
|
+ m_currentSettings.video.enableHardwareAcceleration = m_videoHardwareAccelCheckBox->isChecked();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取输出设置
|
|
|
+ if (m_outputDirectoryEdit) {
|
|
|
+ m_currentSettings.output.outputDirectory = m_outputDirectoryEdit->text();
|
|
|
+ }
|
|
|
+ if (m_fileNameTemplateEdit) {
|
|
|
+ m_currentSettings.output.fileNameTemplate = m_fileNameTemplateEdit->text();
|
|
|
+ }
|
|
|
+ if (m_containerFormatCombo) {
|
|
|
+ m_currentSettings.output.containerFormat = m_containerFormatCombo->currentText().toLower();
|
|
|
+ }
|
|
|
+ if (m_autoCreateDirectoryCheckBox) {
|
|
|
+ m_currentSettings.output.autoCreateDirectory = m_autoCreateDirectoryCheckBox->isChecked();
|
|
|
+ }
|
|
|
+ if (m_overwriteExistingCheckBox) {
|
|
|
+ m_currentSettings.output.overwriteExisting = m_overwriteExistingCheckBox->isChecked();
|
|
|
+ }
|
|
|
+ if (m_maxFileSizeSpinBox) {
|
|
|
+ m_currentSettings.output.maxFileSize = m_maxFileSizeSpinBox->value();
|
|
|
+ }
|
|
|
+ if (m_maxDurationSpinBox) {
|
|
|
+ m_currentSettings.output.maxDuration = m_maxDurationSpinBox->value();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取高级设置
|
|
|
+ if (m_bufferSizeSpinBox) {
|
|
|
+ m_currentSettings.advanced.bufferSize = m_bufferSizeSpinBox->value();
|
|
|
+ }
|
|
|
+ if (m_threadCountSpinBox) {
|
|
|
+ m_currentSettings.advanced.threadCount = m_threadCountSpinBox->value();
|
|
|
+ }
|
|
|
+ if (m_gpuAccelerationCheckBox) {
|
|
|
+ m_currentSettings.advanced.enableGPUAcceleration = m_gpuAccelerationCheckBox->isChecked();
|
|
|
+ }
|
|
|
+ if (m_gpuDeviceCombo) {
|
|
|
+ m_currentSettings.advanced.gpuDevice = m_gpuDeviceCombo->currentText();
|
|
|
+ }
|
|
|
+ if (m_lowLatencyCheckBox) {
|
|
|
+ m_currentSettings.advanced.enableLowLatency = m_lowLatencyCheckBox->isChecked();
|
|
|
+ }
|
|
|
+ if (m_realTimeEncodingCheckBox) {
|
|
|
+ m_currentSettings.advanced.enableRealTimeEncoding = m_realTimeEncodingCheckBox->isChecked();
|
|
|
+ }
|
|
|
+ if (m_encodingPrioritySlider) {
|
|
|
+ m_currentSettings.advanced.encodingPriority = m_encodingPrioritySlider->value();
|
|
|
+ }
|
|
|
+
|
|
|
+ m_updating = false;
|
|
|
+}
|
|
|
+
|
|
|
+void RecorderSettingsDialog::writeSettingsToUI() {
|
|
|
+ m_updating = true;
|
|
|
+
|
|
|
+ // 写入音频设置
|
|
|
+ if (m_audioDeviceCombo) {
|
|
|
+ int index = m_audioDeviceCombo->findText(m_currentSettings.audio.deviceName);
|
|
|
+ if (index >= 0) m_audioDeviceCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_audioSampleRateCombo) {
|
|
|
+ m_audioSampleRateCombo->setCurrentText(QString::number(m_currentSettings.audio.sampleRate));
|
|
|
+ }
|
|
|
+ if (m_audioChannelsCombo) {
|
|
|
+ int index = m_currentSettings.audio.channels == 1 ? 0 :
|
|
|
+ (m_currentSettings.audio.channels == 2 ? 1 :
|
|
|
+ (m_currentSettings.audio.channels == 6 ? 2 : 3));
|
|
|
+ m_audioChannelsCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_audioBitDepthCombo) {
|
|
|
+ m_audioBitDepthCombo->setCurrentText(QString::number(m_currentSettings.audio.bitDepth));
|
|
|
+ }
|
|
|
+ if (m_audioCodecCombo) {
|
|
|
+ QString codec = m_currentSettings.audio.codec.toUpper();
|
|
|
+ int index = m_audioCodecCombo->findText(codec);
|
|
|
+ if (index >= 0) m_audioCodecCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_audioBitrateSpinBox) {
|
|
|
+ m_audioBitrateSpinBox->setValue(m_currentSettings.audio.bitrate / 1000);
|
|
|
+ }
|
|
|
+ if (m_audioNoiseSuppressionCheckBox) {
|
|
|
+ m_audioNoiseSuppressionCheckBox->setChecked(m_currentSettings.audio.enableNoiseSuppression);
|
|
|
+ }
|
|
|
+ if (m_audioEchoCancellationCheckBox) {
|
|
|
+ m_audioEchoCancellationCheckBox->setChecked(m_currentSettings.audio.enableEchoCancellation);
|
|
|
+ }
|
|
|
+ if (m_audioInputGainSpinBox) {
|
|
|
+ m_audioInputGainSpinBox->setValue(m_currentSettings.audio.inputGain);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 写入视频设置
|
|
|
+ if (m_videoDeviceCombo) {
|
|
|
+ int index = m_videoDeviceCombo->findText(m_currentSettings.video.deviceName);
|
|
|
+ if (index >= 0) m_videoDeviceCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_videoResolutionCombo) {
|
|
|
+ QString resolution = QString("%1x%2").arg(m_currentSettings.video.width).arg(m_currentSettings.video.height);
|
|
|
+ int index = m_videoResolutionCombo->findText(resolution);
|
|
|
+ if (index >= 0) m_videoResolutionCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_videoFrameRateSpinBox) {
|
|
|
+ m_videoFrameRateSpinBox->setValue(m_currentSettings.video.frameRate);
|
|
|
+ }
|
|
|
+ if (m_videoCodecCombo) {
|
|
|
+ QString codec = m_currentSettings.video.codec;
|
|
|
+ if (codec == "h264") codec = "H.264";
|
|
|
+ else if (codec == "h265") codec = "H.265";
|
|
|
+ else codec = codec.toUpper();
|
|
|
+ int index = m_videoCodecCombo->findText(codec);
|
|
|
+ if (index >= 0) m_videoCodecCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_videoBitrateSpinBox) {
|
|
|
+ m_videoBitrateSpinBox->setValue(m_currentSettings.video.bitrate / 1000);
|
|
|
+ }
|
|
|
+ if (m_videoPresetCombo) {
|
|
|
+ int index = m_videoPresetCombo->findText(m_currentSettings.video.preset);
|
|
|
+ if (index >= 0) m_videoPresetCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_videoProfileCombo) {
|
|
|
+ int index = m_videoProfileCombo->findText(m_currentSettings.video.profile);
|
|
|
+ if (index >= 0) m_videoProfileCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_videoKeyFrameSpinBox) {
|
|
|
+ m_videoKeyFrameSpinBox->setValue(m_currentSettings.video.keyFrameInterval);
|
|
|
+ }
|
|
|
+ if (m_videoHardwareAccelCheckBox) {
|
|
|
+ m_videoHardwareAccelCheckBox->setChecked(m_currentSettings.video.enableHardwareAcceleration);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 写入输出设置
|
|
|
+ if (m_outputDirectoryEdit) {
|
|
|
+ m_outputDirectoryEdit->setText(m_currentSettings.output.outputDirectory);
|
|
|
+ }
|
|
|
+ if (m_fileNameTemplateEdit) {
|
|
|
+ m_fileNameTemplateEdit->setText(m_currentSettings.output.fileNameTemplate);
|
|
|
+ }
|
|
|
+ if (m_containerFormatCombo) {
|
|
|
+ QString format = m_currentSettings.output.containerFormat.toUpper();
|
|
|
+ int index = m_containerFormatCombo->findText(format);
|
|
|
+ if (index >= 0) m_containerFormatCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_autoCreateDirectoryCheckBox) {
|
|
|
+ m_autoCreateDirectoryCheckBox->setChecked(m_currentSettings.output.autoCreateDirectory);
|
|
|
+ }
|
|
|
+ if (m_overwriteExistingCheckBox) {
|
|
|
+ m_overwriteExistingCheckBox->setChecked(m_currentSettings.output.overwriteExisting);
|
|
|
+ }
|
|
|
+ if (m_maxFileSizeSpinBox) {
|
|
|
+ m_maxFileSizeSpinBox->setValue(m_currentSettings.output.maxFileSize);
|
|
|
+ }
|
|
|
+ if (m_maxDurationSpinBox) {
|
|
|
+ m_maxDurationSpinBox->setValue(m_currentSettings.output.maxDuration);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 写入高级设置
|
|
|
+ if (m_bufferSizeSpinBox) {
|
|
|
+ m_bufferSizeSpinBox->setValue(m_currentSettings.advanced.bufferSize);
|
|
|
+ }
|
|
|
+ if (m_threadCountSpinBox) {
|
|
|
+ m_threadCountSpinBox->setValue(m_currentSettings.advanced.threadCount);
|
|
|
+ }
|
|
|
+ if (m_gpuAccelerationCheckBox) {
|
|
|
+ m_gpuAccelerationCheckBox->setChecked(m_currentSettings.advanced.enableGPUAcceleration);
|
|
|
+ }
|
|
|
+ if (m_gpuDeviceCombo) {
|
|
|
+ int index = m_gpuDeviceCombo->findText(m_currentSettings.advanced.gpuDevice);
|
|
|
+ if (index >= 0) m_gpuDeviceCombo->setCurrentIndex(index);
|
|
|
+ }
|
|
|
+ if (m_lowLatencyCheckBox) {
|
|
|
+ m_lowLatencyCheckBox->setChecked(m_currentSettings.advanced.enableLowLatency);
|
|
|
+ }
|
|
|
+ if (m_realTimeEncodingCheckBox) {
|
|
|
+ m_realTimeEncodingCheckBox->setChecked(m_currentSettings.advanced.enableRealTimeEncoding);
|
|
|
+ }
|
|
|
+ if (m_encodingPrioritySlider) {
|
|
|
+ m_encodingPrioritySlider->setValue(m_currentSettings.advanced.encodingPriority);
|
|
|
+ if (m_encodingPriorityLabel) {
|
|
|
+ QStringList labels = {"最低", "低", "正常", "高", "最高"};
|
|
|
+ m_encodingPriorityLabel->setText(labels[m_currentSettings.advanced.encodingPriority + 2]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ m_updating = false;
|
|
|
+}
|
|
|
+
|
|
|
+RecorderSettingsDialog::Settings RecorderSettingsDialog::getDefaultSettings() const {
|
|
|
+ Settings settings;
|
|
|
+
|
|
|
+ // 默认音频设置
|
|
|
+ settings.audio.deviceName = "";
|
|
|
+ settings.audio.sampleRate = 44100;
|
|
|
+ settings.audio.channels = 2;
|
|
|
+ settings.audio.bitDepth = 16;
|
|
|
+ settings.audio.codec = "aac";
|
|
|
+ settings.audio.bitrate = 128000;
|
|
|
+ settings.audio.enableNoiseSuppression = false;
|
|
|
+ settings.audio.enableEchoCancellation = false;
|
|
|
+ settings.audio.inputGain = 1.0;
|
|
|
+
|
|
|
+ // 默认视频设置
|
|
|
+ settings.video.deviceName = "";
|
|
|
+ settings.video.width = 1920;
|
|
|
+ settings.video.height = 1080;
|
|
|
+ settings.video.frameRate = 30.0;
|
|
|
+ settings.video.codec = "h264";
|
|
|
+ settings.video.bitrate = 5000000;
|
|
|
+ settings.video.preset = "medium";
|
|
|
+ settings.video.profile = "high";
|
|
|
+ settings.video.keyFrameInterval = 60;
|
|
|
+ settings.video.enableHardwareAcceleration = true;
|
|
|
+
|
|
|
+ // 默认输出设置
|
|
|
+ settings.output.outputDirectory = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
|
|
|
+ settings.output.fileNameTemplate = "recording_%Y%m%d_%H%M%S";
|
|
|
+ settings.output.containerFormat = "mp4";
|
|
|
+ settings.output.autoCreateDirectory = true;
|
|
|
+ settings.output.overwriteExisting = false;
|
|
|
+ settings.output.maxFileSize = 0;
|
|
|
+ settings.output.maxDuration = 0;
|
|
|
+
|
|
|
+ // 默认高级设置
|
|
|
+ settings.advanced.bufferSize = 4096;
|
|
|
+ settings.advanced.threadCount = 0;
|
|
|
+ settings.advanced.enableGPUAcceleration = true;
|
|
|
+ settings.advanced.gpuDevice = "自动选择";
|
|
|
+ settings.advanced.enableLowLatency = false;
|
|
|
+ settings.advanced.enableRealTimeEncoding = true;
|
|
|
+ settings.advanced.encodingPriority = 0;
|
|
|
+
|
|
|
+ return settings;
|
|
|
+}
|
|
|
+
|
|
|
+QString RecorderSettingsDialog::formatFileNamePreview() const {
|
|
|
+ QString preview = m_currentSettings.output.fileNameTemplate;
|
|
|
+ QDateTime now = QDateTime::currentDateTime();
|
|
|
+
|
|
|
+ preview.replace("%Y", now.toString("yyyy"));
|
|
|
+ preview.replace("%m", now.toString("MM"));
|
|
|
+ preview.replace("%d", now.toString("dd"));
|
|
|
+ preview.replace("%H", now.toString("hh"));
|
|
|
+ preview.replace("%M", now.toString("mm"));
|
|
|
+ preview.replace("%S", now.toString("ss"));
|
|
|
+
|
|
|
+ preview += "." + m_currentSettings.output.containerFormat;
|
|
|
+
|
|
|
+ return preview;
|
|
|
+}
|
|
|
+
|
|
|
+bool RecorderSettingsDialog::validateOutputDirectory(const QString& path) const {
|
|
|
+ QDir dir(path);
|
|
|
+ return dir.exists() || dir.mkpath(".");
|
|
|
+}
|