839 lines
28 KiB
C++
839 lines
28 KiB
C++
#include "DisplayMovieGLWidget.h"
|
||
|
||
#include <QApplication>
|
||
#include <QDir>
|
||
#include <QImageReader>
|
||
#include <QPainter>
|
||
#include <QDateTime>
|
||
#include <QThreadPool>
|
||
#include <QStringList>
|
||
#include <QOpenGLPixelTransferOptions>
|
||
|
||
#include "MainWindow.h"
|
||
|
||
class LoadImageTask : public QObject, public QRunnable {
|
||
public:
|
||
using HandleResoult = std::function<void(int index, QImage image)>;
|
||
public:
|
||
LoadImageTask(int index, const QVector<QString>& 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<QString>& 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<const void*>(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<const void*>(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;
|
||
}
|