80 lines
2.3 KiB
C++
80 lines
2.3 KiB
C++
#pragma once
|
|
#include <QWidget>
|
|
#include <QImage>
|
|
#include <QSize>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QComboBox>
|
|
#include <QHBoxLayout>
|
|
#include <QVBoxLayout>
|
|
#include <QThread>
|
|
#include <QProcess>
|
|
|
|
#include "v4l2worker.h"
|
|
|
|
// VideoWidget shows the live V4L2 preview and can additionally record it
|
|
// to an MP4 file. Recording works by piping raw BGRA frames into an
|
|
// external `ffmpeg` process (via QProcess/stdin), which encodes them to
|
|
// H.264/MP4 - this avoids reimplementing video encoding and just needs
|
|
// ffmpeg to be installed and on PATH.
|
|
class VideoWidget : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit VideoWidget(QWidget *parent = nullptr);
|
|
~VideoWidget();
|
|
|
|
public:
|
|
void shutdown(); // safe to call multiple times, called from MainWindow::closeEvent
|
|
|
|
public slots:
|
|
void onNewFrame(const QImage &frame);
|
|
void clearFrame(); // blanks the preview (used on ANSI clear-screen)
|
|
|
|
private slots:
|
|
void onStartStop();
|
|
void onFreeze(bool frozen);
|
|
void onScreenshot();
|
|
void onRecordToggled(bool checked);
|
|
void refreshDeviceList();
|
|
|
|
protected:
|
|
void paintEvent(QPaintEvent *event) override;
|
|
void resizeEvent(QResizeEvent *event) override;
|
|
|
|
private:
|
|
void setupUi();
|
|
void startCapture();
|
|
void stopCapture();
|
|
void updateScaled();
|
|
void startRecording();
|
|
void stopRecording();
|
|
void writeRecordingFrame(const QImage &frame);
|
|
|
|
QThread *m_thread = nullptr;
|
|
V4l2Worker *m_worker = nullptr;
|
|
|
|
QImage m_frame;
|
|
QImage m_scaled;
|
|
bool m_frozen = false;
|
|
bool m_running = false;
|
|
bool m_shutdownDone = false;
|
|
|
|
QComboBox *m_deviceCombo = nullptr;
|
|
QPushButton *m_startBtn = nullptr;
|
|
QPushButton *m_freezeBtn = nullptr;
|
|
QPushButton *m_screenshotBtn = nullptr;
|
|
QPushButton *m_recordBtn = nullptr;
|
|
QLabel *m_infoLabel = nullptr;
|
|
|
|
// Recording state. m_recordProcess is the running ffmpeg instance (or
|
|
// nullptr when not recording); m_recordSize is the frame size the
|
|
// recording was started with, so a mid-stream resolution change (which
|
|
// ffmpeg's raw pipe can't handle) can be detected and the recording
|
|
// stopped cleanly instead of corrupting the output file.
|
|
QProcess *m_recordProcess = nullptr;
|
|
bool m_recording = false;
|
|
QSize m_recordSize;
|
|
};
|