QT6使用摄像头进行视频录制

QT 6 使用相机录制视频

使用Qt 6框架的MultimediaWidgets模块QMediaRecorder类进行视频录制。

  1. 创建一个基于QMainWindow应用程序
    选择项目类型
    设置项目名称

    设置qmake构建系统
    设置类名,取消产生窗体的选择框
    选择构建套件

  2. 首先,确保你的Qt项目中包含了多媒体模块‌。这通常在项目的.pro文件中进行配置,通过添加QT += multimedia multimediawidgets来启用多媒体模块。

  3. 添加成员变量和函数方法。为VideoRecorder类添加必要的成员变量和方法来处理视频录制,添加视频录制开始,暂停,停止等功能。

  4. 视频录制‌:使用VideoRecorder类来录制视频。配置好录制的参数后,使用VideoRecorder::record()方法可以开始录制。录制完成后,可以通过VideoRecorder::stop()方法来停止录制。

  5. 处理事件‌:为你的主窗口添加事件处理函数,如开始录制和停止录制的按钮点击事件,以及处理录制的开始和结束等。

首先,确保你的项目文件.pro包含多媒体模块:

 QT       += core gui multimedia multimediawidgets

然后,为VideoRecorder 类添加成员变量和函数:

  • C++头文件"videorecorder.h" 内容如下:
#ifndef VIDEORECORDER_H
#define VIDEORECORDER_H

#include <QMainWindow>
#include <QPushButton>
#include <QLabel>
#include <QComboBox>
#include <QVideoWidget>
#include <QCamera>
#include <QMediaRecorder>
#include <QAudioInput>
#include <QMediaCaptureSession>
#include <QMediaDevices>
#include <QCameraDevice>

class VideoRecorder : public QMainWindow
{
    Q_OBJECT
public:
    VideoRecorder(QWidget *parent = nullptr);
    ~VideoRecorder();

private slots:
    void onDurationChanged(qint64 duration);
    void selectCameraDevice(int index);
    void on_btn_start_clicked();
    void on_btn_pause_clicked();
    void on_btn_stop_clicked();
    void on_btn_close_clicked();
private:
    void createLayout();

    QPushButton *btnStart;
    QPushButton *btnPause;
    QPushButton *btnStop;
    QPushButton *btnClose;
    QComboBox *comboBoxInput;
    QLabel *label1;
    QLabel *labelTime;
    QVideoWidget *videoWidget;

    QCamera *camera;
    QMediaRecorder *recorder;
    QAudioInput *audioInput;
    QMediaCaptureSession *mediaCaptureSession;
    QMediaDevices *mediaDevices;
    QList<QCameraDevice> cameraDevices;

};
#endif // VIDEORECORDER_H
  • C++源文件 widget.cpp 内容如下:
#include "videorecorder.h"
#include <QGridLayout>
#include <QVBoxLayout>
#include <QUrl>
#include <QCoreApplication>
#include <QVideoSink>

VideoRecorder::VideoRecorder(QWidget *parent)
    : QMainWindow(parent)
{
    createLayout();
    camera = new QCamera(QMediaDevices::defaultVideoInput());
    audioInput = new QAudioInput(this);
    recorder = new QMediaRecorder(this);
    mediaCaptureSession = new QMediaCaptureSession(this);
    mediaCaptureSession->setAudioInput(audioInput);
    mediaCaptureSession->setRecorder(recorder);
    mediaCaptureSession->setVideoOutput(videoWidget);

    recorder->setQuality(QMediaRecorder::HighQuality);
    recorder->setOutputLocation(QUrl::fromLocalFile(
        QCoreApplication::applicationDirPath() + "/demo.mp4"));
    recorder->setEncodingMode(QMediaRecorder::ConstantQualityEncoding);
    recorder->setAudioChannelCount(recorder->audioChannelCount());
    connect(recorder,&QMediaRecorder::durationChanged,
            this,&VideoRecorder::onDurationChanged);

    cameraDevices = QMediaDevices::videoInputs();
    comboBoxInput->addItem("<Node>");
    foreach (const QCameraDevice & cam, cameraDevices) {
        comboBoxInput->addItem(cam.description());
    }
    connect(comboBoxInput,&QComboBox::currentIndexChanged,
            this,&VideoRecorder::selectCameraDevice);
}

void VideoRecorder::createLayout()
{
    label1 = new QLabel(tr("Recorded Time(s):"));
    labelTime = new QLabel;
    labelTime->setFrameStyle(QFrame::Box);
    btnClose = new QPushButton(tr("关闭"));
    btnStart = new QPushButton(tr("开始"));
    btnStop = new QPushButton(tr("停止"));
    btnPause = new QPushButton(tr("暂停"));
    comboBoxInput = new QComboBox;
    videoWidget = new QVideoWidget;

    connect(btnStart,&QPushButton::clicked,this,&VideoRecorder::on_btn_start_clicked);
    connect(btnPause,&QPushButton::clicked,this,&VideoRecorder::on_btn_pause_clicked);
    connect(btnStop,&QPushButton::clicked,this,&VideoRecorder::on_btn_stop_clicked);
    connect(btnClose,&QPushButton::clicked,this,&VideoRecorder::on_btn_close_clicked);

    QVBoxLayout *vTopRight = new QVBoxLayout;
    vTopRight->addWidget(comboBoxInput);
    QGridLayout *gLayoutMain = new QGridLayout;

    gLayoutMain->addWidget(videoWidget,0,0,5,3);
    gLayoutMain->addLayout(vTopRight,0,3);
    gLayoutMain->addWidget(btnStart,1,3);
    gLayoutMain->addWidget(btnPause,2,3);
    gLayoutMain->addWidget(btnStop,3,3);
    gLayoutMain->addWidget(label1,5,0);
    gLayoutMain->addWidget(labelTime,5,1,1,2);
    gLayoutMain->addWidget(btnClose,5,3);

    resize(480,320);
    setMinimumSize(480,320);
    setMaximumSize(480,320);
    setWindowTitle(tr("视频录像机"));
    QWidget *wi = new QWidget;
    wi->setLayout(gLayoutMain);
    setCentralWidget(wi);
}

void VideoRecorder::onDurationChanged(qint64 duration){
    labelTime -> setText(QString("%1 s").arg(QString::number(duration / 1000)));
}

void VideoRecorder::selectCameraDevice(int )
{
    //遍历当前选择的设备是否等于可利用的设备,然后进行设备的配置
    for(const QCameraDevice &cam : cameraDevices){
        if(cam.description() == comboBoxInput->currentText()){
            camera -> setCameraDevice(cam);
            mediaCaptureSession -> setCamera(camera);
            camera -> start();
            break;
        }
    }
}

void VideoRecorder::on_btn_start_clicked(){
    recorder -> record();
}

void VideoRecorder::on_btn_pause_clicked(){
    recorder -> pause();
}

void VideoRecorder::on_btn_stop_clicked(){
    recorder -> stop();
    labelTime -> setText("0");
}

void VideoRecorder::on_btn_close_clicked(){
    close();
}

VideoRecorder::~VideoRecorder() {}
  • 主程序main.cpp 内容如下
#include "videorecorder.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    VideoRecorder w;
    w.show();
    return a.exec();
}

小结

​ 这段代码演示了如何使用QT 6的QMediaRecorder类进行视频录制。创建一个QMediaRecorder对象并设置了音视频输入设备、输出位置和输出格式。然后,通过调用record()方法开始录制,通过调用stop()方法停止录制。本例程在Windows 10环境QT 6.7框架上成功运行。

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Qt和FFmpeg实现网络摄像头视频录制,您需要做以下几个步骤: 1. 安装FFmpeg库。您可以从官方网站下载预编译的二进制文件,或者自己编译源代码。 2. 在Qt项目中导入FFmpeg库。您可以使用Qt的插件系统或手动链接库文件。 3. 创建一个Qt界面,用于显示摄像头捕捉到的视频流。 4. 使用FFmpeg库编写代码,将摄像头捕捉到的视频流转换为所需的格式并保存到本地文件。 以下是一个简单的示例代码,演示如何使用Qt和FFmpeg实现网络摄像头视频录制: ```cpp #include <QApplication> #include <QMainWindow> #include <QVBoxLayout> #include <QLabel> #include <QTimer> #include <QDebug> #include <QDateTime> #include <QThread> extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" } #define WIDTH 640 #define HEIGHT 480 #define FPS 25 class CameraWidget : public QWidget { public: CameraWidget(QWidget *parent = nullptr) : QWidget(parent) { label_ = new QLabel(this); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(label_); setLayout(layout); } virtual ~CameraWidget() {} void start() { timer_ = new QTimer(this); connect(timer_, SIGNAL(timeout()), this, SLOT(update())); timer_->start(1000/FPS); } void stop() { timer_->stop(); delete timer_; timer_ = nullptr; } protected: void update() { // Capture camera frame QImage image(WIDTH, HEIGHT, QImage::Format_RGB888); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { QRgb color = qRgb(qrand() % 256, qrand() % 256, qrand() % 256); image.setPixel(x, y, color); } } // Display camera frame label_->setPixmap(QPixmap::fromImage(image)); // Save camera frame to file if (recording_) { if (!formatContext_) { initFormatContext(); } if (formatContext_ && videoStream_) { AVPacket packet; av_init_packet(&packet); packet.data = nullptr; packet.size = 0; if (av_new_packet(&packet, WIDTH * HEIGHT * 3) < 0) { qWarning() << "Failed to allocate packet"; } SwsContext *swsContext = sws_getContext(WIDTH, HEIGHT, AV_PIX_FMT_RGB24, WIDTH, HEIGHT, videoStream_->codecpar->format, SWS_BILINEAR, nullptr, nullptr, nullptr); if (swsContext) { uint8_t *srcData[4] = {(uint8_t *)image.bits(), nullptr, nullptr, nullptr}; int srcLinesize[4] = {image.bytesPerLine(), 0, 0, 0}; uint8_t *dstData[4] = {nullptr, nullptr, nullptr, nullptr}; int dstLinesize[4] = {0, 0, 0, 0}; av_image_alloc(dstData, dstLinesize, videoStream_->codecpar->width, videoStream_->codecpar->height, videoStream_->codecpar->format, 1); if (dstData[0] && av_image_fill_arrays(videoFrame_->data, videoFrame_->linesize, dstData[0], videoStream_->codecpar->format, videoStream_->codecpar->width, videoStream_->codecpar->height, 1) >= 0) { sws_scale(swsContext, srcData, srcLinesize, 0, HEIGHT, videoFrame_->data, videoFrame_->linesize); videoFrame_->pts = pts_++; if (avcodec_send_frame(videoCodecContext_, videoFrame_) == 0) { while (avcodec_receive_packet(videoCodecContext_, &packet) == 0) { packet.stream_index = videoStream_->index; packet.pts = av_rescale_q(packet.pts, videoCodecContext_->time_base, videoStream_->time_base); packet.dts = av_rescale_q(packet.dts, videoCodecContext_->time_base, videoStream_->time_base); packet.duration = av_rescale_q(packet.duration, videoCodecContext_->time_base, videoStream_->time_base); packet.pos = -1; if (av_interleaved_write_frame(formatContext_, &packet) < 0) { qWarning() << "Failed to write packet"; } av_packet_unref(&packet); } } } av_freep(&dstData[0]); sws_freeContext(swsContext); } av_packet_unref(&packet); } } } void initFormatContext() { QString filename = QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss"); filename = QDir::tempPath() + "/" + filename + ".avi"; if (avformat_alloc_output_context2(&formatContext_, nullptr, "avi", filename.toUtf8().constData()) < 0) { qWarning() << "Failed to allocate output format context"; return; } if (avio_open(&formatContext_->pb, filename.toUtf8().constData(), AVIO_FLAG_WRITE) < 0) { qWarning() << "Failed to open output file"; avformat_free_context(formatContext_); formatContext_ = nullptr; return; } videoStream_ = avformat_new_stream(formatContext_, nullptr); if (!videoStream_) { qWarning() << "Failed to create video stream"; avformat_free_context(formatContext_); formatContext_ = nullptr; return; } videoCodecContext_ = avcodec_alloc_context3(nullptr); if (!videoCodecContext_) { qWarning() << "Failed to allocate codec context"; avformat_free_context(formatContext_); formatContext_ = nullptr; return; } videoCodecContext_->codec_id = AV_CODEC_ID_H264; videoCodecContext_->codec_type = AVMEDIA_TYPE_VIDEO; videoCodecContext_->width = WIDTH; videoCodecContext_->height = HEIGHT; videoCodecContext_->pix_fmt = AV_PIX_FMT_YUV420P; videoCodecContext_->time_base = av_make_q(1, FPS); videoStream_->codecpar->codec_id = AV_CODEC_ID_H264; videoStream_->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; videoStream_->codecpar->width = WIDTH; videoStream_->codecpar->height = HEIGHT; videoStream_->codecpar->format = videoCodecContext_->pix_fmt; videoStream_->time_base = av_make_q(1, FPS); if (avcodec_open2(videoCodecContext_, avcodec_find_encoder(videoCodecContext_->codec_id), nullptr) < 0) { qWarning() << "Failed to open codec"; avformat_free_context(formatContext_); formatContext_ = nullptr; return; } if (avformat_write_header(formatContext_, nullptr) < 0) { qWarning() << "Failed to write header"; avformat_free_context(formatContext_); formatContext_ = nullptr; return; } videoFrame_ = av_frame_alloc(); if (!videoFrame_) { qWarning() << "Failed to allocate frame"; avformat_free_context(formatContext_); formatContext_ = nullptr; return; } videoFrame_->format = videoCodecContext_->pix_fmt; videoFrame_->width = WIDTH; videoFrame_->height = HEIGHT; if (av_frame_get_buffer(videoFrame_, 32) < 0) { qWarning() << "Failed to allocate frame buffer"; avformat_free_context(formatContext_); formatContext_ = nullptr; return; } pts_ = 0; } private: QLabel *label_; QTimer *timer_ = nullptr; bool recording_ = false; AVFormatContext *formatContext_ = nullptr; AVStream *videoStream_ = nullptr; AVCodecContext *videoCodecContext_ = nullptr; AVFrame *videoFrame_ = nullptr; int64_t pts_ = 0; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QMainWindow mainWindow; CameraWidget cameraWidget(&mainWindow); mainWindow.setCentralWidget(&cameraWidget); cameraWidget.start(); QThread::sleep(10); cameraWidget.stop(); return a.exec(); } ``` 该示例代码使用Qt中的QTimer类定期捕获摄像头视频流,并将其显示在界面上。如果设置recording_为true,则使用FFmpeg库将当前帧转换为指定格式并写入文件。请注意,此示例代码仅是演示如何使用Qt和FFmpeg实现网络摄像头视频录制的示例,您需要根据您的实际需求进行修改和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值