文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Qt C++如何实现录屏录音功能

2023-07-05 10:00

关注

这篇文章主要介绍了Qt C++如何实现录屏录音功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Qt C++如何实现录屏录音功能文章都会有所收获,下面我们一起来看看吧。

录屏部分

录屏的主要思路为抓取屏幕截图,然后将其合成视频。抓取屏幕若使用qt自带的抓屏会出现抓不到鼠标的问题,所以应重写抓屏:

static QPixmap grabWindow(HWND winId, int x, int y, int w, int h){     RECT r;    GetClientRect(winId, &r);     if (w < 0) w = r.right - r.left;    if (h < 0) h = r.bottom - r.top;     HDC display_dc = GetDC(winId);    HDC bitmap_dc = CreateCompatibleDC(display_dc);    HBITMAP bitmap = CreateCompatibleBitmap(display_dc, w, h);    HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);     BitBlt(bitmap_dc, 0, 0, w, h, display_dc, x, y, SRCCOPY | CAPTUREBLT);     CURSORINFO ci;    ci.cbSize = sizeof(CURSORINFO);    GetCursorInfo(&ci);    if ((ci.ptScreenPos.x > x) && (ci.ptScreenPos.y > y) && (ci.ptScreenPos.x < (x + w)) && (ci.ptScreenPos.y < (y + h)))        DrawIcon(bitmap_dc, ci.ptScreenPos.x - x, ci.ptScreenPos.y - y, ci.hCursor);     // clean up all but bitmap    ReleaseDC(winId, display_dc);    SelectObject(bitmap_dc, null_bitmap);    DeleteDC(bitmap_dc);     QPixmap pixmap = QtWin::fromHBITMAP(bitmap);     DeleteObject(bitmap);     return pixmap; }

这样抓取的图片会包括鼠标。

但是,如果直接while循环进行抓屏的话,一秒顶多抓10帧。所以应该启动一个计时器,按照想要的帧率进行抓屏。可惜,Qt的计时器会有各种各样的限制,所以我自己实现了计时器进行处理:

#pragma once #include <iostream>#include <string>#include <thread>#include <chrono>#include <atomic>#include <memory>#include <condition_variable> using namespace std; class STTimer{public:    ~STTimer(void);    template<class F>    STTimer(F func):m_func(func){};    void Start(unsigned int secd,bool isBimmediately_run = false);    void Stop();    void SetExit(bool b_exit);private: // 私有数据部分    std::atomic_bool m_bexit;    std::atomic_bool m_bimmediately_run; // 是否立即执行    unsigned int m_imsec;    // 间隔时间    std::function<void()> m_func;    // 执行函数    std::thread m_thread;    std::mutex m_mutex;    std::condition_variable m_cond;     void Run();  };
#include "STTimer.h" #include "ScreenController.h"#include <QDebug>STTimer::~STTimer(void){} void STTimer::Start(unsigned int sec, bool bim_run){    m_bexit.store(false);    m_imsec = sec;    m_bimmediately_run.store(bim_run);    m_thread = std::thread(std::bind(&STTimer::Run,this));}void STTimer::Stop(){    m_bexit.store(true);    m_cond.notify_all(); // 唤醒线程    if (m_thread.joinable())    {        m_thread.join();    }}void STTimer::SetExit(bool b_exit){    m_bexit.store(b_exit);}void STTimer::Run(){    if(m_bimmediately_run.load())    {        if(m_func)        {            m_func();        }    }    while(!m_bexit.load())    {        qDebug()<<"runmning";        std::unique_lock<std::mutex> locker(m_mutex);        m_cond.wait_for(locker,std::chrono::milliseconds(m_imsec),[this](){return m_bexit.load(); });        if(m_func)        {            m_func();        }    }    if(m_bexit.load())    {        return;    }    }

这样,就可以多线程进行抓屏了,合成视频我使用的是avilib,理论上它可以同时合成音频,但合成后除了potplayer都无法解码,所以仅用它做合成视频。

void ScreenController::getOneFrame(){    int ids = curController->getId();    controlIds(false, ids);    std::thread t1(startThread,ids);        t1.detach();}void ScreenController::startThread(int ids){    QPixmap mp = grabWindow((HWND)QApplication::desktop()->winId(), curController->curRect.x(), curController->curRect.y(), curController->curRect.width(), curController->curRect.height());    QByteArray ba;    QBuffer bf(&ba);    mp.save(&bf, "jpg", 100);    char* framBf = ba.data();    int byteLen = ba.length();    qDebug()<<byteLen;    QMutexLocker lockeer(&curController->m_smutex2);    AVI_write_frame(curController->avfd, framBf, byteLen, 1);    lockeer.unlock();    controlIds(true, ids);}

在停止录屏时,需要判断抓屏线程是否结束,很多人会想到线程池,其实不必那么复杂,只需为每个线程绑定一个独立的id,然后操作含有这个id的列表即可。

void ScreenController::controlIds(bool isDelete, int index){    QMutexLocker locker(&curController->m_smutex);    if (isDelete)    {        int ind = curController->ids.indexOf(index);        curController->ids.removeAt(ind);    }    else    {        curController->ids.push_back(index);    }}

录音部分

录音部分其实非常简单,仅需使用qt的模板即可实现:

QAudioDeviceInfo info = QAudioDeviceInfo::availableDevices(QAudio::AudioInput).at(macIndex);    recorder = new QAudioRecorder(this);    QAudioEncoderSettings settings = recorder->audioSettings();     settings.setCodec("audio/PCM");   // 这些是QAudioRecorder是设置,见名思意    settings.setBitRate(96000);    //settings.setSampleRate(44100);    settings.setChannelCount(2);    settings.setQuality(QMultimedia::EncodingQuality::HighQuality);    settings.setEncodingMode(QMultimedia::ConstantQualityEncoding);    recorder->setAudioSettings(settings);    recorder->setAudioInput(info.deviceName());    recorder->setOutputLocation(QUrl::fromLocalFile(fileName));    recorder->setContainerFormat("audio/wav");    recorder->record();

合成部分

合成我使用的是ffmpeg进行视频合成。仅需传入参数即可。

void CaptureController::MakeVideo(){    if(curController->isMakingVideo)    {        return;    }    qDebug()<<"making video";    curController->isMakingVideo = true;    QString program = QCoreApplication::applicationDirPath();    program += "/ffmpeg.exe";    qDebug()<<"program";    qDebug() << program;    QProcess process;    QStringList arguments;     arguments << "-i" << curController->voicefileName         << "-i" << curController->screenfileName         << "-s" << QString::number(curController->screenRect.width()) + "x" + QString::number(curController->screenRect.height())        <<"-b:v" << "40000k"        << curController->finalfileName;//传递到exe的参数     qDebug() << arguments;    process.start(program, arguments);     process.waitForFinished();    QFile f1(curController->voicefileName);    QFile f2(curController->screenfileName);    f1.remove();    f2.remove();    curController->isMakingVideo = false;}

转成动态库

有时我们很想将这个功能提供给其他人使用,但是其他人未必使用qt,甚至未必使用C++,那么就需要将其封装成动态库。但是,qt的消息机制是十分独立的,在没有QApplication::exec()的时候,或者说没有发起qt独立的消息循环机制的时候,他的信号槽机制将不会起作用。比如这个录音模块,在直接提供给他人使用的时候将不会录制到任何声音。所以需要对录音部分进行封装。

class MCCtClass:public QThread{public:    MCCtClass();    void startTestingMac(int index);    int getCurrentVoice();    void startCapVoice(int index);    void stopThread();    void setFileName(QString name);protected:    virtual void run(); private:    volatile bool isStop;    int macIndex;    int currentRun;    QEventLoop *lp;    MacController *ct;    QString fileName;};
MCCtClass::MCCtClass(){    currentRun = -1;    ct = nullptr;}void MCCtClass::startCapVoice(int index){    currentRun = 1;    macIndex = index;    this->start();}void MCCtClass::startTestingMac(int index){    currentRun =2;    macIndex = index;    this->start();}void MCCtClass::setFileName(QString name){    fileName = name;}void MCCtClass::run(){    ct = new MacController();    if(currentRun == 1)    {        ct->SetFileName(fileName);        ct->StartRecordingVoice(macIndex);        lp = new QEventLoop();        lp->exec();    }    else if(currentRun == 2)    {        qDebug()<<"run2";        ct->StartTestingMac(macIndex);        lp = new QEventLoop();        lp->exec();    }}int MCCtClass::getCurrentVoice(){    if(ct == nullptr)    {        return 0;    }    return ct->getTestVolume();}void MCCtClass::stopThread(){    lp->exit();    lp->deleteLater();    if(currentRun == 1)    {        ct->StopRecordingVoice();    }    else if(currentRun == 2)    {        ct->StopTestingMac();    }    ct->deleteLater();    ct = nullptr;}

使用qthread派生出一个独立的麦克风操作类,在run函数中启动一个独立的消息循环,这样麦克风的录制功能就可以进行了。

关于动态库的封装,用到了传说中的QMFCAPP,这个大家百度一下随便下载一个就可以,但这样封装还有问题,因为别人未必有qt环境,所以我对它进行了二次封装。相信各位也有其他的解决办法。

关于“Qt C++如何实现录屏录音功能”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Qt C++如何实现录屏录音功能”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯