Qt) Designer로 UI 구성하기(6) - Tab6WebCamera

mommers·2026년 4월 5일

QT

목록 보기
12/15

이전 글 : Qt) Designer로 UI 구성하기(5) - Tab7CamOpencv

이전 글에서 OpenCV와 QThread를 활용해 Tab7 카메라 탭을 구현했습니다.

이번 글에서는 mjpg-streamer를 Qt 앱 내에서 직접 실행하고, QWebEngineView로 스트림을 표시하는 Tab6WebCamera를 구현하는 과정을 정리합니다.

mjpg-streamer 설치 및 브라우저에서의 스트리밍 확인은 이전 글들을 참고 부탁드립니다!

Ubuntu | Rpi ) 웹캠 스트리밍 - mjpg-streamer

Qt) QWebEngineView를 이용한 웹캠 스트리밍


1. mjpg-streamer-master.zip 압축 해제 및 빌드

교수님이 제공하신 mjpg-streamer-master.zip을 홈 디렉토리에서 압축 해제합니다. 관련 github 링크도 첨부해둘테니 여기서 가져오셔도 됩니다.

https://github.com/jacksonliam/mjpg-streamer

cd ~
unzip mjpg-streamer-master.zip
cd mjpg-streamer-master
make
sudo make install

빌드 완료 후 디렉토리 구조를 확인합니다.

ls ~/mjpg-streamer-master
mjpg_streamer  input_uvc.so  output_http.so  www/  start.sh  ...

mjpg_streamer 실행 파일과 input_uvc.so, output_http.so, www/ 가 모두 같은 디렉토리에 위치합니다.

start.sh에서 export LD_LIBRARY_PATH="$(pwd)"를 설정하는 이유도 .so 플러그인 파일들이 시스템 경로가 아닌 같은 디렉토리에 있기 때문입니다.

터미널에서 직접 실행해 정상 동작을 확인합니다.

cd ~/mjpg-streamer-master
vi start.sh  # 필요 시 인증 옵션 확인
bash start.sh
# start.sh 실행 시 아래 명령어가 자동으로 실행됩니다
# export LD_LIBRARY_PATH="$(pwd)"
# ./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so -w ./www"

브라우저에서 http://10.10.16.35:8080에 접속해 스트리밍이 출력되면 정상입니다.


2. Tab6WebCamera 클래스 생성

AiotClient 프로젝트 우클릭 → Add New → Qt → Qt Widgets Designer Form Class → Widget 선택

Class name을 Tab6WebCamera로 입력하면 아래 파일이 자동 생성됩니다.

  • tab6webcamera.h
  • tab6webcamera.cpp
  • tab6webcamera.ui

3. Tab6WebCamera UI 구성

tab6webcamera.ui를 Qt Designer에서 열고 아래와 같이 위젯을 배치합니다.

=====================================
|                                   |
|           pGPView                 |
|      (QGraphicsView)              |
|                                   |
|-----------------------------------|
|    pPBCamStart   |  pPBsnapShot   |
=====================================

레이아웃 비율은 카메라 뷰 9 : 버튼 영역 1로 설정합니다.

주요 위젯 objectName

위젯objectName역할
QGraphicsViewpGPView초기 이미지 및 스트림 영역
QPushButtonpPBCamStart카메라 시작/정지 (Checkable)
QPushButtonpPBsnapShot스냅샷 저장

pPBCamStart는 Property Editor에서 checkable을 체크해야 토글 버튼으로 동작합니다.


4. tab6webcamera.h

Tab6는 QWebEngineViewQProcess를 멤버로 가집니다.
QWebEngineView는 생성자에서 동적으로 생성하고, CamStart 버튼 클릭 시 pGPView 위에 올립니다.

#ifndef TAB6WEBCAMERA_H
#define TAB6WEBCAMERA_H

#include <QWidget>
#include <QWebEngineView>
#include <QProcess>
#include <QGraphicsPixmapItem>
#include <QThread>
#include <QGraphicsScene>

namespace Ui {
class Tab6WebCamera;
}

class Tab6WebCamera : public QWidget
{
    Q_OBJECT

public:
    explicit Tab6WebCamera(QWidget *parent = nullptr);
    ~Tab6WebCamera();

private:
    Ui::Tab6WebCamera *ui;
    QWebEngineView *pQWebEngineView;
    QProcess *pQProcess;
    QUrl webcamUrl;
    QGraphicsScene initDisplayScene;

private slots:
    void camStartSlot(bool);
    void on_pPBsnapShot_clicked();
};

#endif // TAB6WEBCAMERA_H

5. tab6webcamera.cpp

5-1. 생성자

생성자에서 스트림 URL을 설정하고, QProcessQWebEngineView를 생성합니다.
초기 화면은 QGraphicsSceneinitDisplay_2.png를 추가해 pGPView에 표시합니다.

Tab6WebCamera::Tab6WebCamera(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Tab6WebCamera)
{
    ui->setupUi(this);

    webcamUrl = QUrl("http://10.10.16.35:8080/?action=stream");
    webcamUrl.setUserName("user");
    webcamUrl.setPassword("1234");

    pQProcess = new QProcess(this);
    pQWebEngineView = new QWebEngineView(this);

    QPixmap pixMap(":/Images/Images/initDisplay_2.png");
    QGraphicsScene* scene = new QGraphicsScene(ui->pGPView);
    scene->addPixmap(pixMap);
    ui->pGPView->setScene(scene);

    connect(ui->pPBCamStart, SIGNAL(clicked(bool)), this, SLOT(camStartSlot(bool)));
}

스트림 URL에 setUserName, setPassword를 설정하면 mjpg-streamer의 -c user:1234 인증을 자동으로 처리합니다.


5-2. camStartSlot - mjpg-streamer 실행 및 스트림 연결

Tab6의 동작 원리는 다음과 같습니다.

CamStartQProcess가 ubuntu05 로컬에서 mjpg-streamer를 실행합니다. mjpg-streamer는 포트 8080을 열고 HTTP 서버 역할을 시작하고, QWebEngineView가 해당 주소에 접속해 스트림을 표시합니다.

CamStoppQProcess->kill()로 mjpg-streamer 프로세스를 강제 종료합니다. 포트 8080을 열고 있던 프로세스가 종료되면 서버 자체가 사라지므로 스트리밍이 중단됩니다.

CamStart → QProcess로 mjpg-streamer 실행 → 포트 8080 오픈 → QWebEngineView로 스트림 접속
CamStop  → QProcess kill → mjpg-streamer 종료 → 포트 8080 닫힘

실행 파일과 .so 플러그인이 모두 같은 디렉토리에 있기 때문에 경로를 절대경로로 지정합니다.
프로세스가 정상적으로 시작되면 200ms 대기 후 QWebEngineView에 스트림 URL을 로드하고, pGPView의 자식 위젯으로 올린 뒤 기존 QGraphicsScene을 제거합니다.

void Tab6WebCamera::camStartSlot(bool bCheck)
{
    QString webcamProgrm = "/home/ubuntu/mjpg-streamer-master/mjpg_streamer";
    QStringList webcamArg = {
        "-i", "/home/ubuntu/mjpg-streamer-master/input_uvc.so",
        "-o", "/home/ubuntu/mjpg-streamer-master/output_http.so "
              "-w /home/ubuntu/mjpg-streamer-master/www -c user:1234"
    };

    if(bCheck)
    {
        pQProcess->start(webcamProgrm, webcamArg);
        if(pQProcess->waitForStarted())
        {
            QThread::msleep(200);
            pQWebEngineView->load(webcamUrl);
            pQWebEngineView->saveGeometry();
            ui->pPBCamStart->setText("CamStop");

            pQWebEngineView->setParent(ui->pGPView);
            pQWebEngineView->setGeometry(ui->pGPView->rect());
            pQWebEngineView->show();

            if(ui->pGPView->scene())
                ui->pGPView->setScene(nullptr);
        }
    }
    else
    {
        pQProcess->kill();
        pQWebEngineView->stop();
        pQWebEngineView->hide();
        ui->pPBCamStart->setText("CamStart");

        QGraphicsScene* oldScene = ui->pGPView->scene();
        if(oldScene)
        {
            ui->pGPView->setScene(nullptr);
            delete oldScene;
        }
        QPixmap pixMap(":/Images/Images/initDisplay_2.png");
        QGraphicsScene* scene = new QGraphicsScene(ui->pGPView);
        scene->addPixmap(pixMap);
        ui->pGPView->setScene(scene);
    }
}

setGeometry(ui->pGPView->rect())QWebEngineView 크기를 pGPView 영역에 맞게 설정합니다.


5-3. Snapshot

현재 Snapshot 기능은 미구현 상태입니다.
mjpg-streamer의 snapshot URL(?action=snapshot)을 wget으로 저장하는 방식으로 추후 구현할 예정입니다.

void Tab6WebCamera::on_pPBsnapShot_clicked()
{
    //wget -O a.jpg http://10.10.16.35:8080/?action=snapshot
}

6. mainwidget에 Tab6 추가

mainwidget.h

#include <tab6webcamera.h>

Tab6WebCamera *pTab6WebCamera;

mainwidget.cpp

pTab6WebCamera = new Tab6WebCamera(ui->pTab6);
ui->pTab6->setLayout(pTab6WebCamera->layout());

Tab6는 Tab7과 달리 소켓 연동이 없으므로 별도 Signal/Slot 연결이 필요하지 않습니다.


7. Tab6 vs Tab7 비교

Tab6Tab7
카메라 처리mjpg-streamer (QProcess로 외부 실행)OpenCV VideoCapture (직접)
화면 표시QWebEngineView (HTTP 스트림)QLabel + QPixmap
스레드없음QThread
RGB 분류없음HSV 기반 색상 분류
소켓 연동없음있음

전체 흐름 요약

mjpg-streamer-master.zip 압축 해제 → make → sudo make install
    ↓
터미널에서 직접 실행 후 브라우저 스트리밍 확인
    ↓
Tab6WebCamera 클래스 생성 (Qt Widgets Designer Form Class)
    ↓
UI 구성 (QGraphicsView + QPushButton x2)
    ↓
생성자 : 스트림 URL 설정, QProcess/QWebEngineView 생성, 초기 이미지 표시
    ↓
CamStart ON : QProcess로 mjpg-streamer 실행 → 포트 8080 오픈 → QWebEngineView로 스트림 접속
    ↓
QWebEngineView를 pGPView 위에 자식 위젯으로 올리기
    ↓
CamStop : QProcess kill → mjpg-streamer 종료 → QWebEngineView hide → 초기 이미지 복원
    ↓
mainwidget에 Tab6 추가
profile
임베디드 개발자가 되기 위해 공부중입니다!

0개의 댓글