#include "DisplayMovieGLWidget.h" #include #include #include #include #include #include #include #include #include "MainWindow.h" class LoadImageTask : public QObject, public QRunnable { public: using HandleResoult = std::function; public: LoadImageTask(int index, const QVector& texturePaths, HandleResoult handle, QObject* parent = nullptr) : QObject(parent) , m_index(index) , m_texturePaths(texturePaths) , m_handle(std::move(handle)) { setAutoDelete(true); } void run() override { const QString& path = m_texturePaths[m_index]; QPixmap px(path); QImage image = px.toImage().mirrored(); m_handle(m_index, std::move(image)); } private: int m_index{ 0 }; const QVector& m_texturePaths; HandleResoult m_handle; }; SourImasgeHandler::~SourImasgeHandler() { } void SourImasgeHandler::run() { QImage dest(size_.width(), size_.height(), QImage::Format_RGBA8888); dest.fill(Qt::transparent); QImage destAlpha(size_.width(), size_.height(), QImage::Format_RGBA8888); destAlpha.fill(Qt::transparent); QPainter painter(&dest); QPainter painterAlpha(&destAlpha); QPixmap px(path_); if (!px.isNull()) { const QSize& is = MainWindow::Get().GetImageShowSize(); px = px.scaled(is, Qt::KeepAspectRatio); QPoint sp(abs(size_.width() - px.width()) / 2, abs(size_.height() - px.height()) / 2 - 8); painter.drawPixmap(sp, px); QLinearGradient gradient(sp.x(), sp.y(), sp.x() + 100, sp.y()); gradient.setColorAt(0, QColor(255, 255, 255, 0)); gradient.setColorAt(1, QColor(255, 255, 255, 255)); painterAlpha.fillRect(QRect(sp.x(), sp.y(), 100, px.height()), gradient); QLinearGradient gradientr(sp.x() + px.width() - 100, sp.y(), sp.x() + px.width(), sp.y()); gradientr.setColorAt(0, QColor(255, 255, 225, 255)); gradientr.setColorAt(1, QColor(255, 255, 225, 0)); painterAlpha.fillRect(QRect(sp.x() + px.width() - 100, sp.y(), 100, px.height()), gradientr); painterAlpha.fillRect(QRect(sp.x() + 100, sp.y(), px.width() - 200, px.height()), Qt::white); } else { // qWarning() << "DisplayMovieGLWidget::UpdateSourceImage load failed path:" << path_; } dest.mirror(); destAlpha.mirror(); emit Finish(dest, destAlpha); } DisplayMovieGLWidget::DisplayMovieGLWidget(QWidget* parent /*= */) : QOpenGLWidget(parent) { makeCurrent(); setAutoFillBackground(false); } DisplayMovieGLWidget::~DisplayMovieGLWidget() { //m_vbo.destroy(); if (m_program == nullptr) { return; } makeCurrent(); delete m_background; delete m_mask; delete m_source; delete m_sourceAlpha; delete m_program; delete m_vshader; delete m_fshader; m_vbo->destroy(); m_vao->destroy(); doneCurrent(); } void DisplayMovieGLWidget::initializeGL() { makeCurrent(); initializeOpenGLFunctions(); static float vertices[] = { // 位置 // 颜色 // 纹理坐标 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下 -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上 }; static unsigned int indices[] = { // 注意索引从0开始! // 此例的索引(0,1,2,3)就是顶点数组vertices的下标, // 这样可以由下标代表顶点组合成矩形 0, 1, 3, // 第一个三角形 1, 2, 3 // 第二个三角形 }; glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 设置清屏颜色 glDisable(GL_DEPTH_TEST); // 启用深度测试 glEnable(GL_COLOR_BUFFER_BIT); // 启用颜色缓冲区 const QString shaderDir = QApplication::applicationDirPath() + "/ProjectDisplay/shader/"; // 创建顶点着色器对象,并编译 m_vshader = new QOpenGLShader(QOpenGLShader::Vertex); bool success = m_vshader->compileSourceFile(shaderDir + "vertex_shader.vs"); if (!success) { const QString log = m_vshader->log(); qDebug() << log; } // 创建片段着色器对象,并编译 m_fshader = new QOpenGLShader(QOpenGLShader::Fragment); success = m_fshader->compileSourceFile(shaderDir + "fragment_shader.fs"); if (!success) { const QString log = m_fshader->log(); qDebug() << log; } // 创建着色器程序对象,添加顶点着色器和片段着色器,并链接它们 m_program = new QOpenGLShaderProgram; m_program->addShader(m_vshader); m_program->addShader(m_fshader); m_program->link(); // 创建顶点数组对象,并绑定到当前上下文 m_vao = new QOpenGLVertexArrayObject; m_vao->create(); QOpenGLVertexArrayObject::Binder vaoBinder(m_vao); // 创建顶点缓冲对象, m_vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); m_vbo->create(); m_vbo->bind(); // 分配显存大小,并搬运至显存 m_vbo->allocate(vertices, sizeof(vertices)); // 创建元素缓冲对象, m_ebo = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); m_ebo->create(); m_ebo->bind(); // 分配显存大小,并搬运至显存 m_ebo->allocate(indices, sizeof(indices)); // 链接顶点属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0); // 顶点属性默认是禁用的,启用顶点属性0(location=0) m_program->enableAttributeArray(0); // 颜色属性 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); m_program->enableAttributeArray(1); // 纹理坐标属性 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); m_program->enableAttributeArray(2); m_vao->release(); m_vbo->release(); QDateTime dt = QDateTime::currentDateTime(); m_startTimestamp = dt.toUTC().toMSecsSinceEpoch(); #ifdef BG_VLC PlayBackgroundMovie(); #else InitBackgroundImages(); #endif InitBackgroundTexture(); InitMaskImages(); InitMaskTexture(); InitForeMovieTextImage(); m_program->bind(); //在修改uniform值之前,一定要绑定着色器程序到当前激活的opengl上下文 m_program->setUniformValue("bgMap", 0); m_program->setUniformValue("maskMap", 1); m_program->setUniformValue("sourceMap", 2); m_program->setUniformValue("textMap", 3); m_program->setUniformValue("movieTextMap", 4); m_program->setUniformValue("bgMapMask", 5); m_program->setUniformValue("sourceAlphaMap", 6); //connect(&m_timer, &QTimer::timeout, this, &DisplayMovieGLWidget::OnTimeout); //m_timer.start(40); QTimer::singleShot(3000, [this]() { m_showSource = true; } ); //OnMessage("0|1|0"); //OnMessage(""); } void DisplayMovieGLWidget::paintGL() { makeCurrent(); #ifdef BG_VLC if (!videoImage_.isNull()) { QOpenGLTexture::PixelFormat pf = QOpenGLTexture::BGRA; const void* data = reinterpret_cast(videoImage_.constBits()); #else if (m_backgroundFrameCount > 0 && !m_textureData.isEmpty()) { const QImage& image = m_textureData[m_backgroundCurrentFrame]; QOpenGLTexture::PixelFormat pf = QOpenGLTexture::RGB; const void* data = reinterpret_cast(image.constBits()); #endif QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(8); m_background->setData(0, pf, QOpenGLTexture::UInt8, data, &uploadOptions); } if (!videoForeImage_.isNull()) { // const QImage& image = m_textureData[m_backgroundCurrentFrame]; QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(8); m_movieSource->setData(0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt8, videoForeImage_.constBits(), &uploadOptions); } if (m_maskFrame < m_maskTextureData.size() && !m_maskTextureData.isEmpty()) { const QImage& image = m_maskTextureData[m_maskFrame]; QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(1); m_mask->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits(), &uploadOptions); //m_mask->setData(image); } glClearColor(0.f, 0.f, 0.f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 将纹理绑定到当前激活的纹理单元 if (nullptr != m_background) { m_background->bind(0); } if (nullptr != m_mask) { m_mask->bind(1); } if (nullptr != m_source) { m_source->bind(2); } if (nullptr != m_textSource) { m_textSource->bind(3); } if (nullptr != m_movieSource) { m_movieSource->bind(4); } if (nullptr != m_backgroundMask) { m_backgroundMask->bind(5); } if (nullptr != m_sourceAlpha) { m_sourceAlpha->bind(6); } QMatrix4x4 projection; QMatrix4x4 view; view.translate(0.0f, 0.0f, -1.0000f); QMatrix4x4 model; // 绑定着色器程序至当前上下文,相当于调用glUseProgram() m_program->bind(); m_program->setUniformValue("view", view); m_program->setUniformValue("projection", projection); m_program->setUniformValue("model", model); QDateTime dt = QDateTime::currentDateTime(); qint64 nowTimeStamp = dt.toUTC().toMSecsSinceEpoch(); float timeStamp = nowTimeStamp - m_startTimestamp; m_program->setUniformValue("fusion", m_fusion); m_program->setUniformValue("alpha", m_alpha); m_program->setUniformValue("time", timeStamp * 0.001f); // 绑定VAO,调用设置的一组状态 QOpenGLVertexArrayObject::Binder vaoBinder(m_vao); // 绘制三角形 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); m_program->release(); // 交换缓存 auto* context = QOpenGLContext::currentContext(); context->swapBuffers(context->surface()); } void DisplayMovieGLWidget::resizeGL(int w, int h) { makeCurrent(); glViewport(0, 0, w, h); update(); } #if FPS_DISPLAY int gettimeofday(struct timeval* tp, struct timezone* tzp) { // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) // until 00:00:00 January 1, 1970 static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); SYSTEMTIME system_time; FILETIME file_time; uint64_t time; GetSystemTime(&system_time); SystemTimeToFileTime(&system_time, &file_time); time = ((uint64_t)file_time.dwLowDateTime); time += ((uint64_t)file_time.dwHighDateTime) << 32; tp->tv_sec = (long)((time - EPOCH) / 10000000L); tp->tv_usec = (long)(system_time.wMilliseconds * 1000); return 0; } static double GetFPSAverageCount(int seconds) { static struct timeval timeStart; static struct timeval timeFinish; static bool init{ false }; static int count{ 0 }; static double fps = 0.0; if (!init) { gettimeofday(&timeStart, NULL); gettimeofday(&timeFinish, NULL); init = true; } else { int cycle = timeFinish.tv_sec - timeStart.tv_sec; gettimeofday(&timeFinish, NULL); if (cycle >= seconds) { gettimeofday(&timeStart, NULL); fps = count / seconds; count = 0; printf("----------\n"); printf("%d S average FPS value is: %f\n", seconds, fps); } count++; } return fps; } void DisplayMovieGLWidget::paintEvent(QPaintEvent* event) { QPainter painter; painter.begin(this); painter.setRenderHint(QPainter::Antialiasing); painter.translate(100, 100); painter.fillRect(rect(), QBrush(QColor(64, 32, 64))); painter.setPen(Qt::red); double fps = GetFPSAverageCount(1); painter.drawText(rect().topLeft() + QPoint(20, 100), QString("fps:%1").arg(QString::number(fps))); // painter.drawLine(rect().topLeft(), rect().bottomRight()); painter.end(); } #endif void DisplayMovieGLWidget::OnTimeout() { makeCurrent(); #ifndef BG_VLC LoadBackgroundTexture(); if (!m_textureData.isEmpty()) { m_backgroundCurrentFrame = (m_backgroundCurrentFrame + 1) % m_textureData.size(); } #endif LoadMaskTexture(); if (++m_maskFrame >= m_maskTextureData.size()) { m_maskFrame = m_maskTextureData.size() - 1; } if (m_showSource && (++m_colorMaskFrame >= m_maskTextureData.size())) { m_colorMaskFrame = m_maskTextureData.size() - 1; } if (m_delayTime > 0) { m_delayTime -= 40; if (m_alpha >= 1.0f) { m_alpha = 1.0f; } else { m_alpha *= 1.05f; } } else { if (m_alpha == 0.0f) { update(); return; } if (m_alpha > 0.000001f) { m_alpha *= 0.95f; } else { m_alpha = 0.0f; m_maskFrame = 0; m_place = 0; m_showText = ""; UpdateTextImage(); m_fusion = false; } } emit AlphaChanged(m_alpha); update(); } void DisplayMovieGLWidget::OnMoveFrame(const QImage& movieImage) { videoForeImage_ = movieImage.mirrored(); } //void DisplayMovieGLWidget::LoadBackgroundTexture() { // if (m_textureData.count() >= m_backgroundFrameCount) { // return; // } // // QImageReader reader; // reader.setAutoTransform(true); // // reader.setFileName(m_backgourndTexturePaths[m_backgroundCurrentFrame]); // QImage image = reader.read(); // image = image.mirrored().convertToFormat(QImage::Format_RGBA8888); // m_textureData.emplace_back(std::move(image)); //} void DisplayMovieGLWidget::InitBackgroundImages() { #ifndef BG_VLC const QString imageDir = QApplication::applicationDirPath() + "/ProjectDisplay/background/out"; QStringList jpgFiles; QDir dir(imageDir); QStringList filters; filters << "*.jpg"; // 添加 JPG 的文件扩展名 QFileInfoList fileInfoList = dir.entryInfoList(filters, QDir::Files); // 使用过滤器获取文件列表 m_backgroundFrameCount = fileInfoList.size(); m_textureData.resize(m_backgroundFrameCount); foreach(const QFileInfo & fileInfo, fileInfoList) { m_backgourndTexturePaths.append(fileInfo.absoluteFilePath()); } auto handle = [&](int index, QImage image) { image = image.convertToFormat(QImage::Format_RGB888); m_textureData[index] = std::move(image); }; QThreadPool pool; pool.setMaxThreadCount(std::thread::hardware_concurrency()); for (int i = 0; i < m_backgourndTexturePaths.count(); ++i) { LoadImageTask* task = new LoadImageTask(i, m_backgourndTexturePaths, handle); pool.start(task); } pool.waitForDone(); #endif } void DisplayMovieGLWidget::LoadMaskTexture() { if (m_maskTextureData.count() >= m_maskFrameCount) { return; } QImageReader reader; reader.setAutoTransform(true); reader.setFileName(m_maskTexturePaths[m_maskFrame]); QSize s = size(); QImage image = reader.read(); image = image.scaled(s, Qt::KeepAspectRatio); m_maskTextureData.emplace_back(std::move(image.mirrored())); } void DisplayMovieGLWidget::InitBackgroundTexture() { if (nullptr == m_background) { // QPixmap px(m_backgourndTexturePaths[m_backgroundCurrentFrame]); m_background = new QOpenGLTexture(QOpenGLTexture::Target2D); m_background->setAutoMipMapGenerationEnabled(false); m_background->setSize(3840, 1200); m_background->setMipLevels(1); #ifndef BG_VLC m_background->setFormat(QOpenGLTexture::RGB8_UNorm); /*m_background->setMinificationFilter(QOpenGLTexture::Nearest); m_background->setMagnificationFilter(QOpenGLTexture::Nearest); m_background->allocateStorage();*/ m_background->allocateStorage(QOpenGLTexture::RGB, QOpenGLTexture::UInt8); #else m_background->setFormat(QOpenGLTexture::RGBA8_UNorm); /*m_background->setMinificationFilter(QOpenGLTexture::Nearest); m_background->setMagnificationFilter(QOpenGLTexture::Nearest); m_background->allocateStorage();*/ m_background->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); #endif //// 设置纹理环绕方式 m_background->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat); m_background->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat); // 设置多级渐远纹理过滤方式 //m_background->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear); } if (nullptr == m_backgroundMask) { m_backgroundMask = new QOpenGLTexture(QOpenGLTexture::Target2D); m_backgroundMask->setAutoMipMapGenerationEnabled(false); m_backgroundMask->setFormat(QOpenGLTexture::RGBA8_UNorm); m_backgroundMask->setSize(3840, 1200); m_backgroundMask->setMipLevels(1); m_backgroundMask->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); m_backgroundMask->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat); m_backgroundMask->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat); QImageReader reader; reader.setAutoTransform(true); const QString filePath = QCoreApplication::applicationDirPath() + "/ProjectDisplay/background/bg.png"; reader.setFileName(filePath); QImage image = reader.read(); QImage dest(3840, 1200, QImage::Format_RGBA8888); dest.fill(0); QPainter painter(&dest); painter.drawImage(0, 0, image); painter.end(); dest.mirror(); QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(1); m_backgroundMask->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, dest.constBits(), &uploadOptions); } } void DisplayMovieGLWidget::InitMaskTexture() { if (nullptr == m_mask) { QImageReader reader; reader.setAutoTransform(true); reader.setFileName(m_maskTexturePaths[m_maskFrame]); QImage image = reader.read(); m_mask = new QOpenGLTexture(QOpenGLTexture::Target2D); m_mask->setAutoMipMapGenerationEnabled(false); m_mask->setFormat(QOpenGLTexture::RGBA8_UNorm); int with = image.width(); int height = image.height(); m_mask->setSize(with, height); m_mask->setMipLevels(1); m_mask->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); /*m_mask = new QOpenGLTexture(image.mirrored()); m_mask->setAutoMipMapGenerationEnabled(false);*/ // 设置纹理环绕方式 m_mask->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat); m_mask->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat); } } void DisplayMovieGLWidget::UpdateSourceImage(const QString& path) { if (path.isEmpty()) { qWarning() << "DisplayMovieGLWidget::UpdateSourceImage source path is empty"; return; } const QSize s = size(); if (nullptr == m_source) { makeCurrent(); m_source = new QOpenGLTexture(QOpenGLTexture::Target2D); m_source->setAutoMipMapGenerationEnabled(false); m_source->setFormat(QOpenGLTexture::RGBA8_UNorm); m_source->setSize(s.width(), s.height()); m_source->setMipLevels(1); m_source->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); // 设置纹理环绕方式 m_source->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge); m_source->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge); } if (nullptr == m_sourceAlpha) { makeCurrent(); m_sourceAlpha = new QOpenGLTexture(QOpenGLTexture::Target2D); m_sourceAlpha->setAutoMipMapGenerationEnabled(false); m_sourceAlpha->setFormat(QOpenGLTexture::RGBA8_UNorm); m_sourceAlpha->setSize(s.width(), s.height()); m_sourceAlpha->setMipLevels(1); m_sourceAlpha->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); // 设置纹理环绕方式 m_sourceAlpha->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge); m_sourceAlpha->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge); } ; SourImasgeHandler* handler = new SourImasgeHandler(path, s); connect(handler, &SourImasgeHandler::Finish, this, &DisplayMovieGLWidget::OnUpdateSourceImage, Qt::QueuedConnection); QThreadPool::globalInstance()->start(handler); } void DisplayMovieGLWidget::UpdateTextImage() { makeCurrent(); const QSize s = size(); QImage dest(s.width(), s.height(), QImage::Format_RGB888); dest.fill(Qt::transparent); QPainter painter(&dest); //const QStringList& fontFamilies = MainWindow::Get().GetDefaultFontFamily(); //QFont font(fontFamilies[0], 30, QFont::Black); QFont font("Microsoft YaHei", 30, QFont::Bold); painter.setPen(QColor(255, 255, 255)); painter.setFont(font); QFontMetrics fm(font); const QSize textSize = fm.size(Qt::TextWordWrap, m_showText); QTextOption textOption(Qt::AlignHCenter); textOption.setWrapMode(QTextOption::NoWrap); painter.drawText(MainWindow::Get().GetTextRect(), m_showText, textOption); painter.end(); QImage image = dest.mirrored(); if (nullptr == m_textSource) { //m_textSource = new QOpenGLTexture(image); m_textSource = new QOpenGLTexture(QOpenGLTexture::Target2D); m_textSource->setAutoMipMapGenerationEnabled(false); m_textSource->setFormat(QOpenGLTexture::RGB8_UNorm); m_textSource->setSize(image.width(), image.height()); m_textSource->setMipLevels(1); m_textSource->allocateStorage(QOpenGLTexture::RGB, QOpenGLTexture::UInt8); // 设置纹理环绕方式 m_textSource->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge); m_textSource->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge); } QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(1); m_textSource->setData(0, QOpenGLTexture::RGB, QOpenGLTexture::UInt8, image.constBits(), &uploadOptions); //m_textSource->setData(dest.mirrored()); } void DisplayMovieGLWidget::InitForeMovieTextImage() { makeCurrent(); QImage dest(3240, 1200, QImage::Format_RGBA8888); dest.fill(Qt::transparent); videoForeImage_ = dest.mirrored(); if (nullptr == m_movieSource) { //m_textSource = new QOpenGLTexture(image); m_movieSource = new QOpenGLTexture(QOpenGLTexture::Target2D); m_movieSource->setAutoMipMapGenerationEnabled(false); m_movieSource->setFormat(QOpenGLTexture::RGBA8_UNorm); m_movieSource->setSize(dest.width(), dest.height()); m_movieSource->setMipLevels(1); m_movieSource->allocateStorage(QOpenGLTexture::RGB, QOpenGLTexture::UInt8); // 设置纹理环绕方式 m_movieSource->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge); m_movieSource->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge); } QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(1); m_movieSource->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, videoForeImage_.constBits(), &uploadOptions); } void DisplayMovieGLWidget::PlayBackgroundMovie() { #ifdef BG_VLC videoImage_ = QImage(3840, 1200, QImage::Format_RGBA8888); connect(&vlcPlayer_, &VlcMediaListPlayer::VideoDataOutput, this, &DisplayMovieGLWidget::SlotSetOneFrame, Qt::QueuedConnection); vlcPlayer_.SetPlayMode(VlcMediaListPlayer::Loop); const QString filePath = QCoreApplication::applicationDirPath() + "/ProjectDisplay/background/bg.mp4"; QStringList paths; paths.append(filePath); vlcPlayer_.SetResolution(3840, 1200); vlcPlayer_.SetMediaList(paths); vlcPlayer_.Play(); #endif } void DisplayMovieGLWidget::SlotSetOneFrame(QImage image) { #ifdef BG_VLC videoImage_ = image.mirrored(); #endif } void DisplayMovieGLWidget::OnUpdateSourceImage(QImage source, QImage sourceAlpha) { makeCurrent(); QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(1); m_source->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, source.constBits(), &uploadOptions); m_sourceAlpha->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, sourceAlpha.constBits(), &uploadOptions); } void DisplayMovieGLWidget::LoadBackgroundTexture() { #ifndef BG_VLC if (m_textureData.count() >= m_backgroundFrameCount) { return; } QImageReader reader; reader.setAutoTransform(true); reader.setFileName(m_backgourndTexturePaths[m_backgroundCurrentFrame]); QImage image = reader.read(); image = image.mirrored().convertToFormat(QImage::Format_RGB888); m_textureData.emplace_back(std::move(image)); #endif } void DisplayMovieGLWidget::InitMaskImages() { const QString imageDir = QApplication::applicationDirPath() + "/ProjectDisplay/mask"; QStringList jpgFiles; QDir dir(imageDir); QStringList filters; filters << "*.jpg"; // 添加 JPG 的文件扩展名 QFileInfoList fileInfoList = dir.entryInfoList(filters, QDir::Files); // 使用过滤器获取文件列表 m_maskFrameCount = fileInfoList.size(); m_maskTextureData.resize(fileInfoList.size()); foreach(const QFileInfo & fileInfo, fileInfoList) { m_maskTexturePaths.append(fileInfo.absoluteFilePath()); } auto handle = [&](int index, QImage image) { m_maskTextureData[index] = std::move(image); }; QThreadPool pool; pool.setMaxThreadCount(std::thread::hardware_concurrency()); for (int i = 0; i < m_maskTexturePaths.count(); ++i) { LoadImageTask* task = new LoadImageTask(i, m_maskTexturePaths, handle); pool.start(task); } pool.waitForDone(); } void DisplayMovieGLWidget::ReInit() { // m_backgroundCurrentFrame = 0; m_maskFrame = 0; m_colorMaskFrame = 0; m_showSource = false; QTimer::singleShot(5000, [this]() { m_showSource = true; } ); } void DisplayMovieGLWidget::SetNetConnectStatus(int connected) { m_connected = connected; //UpdateNetworkTextImage(); } void DisplayMovieGLWidget::OnMessage(const QString& cmd) { // cmd = "0/0/0" const QStringList params = cmd.split("|"); if (params.count() < 3) { qWarning() << "invalid cmd:" << cmd; return; } int32_t town = params[0].toInt(); int32_t place = params[1].toInt(); int32_t image = params[2].toInt(); if (/*m_place != place*/true) { m_place = place; m_maskFrame = 0; m_colorMaskFrame = 0; m_showSource = false; QDateTime dt = QDateTime::currentDateTime(); m_startTimestamp = dt.toUTC().toMSecsSinceEpoch(); QTimer::singleShot(5000, [this]() { m_showSource = true; }); QTimer::singleShot(100, [this]() { MainWindow::Get().PlayWav(); }); } m_alpha = 0.13f; const QString townName = MainWindow::Get().GetTownName(town); const QString placeName = MainWindow::Get().GetPlaceName(town, place); const QString imageName = MainWindow::Get().GetImageName(town, place, image); /*if (imageName.isEmpty()) { qWarning() << "image name is empty"; return; }*/ const QString& path = QString("%1/ProjectDisplay/images/%2/%3/%4").arg(QApplication::applicationDirPath(), townName, placeName, imageName); UpdateSourceImage(path); m_showText = MainWindow::Get().GetTitleName(town, place); UpdateTextImage(); m_fusion = true; m_delayTime = MainWindow::Get().GetDelayRetore() * 1000; }