Browse Source

V0.7.14
1、添加了OpenGLWidget的api接口,但是还未刷新出来

Apple 1 week ago
parent
commit
519a89e698

+ 2 - 1
CMakeLists.txt

@@ -197,6 +197,7 @@ file(GLOB GLOBAL_SRC
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/DesignerPattern)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/ViewModel)
 add_subdirectory(${CMAKE_SOURCE_DIR}/demo/OpenGLWidget)
-add_subdirectory(${CMAKE_SOURCE_DIR}/demo/VideoPlayerGL)
+# add_subdirectory(${CMAKE_SOURCE_DIR}/demo/VideoPlayerGL)
+add_subdirectory(${CMAKE_SOURCE_DIR}/demo/OpenGLWidgetTest)
 
 

+ 1 - 1
demo/OpenGLWidget/GLShader/ShaderRect.cpp

@@ -125,7 +125,7 @@ bool ShaderRect::initTextures()
 bool ShaderRect::refreshFrameRGBA(const QImage& image, int textureUnit)
 {
     if(image.isNull()) {
-        SPDLOG_WARN("Texture Image is null");
+        SPDLOG_WARN("Image is null");
         return false;
     }
     QOpenGLTexture* texture = m_mapTexture.find(textureUnit)->second;

+ 85 - 0
demo/OpenGLWidget/OpenGLWidgetAPI.cpp

@@ -0,0 +1,85 @@
+#include "OpenGLWidgetAPI.h"
+
+#include "PlayerGLWidget.h"
+
+#include "spdlog/spdlog.h"
+
+/* 创建窗口,返回QWidget指针 */
+QWidget* createOpenGLWidget(QWidget* parent)
+{
+    PlayerGLWidget* widget = new PlayerGLWidget(parent);
+    if(widget == nullptr)
+    {
+        return nullptr; // 创建失败
+    }
+    
+    return widget;
+}
+
+/* 销毁窗口 */
+void destroyOpenGLWidget(QWidget* widget)
+{
+    if(widget == nullptr)
+    {
+        SPDLOG_ERROR("destroyOpenGLWidget: widget is nullptr");
+        return;
+    }
+    
+    PlayerGLWidget* playerWidget = qobject_cast<PlayerGLWidget*>(widget);
+    if(playerWidget == nullptr)
+    {
+        SPDLOG_WARN("destroyOpenGLWidget: widget is not a PlayerGLWidget");
+        return;
+    }
+    delete playerWidget;
+    playerWidget = nullptr;
+    widget = nullptr;
+}
+
+/* 刷新一帧RGBA图片 */
+void refreshRGBAImage(QWidget* widget, QImage& image)
+{
+    if(widget == nullptr)
+    {
+        SPDLOG_ERROR("refreshRGBAImage: widget is nullptr");
+        return;
+    }
+    
+    PlayerGLWidget* playerWidget = qobject_cast<PlayerGLWidget*>(widget);
+    if(playerWidget == nullptr)
+    {
+        SPDLOG_WARN("refreshRGBAImage: widget is not a PlayerGLWidget");
+        return;
+    }
+    
+    playerWidget->showOneRGBAImage(image);
+}
+
+/* 刷新一帧YUV420图片 */
+void refreshYUV420Image(QWidget* widget, Image_YUV420* yuvData)
+{
+    if(widget == nullptr)
+    {
+        SPDLOG_ERROR("refreshYUV420Image: widget is nullptr");
+        return;
+    }
+    
+    PlayerGLWidget* playerWidget = qobject_cast<PlayerGLWidget*>(widget);
+    if(playerWidget == nullptr)
+    {
+        SPDLOG_WARN("refreshYUV420Image: widget is not a PlayerGLWidget");
+        return;
+    }
+    
+    if(yuvData == nullptr || !yuvData->isValid())
+    {
+        SPDLOG_WARN("refreshYUV420Image: yuvData is nullptr or invalid");
+        return;
+    }
+    
+    playerWidget->showOneYUV420Image(*yuvData);
+}
+
+
+
+

+ 23 - 0
demo/OpenGLWidget/OpenGLWidgetAPI.h

@@ -0,0 +1,23 @@
+#ifndef _OPENGLWIDGET_H_
+#define _OPENGLWIDGET_H_
+
+#include <QWidget>
+class QImage;
+
+struct Image_YUV420;
+
+extern "C" {
+
+/* 创建窗口,返回QWidget指针 */
+Q_DECL_EXPORT QWidget* createOpenGLWidget(QWidget* parent = nullptr);
+/* 销毁窗口 */
+Q_DECL_EXPORT void destroyOpenGLWidget(QWidget* widget);
+
+/* 刷新一帧RGBA图片 */
+Q_DECL_EXPORT void refreshRGBAImage(QWidget* widget, QImage& image);
+/* 刷新一帧YUV420图片 */
+Q_DECL_EXPORT void refreshYUV420Image(QWidget* widget, Image_YUV420* yuvData);
+
+};
+
+#endif // _OPENGLWIDGET_H_

+ 109 - 0
demo/OpenGLWidgetTest/CMakeLists.txt

@@ -0,0 +1,109 @@
+cmake_minimum_required(VERSION 3.10)
+
+set(this_exe PlayerGL)
+
+
+
+#包含源文件
+file(GLOB LOCAL_SRC
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.rc
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.ui
+    ${CMAKE_CURRENT_SOURCE_DIR}/OpenGLWidgetAPI/*.cpp
+
+
+    ${CMAKE_SOURCE_DIR}/External/module/Logs/*.cpp
+    ${CMAKE_SOURCE_DIR}/External/module/ThreadPool/*.cpp
+    
+)
+
+
+# 生成可执行程序
+
+add_executable(${this_exe}
+    # WIN32
+    ${GLOBAL_SRC}
+    ${LOCAL_SRC} 
+)
+
+# set_target_properties(${this_exe} PROPERTIES
+    
+# )
+
+
+#添加头文件
+target_include_directories(${this_exe} PRIVATE
+
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/OpenGLWidgetAPI
+
+    ${CMAKE_SOURCE_DIR}/External/common
+    ${CMAKE_SOURCE_DIR}/External/module
+    ${CMAKE_SOURCE_DIR}/External/module/ThreadPool
+    ${CMAKE_SOURCE_DIR}/External/module/RingQueue
+    
+    # ${CURL_INCLUDE_DIR}
+    # ${FFMPEG_INCLUDE_DIR}
+    ${spdlog_INCLUDE_DIR}
+)
+
+
+target_link_libraries(${this_exe} PRIVATE
+    Qt${QT_VERSION_MAJOR}::Widgets
+    Qt${QT_VERSION_MAJOR}::Core
+    Qt${QT_VERSION_MAJOR}::Network
+    # Qt${QT_VERSION_MAJOR}::Gui
+
+)
+
+if(QT_VERSION_MAJOR EQUAL 5)
+    target_link_libraries(${this_exe} PRIVATE
+        Qt5::OpenGL
+    )
+elseif(QT_VERSION_MAJOR EQUAL 6)
+    target_link_libraries(${this_exe} PRIVATE
+        Qt6::OpenGLWidgets
+    )
+endif(QT_VERSION_MAJOR EQUAL 5)
+
+if(CMAKE_SYSTEM_NAME MATCHES "Windows")
+    target_link_libraries(${this_exe} PRIVATE 
+        # ${CURL_LIBRARY}
+        # ${FFMPEG_LIBRARY}
+        ${spdlog_LIBRARY}
+        opengl32
+    )
+elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
+    target_link_libraries(${this_exe} PRIVATE 
+        ${spdlog_LIBRARY}
+        GL
+    )
+endif()
+
+# if(CMAKE_CXX_COMPILER_VERSION LESS 9.0)
+#     target_link_libraries(${this_exe} PRIVATE
+#         stdc++fs
+#     )
+# endif()
+
+
+
+# target_link_libraries(${this_exe} PRIVATE
+#     GL
+#     GUL
+# )
+# message(STATUS "CURL_LIBRARY: ${CURL_LIBRARY}")
+
+
+# if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+#     target_link_libraries(${this_exe} PRIVATE
+#         # debug spdlogd.lib
+#         # optimized spdlog.lib
+#     )
+# elseif(CMAKE_CXX_COMPILER_ID MATCHES GNU)
+#     target_link_libraries(${this_exe} PRIVATE
+#         # debug 
+#         # optimized ${SM_DLL}
+#     )
+# endif()

+ 154 - 0
demo/OpenGLWidgetTest/OpenGLWidgetAPI/OpenGLWidgetAPI.cpp

@@ -0,0 +1,154 @@
+#include "OpenGLWidgetAPI.h"
+
+#include <QApplication>
+#include <QLibrary>
+
+#include "spdlog/spdlog.h"
+
+Image_YUV420::Image_YUV420(Image_YUV420&& other): width(other.width), height(other.height),
+          yData(std::move(other.yData)), uData(std::move(other.uData)), vData(std::move(other.vData))
+{}
+
+Image_YUV420::Image_YUV420(const Image_YUV420& other)
+        : width(other.width), height(other.height),
+          yData(other.yData), uData(other.uData), vData(other.vData)
+{}
+
+Image_YUV420& Image_YUV420::operator=(Image_YUV420&& other) 
+{
+    if (this != &other) {
+        width = other.width;
+        height = other.height;
+        yData = std::move(other.yData);
+        uData = std::move(other.uData);
+        vData = std::move(other.vData);
+    }
+    return *this;
+}
+
+Image_YUV420& Image_YUV420::operator=(const Image_YUV420& other) 
+{
+    if (this != &other) {
+        width = other.width;
+        height = other.height;
+        yData = other.yData;
+        uData = other.uData;
+        vData = other.vData;
+    }
+    return *this;
+}
+
+bool Image_YUV420::isValid() const 
+{
+    return width > 0 && height > 0 && !yData.isEmpty() && !uData.isEmpty() && !vData.isEmpty();
+}
+
+void Image_YUV420::clear()
+{
+    width = 0;
+    height = 0;
+    yData.clear();
+    uData.clear();
+    vData.clear();
+}
+
+/* ----------------------------------------------------------------
+ * OpenGLWidget动态库 API
+ * ---------------------------------------------------------------- */
+
+using funcCreateOpenGLWidget = QWidget* (*)(QWidget*);
+using funcDestroyOpenGLWidget = void (*)(QWidget* widget);
+using funcRefreshRGBAImage = void (*)(QWidget* widget, QImage& image);
+using funcRefreshYUV420Image = void (*)(QWidget* widget, Image_YUV420* yuvData);
+
+
+funcCreateOpenGLWidget pCreateOpenGLWidget = nullptr;
+funcDestroyOpenGLWidget pDestroyOpenGLWidget = nullptr;
+funcRefreshRGBAImage pRefreshRGBAImage = nullptr;
+funcRefreshYUV420Image pRefreshYUV420Image = nullptr;
+
+static bool isLibraryLoaded = false;
+/* 加载动态库 */
+bool loadOpenGLWidgetLibrary()
+{
+    if(isLibraryLoaded) 
+    {
+        return true;
+    }
+
+    QString libPath = QApplication::applicationDirPath();
+#ifdef Q_OS_WIN
+    libPath += "/OpenGLWidget.dll";
+#elif defined(Q_OS_MACOS)
+    libPath += "/libOpenGLWidget.dylib";
+#elif defined(Q_OS_LINUX)
+    libPath += "/libOpenGLWidget.so";
+#endif
+    QLibrary lib(libPath);
+    if (!lib.load()) 
+    {
+        SPDLOG_ERROR("加载OpenGLWidget动态库失败: {}", libPath.toStdString());
+        SPDLOG_ERROR("错误信息: {}", lib.errorString().toStdString());
+        return false;
+    }
+
+    pCreateOpenGLWidget = reinterpret_cast<funcCreateOpenGLWidget>(lib.resolve("createOpenGLWidget"));
+    pDestroyOpenGLWidget = reinterpret_cast<funcDestroyOpenGLWidget>(lib.resolve("destroyOpenGLWidget"));
+    pRefreshRGBAImage = reinterpret_cast<funcRefreshRGBAImage>(lib.resolve("refreshRGBAImage"));
+    pRefreshYUV420Image = reinterpret_cast<funcRefreshYUV420Image>(lib.resolve("refreshYUV420Image"));
+
+    if(!pCreateOpenGLWidget || !pDestroyOpenGLWidget || 
+       !pRefreshRGBAImage || !pRefreshYUV420Image) 
+    {
+        SPDLOG_ERROR("加载OpenGLWidget动态库函数失败");
+        return false;
+    }
+
+    isLibraryLoaded = true;
+    return true;
+}
+
+/* 创建OpenGL窗口,返回QWidget指针 */
+QWidget* createOpenGLWidget(QWidget* parent)
+{
+    if(pCreateOpenGLWidget == nullptr) 
+    {
+        SPDLOG_ERROR("OpenGLWidget动态库函数未加载");
+        return nullptr;
+    }
+    return pCreateOpenGLWidget(parent);
+}
+
+/* 销毁OpenGL窗口 */
+void destroyOpenGLWidget(QWidget* widget)
+{
+    if(pDestroyOpenGLWidget == nullptr) 
+    {
+        SPDLOG_ERROR("OpenGLWidget动态库函数未加载");
+        return;
+    }
+    pDestroyOpenGLWidget(widget);
+}
+
+/* 刷新一帧RGBA图片 */
+void refreshRGBAImage(QWidget* widget, QImage& image)
+{
+    if(pRefreshRGBAImage == nullptr) 
+    {
+        SPDLOG_ERROR("OpenGLWidget动态库函数未加载");
+        return;
+    }
+    pRefreshRGBAImage(widget, image);
+}
+
+/* 刷新一帧YUV420图片 */
+void refreshYUV420Image(QWidget* widget, Image_YUV420& yuvData)
+{
+    if(pRefreshYUV420Image == nullptr) 
+    {
+        SPDLOG_ERROR("OpenGLWidget动态库函数未加载");
+        return;
+    }
+    pRefreshYUV420Image(widget, &yuvData);
+}
+

+ 42 - 0
demo/OpenGLWidgetTest/OpenGLWidgetAPI/OpenGLWidgetAPI.h

@@ -0,0 +1,42 @@
+#ifndef _OPENGLWIDGETAPI_H_
+#define _OPENGLWIDGETAPI_H_
+
+#include <QWidget>
+#include <QString>
+
+/**
+ * @brief YUV420图片格式
+ * 
+ */
+struct Image_YUV420
+{
+    int width;          /* 宽度 */
+    int height;         /* 高度 */
+    QByteArray yData;   /* Y分量数据 */
+    QByteArray uData;   /* U分量数据 */
+    QByteArray vData;   /* V分量数据 */
+
+    Image_YUV420() : width(0), height(0) {}
+    Image_YUV420(Image_YUV420&& other);
+    Image_YUV420(const Image_YUV420& other);
+    Image_YUV420& operator=(Image_YUV420&& other);
+    Image_YUV420& operator=(const Image_YUV420& other);
+    bool isValid() const;
+    void clear();
+};
+
+/* 加载动态库 */
+bool loadOpenGLWidgetLibrary();
+
+/* 创建OpenGL窗口,返回QWidget指针 */
+QWidget* createOpenGLWidget(QWidget* parent = nullptr);
+/* 销毁OpenGL窗口 */
+void destroyOpenGLWidget(QWidget* widget);
+
+/* 刷新一帧RGBA图片 */
+void refreshRGBAImage(QWidget* widget, QImage& image);
+/* 刷新一帧YUV420图片 */
+void refreshYUV420Image(QWidget* widget, Image_YUV420& yuvData);
+
+
+#endif // _OPENGLWIDGETAPI_H_

BIN
demo/OpenGLWidgetTest/image/1.jpg


BIN
demo/OpenGLWidgetTest/image/awesomeface.png


+ 28 - 0
demo/OpenGLWidgetTest/main.cpp

@@ -0,0 +1,28 @@
+#include "widget.h"
+
+#include <QApplication>
+#include "Logs/loginit.h"
+#include "spdlog/spdlog.h"
+#include <QDebug>
+#include <qwidget.h>
+
+// extern "C" {
+// #include <libavcodec/avcodec.h>
+// #include <libavutil/hwcontext.h>
+// }
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+
+    init_log();
+
+    SPDLOG_INFO("********** VideoPlayer **********");
+
+
+    Widget w;
+    w.show();
+
+
+    return a.exec();
+}

+ 6 - 0
demo/OpenGLWidgetTest/res.qrc

@@ -0,0 +1,6 @@
+<RCC>
+    <qresource prefix="/">
+        <file>image/1.jpg</file>
+        <file>image/awesomeface.png</file>
+    </qresource>
+</RCC>

+ 59 - 0
demo/OpenGLWidgetTest/widget.cpp

@@ -0,0 +1,59 @@
+#include "widget.h"
+#include "./ui_widget.h"
+
+#include <QTimer>
+#include "spdlog/spdlog.h"
+
+#include "OpenGLWidgetAPI.h"
+
+Widget::Widget(QWidget *parent)
+    : QWidget(parent)
+    , ui(new Ui::Widget)
+{
+    ui->setupUi(this);
+
+    loadOpenGLWidgetLibrary(); // 加载OpenGL窗口库
+
+    m_playerGLWidget = createOpenGLWidget(ui->widget_display);
+    m_playerGLWidget->show(); // 显示OpenGL窗口
+    m_playerGLWidget->setGeometry(0, 0, ui->widget_display->width(), ui->widget_display->height());
+    m_playerGLWidget->setStyleSheet(R"(border-radius:10px;)");
+
+    /* 设置背景颜色 */
+    this->setAutoFillBackground(true);
+    QPalette palette = m_playerGLWidget->palette();
+    palette.setColor(QPalette::Window, Qt::black); // 设置背景颜色为黑色
+    this->setPalette(palette);
+
+    QImage image = QImage(":/image/1.jpg");
+    connect(&m_timer, &QTimer::timeout, this, [&]() {
+        // SPDLOG_DEBUG("刷新一帧");
+        if(image.isNull()) {
+            SPDLOG_WARN("Image is null, cannot refresh.");
+            return;
+        }
+        refreshRGBAImage(m_playerGLWidget, image); // 显示一张测试图片
+    });
+    m_timer.setSingleShot(false);
+    m_timer.start(10); // 60 FPS
+    
+}
+
+Widget::~Widget()
+{
+
+    delete ui;
+}
+
+void Widget::resizeEvent(QResizeEvent *event) 
+{
+    if (m_playerGLWidget) {
+        m_playerGLWidget->setGeometry(0, 0, ui->widget_display->width(), ui->widget_display->height());
+    }
+    QWidget::resizeEvent(event);
+}
+
+
+
+
+

+ 33 - 0
demo/OpenGLWidgetTest/widget.h

@@ -0,0 +1,33 @@
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include <QWidget>
+#include <memory>
+#include <QTimer>
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class Widget; }
+QT_END_NAMESPACE
+
+class Widget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    Widget(QWidget *parent = nullptr);
+    ~Widget();
+
+private slots:
+
+protected:
+    void resizeEvent(QResizeEvent *event) override;
+    
+private:
+    Ui::Widget *ui;
+
+    QWidget *m_playerGLWidget = nullptr;
+
+    QTimer m_timer;
+
+};
+#endif // WIDGET_H

+ 39 - 0
demo/OpenGLWidgetTest/widget.ui

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget</class>
+ <widget class="QWidget" name="Widget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1600</width>
+    <height>900</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Widget</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>20</number>
+   </property>
+   <property name="topMargin">
+    <number>20</number>
+   </property>
+   <property name="rightMargin">
+    <number>20</number>
+   </property>
+   <property name="bottomMargin">
+    <number>20</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget_display" native="true"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 3 - 3
demo/VideoPlayerGL/widget.cpp

@@ -5,14 +5,13 @@
 #include "spdlog/spdlog.h"
 
 
-
 Widget::Widget(QWidget *parent)
     : QWidget(parent)
     , ui(new Ui::Widget)
 {
     ui->setupUi(this);
 
-    m_playerGLWidget = new PlayerGLWidget(ui->widget_display);
+    m_playerGLWidget = new PlayerGLWidget(this);
     m_playerGLWidget->setGeometry(0, 0, ui->widget_display->width(), ui->widget_display->height());
     m_playerGLWidget->setStyleSheet(R"(border-radius:10px;)");
 
@@ -22,9 +21,10 @@ Widget::Widget(QWidget *parent)
     palette.setColor(QPalette::Window, Qt::black); // 设置背景颜色为黑色
     this->setPalette(palette);
 
+    QImage image = QImage(":/image/1.jpg");
     connect(&m_timer, &QTimer::timeout, this, [=]() {
         // SPDLOG_DEBUG("刷新一帧");
-        m_playerGLWidget->testShowYUV420Image(QImage(":/image/1.jpg")); // 显示一张测试图片
+        m_playerGLWidget->testShowYUV420Image(image); // 显示一张测试图片
     });
     m_timer.setSingleShot(false);
     m_timer.start(10); // 60 FPS