Erster Commit

This commit is contained in:
2026-08-27 09:47:58 +02:00
commit 7d3adbf8b0
87 changed files with 26885 additions and 0 deletions

148
src/DeviceDialog.cpp Normal file
View File

@@ -0,0 +1,148 @@
#include "DeviceDialog.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QComboBox>
#include <QLabel>
#include <QPushButton>
#include <QDir>
#include <QDebug>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <alsa/asoundlib.h>
#include <cerrno>
#include <cstring>
static int xioctl(int fd, unsigned long req, void* arg)
{
int r;
do { r = ioctl(fd, req, arg); } while (r == -1 && errno == EINTR);
return r;
}
DeviceDialog::DeviceDialog(QWidget* parent)
: QDialog(parent)
{
setWindowTitle("HDMI Viewer Gerät auswählen");
setMinimumWidth(520);
auto* form = new QFormLayout;
m_videoCombo = new QComboBox(this);
m_audioCombo = new QComboBox(this);
m_fpsCombo = new QComboBox(this);
m_videoCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_audioCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
populateVideoDevices();
populateAudioDevices();
// FPS-Optionen: gängige Werte für HDMI-Grabber
for (int fps : {10, 15, 20, 24, 25, 30, 50, 60})
m_fpsCombo->addItem(QString::number(fps) + " fps", fps);
// Default: 30
setPreselectedFps(30);
form->addRow("Video-Gerät (V4L2):", m_videoCombo);
form->addRow("Audio-Gerät (ALSA):", m_audioCombo);
form->addRow("Ziel-Framerate:", m_fpsCombo);
auto* hint = new QLabel(
"<small><b>Hinweis:</b> Der Grabber liefert die gewünschte FPS-Zahl nur wenn "
"genug USB-Bandbreite vorhanden ist. Die tatsächliche Rate wird in der "
"Titelleiste angezeigt.<br>"
"<b>F</b> = Vollbild &nbsp;·&nbsp; <b>Esc</b> = zurück hierher</small>",
this);
hint->setWordWrap(true);
auto* btnBox = new QHBoxLayout;
auto* btnOk = new QPushButton("Starten", this);
auto* btnClose = new QPushButton("Beenden", this);
btnOk->setDefault(true);
btnBox->addStretch();
btnBox->addWidget(btnClose);
btnBox->addWidget(btnOk);
connect(btnOk, &QPushButton::clicked, this, &QDialog::accept);
connect(btnClose, &QPushButton::clicked, this, &QDialog::reject);
auto* main = new QVBoxLayout(this);
main->addLayout(form);
main->addSpacing(8);
main->addWidget(hint);
main->addSpacing(12);
main->addLayout(btnBox);
}
QString DeviceDialog::selectedVideoDevice() const { return m_videoCombo->currentData().toString(); }
QString DeviceDialog::selectedAudioDevice() const { return m_audioCombo->currentData().toString(); }
int DeviceDialog::selectedFps() const { return m_fpsCombo->currentData().toInt(); }
void DeviceDialog::setPreselectedVideo(const QString& device) { selectByData(m_videoCombo, device); }
void DeviceDialog::setPreselectedAudio(const QString& device) { selectByData(m_audioCombo, device); }
void DeviceDialog::setPreselectedFps(int fps) { selectByData(m_fpsCombo, QString::number(fps)); }
void DeviceDialog::selectByData(QComboBox* combo, const QString& data)
{
for (int i = 0; i < combo->count(); ++i)
if (combo->itemData(i).toString() == data) { combo->setCurrentIndex(i); return; }
}
void DeviceDialog::populateVideoDevices()
{
QDir dev("/dev");
const QStringList entries = dev.entryList({"video*"}, QDir::System, QDir::Name);
for (const QString& entry : entries) {
const QString path = "/dev/" + entry;
int fd = ::open(path.toLocal8Bit().constData(), O_RDWR | O_NONBLOCK);
if (fd == -1) continue;
v4l2_capability cap{};
QString label = path;
if (xioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { ::close(fd); continue; }
const QString card = QString::fromLatin1(
reinterpret_cast<const char*>(cap.card), 32).trimmed();
if (!card.isEmpty())
label = QString("%1 [%2]").arg(path, card);
}
::close(fd);
m_videoCombo->addItem(label, path);
}
if (m_videoCombo->count() == 0)
m_videoCombo->addItem("Kein V4L2-Gerät gefunden", "");
}
void DeviceDialog::populateAudioDevices()
{
m_audioCombo->addItem("default [System-Standard]", "default");
void** hints = nullptr;
if (snd_device_name_hint(-1, "pcm", &hints) < 0) return;
for (void** hint = hints; *hint != nullptr; ++hint) {
char* ioid = snd_device_name_get_hint(*hint, "IOID");
const bool isCapture = (ioid == nullptr || strcmp(ioid, "Input") == 0);
free(ioid);
if (!isCapture) continue;
char* name = snd_device_name_get_hint(*hint, "NAME");
char* desc = snd_device_name_get_hint(*hint, "DESC");
if (name) {
const QString n = QString::fromLatin1(name);
const QString d = desc ? QString::fromLatin1(desc).replace('\n', ' ') : n;
if (n != "default")
m_audioCombo->addItem(QString("%1 [%2]").arg(n, d.left(60)), n);
free(name);
}
if (desc) free(desc);
}
snd_device_name_free_hint(hints);
}