From bef80372b6bfbb627fbcf2b0aff2ed2764eef0cd Mon Sep 17 00:00:00 2001 From: Maik Jurischka Date: Fri, 19 Dec 2025 07:27:21 +0100 Subject: [PATCH] clang optimizations and cleanup --- cameracontrolwidget.cpp | 52 +++++++++++------------ gstreamerpipelinewidget.cpp | 34 +++++---------- mainwindow.cpp | 9 +--- videoviewerwidget.cpp | 83 ++++++++++++++----------------------- videoviewerwidget.h | 16 ++++--- 5 files changed, 78 insertions(+), 116 deletions(-) diff --git a/cameracontrolwidget.cpp b/cameracontrolwidget.cpp index 7825924..5bd951f 100644 --- a/cameracontrolwidget.cpp +++ b/cameracontrolwidget.cpp @@ -14,17 +14,15 @@ CameraControlWidget::CameraControlWidget(SocketClient* socketClient, QWidget *pa void CameraControlWidget::setupUI() { - QVBoxLayout* mainLayout = new QVBoxLayout(this); + auto* mainLayout = new QVBoxLayout(this); - // Create scroll area for all controls - QScrollArea* scrollArea = new QScrollArea(this); + auto* scrollArea = new QScrollArea(this); scrollArea->setWidgetResizable(true); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - QWidget* scrollWidget = new QWidget(); - QVBoxLayout* scrollLayout = new QVBoxLayout(scrollWidget); + auto* scrollWidget = new QWidget(); + auto* scrollLayout = new QVBoxLayout(scrollWidget); - // Add all control groups scrollLayout->addWidget(createFormatGroup()); scrollLayout->addWidget(createExposureGroup()); scrollLayout->addWidget(createWhiteBalanceGroup()); @@ -36,7 +34,6 @@ void CameraControlWidget::setupUI() mainLayout->addWidget(scrollArea); - // Status label at bottom m_statusLabel = new QLabel("Status: Ready", this); m_statusLabel->setStyleSheet("QLabel { background-color: #f0f0f0; padding: 5px; border-radius: 3px; }"); mainLayout->addWidget(m_statusLabel); @@ -46,8 +43,8 @@ void CameraControlWidget::setupUI() QGroupBox* CameraControlWidget::createFormatGroup() { - QGroupBox* groupBox = new QGroupBox("Video Format", this); - QVBoxLayout* layout = new QVBoxLayout(); + auto* groupBox = new QGroupBox("Video Format", this); + auto* layout = new QVBoxLayout(); m_formatCombo = new QComboBox(this); m_formatCombo->addItem("1280x720@30fps UYVY (Supported)", "1280,720,30,UYVY"); @@ -69,10 +66,10 @@ QGroupBox* CameraControlWidget::createFormatGroup() QGroupBox* CameraControlWidget::createExposureGroup() { - QGroupBox* groupBox = new QGroupBox("Exposure", this); - QVBoxLayout* layout = new QVBoxLayout(); + auto* groupBox = new QGroupBox("Exposure", this); + auto* layout = new QVBoxLayout(); - QButtonGroup* exposureGroup = new QButtonGroup(this); + auto* exposureGroup = new QButtonGroup(this); m_exposureAuto = new QRadioButton("Auto", this); m_exposureManual = new QRadioButton("Manual", this); m_exposureAuto->setChecked(true); @@ -82,7 +79,7 @@ QGroupBox* CameraControlWidget::createExposureGroup() connect(m_exposureAuto, &QRadioButton::toggled, this, &CameraControlWidget::onExposureModeChanged); - QHBoxLayout* modeLayout = new QHBoxLayout(); + auto* modeLayout = new QHBoxLayout(); modeLayout->addWidget(m_exposureAuto); modeLayout->addWidget(m_exposureManual); @@ -94,7 +91,7 @@ QGroupBox* CameraControlWidget::createExposureGroup() m_setExposureBtn = new QPushButton("Set Exposure", this); connect(m_setExposureBtn, &QPushButton::clicked, this, &CameraControlWidget::onSetExposure); - QFormLayout* formLayout = new QFormLayout(); + auto* formLayout = new QFormLayout(); formLayout->addRow("Mode:", modeLayout); formLayout->addRow("Value:", m_exposureValue); @@ -107,10 +104,10 @@ QGroupBox* CameraControlWidget::createExposureGroup() QGroupBox* CameraControlWidget::createWhiteBalanceGroup() { - QGroupBox* groupBox = new QGroupBox("White Balance", this); - QVBoxLayout* layout = new QVBoxLayout(); + auto* groupBox = new QGroupBox("White Balance", this); + auto* layout = new QVBoxLayout(); - QButtonGroup* wbGroup = new QButtonGroup(this); + auto* wbGroup = new QButtonGroup(this); m_whiteBalanceAuto = new QRadioButton("Auto", this); m_whiteBalanceManual = new QRadioButton("Manual", this); m_whiteBalanceAuto->setChecked(true); @@ -120,7 +117,7 @@ QGroupBox* CameraControlWidget::createWhiteBalanceGroup() connect(m_whiteBalanceAuto, &QRadioButton::toggled, this, &CameraControlWidget::onWhiteBalanceModeChanged); - QHBoxLayout* modeLayout = new QHBoxLayout(); + auto* modeLayout = new QHBoxLayout(); modeLayout->addWidget(m_whiteBalanceAuto); modeLayout->addWidget(m_whiteBalanceManual); @@ -133,7 +130,7 @@ QGroupBox* CameraControlWidget::createWhiteBalanceGroup() m_setWhiteBalanceBtn = new QPushButton("Set White Balance", this); connect(m_setWhiteBalanceBtn, &QPushButton::clicked, this, &CameraControlWidget::onSetWhiteBalance); - QFormLayout* formLayout = new QFormLayout(); + auto* formLayout = new QFormLayout(); formLayout->addRow("Mode:", modeLayout); formLayout->addRow("Temperature:", m_whiteBalanceTemp); @@ -146,8 +143,8 @@ QGroupBox* CameraControlWidget::createWhiteBalanceGroup() QGroupBox* CameraControlWidget::createImageAdjustmentGroup() { - QGroupBox* groupBox = new QGroupBox("Image Adjustments", this); - QVBoxLayout* layout = new QVBoxLayout(); + auto* groupBox = new QGroupBox("Image Adjustments", this); + auto* layout = new QVBoxLayout(); layout->addWidget(createSliderControl("Brightness (0-255):", 0, 255, 128, &m_brightnessSlider, &m_brightnessSpinBox)); @@ -180,13 +177,13 @@ QGroupBox* CameraControlWidget::createImageAdjustmentGroup() QWidget* CameraControlWidget::createSliderControl(const QString& label, int min, int max, int defaultValue, QSlider** slider, QSpinBox** spinBox) { - QWidget* widget = new QWidget(this); - QVBoxLayout* layout = new QVBoxLayout(widget); + auto* widget = new QWidget(this); + auto* layout = new QVBoxLayout(widget); layout->setContentsMargins(0, 5, 0, 5); - QLabel* titleLabel = new QLabel(label, this); + auto* titleLabel = new QLabel(label, this); - QHBoxLayout* controlLayout = new QHBoxLayout(); + auto* controlLayout = new QHBoxLayout(); *slider = new QSlider(Qt::Horizontal, this); (*slider)->setRange(min, max); @@ -223,9 +220,8 @@ void CameraControlWidget::onGetFormats() int fps = fmt["framerate"].toInt(); QString format = fmt["format"].toString(); - QString displayText = QString("%1x%2@%3fps %4") - .arg(width).arg(height).arg(fps).arg(format); - QString data = QString("%1,%2,%3,%4").arg(width).arg(height).arg(fps).arg(format); + QString displayText = QString("%1x%2@%3fps %4").arg(width, height, fps).arg(format); + QString data = QString("%1,%2,%3,%4").arg(width, height, fps).arg(format); m_formatCombo->addItem(displayText, data); } diff --git a/gstreamerpipelinewidget.cpp b/gstreamerpipelinewidget.cpp index 20d1476..6829971 100644 --- a/gstreamerpipelinewidget.cpp +++ b/gstreamerpipelinewidget.cpp @@ -16,12 +16,11 @@ GStreamerPipelineWidget::GStreamerPipelineWidget(SocketClient* socketClient, QWi void GStreamerPipelineWidget::setupUI() { - QVBoxLayout* mainLayout = new QVBoxLayout(this); + auto* mainLayout = new QVBoxLayout(this); - QGroupBox* groupBox = new QGroupBox("GStreamer Pipeline", this); - QVBoxLayout* groupLayout = new QVBoxLayout(groupBox); + auto* groupBox = new QGroupBox("GStreamer Pipeline", this); + auto* groupLayout = new QVBoxLayout(groupBox); - // Info label with instructions m_infoLabel = new QLabel( "Quick Start: Click 'Quick Start' to automatically configure and start streaming.
" "Manual: 1. Set video format → 2. Set pipeline → 3. Start stream", this); @@ -29,27 +28,23 @@ void GStreamerPipelineWidget::setupUI() m_infoLabel->setWordWrap(true); groupLayout->addWidget(m_infoLabel); - // Quick Start button (prominent) m_quickStartBtn = new QPushButton("⚡ Quick Start (Auto Configure & Stream)", this); m_quickStartBtn->setStyleSheet("QPushButton { background-color: #4CAF50; color: white; font-weight: bold; padding: 10px; }"); connect(m_quickStartBtn, &QPushButton::clicked, this, &GStreamerPipelineWidget::onQuickStart); groupLayout->addWidget(m_quickStartBtn); - // Separator - QFrame* line = new QFrame(this); + auto* line = new QFrame(this); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); groupLayout->addWidget(line); - // Format selection - QLabel* formatLabel = new QLabel("Video Format:", this); + auto* formatLabel = new QLabel("Video Format:", this); m_formatCombo = new QComboBox(this); m_formatCombo->addItem("1280x720@30fps UYVY (Default/Supported)", "1280,720,30,UYVY"); groupLayout->addWidget(formatLabel); groupLayout->addWidget(m_formatCombo); - // Pipeline presets - QLabel* presetsLabel = new QLabel("Pipeline Presets:", this); + auto* presetsLabel = new QLabel("Pipeline Presets:", this); m_pipelinePresets = new QComboBox(this); m_pipelinePresets->addItem("MJPEG UDP Stream (Best for raw formats)", "videoconvert ! jpegenc ! rtpjpegpay ! udpsink host=127.0.0.1 port=5000"); m_pipelinePresets->addItem("UDP H.264 Stream (Requires gst-libav)", "videoconvert ! x264enc tune=zerolatency ! rtph264pay ! udpsink host=127.0.0.1 port=5000"); @@ -66,8 +61,7 @@ void GStreamerPipelineWidget::setupUI() groupLayout->addWidget(presetsLabel); groupLayout->addWidget(m_pipelinePresets); - // Pipeline editor - QLabel* pipelineLabel = new QLabel("Pipeline:", this); + auto* pipelineLabel = new QLabel("Pipeline:", this); m_pipelineEdit = new QTextEdit(this); m_pipelineEdit->setMaximumHeight(80); m_pipelineEdit->setPlaceholderText("Enter GStreamer pipeline here...\nExample: videoconvert ! autovideosink"); @@ -75,13 +69,11 @@ void GStreamerPipelineWidget::setupUI() groupLayout->addWidget(pipelineLabel); groupLayout->addWidget(m_pipelineEdit); - // Set pipeline button m_setPipelineBtn = new QPushButton("Set Pipeline", this); connect(m_setPipelineBtn, &QPushButton::clicked, this, &GStreamerPipelineWidget::onSetPipeline); groupLayout->addWidget(m_setPipelineBtn); - // Stream control buttons - QHBoxLayout* buttonLayout = new QHBoxLayout(); + auto* buttonLayout = new QHBoxLayout(); m_startStreamBtn = new QPushButton("Start Stream", this); m_stopStreamBtn = new QPushButton("Stop Stream", this); m_getStatusBtn = new QPushButton("Get Status", this); @@ -95,7 +87,6 @@ void GStreamerPipelineWidget::setupUI() buttonLayout->addWidget(m_getStatusBtn); groupLayout->addLayout(buttonLayout); - // Status label m_statusLabel = new QLabel("Status: Unknown", this); m_statusLabel->setStyleSheet("QLabel { background-color: #f0f0f0; padding: 5px; border-radius: 3px; }"); groupLayout->addWidget(m_statusLabel); @@ -148,7 +139,6 @@ void GStreamerPipelineWidget::onStartStream() m_socketClient->sendCommand("set_format", formatParams, [this](const QJsonObject& response) { - // Now start stream m_socketClient->sendCommand("start_stream", QJsonObject(), [this](const QJsonObject& response) { updateStatus("Streaming started", true); @@ -213,7 +203,6 @@ void GStreamerPipelineWidget::updateStatus(const QString& status, bool streaming void GStreamerPipelineWidget::onQuickStart() { - // Disable button during process m_quickStartBtn->setEnabled(false); m_quickStartBtn->setText("Configuring..."); @@ -306,10 +295,8 @@ void GStreamerPipelineWidget::onFormatsReceived(const QJsonObject& response) return; } - // Clear existing formats m_formatCombo->clear(); - // Add all available formats for (const QJsonValue& val : formats) { QJsonObject fmt = val.toObject(); int width = fmt["width"].toInt(); @@ -317,9 +304,8 @@ void GStreamerPipelineWidget::onFormatsReceived(const QJsonObject& response) int fps = fmt["framerate"].toInt(); QString format = fmt["format"].toString(); - QString displayText = QString("%1x%2@%3fps %4") - .arg(width).arg(height).arg(fps).arg(format); - QString data = QString("%1,%2,%3,%4").arg(width).arg(height).arg(fps).arg(format); + QString displayText = QString("%1x%2@%3fps %4").arg(width, height, fps).arg(format); + QString data = QString("%1,%2,%3,%4").arg(width, height, fps).arg(format); m_formatCombo->addItem(displayText, data); } diff --git a/mainwindow.cpp b/mainwindow.cpp index 30b979a..0858a0a 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -24,26 +24,21 @@ MainWindow::~MainWindow() void MainWindow::setupUI() { - // Create socket client m_socketClient = new SocketClient("/tmp/vizion_control.sock", this); - // Create widgets m_videoWidget = new VideoViewerWidget(this); m_pipelineWidget = new GStreamerPipelineWidget(m_socketClient, this); m_cameraWidget = new CameraControlWidget(m_socketClient, this); - // Create tab widget for controls on the right - QTabWidget* controlTabs = new QTabWidget(this); + auto* controlTabs = new QTabWidget(this); controlTabs->addTab(m_pipelineWidget, "Pipeline Control"); controlTabs->addTab(m_cameraWidget, "Camera Control"); - // Create horizontal splitter: video on left (full height), controls on right - QSplitter* mainSplitter = new QSplitter(Qt::Horizontal, this); + auto* mainSplitter = new QSplitter(Qt::Horizontal, this); mainSplitter->addWidget(m_videoWidget); mainSplitter->addWidget(controlTabs); mainSplitter->setStretchFactor(0, 2); // Video gets more space (2/3) mainSplitter->setStretchFactor(1, 1); // Controls get less space (1/3) - // Set as central widget setCentralWidget(mainSplitter); } diff --git a/videoviewerwidget.cpp b/videoviewerwidget.cpp index 27d24a5..33d97f4 100644 --- a/videoviewerwidget.cpp +++ b/videoviewerwidget.cpp @@ -8,16 +8,25 @@ #include VideoViewerWidget::VideoViewerWidget(QWidget *parent) - : QWidget(parent), m_pipeline(nullptr), m_appSink(nullptr), - m_busWatchId(0), m_zoomFactor(1.0) + : QWidget(parent), + m_scrollArea(nullptr), + m_videoDisplay(nullptr), + m_startBtn(nullptr), + m_stopBtn(nullptr), + m_sourceType(nullptr), + m_hostEdit(nullptr), + m_portEdit(nullptr), + m_statusLabel(nullptr), + m_zoomSlider(nullptr), + m_zoomLabel(nullptr), + m_pipeline(nullptr), + m_appSink(nullptr), + m_zoomFactor(1.0), + m_busWatchId(0) { - // Register QImage as meta type for signal/slot across threads - qRegisterMetaType("QImage"); - initGStreamer(); setupUI(); - // Connect signal for frame display connect(this, &VideoViewerWidget::newFrameAvailable, this, &VideoViewerWidget::displayFrame, Qt::QueuedConnection); } @@ -34,11 +43,10 @@ void VideoViewerWidget::initGStreamer() void VideoViewerWidget::setupUI() { - QVBoxLayout* mainLayout = new QVBoxLayout(this); + auto* mainLayout = new QVBoxLayout(this); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(5); - // Video display in scroll area for zoom support m_scrollArea = new QScrollArea(this); m_scrollArea->setWidgetResizable(false); m_scrollArea->setAlignment(Qt::AlignCenter); @@ -52,8 +60,7 @@ void VideoViewerWidget::setupUI() m_scrollArea->setWidget(m_videoDisplay); - // Zoom control - QHBoxLayout* zoomLayout = new QHBoxLayout(); + auto* zoomLayout = new QHBoxLayout(); zoomLayout->addWidget(new QLabel("Zoom:", this)); m_zoomSlider = new QSlider(Qt::Horizontal, this); @@ -70,12 +77,10 @@ void VideoViewerWidget::setupUI() zoomLayout->addWidget(m_zoomSlider); zoomLayout->addWidget(m_zoomLabel); - // Controls - QGroupBox* controlGroup = new QGroupBox("Viewer Controls", this); - QVBoxLayout* controlLayout = new QVBoxLayout(); + auto* controlGroup = new QGroupBox("Viewer Controls", this); + auto* controlLayout = new QVBoxLayout(); - // Source type selection - QHBoxLayout* sourceLayout = new QHBoxLayout(); + auto* sourceLayout = new QHBoxLayout(); sourceLayout->addWidget(new QLabel("Source Type:", this)); m_sourceType = new QComboBox(this); m_sourceType->addItem("UDP MJPEG Stream (No plugins needed)", "udp-mjpeg"); @@ -87,15 +92,13 @@ void VideoViewerWidget::setupUI() this, &VideoViewerWidget::onSourceTypeChanged); sourceLayout->addWidget(m_sourceType); - // Host and port - QFormLayout* formLayout = new QFormLayout(); + auto* formLayout = new QFormLayout(); m_hostEdit = new QLineEdit("127.0.0.1", this); m_portEdit = new QLineEdit("5000", this); formLayout->addRow("Host:", m_hostEdit); formLayout->addRow("Port:", m_portEdit); - // Control buttons - QHBoxLayout* buttonLayout = new QHBoxLayout(); + auto* buttonLayout = new QHBoxLayout(); m_startBtn = new QPushButton("Start Viewer", this); m_stopBtn = new QPushButton("Stop Viewer", this); m_stopBtn->setEnabled(false); @@ -106,7 +109,6 @@ void VideoViewerWidget::setupUI() buttonLayout->addWidget(m_startBtn); buttonLayout->addWidget(m_stopBtn); - // Status label m_statusLabel = new QLabel("Status: Stopped", this); m_statusLabel->setStyleSheet("QLabel { background-color: #f0f0f0; padding: 5px; border-radius: 3px; }"); @@ -116,7 +118,6 @@ void VideoViewerWidget::setupUI() controlLayout->addWidget(m_statusLabel); controlGroup->setLayout(controlLayout); - // Add to main layout: video takes most space, zoom control, then viewer controls at bottom mainLayout->addWidget(m_scrollArea, 1); mainLayout->addLayout(zoomLayout); mainLayout->addWidget(controlGroup); @@ -124,8 +125,7 @@ void VideoViewerWidget::setupUI() setLayout(mainLayout); } -QString VideoViewerWidget::buildPipelineString() -{ +QString VideoViewerWidget::buildPipelineString() const { QString sourceType = m_sourceType->currentData().toString(); QString host = m_hostEdit->text(); QString port = m_portEdit->text(); @@ -136,19 +136,17 @@ QString VideoViewerWidget::buildPipelineString() QString sinkPipeline = "videoconvert ! video/x-raw,format=RGB ! appsink name=videosink emit-signals=true"; if (sourceType == "udp-mjpeg") { - pipeline = QString("udpsrc port=%1 ! application/x-rtp,encoding-name=JPEG,payload=26 ! " - "rtpjpegdepay ! jpegdec ! %2") - .arg(port).arg(sinkPipeline); + pipeline = QString("udpsrc port=%1 ! application/x-rtp,encoding-name=JPEG,payload=26 ! rtpjpegdepay ! jpegdec ! %2") + .arg(port, sinkPipeline); } else if (sourceType == "udp-h264") { - pipeline = QString("udpsrc port=%1 ! application/x-rtp,encoding-name=H264 ! " - "rtph264depay ! h264parse ! avdec_h264 ! %2") - .arg(port).arg(sinkPipeline); + pipeline = QString("udpsrc port=%1 ! application/x-rtp,encoding-name=H264 ! rtph264depay ! h264parse ! avdec_h264 ! %2") + .arg(port, sinkPipeline); } else if (sourceType == "tcp") { pipeline = QString("tcpclientsrc host=%1 port=%2 ! tsdemux ! h264parse ! avdec_h264 ! %3") - .arg(host).arg(port).arg(sinkPipeline); + .arg(host, port, sinkPipeline); } else if (sourceType == "http") { pipeline = QString("souphttpsrc location=http://%1:%2 ! multipartdemux ! jpegdec ! %3") - .arg(host).arg(port).arg(sinkPipeline); + .arg(host, port, sinkPipeline); } else if (sourceType == "test") { pipeline = QString("videotestsrc ! %1").arg(sinkPipeline); } @@ -182,12 +180,10 @@ void VideoViewerWidget::startPipeline() return; } - // Set up bus callback GstBus* bus = gst_element_get_bus(m_pipeline); m_busWatchId = gst_bus_add_watch(bus, busCallback, this); gst_object_unref(bus); - // Get appsink element and configure it m_appSink = gst_bin_get_by_name(GST_BIN(m_pipeline), "videosink"); if (!m_appSink) { m_statusLabel->setText("Status: Failed to get appsink element"); @@ -196,10 +192,9 @@ void VideoViewerWidget::startPipeline() return; } - // Configure appsink g_object_set(m_appSink, "emit-signals", TRUE, "sync", FALSE, "max-buffers", 1, "drop", TRUE, nullptr); - // Set callback for new samples - properly initialize all fields + // Properly initialize all callback fields GstAppSinkCallbacks callbacks = { 0 }; callbacks.new_sample = newSampleCallback; callbacks.eos = nullptr; @@ -209,7 +204,6 @@ void VideoViewerWidget::startPipeline() #endif gst_app_sink_set_callbacks(GST_APP_SINK(m_appSink), &callbacks, this, nullptr); - // Start playing GstStateChangeReturn ret = gst_element_set_state(m_pipeline, GST_STATE_PLAYING); qDebug() << "[VideoViewer] Pipeline state change return:" << ret; @@ -246,7 +240,6 @@ void VideoViewerWidget::stopPipeline() m_busWatchId = 0; } - // Clear video display and current frame m_videoDisplay->clear(); m_videoDisplay->setText(""); m_currentFrame = QImage(); @@ -354,7 +347,6 @@ void VideoViewerWidget::onZoomChanged(int value) m_zoomFactor = value / 100.0; m_zoomLabel->setText(QString("%1%").arg(value)); - // Re-display the current frame with new zoom factor if (!m_currentFrame.isNull()) { displayFrame(m_currentFrame); } @@ -377,14 +369,12 @@ GstFlowReturn VideoViewerWidget::newSampleCallback(GstAppSink* appsink, gpointer return GST_FLOW_ERROR; } - // Pull the sample from appsink GstSample* sample = gst_app_sink_pull_sample(appsink); if (!sample) { qDebug() << "[VideoViewer] Callback: Failed to pull sample"; return GST_FLOW_ERROR; } - // Get the buffer from the sample GstBuffer* buffer = gst_sample_get_buffer(sample); if (!buffer) { qDebug() << "[VideoViewer] Callback: No buffer in sample"; @@ -392,7 +382,6 @@ GstFlowReturn VideoViewerWidget::newSampleCallback(GstAppSink* appsink, gpointer return GST_FLOW_ERROR; } - // Get the caps to extract width and height GstCaps* caps = gst_sample_get_caps(sample); if (!caps) { qDebug() << "[VideoViewer] Callback: No caps in sample"; @@ -409,7 +398,6 @@ GstFlowReturn VideoViewerWidget::newSampleCallback(GstAppSink* appsink, gpointer return GST_FLOW_ERROR; } - // Map the buffer to access the raw data GstMapInfo map; if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { qDebug() << "[VideoViewer] Callback: Failed to map buffer"; @@ -417,7 +405,7 @@ GstFlowReturn VideoViewerWidget::newSampleCallback(GstAppSink* appsink, gpointer return GST_FLOW_ERROR; } - // Calculate expected size for RGB888 format + // RGB888 format: width * height * 3 bytes gsize expected_size = width * height * 3; if (map.size < expected_size) { qDebug() << "[VideoViewer] Callback: Buffer too small. Expected:" << expected_size << "Got:" << map.size; @@ -426,14 +414,12 @@ GstFlowReturn VideoViewerWidget::newSampleCallback(GstAppSink* appsink, gpointer return GST_FLOW_ERROR; } - // Create QImage from the RGB data with proper stride - // QImage::Format_RGB888 expects RGB data + // QImage requires RGB data with proper stride (width * 3 bytes per row) QImage frame(map.data, width, height, width * 3, QImage::Format_RGB888); // Make a deep copy since the buffer will be unmapped QImage frameCopy = frame.copy(); - // Unmap and cleanup gst_buffer_unmap(buffer, &map); gst_sample_unref(sample); @@ -465,20 +451,16 @@ void VideoViewerWidget::displayFrame(const QImage& frame) qDebug() << "[VideoViewer] Frames received:" << frameCount; } - // Store current frame for zoom changes m_currentFrame = frame; - // Convert QImage to QPixmap QPixmap pixmap = QPixmap::fromImage(frame); if (pixmap.isNull()) { qDebug() << "[VideoViewer] ERROR: Pixmap conversion failed!"; return; } - // Calculate target size with zoom factor QSize targetSize = frame.size() * m_zoomFactor; - // Scale pixmap with zoom factor QPixmap scaledPixmap = pixmap.scaled(targetSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); @@ -488,7 +470,6 @@ void VideoViewerWidget::displayFrame(const QImage& frame) << "Scaled pixmap:" << scaledPixmap.size(); } - // Update the label size to match the scaled pixmap m_videoDisplay->setPixmap(scaledPixmap); m_videoDisplay->resize(scaledPixmap.size()); m_videoDisplay->update(); diff --git a/videoviewerwidget.h b/videoviewerwidget.h index 289b394..89f5437 100644 --- a/videoviewerwidget.h +++ b/videoviewerwidget.h @@ -18,7 +18,7 @@ class VideoViewerWidget : public QWidget public: explicit VideoViewerWidget(QWidget *parent = nullptr); - ~VideoViewerWidget(); + ~VideoViewerWidget() override; signals: void newFrameAvailable(const QImage& frame); @@ -36,12 +36,12 @@ private: void cleanupGStreamer(); void startPipeline(); void stopPipeline(); - QString buildPipelineString(); + QString buildPipelineString() const; static gboolean busCallback(GstBus* bus, GstMessage* msg, gpointer data); static GstFlowReturn newSampleCallback(GstAppSink* appsink, gpointer user_data); - // UI elements + // UI elements (8-byte pointers) QScrollArea* m_scrollArea; QLabel* m_videoDisplay; QPushButton* m_startBtn; @@ -53,14 +53,18 @@ private: QSlider* m_zoomSlider; QLabel* m_zoomLabel; - // GStreamer elements + // GStreamer elements (8-byte pointers) GstElement* m_pipeline; GstElement* m_appSink; + + // Zoom factor (8-byte double) + double m_zoomFactor; + + // Bus watch ID (4-byte unsigned int) guint m_busWatchId; - // Video state + // Video state (large object at end) QImage m_currentFrame; - double m_zoomFactor; }; #endif // VIDEOVIEWERWIDGET_H